move a few unmaintained packages from trunk to /packages
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Sun, 7 Oct 2012 12:50:15 +0000 (12:50 +0000)
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Sun, 7 Oct 2012 12:50:15 +0000 (12:50 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/packages@33634 3c298f89-4303-0410-b956-a3cf2f4a3e73

220 files changed:
libs/libipfix/Makefile [new file with mode: 0644]
libs/libipfix/extra/append-wprobe-ie.pl [new file with mode: 0644]
libs/libipfix/extra/wprobe-ie.txt [new file with mode: 0644]
libs/libipfix/patches/100-openimp_sync.patch [new file with mode: 0644]
libs/libipfix/patches/110-wprobe_ie.patch [new file with mode: 0644]
libs/libipfix/patches/120-ipfixmisc.patch [new file with mode: 0644]
net/bridge-utils/Makefile [new file with mode: 0644]
net/bridge-utils/patches/001-libbridge_cflags.patch [new file with mode: 0644]
net/crda/Makefile [new file with mode: 0644]
net/crda/files/hotplug.rule [new file with mode: 0644]
net/crda/patches/101-make_crypto_use_optional.patch [new file with mode: 0644]
net/madwifi/Config.in [new file with mode: 0644]
net/madwifi/Makefile [new file with mode: 0644]
net/madwifi/files/etc/hotplug.d/net/10-madwifi [new file with mode: 0644]
net/madwifi/files/lib/wifi/madwifi.sh [new file with mode: 0755]
net/madwifi/files/lib/wifi/madwifi_countrycodes.txt [new file with mode: 0644]
net/madwifi/patches/102-multicall_binary.patch [new file with mode: 0644]
net/madwifi/patches/104-autocreate_none.patch [new file with mode: 0644]
net/madwifi/patches/105-ratectl_attach.patch [new file with mode: 0644]
net/madwifi/patches/106-get_arch.patch [new file with mode: 0644]
net/madwifi/patches/111-minstrel_crash.patch [new file with mode: 0644]
net/madwifi/patches/113-no_ibss_pwrsave.patch [new file with mode: 0644]
net/madwifi/patches/122-replayfail_workaround.patch [new file with mode: 0644]
net/madwifi/patches/123-ccmp_checks.patch [new file with mode: 0644]
net/madwifi/patches/124-linux24_compat.patch [new file with mode: 0644]
net/madwifi/patches/126-rxerr_frames.patch [new file with mode: 0644]
net/madwifi/patches/200-no_debug.patch [new file with mode: 0644]
net/madwifi/patches/201-debug_fix.patch [new file with mode: 0644]
net/madwifi/patches/202-debug_variables.patch [new file with mode: 0644]
net/madwifi/patches/300-napi_polling.patch [new file with mode: 0644]
net/madwifi/patches/305-pureg_fix.patch [new file with mode: 0644]
net/madwifi/patches/309-micfail_detect.patch [new file with mode: 0644]
net/madwifi/patches/310-noise_get.patch [new file with mode: 0644]
net/madwifi/patches/311-bssid_alloc.patch [new file with mode: 0644]
net/madwifi/patches/312-erpupdate.patch [new file with mode: 0644]
net/madwifi/patches/317-bmask.patch [new file with mode: 0644]
net/madwifi/patches/323-dfs_optional.patch [new file with mode: 0644]
net/madwifi/patches/324-alignment.patch [new file with mode: 0644]
net/madwifi/patches/325-channel_spam.patch [new file with mode: 0644]
net/madwifi/patches/327-queue.patch [new file with mode: 0644]
net/madwifi/patches/330-beaconcal.patch [new file with mode: 0644]
net/madwifi/patches/331-memory_alloc.patch [new file with mode: 0644]
net/madwifi/patches/332-reset_beacons.patch [new file with mode: 0644]
net/madwifi/patches/333-apscan_mode.patch [new file with mode: 0644]
net/madwifi/patches/334-input.patch [new file with mode: 0644]
net/madwifi/patches/340-maxrate.patch [new file with mode: 0644]
net/madwifi/patches/341-minrate.patch [new file with mode: 0644]
net/madwifi/patches/342-performance.patch [new file with mode: 0644]
net/madwifi/patches/343-txqueue_races.patch [new file with mode: 0644]
net/madwifi/patches/344-minstrel_failcnt.patch [new file with mode: 0644]
net/madwifi/patches/345-minstrel_sampling.patch [new file with mode: 0644]
net/madwifi/patches/346-protmode_trig.patch [new file with mode: 0644]
net/madwifi/patches/347-tuning.patch [new file with mode: 0644]
net/madwifi/patches/348-ackcts.patch [new file with mode: 0644]
net/madwifi/patches/349-reset.patch [new file with mode: 0644]
net/madwifi/patches/350-wisoc_softled.patch [new file with mode: 0644]
net/madwifi/patches/351-scanlist.patch [new file with mode: 0644]
net/madwifi/patches/352-ani_fix.patch [new file with mode: 0644]
net/madwifi/patches/353-devid.patch [new file with mode: 0644]
net/madwifi/patches/354-lantiq_eeprom.patch [new file with mode: 0644]
net/madwifi/patches/355-eap_auth_disassoc.patch [new file with mode: 0644]
net/madwifi/patches/356-hidden_ssid.patch [new file with mode: 0644]
net/madwifi/patches/357-bgscan_thresh.patch [new file with mode: 0644]
net/madwifi/patches/358-ignore_broken_bssid.patch [new file with mode: 0644]
net/madwifi/patches/359-disable_reassoc.patch [new file with mode: 0644]
net/madwifi/patches/360-sta_nodes.patch [new file with mode: 0644]
net/madwifi/patches/361-bmiss_handling.patch [new file with mode: 0644]
net/madwifi/patches/362-rssithr.patch [new file with mode: 0644]
net/madwifi/patches/363-fix_turbo.patch [new file with mode: 0644]
net/madwifi/patches/364-memory_alloc.patch [new file with mode: 0644]
net/madwifi/patches/365-turbo_channelsearch.patch [new file with mode: 0644]
net/madwifi/patches/366-bstuck_thresh.patch [new file with mode: 0644]
net/madwifi/patches/367-roaming.patch [new file with mode: 0644]
net/madwifi/patches/368-sta_ie_preserve.patch [new file with mode: 0644]
net/madwifi/patches/369-mlme_assoc.patch [new file with mode: 0644]
net/madwifi/patches/370-wdsvap.patch [new file with mode: 0644]
net/madwifi/patches/372-queue_vif.patch [new file with mode: 0644]
net/madwifi/patches/373-sanity_check.patch [new file with mode: 0644]
net/madwifi/patches/374-nbtt_fix.patch [new file with mode: 0644]
net/madwifi/patches/375-atim_tsf_update.patch [new file with mode: 0644]
net/madwifi/patches/377-disable_vlan_code.patch [new file with mode: 0644]
net/madwifi/patches/378-adhoc_crash_fix.patch [new file with mode: 0644]
net/madwifi/patches/379-invalid_rate_fix.patch [new file with mode: 0644]
net/madwifi/patches/380-noderef_hack.patch [new file with mode: 0644]
net/madwifi/patches/381-ibss_modes.patch [new file with mode: 0644]
net/madwifi/patches/382-relax_bintval.patch [new file with mode: 0644]
net/madwifi/patches/383-ibss_hostap.patch [new file with mode: 0644]
net/madwifi/patches/384-hwdetect.patch [new file with mode: 0644]
net/madwifi/patches/385-antenna_fix.patch [new file with mode: 0644]
net/madwifi/patches/386-acl_crashfix.patch [new file with mode: 0644]
net/madwifi/patches/387-maxassoc.patch [new file with mode: 0644]
net/madwifi/patches/388-apsta_fix.patch [new file with mode: 0644]
net/madwifi/patches/389-autochannel.patch [new file with mode: 0644]
net/madwifi/patches/390-frame_type.patch [new file with mode: 0644]
net/madwifi/patches/391-vap_auth.patch [new file with mode: 0644]
net/madwifi/patches/392-remove_wds_nodetracking.patch [new file with mode: 0644]
net/madwifi/patches/393-mbss_vap_auth.patch [new file with mode: 0644]
net/madwifi/patches/394-probereq.patch [new file with mode: 0644]
net/madwifi/patches/395-ath_ff_unmap.patch [new file with mode: 0644]
net/madwifi/patches/396-napi_ff_fix.patch [new file with mode: 0644]
net/madwifi/patches/400-new_hal.patch [new file with mode: 0644]
net/madwifi/patches/401-changeset_r3602.patch [new file with mode: 0644]
net/madwifi/patches/402-changeset_r3603.patch [new file with mode: 0644]
net/madwifi/patches/403-changeset_r3605.patch [new file with mode: 0644]
net/madwifi/patches/404-linux24_fix.patch [new file with mode: 0644]
net/madwifi/patches/405-retransmit_check.patch [new file with mode: 0644]
net/madwifi/patches/406-monitor_r3711.patch [new file with mode: 0644]
net/madwifi/patches/407-new_athinfo.patch [new file with mode: 0644]
net/madwifi/patches/408-changeset_r3337.patch [new file with mode: 0644]
net/madwifi/patches/409-wext_compat.patch [new file with mode: 0644]
net/madwifi/patches/410-ar231x_2.6.28.patch [new file with mode: 0644]
net/madwifi/patches/411-autochannel_multi.patch [new file with mode: 0644]
net/madwifi/patches/412-fragmentation_fix.patch [new file with mode: 0644]
net/madwifi/patches/413-rxorn.patch [new file with mode: 0644]
net/madwifi/patches/414-txpower.patch [new file with mode: 0644]
net/madwifi/patches/415-chan_switch.patch [new file with mode: 0644]
net/madwifi/patches/416-wprobe.patch [new file with mode: 0644]
net/madwifi/patches/417-beacon_txpower.patch [new file with mode: 0644]
net/madwifi/patches/419-skb_unmap_crash.patch [new file with mode: 0644]
net/madwifi/patches/420-diversity_fix.patch [new file with mode: 0644]
net/madwifi/patches/421-channel_handling.patch [new file with mode: 0644]
net/madwifi/patches/422-confchange_reset.patch [new file with mode: 0644]
net/madwifi/patches/423-phyerr_handling.patch [new file with mode: 0644]
net/madwifi/patches/424-timing.patch [new file with mode: 0644]
net/madwifi/patches/425-rc_rexmit.patch [new file with mode: 0644]
net/madwifi/patches/426-header_len.patch [new file with mode: 0644]
net/madwifi/patches/427-ignore_eeprom_ff.patch [new file with mode: 0644]
net/madwifi/patches/430-use_netdev_priv.patch [new file with mode: 0644]
net/madwifi/patches/431-compile_fixes.patch [new file with mode: 0644]
net/madwifi/patches/432-netdev_ops.patch [new file with mode: 0644]
net/madwifi/patches/433-backport_remove_irq_none.patch [new file with mode: 0644]
net/madwifi/patches/434-name-alloc-fix.patch [new file with mode: 0644]
net/madwifi/patches/435-ibss_neighbor_fix.patch [new file with mode: 0644]
net/madwifi/patches/436-injection_checks.patch [new file with mode: 0644]
net/madwifi/patches/437-sysctl_cleanup.patch [new file with mode: 0644]
net/madwifi/patches/438-poweroffset_sysctl.patch [new file with mode: 0644]
net/madwifi/patches/439-wlanconfig_stack_usage.patch [new file with mode: 0644]
net/madwifi/patches/440-wme_cleanup.patch [new file with mode: 0644]
net/madwifi/patches/441-fix_ibss_node_handling.patch [new file with mode: 0644]
net/madwifi/patches/442-ibss_rx_filter.patch [new file with mode: 0644]
net/madwifi/patches/443-tx_drop_counter.patch [new file with mode: 0644]
net/madwifi/patches/444-beacon_update_war.patch [new file with mode: 0644]
net/madwifi/patches/445-fix_ps_sta_count.patch [new file with mode: 0644]
net/madwifi/patches/446-single_module.patch [new file with mode: 0644]
net/madwifi/patches/447-sta_reconnect.patch [new file with mode: 0644]
net/madwifi/patches/448-beacon_handling_fixes.patch [new file with mode: 0644]
net/madwifi/patches/449-fix_txbuf_leak.patch [new file with mode: 0644]
net/madwifi/patches/450-calibration.patch [new file with mode: 0644]
net/madwifi/patches/451-ibss_race_fix.patch [new file with mode: 0644]
net/madwifi/patches/452-minstrel_no_timer.patch [new file with mode: 0644]
net/madwifi/patches/453-procps.patch [new file with mode: 0644]
net/madwifi/patches/454-cca.patch [new file with mode: 0644]
net/madwifi/patches/455-beacon_watchdog.patch [new file with mode: 0644]
net/madwifi/patches/456-rfsilent.patch [new file with mode: 0644]
net/madwifi/patches/457-idletime.patch [new file with mode: 0644]
net/madwifi/patches/458-ibss_wpa_none.patch [new file with mode: 0644]
net/madwifi/patches/459-2.6.33_compile.patch [new file with mode: 0644]
net/madwifi/patches/460-pci_softled_disable.patch [new file with mode: 0644]
net/madwifi/patches/461-rx_stats_count_fix.patch [new file with mode: 0644]
net/madwifi/patches/462-fix_ap_scan.patch [new file with mode: 0644]
net/madwifi/patches/463-fix_txrate_display.patch [new file with mode: 0644]
net/madwifi/patches/464-0dbm_txpower_fix.patch [new file with mode: 0644]
net/madwifi/patches/465-mc_list-2.6.35.patch [new file with mode: 0644]
net/madwifi/patches/466-2.6.38_compile.patch [new file with mode: 0644]
net/madwifi/patches/470-mac_addresss_from_ath5k_platform_data.patch [new file with mode: 0644]
net/madwifi/patches/471-netdev_ops_mac_mtu.patch [new file with mode: 0644]
net/madwifi/patches/472-remove_11n_devids.patch [new file with mode: 0644]
net/madwifi/patches/473-mutex_fix.patch [new file with mode: 0644]
net/madwifi/patches/474_fix_ssid_scan_length.patch [new file with mode: 0644]
net/madwifi/patches/475-2.6.39-compile.patch [new file with mode: 0644]
net/madwifi/patches/476-3.0_detection_fix.patch [new file with mode: 0644]
net/madwifi/patches/477-3.2_fixes.patch [new file with mode: 0644]
net/madwifi/patches/478-remove_vlan_code.patch [new file with mode: 0644]
net/siit/Makefile [new file with mode: 0644]
net/siit/src/Makefile [new file with mode: 0644]
net/siit/src/siit.c [new file with mode: 0644]
net/siit/src/siit.h [new file with mode: 0644]
net/wprobe/Makefile [new file with mode: 0644]
net/wprobe/files/wprobe.config [new file with mode: 0644]
net/wprobe/files/wprobe.init [new file with mode: 0755]
net/wprobe/src/Makefile.inc [new file with mode: 0644]
net/wprobe/src/exporter/Makefile [new file with mode: 0644]
net/wprobe/src/exporter/wprobe-export.c [new file with mode: 0644]
net/wprobe/src/exporter/wprobe-export.h [new file with mode: 0644]
net/wprobe/src/filter/README.txt [new file with mode: 0644]
net/wprobe/src/filter/gen_filter.pl [new file with mode: 0755]
net/wprobe/src/filter/pfc.c [new file with mode: 0644]
net/wprobe/src/kernel/Makefile [new file with mode: 0644]
net/wprobe/src/kernel/linux/wprobe.h [new file with mode: 0644]
net/wprobe/src/kernel/wprobe-core.c [new file with mode: 0644]
net/wprobe/src/kernel/wprobe-dummy.c [new file with mode: 0644]
net/wprobe/src/user/Makefile [new file with mode: 0644]
net/wprobe/src/user/list.h [new file with mode: 0644]
net/wprobe/src/user/wprobe-lib.c [new file with mode: 0644]
net/wprobe/src/user/wprobe-util.c [new file with mode: 0644]
net/wprobe/src/user/wprobe.h [new file with mode: 0644]
utils/goldfish-qemu/Makefile [new file with mode: 0644]
utils/goldfish-qemu/patches/100-darwin_fix.patch [new file with mode: 0644]
utils/goldfish-qemu/patches/110-single_image.patch [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/arrow_down.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/arrow_left.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/arrow_right.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/arrow_up.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/back.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/device.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/end.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/home.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/key.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/keyboard.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/layout [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/menu.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/power.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/select.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/send.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/spacebar.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/volume_down.png [new file with mode: 0644]
utils/goldfish-qemu/skins/HVGA/volume_up.png [new file with mode: 0644]
utils/ps3-utils/Makefile [new file with mode: 0644]
utils/redboot-ar231x/Makefile [new file with mode: 0644]
utils/redboot-ar231x/patches/010-fix-compile.patch [new file with mode: 0644]

diff --git a/libs/libipfix/Makefile b/libs/libipfix/Makefile
new file mode 100644 (file)
index 0000000..e4c9315
--- /dev/null
@@ -0,0 +1,47 @@
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libipfix
+PKG_VERSION:=r51
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME).$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
+PKG_MD5SUM:=0e5b2871ea20ac48eda3f6006c5dba28
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME).$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libipfix
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=IP Flow Information Export Library
+  URL:=http://www.fokus.fraunhofer.de/de/net/more_about/download/ipfixlib.html
+  BUILDONLY:=1
+endef
+
+TARGET_CFLAGS += \
+       -ffunction-sections -fdata-sections
+
+define Build/Compile
+       $(MAKE) -C $(PKG_BUILD_DIR) \
+               CCOPT="$(TARGET_CFLAGS) -I$(BUILD_DIR)/linux/include" \
+               prefix="$(PKG_INSTALL_DIR)/usr" \
+               exec_prefix="$(PKG_INSTALL_DIR)/usr" \
+               all install
+       $(TARGET_CROSS)ranlib $(PKG_INSTALL_DIR)/usr/lib/libipfix.a
+       $(TARGET_CROSS)ranlib $(PKG_INSTALL_DIR)/usr/lib/libipfixmisc.a
+endef
+
+define Build/InstallDev
+       $(INSTALL_DIR) $(1)
+       $(CP) $(PKG_INSTALL_DIR)/* $(1)/
+endef
+
+$(eval $(call BuildPackage,libipfix))
diff --git a/libs/libipfix/extra/append-wprobe-ie.pl b/libs/libipfix/extra/append-wprobe-ie.pl
new file mode 100644 (file)
index 0000000..8bb658b
--- /dev/null
@@ -0,0 +1,38 @@
+use strict;
+
+my @fields = (
+       [ "_n", "UINT", " - Number of samples", 4 ],
+       [ "_s", "UINT", " - Sum of samples", 8 ],
+       [ "_ss", "UINT", " - Sum of squared samples", 8 ],
+);
+
+my $file = $ARGV[0] or die "Syntax: $0 <file> <start>\n";
+-f $file or die "File not found\n";
+my $start = $ARGV[1];
+$start =~ /^\d+$/ or die "Invalid start number";
+open FILE, "<$file" or die "Can't open file";
+while (<FILE>) {
+       /^(%?)(\w+),\s*(\w+),\s*(.+)$/ and do {
+               my $counter = $1;
+               my $rfield = $2;
+               my $nfield = $3;
+               my $descr = $4;
+               my @f;
+               if ($counter) {
+                       @f = [ "", "UINT", "", 4];
+               } else {
+                       @f = @fields;
+               }
+               foreach my $f (@f) {
+                       my $nr = $start++;
+                       my $n = $f->[0];
+                       my $N = uc $n;
+                       my $ftype = $f->[1];
+                       my $fdesc = $f->[2];
+                       my $size = $f->[3];
+                       print "$nr, IPFIX_FT_WPROBE_$rfield$N, $size, IPFIX_CODING_$ftype, \"$nfield$n\", \"$descr$fdesc\"\n";
+               }
+       };
+}
+close FILE;
+
diff --git a/libs/libipfix/extra/wprobe-ie.txt b/libs/libipfix/extra/wprobe-ie.txt
new file mode 100644 (file)
index 0000000..26d64d2
--- /dev/null
@@ -0,0 +1,14 @@
+NOISE, global_noise, wprobe global noice floor
+PHY_BUSY, global_phy_busy, wprobe global airtime total
+PHY_RX, global_phy_rx, wprobe global airtime total from rx-frame
+PHY_TX, global_phy_tx, wprobe global airtime total from tx-frame
+RSSI, link_rssi, wprobe link received signal strength indication
+SIGNAL, link_signal, wprobe link signal strength in dB
+IEEE_RX_RATE, link_ieee_rx_rate, wprobe link IEEE 802.11 RX data rate
+IEEE_TX_RATE, link_ieee_tx_rate, wprobe link IEEE 802.11 TX data rate
+RETRANSMIT_200, link_retransmit_200, wprobe link total retransmissions per packet - <200 bytes
+RETRANSMIT_400, link_retransmit_400, wprobe link total retransmissions per packet - <400 bytes
+RETRANSMIT_800, link_retransmit_800, wprobe link total retransmissions per packet - <800 bytes
+RETRANSMIT_1600, link_retransmit_1600, wprobe link total retransmissions per packet - >800 bytes
+%FRAMES, global_frames, wprobe global number of 802.11 frames seen
+%PROBEREQ, global_probereq, wprobe global number of 802.11 probe requests seen
diff --git a/libs/libipfix/patches/100-openimp_sync.patch b/libs/libipfix/patches/100-openimp_sync.patch
new file mode 100644 (file)
index 0000000..5b6e2e3
--- /dev/null
@@ -0,0 +1,474 @@
+--- a/lib/ipfix.c
++++ b/lib/ipfix.c
+@@ -37,6 +37,9 @@ $$LIC$$
+ #ifdef SCTPSUPPORT
+ #include <netinet/sctp.h>
+ #endif
++#ifndef NOTHREADS
++#include <pthread.h>
++#endif
+ #include <fcntl.h>
+ #include <netdb.h>
+@@ -123,6 +126,18 @@ static uint16_t           g_lasttid;    
+ static ipfix_datarecord_t g_data = { NULL, NULL, 0 }; /* ipfix_export */
+ static ipfix_field_t      *g_ipfix_fields;
++#ifndef NOTHREADS
++static pthread_mutex_t    g_mutex;
++#define mod_lock()        { \
++                            if ( pthread_mutex_lock( &g_mutex ) !=0 ) \
++                                mlogf( 0, "[ipfix] mutex_lock() failed: %s\n", \
++                                       strerror( errno ) ); \
++                          }
++#define mod_unlock()      {  pthread_mutex_unlock( &g_mutex ); }
++#else
++#define mod_lock()
++#define mod_unlock()
++#endif
+ /*----- prototypes -------------------------------------------------------*/
+@@ -133,6 +148,7 @@ int  _ipfix_send_message( ipfix_t *ifh, 
+                           ipfix_message_t *message );
+ int  _ipfix_write_msghdr( ipfix_t *ifh, ipfix_message_t *msg, iobuf_t *buf );
+ void _ipfix_disconnect( ipfix_collector_t *col );
++int  _ipfix_export_flush( ipfix_t *ifh );
+ /* name      : do_writeselect
+@@ -576,16 +592,18 @@ int ipfix_decode_float( void *in, void *
+ int ipfix_snprint_float( char *str, size_t size, void *data, size_t len )
+ {
+-    float tmp32;
+-    double tmp64;
++    uint32_t tmp32;
++    uint64_t tmp64;
+     switch ( len ) {
+       case 4:
+-          ipfix_decode_float( data, &tmp32, 4);
+-          return snprintf( str, size, "%f", tmp32 );
++          memcpy( &tmp32, data, len );
++          tmp32 = htonl( tmp32 );
++          return snprintf( str, size, "%f", (float)tmp32 );
+       case 8:
+-          ipfix_decode_float( data, &tmp64, 8);
+-          return snprintf( str, size, "%lf", tmp64);
++          memcpy( &tmp64, data, len );
++          tmp64 = HTONLL( tmp64 );
++          return snprintf( str, size, "%lf", (double)tmp64 );
+       default:
+           break;
+     }
+@@ -682,12 +700,19 @@ int ipfix_get_eno_ieid( char *field, int
+  * parameters:
+  * remarks:     init module, read field type info.
+  */
+-int ipfix_init ( void )
++int ipfix_init( void )
+ {
+     if ( g_tstart ) {
+         ipfix_cleanup();
+     }
++#ifndef NOTHREADS
++    if ( pthread_mutex_init( &g_mutex, NULL ) !=0 ) {
++        mlogf( 0, "[ipfix] pthread_mutex_init() failed: %s\n",
++               strerror(errno) );
++        return -1;
++    }
++#endif
+     g_tstart = time(NULL);
+     signal( SIGPIPE, SIG_IGN );
+     g_lasttid = 255;
+@@ -806,6 +831,9 @@ void ipfix_cleanup ( void )
+     g_data.maxfields = 0;
+     g_data.lens  = NULL;
+     g_data.addrs = NULL;
++#ifndef NOTHREADS
++    (void)pthread_mutex_destroy( &g_mutex );
++#endif
+ }
+ int _ipfix_connect ( ipfix_collector_t *col )
+@@ -1465,7 +1493,7 @@ int _ipfix_write_template( ipfix_t      
+       default:
+           /* check space */
+           if ( tsize+ifh->offset > IPFIX_DEFAULT_BUFLEN ) {
+-              if ( ipfix_export_flush( ifh ) < 0 )
++              if ( _ipfix_export_flush( ifh ) < 0 )
+                   return -1;
+               if ( tsize+ifh->offset > IPFIX_DEFAULT_BUFLEN )
+                   return -1;
+@@ -1474,6 +1502,8 @@ int _ipfix_write_template( ipfix_t      
+           /* write template prior to data */
+           if ( ifh->offset > 0 ) {
+               memmove( ifh->buffer + tsize, ifh->buffer, ifh->offset );
++              if ( ifh->cs_tid )
++                  ifh->cs_header += tsize;
+           }
+           buf = ifh->buffer;
+@@ -1615,8 +1645,11 @@ int ipfix_open( ipfix_t **ipfixh, int so
+         return -1;
+     }
+     node->ifh   = i;
++
++    mod_lock();
+     node->next  = g_ipfixlist;
+     g_ipfixlist = node;
++    mod_unlock();
+     *ipfixh = i;
+     return 0;
+@@ -1633,7 +1666,8 @@ void ipfix_close( ipfix_t *h )
+     {
+         ipfix_node_t *l, *n;
+-        ipfix_export_flush( h );
++        mod_lock();
++        _ipfix_export_flush( h );
+         while( h->collectors )
+             _ipfix_drop_collector( (ipfix_collector_t**)&h->collectors );
+@@ -1659,6 +1693,7 @@ void ipfix_close( ipfix_t *h )
+ #endif
+         free(h->buffer);
+         free(h);
++        mod_unlock();
+     }
+ }
+@@ -2156,6 +2191,22 @@ void ipfix_release_template( ipfix_t *if
+     ipfix_delete_template( ifh, templ );
+ }
++static void _finish_cs( ipfix_t *ifh )
++{
++    size_t   buflen;
++    uint8_t  *buf;
++
++    /* finish current dataset */
++    if ( (buf=ifh->cs_header) ==NULL )
++        return;
++    buflen = 0;
++    INSERTU16( buf+buflen, buflen, ifh->cs_tid );
++    INSERTU16( buf+buflen, buflen, ifh->cs_bytes );
++    ifh->cs_bytes = 0;
++    ifh->cs_header = NULL;
++    ifh->cs_tid = 0;
++}
++
+ int ipfix_export( ipfix_t *ifh, ipfix_template_t *templ, ... )
+ {
+     int       i;
+@@ -2199,13 +2250,14 @@ int ipfix_export( ipfix_t *ifh, ipfix_te
+                                g_data.addrs, g_data.lens );
+ }
+-int ipfix_export_array( ipfix_t          *ifh,
+-                        ipfix_template_t *templ,
+-                        int              nfields,
+-                        void             **fields,
+-                        uint16_t         *lengths )
++static int
++_ipfix_export_array( ipfix_t          *ifh,
++                     ipfix_template_t *templ,
++                     int              nfields,
++                     void             **fields,
++                     uint16_t         *lengths )
+ {
+-    int               i;
++    int               i, newset_f=0;
+     size_t            buflen, datasetlen;
+     uint8_t           *p, *buf;
+@@ -2249,7 +2301,19 @@ int ipfix_export_array( ipfix_t         
+     /** get size of data set, check space
+      */
+-    for ( i=0, datasetlen=4; i<nfields; i++ ) {
++    if ( templ->tid == ifh->cs_tid ) {
++        newset_f = 0;
++        datasetlen = 0;
++    }
++    else {
++        if ( ifh->cs_tid > 0 ) {
++            _finish_cs( ifh );
++        }
++        newset_f = 1;
++        datasetlen = 4;
++    }
++
++    for ( i=0; i<nfields; i++ ) {
+         if ( templ->fields[i].flength == IPFIX_FT_VARLEN ) {
+             if ( lengths[i]>254 )
+                 datasetlen += 3;
+@@ -2263,21 +2327,29 @@ int ipfix_export_array( ipfix_t         
+         }
+         datasetlen += lengths[i];
+     }
+-    if ( ((ifh->offset + datasetlen) > IPFIX_DEFAULT_BUFLEN )
+-         && (ipfix_export_flush( ifh ) <0) ) {
+-        return -1;
++
++    if ( (ifh->offset + datasetlen) > IPFIX_DEFAULT_BUFLEN ) {
++        if ( ifh->cs_tid )
++            _finish_cs( ifh );
++        newset_f = 1;
++
++        if ( _ipfix_export_flush( ifh ) <0 )
++            return -1;
+     }
+-    /* fill buffer
+-     */
++    /* fill buffer */
+     buf    = (uint8_t*)(ifh->buffer) + ifh->offset;
+     buflen = 0;
+-    /* insert data set
+-     */
+-    ifh->nrecords ++;
+-    INSERTU16( buf+buflen, buflen, templ->tid );
+-    INSERTU16( buf+buflen, buflen, datasetlen );
++    if ( newset_f ) {
++        /* insert data set
++         */
++        ifh->cs_bytes = 0;
++        ifh->cs_header = buf;
++        ifh->cs_tid = templ->tid;
++        INSERTU16( buf+buflen, buflen, templ->tid );
++        INSERTU16( buf+buflen, buflen, 4 );
++    }
+     /* insert data record
+      */
+@@ -2303,7 +2375,9 @@ int ipfix_export_array( ipfix_t         
+         buflen += lengths[i];
+     }
++    ifh->nrecords ++;
+     ifh->offset += buflen;
++    ifh->cs_bytes += buflen;
+     if ( ifh->version == IPFIX_VERSION )
+         ifh->seqno ++;
+     return 0;
+@@ -2313,7 +2387,7 @@ int ipfix_export_array( ipfix_t         
+  * parameters:
+  * remarks:     rewrite this func!
+  */
+-int ipfix_export_flush( ipfix_t *ifh )
++int _ipfix_export_flush( ipfix_t *ifh )
+ {
+     iobuf_t           *buf;
+     ipfix_collector_t *col;
+@@ -2322,8 +2396,14 @@ int ipfix_export_flush( ipfix_t *ifh )
+     if ( (ifh==NULL) || (ifh->offset==0) )
+         return 0;
+-    if ( (buf=_ipfix_getbuf()) ==NULL )
++    if ( ifh->cs_tid > 0 ) {
++        /* finish current dataset */
++        _finish_cs( ifh );
++    }
++
++    if ( (buf=_ipfix_getbuf()) ==NULL ) {
+         return -1;
++    }
+ #ifdef DEBUG
+     mlogf( 0, "[ipfix_export_flush] msg has %d records, %d bytes\n",
+@@ -2350,3 +2430,30 @@ int ipfix_export_flush( ipfix_t *ifh )
+     _ipfix_freebuf( buf );
+     return ret;
+ }
++
++int ipfix_export_array( ipfix_t          *ifh,
++                        ipfix_template_t *templ,
++                        int              nfields,
++                        void             **fields,
++                        uint16_t         *lengths )
++{
++    int ret;
++
++    mod_lock();
++    ret = _ipfix_export_array( ifh, templ, nfields, fields, lengths );
++    mod_unlock();
++
++    return ret;
++}
++
++int ipfix_export_flush( ipfix_t *ifh )
++{
++    int ret;
++
++    mod_lock();
++    ret = _ipfix_export_flush( ifh );
++    mod_unlock();
++
++    return ret;
++}
++
+--- a/lib/ipfix.h
++++ b/lib/ipfix.h
+@@ -142,6 +142,12 @@ typedef struct
+     int         nrecords;         /* no. of records in buffer */
+     size_t      offset;           /* output buffer fill level */
+     uint32_t    seqno;            /* sequence no. of next message */
++
++    /* experimental */
++    int        cs_tid;            /* template id of current dataset */
++    int        cs_bytes;          /* size of current set */
++    uint8_t    *cs_header;        /* start of current set */
++
+ } ipfix_t;
+ /** exporter funcs
+--- a/lib/ipfix_col.c
++++ b/lib/ipfix_col.c
+@@ -897,6 +897,8 @@ int ipfix_decode_datarecord( ipfixt_node
+             return -1;
+         }
++        n->ipfixt->fields[i].elem->decode(p,p,len);
++
+         data->lens[i]  = len;
+         data->addrs[i] = p;
+@@ -907,7 +909,7 @@ int ipfix_decode_datarecord( ipfixt_node
+     return 0;
+ }
+-static void do_free_datarecord( ipfix_datarecord_t   *data )
++void ipfix_free_datarecord( ipfix_datarecord_t   *data )
+ { 
+     if ( data ) {
+         if ( data->addrs )
+@@ -925,6 +927,7 @@ int ipfix_parse_msg( ipfix_input_t *inpu
+     ipfix_hdr_t          hdr;                  /* ipfix packet header */
+     ipfixs_node_t        *s;
+     ipfix_datarecord_t   data = { NULL, NULL, 0 };
++    ipfixe_node_t        *e;
+     uint8_t              *buf;                 /* ipfix payload */
+     uint16_t             setid, setlen;        /* set id, set lenght */
+     int                  i, nread, offset;     /* counter */
+@@ -1042,6 +1045,12 @@ int ipfix_parse_msg( ipfix_input_t *inpu
+                 err_flag = 1;
+             } 
+             else {
++                for ( e=g_exporter; e!=NULL; e=e->next ) {
++                    if ( e->elem->export_dset )
++                        (void) e->elem->export_dset( t, buf+nread, setlen,
++                                                     e->elem->data );
++                }
++
+                 /** read data records
+                  */
+                 for ( offset=nread, bytesleft=setlen; bytesleft>4; ) {
+@@ -1076,11 +1085,11 @@ int ipfix_parse_msg( ipfix_input_t *inpu
+         goto errend;
+  end:
+-    do_free_datarecord( &data );
++    ipfix_free_datarecord( &data );
+     return nread;
+  errend:
+-    do_free_datarecord( &data );
++    ipfix_free_datarecord( &data );
+     return -1;
+ }
+@@ -1093,7 +1102,7 @@ void process_client_tcp( int fd, int mas
+     tcp_conn_t   *tcon = (tcp_conn_t*)data;
+     char         *func = "process_client_tcp";
+-    mlogf( 3,  "[%s] fd %d mask %d called.\n", func, fd, mask );
++    mlogf( 4,  "[%s] fd %d mask %d called.\n", func, fd, mask );
+     /** read ipfix header 
+      */
+--- a/lib/ipfix_col.h
++++ b/lib/ipfix_col.h
+@@ -88,6 +88,7 @@ typedef struct ipfix_col_info
+     int (*export_newsource)(ipfixs_node_t*,void*);
+     int (*export_newmsg)(ipfixs_node_t*,ipfix_hdr_t*,void*);
+     int (*export_trecord)(ipfixs_node_t*,ipfixt_node_t*,void*);
++    int (*export_dset)(ipfixt_node_t*,uint8_t*,size_t,void*);
+     int (*export_drecord)(ipfixs_node_t*,ipfixt_node_t*,
+                           ipfix_datarecord_t*,void*);
+     void (*export_cleanup)(void*);
+--- a/lib/ipfix_col_files.c
++++ b/lib/ipfix_col_files.c
+@@ -68,7 +68,7 @@ static int export_newsource_file( ipfixs
+             return -1;
+         }
+         snprintf( s->fname+strlen(s->fname), PATH_MAX-strlen(s->fname),
+-                  "/%u", s->odid );
++                  "/%u", (unsigned int)s->odid );
+         if ( (access( s->fname, R_OK ) <0 )
+              && (mkdir( s->fname, S_IRWXU ) <0) ) {
+             mlogf( 0, "[%s] cannot access dir '%s': %s\n",
+--- a/lib/ipfix_FOKUS_IEs.txt
++++ b/lib/ipfix_FOKUS_IEs.txt
+@@ -24,6 +24,8 @@
+ 196, IPFIX_FT_PKTID,                4, IPFIX_CODING_UINT, "pktId", "FOKUS packet id"
+ 197, IPFIX_FT_STARTTIME,            4, IPFIX_CODING_INT, "startTime", "FOKUS interval start"
+ 198, IPFIX_FT_ENDTIME,              4, IPFIX_CODING_INT, "endTime", "FOKUS interval end"
++199, IPFIX_FT_RTT_USEC,             8, IPFIX_CODING_UINT, "rtt_usec", "FOKUS rtt in us"
++
+ 300, IPFIX_FT_FLOWCREATIONTIMEUSEC, 4, IPFIX_CODING_INT, "flowCreationTimeUsec", "FOKUS flow start usec fraction"
+ 301, IPFIX_FT_FLOWENDTIMEUSEC,      4, IPFIX_CODING_INT, "flowEndTimeUsec", "FOKUS flow end usec fraction"
+ 303, IPFIX_FT_TC_PACKETS,           4, IPFIX_CODING_UINT, "tcPackets", "DAIDALOS Packets seen"
+@@ -39,3 +41,48 @@
+ 313, IPFIX_FT_OWDVARMIN_NSEC,       4, IPFIX_CODING_INT, "owdvarmin_nsec", "FOKUS minimum owd variance in ns"
+ 314, IPFIX_FT_OWDVARMAX_NSEC,       4, IPFIX_CODING_INT, "owdvarmax_nsec", "FOKUS maximum ow variance in ns"
++# Project INTERSECTION
++315, IPFIX_FT_SOURCEIPV4FANOUT,     4, IPFIX_CODING_UINT,"sourceIPv4FanOut", "FOKUS IPv4 fanout"
++316, IPFIX_FT_DESTINATIONIPV4FANIN, 4, IPFIX_CODING_UINT,"destinationIPv4FanIn", "FOKUS IPv4 fanin"
++
++# Project PRISM
++
++330, IPFIX_FT_PR_SESSIONID,   4, IPFIX_CODING_UINT, "sessionId", "PRISM Session ID"
++331, IPFIX_FT_PR_TRANSACTIONID, 4, IPFIX_CODING_UINT, "transactionId", "PRISM Transaction ID"
++332, IPFIX_FT_PR_ENCRYPTEDDATA, 65535, IPFIX_CODING_STRING, "encryptedData", "PRISM encrypted data"
++333, IPFIX_FT_PR_DECRYPTIONKEY, 65535, IPFIX_CODING_STRING, "decryptionKey", "PRISM decryption key"
++334, IPFIX_FT_PR_KEYSHARE,      65535, IPFIX_CODING_STRING, "keyShare", "PRISM key share"
++335, IPFIX_FT_PR_KEYSHAREADP,   65535, IPFIX_CODING_STRING, "keyShareAdp", "PRISM key share ADP"
++336, IPFIX_FT_PR_INITVECTOR,    65535, IPFIX_CODING_STRING, "cryptoInitVector", "PRISM crypto init vector"
++
++
++# these information elements have been defined by FOKUS for the Oracle project
++
++402, IPFIX_FT_ORsignalBandwidth, 4, IPFIX_CODING_UINT, "ORsignalBandwidth", "signal bandwidth" 
++403, IPFIX_FT_ORsignalPower, 2, IPFIX_CODING_UINT, "ORsignalPower", "ERIP" 
++404, IPFIX_FT_ORmodulationType, 2, IPFIX_CODING_UINT, "ORmodulationType", "AM/FM,.."
++405, IPFIX_FT_ORsymbolRate, 2, IPFIX_CODING_UINT, "ORsymbolRate", "symbol rate"
++406, IPFIX_FT_ORmodulationOrder, 1, IPFIX_CODING_UINT, "ORmodulationOrder", "number of levels"
++407, IPFIX_FT_ORrolloffFactor, 2, IPFIX_CODING_UINT, "ORrolloffFactor", "roll of factor"
++408, IPFIX_FT_ORgeopositionLon, 4, IPFIX_CODING_UINT, "ORgeopositionLon", "GPS coordinate, resolution 1 cm"
++409, IPFIX_FT_ORgeopositionLat, 4, IPFIX_CODING_UINT, "ORgeopositionLat", "GPS coordinate, resolution 1 cm"
++410, IPFIX_FT_ORgeopositionElev, 4, IPFIX_CODING_UINT, "ORgeopositionElev", "GPS coordinate, resolution 1 cm"
++411, IPFIX_FT_ORpolicyRecord, 65535, IPFIX_CODING_STRING, "ORpolicyRecord", "policy record has variable length, First 8 bits in data describe the length (in bytes) of the field"
++420, IPFIX_FT_channel_status, 1, IPFIX_CODING_UINT, "channel_status", vacancy of the scanned channel (1: channel busy, 0: channel idle)"
++421, IPFIX_FT_sensing_value, 2, IPFIX_CODING_UINT, "sensing_value", "Cost function output"
++422, IPFIX_FT_sensing_threshold, 2, IPFIX_CODING_UINT, "sensing_threshold", "Decision threshold"
++423, IPFIX_FT_OR_terminal_id, 1, IPFIX_CODING_UINT, "OR_terminal_id", "terminal identifier"
++424, IPFIX_FT_OR_terminal_id_list, 65535, IPFIX_CODING_STRING, "OR_terminal_id_list", "terminal identifier list"
++425, IPFIX_FT_Infrastructure_network_id, 1, IPFIX_CODING_UINT, "Infrastructure_network_id", "network identifier"
++426, IPFIX_FT_Infrastructure_network_type, 1, IPFIX_CODING_UINT, "Infrastructure_network_type", "network type (GSM - 1, UMTS - 2, WiMAX - 3, WiFi - 4)" 
++427, IPFIX_FT_Battery_lifetime_min, 1, IPFIX_CODING_UINT, "Battery_lifetime_min", "expected battery lifetime to provide requested services or functionalities, in minutes"
++428, IPFIX_FT_Battery_lifetime_h, 1, IPFIX_CODING_UINT, "Battery_lifetime_h", "expected battery lifetime to provide requested services or functionalities, in hours"
++429, IPFIX_FT_Battery_status, 1, IPFIX_CODING_UINT, "Battery_status", "expected battery lifetime to provide requested services or functionalities, 1 bit status flag, values 1 or 0"
++430, IPFIX_FT_Cell_id_number, 4, IPFIX_CODING_UINT, "Cell_id_number", "16-32 bit cell id number, identifier"
++431, IPFIX_FT_Spectral_allocation_vector, 1, IPFIX_CODING_UINT, "Spectral_allocation_vector", "binary vector to indicate whether a band is free 1 bit 0 or not 1 bit 1"
++432, IPFIX_FT_Spectral_allocation_profile, 2, IPFIX_CODING_UINT, "Spectral_allocation_profile", "received power spectral density vs. frequency to indicate spectral activity in the band of interest (8-16 bits per discrete frequency value)"
++433, IPFIX_FT_Center_frequency, 2, IPFIX_CODING_UINT, "Center_frequency", "Center frequency of the sensed band"
++434, IPFIX_FT_Bandwidth_of_CAP, 2, IPFIX_CODING_UINT, "Bandwidth_of_CAP", "Bandwidth of the spectral allocation profile"
++435, IPFIX_FT_ORmodulation, 1, IPFIX_CODING_UINT, "ORmodulation", "CREST factor"
++436, IPFIX_FT_ORprofileRecord, 65535, IPFIX_CODING_STRING, "ORprofileRecord", "profile record has variable length, First 8 bits in data describe the length (in bytes) of the field"
++
diff --git a/libs/libipfix/patches/110-wprobe_ie.patch b/libs/libipfix/patches/110-wprobe_ie.patch
new file mode 100644 (file)
index 0000000..5e37280
--- /dev/null
@@ -0,0 +1,44 @@
+--- a/lib/ipfix_FOKUS_IEs.txt
++++ b/lib/ipfix_FOKUS_IEs.txt
+@@ -86,3 +86,41 @@
+ 435, IPFIX_FT_ORmodulation, 1, IPFIX_CODING_UINT, "ORmodulation", "CREST factor"
+ 436, IPFIX_FT_ORprofileRecord, 65535, IPFIX_CODING_STRING, "ORprofileRecord", "profile record has variable length, First 8 bits in data describe the length (in bytes) of the field"
++500, IPFIX_FT_WPROBE_NOISE_N, 4, IPFIX_CODING_UINT, "global_noise_n", "wprobe global noice floor - Number of samples"
++501, IPFIX_FT_WPROBE_NOISE_S, 8, IPFIX_CODING_UINT, "global_noise_s", "wprobe global noice floor - Sum of samples"
++502, IPFIX_FT_WPROBE_NOISE_SS, 8, IPFIX_CODING_UINT, "global_noise_ss", "wprobe global noice floor - Sum of squared samples"
++503, IPFIX_FT_WPROBE_PHY_BUSY_N, 4, IPFIX_CODING_UINT, "global_phy_busy_n", "wprobe global airtime total - Number of samples"
++504, IPFIX_FT_WPROBE_PHY_BUSY_S, 8, IPFIX_CODING_UINT, "global_phy_busy_s", "wprobe global airtime total - Sum of samples"
++505, IPFIX_FT_WPROBE_PHY_BUSY_SS, 8, IPFIX_CODING_UINT, "global_phy_busy_ss", "wprobe global airtime total - Sum of squared samples"
++506, IPFIX_FT_WPROBE_PHY_RX_N, 4, IPFIX_CODING_UINT, "global_phy_rx_n", "wprobe global airtime total from rx-frame - Number of samples"
++507, IPFIX_FT_WPROBE_PHY_RX_S, 8, IPFIX_CODING_UINT, "global_phy_rx_s", "wprobe global airtime total from rx-frame - Sum of samples"
++508, IPFIX_FT_WPROBE_PHY_RX_SS, 8, IPFIX_CODING_UINT, "global_phy_rx_ss", "wprobe global airtime total from rx-frame - Sum of squared samples"
++509, IPFIX_FT_WPROBE_PHY_TX_N, 4, IPFIX_CODING_UINT, "global_phy_tx_n", "wprobe global airtime total from tx-frame - Number of samples"
++510, IPFIX_FT_WPROBE_PHY_TX_S, 8, IPFIX_CODING_UINT, "global_phy_tx_s", "wprobe global airtime total from tx-frame - Sum of samples"
++511, IPFIX_FT_WPROBE_PHY_TX_SS, 8, IPFIX_CODING_UINT, "global_phy_tx_ss", "wprobe global airtime total from tx-frame - Sum of squared samples"
++512, IPFIX_FT_WPROBE_RSSI_N, 4, IPFIX_CODING_UINT, "link_rssi_n", "wprobe link received signal strength indication - Number of samples"
++513, IPFIX_FT_WPROBE_RSSI_S, 8, IPFIX_CODING_UINT, "link_rssi_s", "wprobe link received signal strength indication - Sum of samples"
++514, IPFIX_FT_WPROBE_RSSI_SS, 8, IPFIX_CODING_UINT, "link_rssi_ss", "wprobe link received signal strength indication - Sum of squared samples"
++515, IPFIX_FT_WPROBE_SIGNAL_N, 4, IPFIX_CODING_UINT, "link_signal_n", "wprobe link signal strength in dB - Number of samples"
++516, IPFIX_FT_WPROBE_SIGNAL_S, 8, IPFIX_CODING_UINT, "link_signal_s", "wprobe link signal strength in dB - Sum of samples"
++517, IPFIX_FT_WPROBE_SIGNAL_SS, 8, IPFIX_CODING_UINT, "link_signal_ss", "wprobe link signal strength in dB - Sum of squared samples"
++518, IPFIX_FT_WPROBE_IEEE_RX_RATE_N, 4, IPFIX_CODING_UINT, "link_ieee_rx_rate_n", "wprobe link IEEE 802.11 RX data rate - Number of samples"
++519, IPFIX_FT_WPROBE_IEEE_RX_RATE_S, 8, IPFIX_CODING_UINT, "link_ieee_rx_rate_s", "wprobe link IEEE 802.11 RX data rate - Sum of samples"
++520, IPFIX_FT_WPROBE_IEEE_RX_RATE_SS, 8, IPFIX_CODING_UINT, "link_ieee_rx_rate_ss", "wprobe link IEEE 802.11 RX data rate - Sum of squared samples"
++521, IPFIX_FT_WPROBE_IEEE_TX_RATE_N, 4, IPFIX_CODING_UINT, "link_ieee_tx_rate_n", "wprobe link IEEE 802.11 TX data rate - Number of samples"
++522, IPFIX_FT_WPROBE_IEEE_TX_RATE_S, 8, IPFIX_CODING_UINT, "link_ieee_tx_rate_s", "wprobe link IEEE 802.11 TX data rate - Sum of samples"
++523, IPFIX_FT_WPROBE_IEEE_TX_RATE_SS, 8, IPFIX_CODING_UINT, "link_ieee_tx_rate_ss", "wprobe link IEEE 802.11 TX data rate - Sum of squared samples"
++524, IPFIX_FT_WPROBE_RETRANSMIT_200_N, 4, IPFIX_CODING_UINT, "link_retransmit_200_n", "wprobe link total retransmissions per packet - <200 bytes - Number of samples"
++525, IPFIX_FT_WPROBE_RETRANSMIT_200_S, 8, IPFIX_CODING_UINT, "link_retransmit_200_s", "wprobe link total retransmissions per packet - <200 bytes - Sum of samples"
++526, IPFIX_FT_WPROBE_RETRANSMIT_200_SS, 8, IPFIX_CODING_UINT, "link_retransmit_200_ss", "wprobe link total retransmissions per packet - <200 bytes - Sum of squared samples"
++527, IPFIX_FT_WPROBE_RETRANSMIT_400_N, 4, IPFIX_CODING_UINT, "link_retransmit_400_n", "wprobe link total retransmissions per packet - <400 bytes - Number of samples"
++528, IPFIX_FT_WPROBE_RETRANSMIT_400_S, 8, IPFIX_CODING_UINT, "link_retransmit_400_s", "wprobe link total retransmissions per packet - <400 bytes - Sum of samples"
++529, IPFIX_FT_WPROBE_RETRANSMIT_400_SS, 8, IPFIX_CODING_UINT, "link_retransmit_400_ss", "wprobe link total retransmissions per packet - <400 bytes - Sum of squared samples"
++530, IPFIX_FT_WPROBE_RETRANSMIT_800_N, 4, IPFIX_CODING_UINT, "link_retransmit_800_n", "wprobe link total retransmissions per packet - <800 bytes - Number of samples"
++531, IPFIX_FT_WPROBE_RETRANSMIT_800_S, 8, IPFIX_CODING_UINT, "link_retransmit_800_s", "wprobe link total retransmissions per packet - <800 bytes - Sum of samples"
++532, IPFIX_FT_WPROBE_RETRANSMIT_800_SS, 8, IPFIX_CODING_UINT, "link_retransmit_800_ss", "wprobe link total retransmissions per packet - <800 bytes - Sum of squared samples"
++533, IPFIX_FT_WPROBE_RETRANSMIT_1600_N, 4, IPFIX_CODING_UINT, "link_retransmit_1600_n", "wprobe link total retransmissions per packet - >800 bytes - Number of samples"
++534, IPFIX_FT_WPROBE_RETRANSMIT_1600_S, 8, IPFIX_CODING_UINT, "link_retransmit_1600_s", "wprobe link total retransmissions per packet - >800 bytes - Sum of samples"
++535, IPFIX_FT_WPROBE_RETRANSMIT_1600_SS, 8, IPFIX_CODING_UINT, "link_retransmit_1600_ss", "wprobe link total retransmissions per packet - >800 bytes - Sum of squared samples"
++536, IPFIX_FT_WPROBE_FRAMES, 4, IPFIX_CODING_UINT, "global_frames", "wprobe global number of 802.11 frames seen"
++537, IPFIX_FT_WPROBE_PROBEREQ, 4, IPFIX_CODING_UINT, "global_probereq", "wprobe global number of 802.11 probe requests seen"
diff --git a/libs/libipfix/patches/120-ipfixmisc.patch b/libs/libipfix/patches/120-ipfixmisc.patch
new file mode 100644 (file)
index 0000000..e3f5a05
--- /dev/null
@@ -0,0 +1,27 @@
+Index: libipfix.r51/lib/Makefile.in
+===================================================================
+--- libipfix.r51.orig/lib/Makefile.in  2008-08-05 15:15:23.000000000 +0200
++++ libipfix.r51/lib/Makefile.in       2012-06-05 19:26:34.061692890 +0200
+@@ -41,7 +41,7 @@
+ INCLS = -I. -I..
+ CFLAGS = $(CCOPT) $(INCLS) $(DEFS)
+-TARGETS = libmisc.a libipfix.a
++TARGETS = libipfixmisc.a libipfix.a
+ OBJS = ipfix.o ipfix_col.o ipfix_print.o \
+        ipfix_col_files.o ipfix_col_db.o @IPFIX_DB_OBJ@ @IPFIX_SSL_OBJ@
+ DEPHDR = ipfix.h ipfix_def.h ipfix_fields.h ipfix_def_fokus.h ipfix_fields_fokus.h
+@@ -60,11 +60,11 @@
+ install:
+       @[ -d ${libdir} ] || (mkdir -p ${libdir}; chmod 755 ${libdir})
+       $(INSTALL_DATA) libipfix.a ${libdir}/
+-      $(INSTALL_DATA) libmisc.a ${libdir}/
++      $(INSTALL_DATA) libipfixmisc.a ${libdir}/
+       @[ -d ${includedir} ] || (mkdir -p ${includedir}; chmod 755 ${includedir})
+       $(INSTALL_HEADER) ipfix*.h mlog.h mpoll.h ${includedir}/
+-libmisc.a: $(MISCOBJS) Makefile
++libipfixmisc.a: $(MISCOBJS) Makefile
+       @rm -f $@
+       $(AR) rc $@ $(MISCOBJS) 
diff --git a/net/bridge-utils/Makefile b/net/bridge-utils/Makefile
new file mode 100644 (file)
index 0000000..f87551c
--- /dev/null
@@ -0,0 +1,51 @@
+# 
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=bridge-utils
+PKG_RELEASE:=1
+PKG_SOURCE_URL:=@SF/bridge
+PKG_VERSION:=1.5
+PKG_MD5SUM:=ec7b381160b340648dede58c31bb2238
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/bridge
+  SECTION:=net
+  CATEGORY:=Base system
+  TITLE:=Ethernet bridging configuration utility
+  URL:=http://bridge.sourceforge.net/
+endef
+
+define Package/bridge/description
+ Manage ethernet bridging: a way to connect networks together to 
+ form a larger network.
+endef
+
+CONFIGURE_ARGS += \
+       --with-linux-headers="$(LINUX_DIR)" \
+
+define Build/Prepare
+$(call Build/Prepare/Default)
+       ( cd $(PKG_BUILD_DIR) ; \
+               [ -f ./configure ] || { \
+                       ln -sf configure.in configure.ac ; \
+                       autoconf ; \
+               } \
+       )
+endef
+
+define Package/bridge/install
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/brctl/brctl $(1)/usr/sbin
+endef
+
+$(eval $(call BuildPackage,bridge))
diff --git a/net/bridge-utils/patches/001-libbridge_cflags.patch b/net/bridge-utils/patches/001-libbridge_cflags.patch
new file mode 100644 (file)
index 0000000..e35a649
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/libbridge/Makefile.in
++++ b/libbridge/Makefile.in
+@@ -5,7 +5,7 @@ AR=ar
+ RANLIB=@RANLIB@
+ CC=@CC@
+-CFLAGS = -Wall -g $(KERNEL_HEADERS)
++CFLAGS = -Wall -g @CFLAGS@ $(KERNEL_HEADERS)
+ prefix=@prefix@
+ exec_prefix=@exec_prefix@
diff --git a/net/crda/Makefile b/net/crda/Makefile
new file mode 100644 (file)
index 0000000..0d075f1
--- /dev/null
@@ -0,0 +1,74 @@
+#
+# Copyright (C) 2009-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=crda
+PKG_RELEASE:=1
+PKG_VERSION:=1.1.2
+PKG_SOURCE_URL:=http://wireless.kernel.org/download/crda
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_MD5SUM:=5226f65aebacf94baaf820f8b4e06df4
+
+PKG_REGULATORY_NAME:=regulatory
+PKG_REGULATORY_VERSION:=2011.04.28
+PKG_REGULATORY_SOURCE_URL:=http://wireless.kernel.org/download/wireless-regdb/regulatory.bins
+PKG_REGULATORY_SOURCE:=$(PKG_REGULATORY_VERSION)-$(PKG_REGULATORY_NAME).bin
+PKG_REGULATORY_MD5SUM:=1535e98bcaba732e2f8e8f62dac6f369
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/crda
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=Central Regulatory Domain Agent (CRDA)
+  DEPENDS:=+libnl-tiny
+  URL:=http://wireless.kernel.org/en/developers/Regulatory/CRDA
+endef
+
+define Download/wireless-regdb
+  FILE:=$(PKG_REGULATORY_SOURCE)
+  URL:=$(PKG_REGULATORY_SOURCE_URL)
+  VERSION:=$(PKG_REGULATORY_VERSION)
+  MD5SUM:=$(PKG_REGULATORY_MD5SUM)
+endef
+$(eval $(call Download,wireless-regdb))
+
+define Package/crda/description
+ This is the Central Regulatory Domain Agent for Linux. It serves one
+ purpose: tell Linux kernel what to enforce. In essence it is a udev
+ helper for communication between the kernel and userspace. You only
+ need to run this manually for debugging purposes. For manual changing
+ of regulatory domains use iw (iw reg set) or wpa_supplicant (feature
+ yet to be added).
+endef
+
+TARGET_CPPFLAGS := \
+       -I$(STAGING_DIR)/usr/include/libnl-tiny \
+       -D_GNU_SOURCE \
+       $(TARGET_CPPFLAGS)
+
+MAKE_FLAGS += \
+       NL1FOUND="" NL2FOUND=Y \
+       NLLIBNAME="libnl-tiny" \
+       NLLIBS="-lnl-tiny -lm" \
+       REG_BIN="$(DL_DIR)/$(PKG_REGULATORY_SOURCE)" \
+       crda
+
+define Package/crda/install
+       $(INSTALL_DIR) $(1)/sbin
+       $(INSTALL_DIR) $(1)/etc/hotplug.d
+       $(INSTALL_DIR) $(1)/etc/hotplug.d/platform
+       $(INSTALL_DIR) $(1)/usr/lib/crda
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/crda $(1)/sbin/
+       $(INSTALL_DATA) ./files/hotplug.rule $(1)/etc/hotplug.d/platform/10-regulatory
+       $(INSTALL_DATA) $(DL_DIR)/$(PKG_REGULATORY_SOURCE) $(1)/usr/lib/crda/regulatory.bin
+endef
+
+$(eval $(call BuildPackage,crda))
+
diff --git a/net/crda/files/hotplug.rule b/net/crda/files/hotplug.rule
new file mode 100644 (file)
index 0000000..1ec033f
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# Copyright (C) 2009 OpenWrt.org
+
+[ change = "$ACTION" -a regulatory.0 = "$DEVICENAME" ] && {
+       /sbin/crda
+}
diff --git a/net/crda/patches/101-make_crypto_use_optional.patch b/net/crda/patches/101-make_crypto_use_optional.patch
new file mode 100644 (file)
index 0000000..c7ace42
--- /dev/null
@@ -0,0 +1,13 @@
+--- a/Makefile
++++ b/Makefile
+@@ -35,7 +35,9 @@ LDLIBS += `pkg-config --libs openssl`
+ reglib.o: keys-ssl.c
+-else
++endif
++
++ifeq ($(USE_GCRYPT),1)
+ CFLAGS += -DUSE_GCRYPT
+ LDLIBS += -lgcrypt
diff --git a/net/madwifi/Config.in b/net/madwifi/Config.in
new file mode 100644 (file)
index 0000000..7b72eb8
--- /dev/null
@@ -0,0 +1,55 @@
+menu "Configuration"
+       depends on PACKAGE_kmod-madwifi
+
+config MADWIFI_DEBUG
+       bool "Enable compilation of debugging features"
+       depends on DEVEL
+       default n
+
+config MADWIFI_COMPRESSION
+       bool "Enable Atheros Super A/G Compression"
+       depends !TARGET_ar71xx
+       default n
+       help
+         Enables Atheros Super A/G Hardware Compression Engine.
+
+config MADWIFI_SINGLE_MODULE
+       bool "Combine driver and net80211 into a single module"
+       default y
+       help
+         This option combines all driver and stack related code (except for HAL)
+         into a single module, thus saving space and removing unnecessary kernel
+         exports
+
+choice
+       prompt "Rate control algorithm selection"
+       default MADWIFI_RCA_MINSTREL
+       help
+         This option controls how MadWifi chooses its bitrate.
+
+config MADWIFI_RCA_MINSTREL
+       bool "Use the Minstrel rate control algorithm"
+       help
+         This code is takes a wandering minstrel approach. Wander around the
+         different rates, singing wherever you can. And then, look at the
+         performance, and make a choice. Note that the wandering minstrel will
+         always wander in directions where he/she feels he/she will get paid
+         the best for his/her work.
+
+config MADWIFI_RCA_SAMPLERATE
+       bool "Use the SampleRate rate control algorithm"
+       help
+         SampleRate decides on the transmission bit-rate based on the past
+         history of performance; it keeps a record of the number of successive
+         failures, the number of successful transmits and the total transmission
+         time along with the destination for that bit-rate. Stale samples are
+         removed based on a EWMA windowing mechanism. If in the sampling
+         process, no successful acknowledgment is received or the number of
+         packets sent is multiple of 10 on a specific link, it transmits the
+         packet with the highest rate which has not failed 4 successive times.
+         Other than that it transmits packets at the rate which has the lowest
+         average transmission time.
+
+endchoice
+
+endmenu
diff --git a/net/madwifi/Makefile b/net/madwifi/Makefile
new file mode 100644 (file)
index 0000000..f915f56
--- /dev/null
@@ -0,0 +1,266 @@
+#
+# Copyright (C) 2006-2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=madwifi
+
+PKG_REV:=3314
+PKG_VERSION:=r$(PKG_REV)
+PKG_RELEASE:=6
+
+PKG_SOURCE_PROTO:=svn
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_SOURCE_SUBDIR:=$(if $(PKG_BRANCH),$(PKG_BRANCH),madwifi-trunk)-$(PKG_VERSION)
+PKG_SOURCE_URL:=http://madwifi-project.org/svn/madwifi/$(if $(PKG_BRANCH),branches/$(PKG_BRANCH),trunk)
+PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.gz
+PKG_MIRROR_MD5SUM:=086b026d1c1561be8a949b79b0931404
+
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(if $(PKG_BRANCH),$(PKG_BRANCH),madwifi-trunk)-$(PKG_VERSION)
+
+HAL_VERSION:=20090508
+HAL_FILE:=ath_hal-$(HAL_VERSION).tgz
+HAL_MD5SUM:=4ab7ae8bdb96c0be388c98bf8f92d5ca
+
+PKG_BUILD_DEPENDS:=wprobe
+
+include $(INCLUDE_DIR)/package.mk
+
+ifdef CONFIG_MADWIFI_COMPRESSION
+  COMPRESSION:=1
+else
+  COMPRESSION:=0
+endif
+
+define Download/hal
+  FILE:=$(HAL_FILE)
+  URL:=http://mirror2.openwrt.org/sources
+  MD5SUM:=$(HAL_MD5SUM)
+endef
+$(eval $(call Download,hal))
+
+
+ifneq ($(CONFIG_TARGET_atheros),)
+  BUS:=AHB
+else
+  ifneq ($(CONFIG_PCI_SUPPORT),)
+    BUS:=PCI
+  endif
+endif
+
+ifneq ($(CONFIG_CPU_MIPS32_R2),)
+  ifeq ($(ARCH),mips)
+    HAL_TARGET:=mips32r2-be-elf
+  endif
+  ifeq ($(ARCH),mipsel)
+    HAL_TARGET:=mips32r2-le-elf
+  endif
+else
+  ifeq ($(ARCH),mips)
+    HAL_TARGET:=mips32-be-elf
+  endif
+  ifeq ($(ARCH),mipsel)
+    HAL_TARGET:=mips32-le-elf
+  endif
+endif
+ifeq ($(ARCH),i386)
+  HAL_TARGET:=i386-elf
+endif
+ifeq ($(ARCH),i686)
+  HAL_TARGET:=i386-elf
+endif
+ifeq ($(ARCH),armeb)
+  HAL_TARGET:=xscale-be-elfgnueabi
+endif
+ifeq ($(ARCH),arm)
+  HAL_TARGET:=xscale-le-elfgnueabi
+  ifeq ($(BOARD),cns21xx)
+    HAL_TARGET:=armv4-le-elfgnueabi
+  endif
+  ifeq ($(BOARD),cns3xxx)
+    HAL_TARGET:=arm11-le-elfgnueabi
+  endif
+  ifeq ($(BOARD),gemini)
+    HAL_TARGET:=armv4-le-elfgnueabi
+  endif
+endif
+ifeq ($(ARCH),powerpc)
+  HAL_TARGET:=powerpc-be-elf
+endif
+ifneq ($(CONFIG_TARGET_atheros),)
+  HAL_TARGET:=wisoc
+endif
+
+ifdef CONFIG_MADWIFI_RCA_MINSTREL
+  RATE_CONTROL:=minstrel
+endif
+
+ifdef CONFIG_MADWIFI_RCA_ONOE
+  RATE_CONTROL:=onoe
+endif
+
+ifdef CONFIG_MADWIFI_RCA_AMRR
+  RATE_CONTROL:=amrr
+endif
+
+ifdef CONFIG_MADWIFI_RCA_SAMPLERATE
+  RATE_CONTROL:=sample
+endif
+
+ifneq ($(CONFIG_MADWIFI_SINGLE_MODULE),)
+MADWIFI_FILES:= $(PKG_BUILD_DIR)/ath_hal/ath_hal.ko
+else
+MADWIFI_FILES:= \
+       $(PKG_BUILD_DIR)/net80211/wlan.ko \
+       $(PKG_BUILD_DIR)/net80211/wlan_scan_ap.ko \
+       $(PKG_BUILD_DIR)/net80211/wlan_scan_sta.ko \
+       $(PKG_BUILD_DIR)/ath_hal/ath_hal.ko \
+       $(PKG_BUILD_DIR)/ath_rate/$(RATE_CONTROL)/ath_rate_$(RATE_CONTROL).ko \
+       $(PKG_BUILD_DIR)/net80211/wlan_acl.ko \
+       $(PKG_BUILD_DIR)/net80211/wlan_ccmp.ko \
+       $(PKG_BUILD_DIR)/net80211/wlan_tkip.ko \
+       $(PKG_BUILD_DIR)/net80211/wlan_wep.ko \
+       $(PKG_BUILD_DIR)/net80211/wlan_xauth.ko
+endif
+
+ifneq ($(CONFIG_MADWIFI_SINGLE_MODULE),)
+  MADWIFI_AUTOLOAD:= ath_hal
+else
+  MADWIFI_AUTOLOAD:= \
+       wlan \
+       wlan_scan_ap \
+       wlan_scan_sta \
+       ath_hal \
+       ath_rate_$(RATE_CONTROL) \
+       wlan_acl \
+       wlan_ccmp \
+       wlan_tkip \
+       wlan_wep \
+       wlan_xauth
+endif
+
+ifeq ($(findstring AHB,$(BUS)),AHB)
+  MADWIFI_FILES+= $(PKG_BUILD_DIR)/ath/ath_ahb.ko
+  MADWIFI_AUTOLOAD+= ath_ahb
+endif
+ifeq ($(findstring PCI,$(BUS)),PCI)
+  MADWIFI_FILES+= $(PKG_BUILD_DIR)/ath/ath_pci.ko
+  MADWIFI_AUTOLOAD+= ath_pci
+endif
+
+MADWIFI_APPLETS:=80211stats athchans athkey athstats wlanconfig ath_info madwifi_multi
+ifdef CONFIG_MADWIFI_DEBUG
+  MADWIFI_APPLETS += athdebug 80211debug
+endif
+
+define KernelPackage/madwifi
+  SUBMENU:=Wireless Drivers
+  TITLE:=Driver for Atheros wireless chipsets
+  URL:=http://madwifi-project.org/
+  DEPENDS:=+wireless-tools @PCI_SUPPORT @(!(TARGET_avr32||TARGET_cobalt||TARGET_ep93xx||TARGET_etrax||TARGET_octeon||TARGET_pxcab||TARGET_sibyte)||BROKEN) +@DRIVER_WEXT_SUPPORT
+  FILES:=$(MADWIFI_FILES)
+  AUTOLOAD:=$(call AutoLoad,50,$(MADWIFI_AUTOLOAD))
+  MENU:=1
+endef
+
+define KernelPackage/madwifi/description
+ This package contains a driver for Atheros 802.11a/b/g chipsets.
+endef
+
+define KernelPackage/madwifi/config
+       source "$(SOURCE)/Config.in"
+endef
+
+MADWIFI_INC = \
+       -I$(PKG_BUILD_DIR) \
+       -I$(PKG_BUILD_DIR)/include \
+       -I$(PKG_BUILD_DIR)/hal \
+       -I$(PKG_BUILD_DIR)/ath \
+       -I$(PKG_BUILD_DIR)/ath_hal \
+       -I$(PKG_BUILD_DIR)/net80211 \
+       -I$(STAGING_DIR)/usr/include/wprobe \
+       -include $(PKG_BUILD_DIR)/include/compat.h
+
+MAKE_ARGS:= \
+       PATH="$(TARGET_PATH)" \
+       ARCH="$(LINUX_KARCH)" \
+       ARCH-y="$(LINUX_KARCH)" \
+       CROSS_COMPILE="$(TARGET_CROSS)" \
+       TARGET="$(HAL_TARGET)" \
+       TOOLPREFIX="$(KERNEL_CROSS)" \
+       TOOLPATH="$(KERNEL_CROSS)" \
+       KERNELPATH="$(LINUX_DIR)" \
+       LDOPTS="--no-warn-mismatch " \
+       ATH_RATE="$(RATE_CONTROL)" \
+       ATH_CAP_SUPERG_COMP="$(COMPRESSION)" \
+       DO_MULTI=1 \
+       SINGLE_MODULE=$(if $(CONFIG_MADWIFI_SINGLE_MODULE),1) \
+       INCS="$(MADWIFI_INC)" \
+       $(if $(CONFIG_MADWIFI_DEBUG),,DEBUG=) WARNINGS="-Wno-unused"
+
+MAKE_VARS:= \
+       COPTS="-DATH_REVERSE_ENGINEERING=1" \
+
+define Build/Prepare/HAL
+       rm -rf $(PKG_BUILD_DIR)/tmp
+       mkdir -p $(PKG_BUILD_DIR)/tmp
+       tar xvzf $(DL_DIR)/$(HAL_FILE) -C $(PKG_BUILD_DIR)/tmp
+       $(CP) $(PKG_BUILD_DIR)/tmp/ath_hal*/* $(PKG_BUILD_DIR)/hal/
+       rm -rf $(PKG_BUILD_DIR)/tmp
+endef
+
+define Build/Prepare
+       $(call Build/Prepare/Default)
+       $(call Build/Prepare/HAL)
+       # patch cflags
+       $(SED) 's, -E[LB],,' \
+               -e 's, -mips2,,' \
+               -e 's, -mapcs-32,,' \
+               -e 's, -mlong-calls,,' \
+               $(PKG_BUILD_DIR)/hal/public/*.inc
+       $(SED) 's,march=armv4,march=armv5te,' \
+               $(PKG_BUILD_DIR)/hal/public/xscale*.inc
+endef
+
+ifeq ($(findstring AHB,$(BUS)),AHB)
+  define Build/Compile/ahb
+       $(MAKE_VARS) $(MAKE) -C $(PKG_BUILD_DIR) $(MAKE_ARGS) BUS="AHB" modules
+       $(MAKE) -C $(PKG_BUILD_DIR) $(MAKE_ARGS) CFLAGS="$(TARGET_CFLAGS)" tools
+  endef
+endif
+
+ifeq ($(findstring PCI,$(BUS)),PCI)
+  define Build/Compile/pci
+       $(MAKE_VARS) $(MAKE) -C $(PKG_BUILD_DIR) $(MAKE_ARGS) BUS="PCI" modules
+       $(MAKE) -C $(PKG_BUILD_DIR) $(MAKE_ARGS) CFLAGS="$(TARGET_CFLAGS)" tools
+  endef
+endif
+
+define Build/Configure
+       $(SED) 's,-E[LB] ,,g' $(PKG_BUILD_DIR)/hal/public/*.inc
+endef
+
+define Build/Compile
+       $(call Build/Compile/ahb)
+       $(call Build/Compile/pci)
+endef
+
+define Build/InstallDev
+       mkdir -p $(1)/usr/include/madwifi
+       $(CP) $(PKG_BUILD_DIR)/include $(1)/usr/include/madwifi/
+       mkdir -p $(1)/usr/include/madwifi/net80211
+       $(CP) $(PKG_BUILD_DIR)/net80211/*.h $(1)/usr/include/madwifi/net80211/
+endef
+
+define KernelPackage/madwifi/install
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(CP) ./files/* $(1)/
+       $(CP) $(foreach applet,$(MADWIFI_APPLETS),$(PKG_BUILD_DIR)/tools/$(applet)) $(1)/usr/sbin/
+endef
+
+$(eval $(call KernelPackage,madwifi))
diff --git a/net/madwifi/files/etc/hotplug.d/net/10-madwifi b/net/madwifi/files/etc/hotplug.d/net/10-madwifi
new file mode 100644 (file)
index 0000000..f5afce3
--- /dev/null
@@ -0,0 +1,12 @@
+if [ "$ACTION" = "add" -o "$ACTION" = "register" ]; then
+       case "$INTERFACE" in
+               ath*.sta*)
+                       local BASEIF="${INTERFACE%%\.*}"
+
+                       include /lib/network
+                       scan_interfaces
+                       local CONFIG="$(find_config "$BASEIF")" 
+                       [ -n "$CONFIG" ] && setup_interface "$INTERFACE" "$CONFIG"
+               ;;
+       esac
+fi
diff --git a/net/madwifi/files/lib/wifi/madwifi.sh b/net/madwifi/files/lib/wifi/madwifi.sh
new file mode 100755 (executable)
index 0000000..2e37325
--- /dev/null
@@ -0,0 +1,498 @@
+#!/bin/sh
+append DRIVERS "atheros"
+
+find_atheros_phy() {
+       local device="$1"
+
+       local macaddr="$(config_get "$device" macaddr | tr 'A-Z' 'a-z')"
+       config_get phy "$device" phy
+       [ -z "$phy" -a -n "$macaddr" ] && {
+               cd /proc/sys/dev
+               for phy in $(ls -d wifi* 2>&-); do
+                       [ "$macaddr" = "$(cat /sys/class/net/${phy}/address)" ] || continue
+                       config_set "$device" phy "$phy"
+                       break
+               done
+               config_get phy "$device" phy
+       }
+       [ -n "$phy" -a -d "/proc/sys/dev/$phy" ] || {
+               echo "phy for wifi device $1 not found"
+               return 1
+       }
+       [ -z "$macaddr" ] && {
+               config_set "$device" macaddr "$(cat /sys/class/net/${phy}/address)"
+       }
+       return 0
+}
+
+scan_atheros() {
+       local device="$1"
+       local wds
+       local adhoc ahdemo sta ap monitor disabled
+
+       [ ${device%[0-9]} = "wifi" ] && config_set "$device" phy "$device"
+
+       local ifidx=0
+       
+       config_get vifs "$device" vifs
+       for vif in $vifs; do
+               config_get_bool disabled "$vif" disabled 0
+               [ $disabled = 0 ] || continue
+
+               local vifname
+               [ $ifidx -gt 0 ] && vifname="ath${device#radio}-$ifidx" || vifname="ath${device#radio}"
+
+               config_get ifname "$vif" ifname
+               config_set "$vif" ifname "${ifname:-$vifname}"
+               
+               config_get mode "$vif" mode
+               case "$mode" in
+                       adhoc|ahdemo|sta|ap|monitor)
+                               append $mode "$vif"
+                       ;;
+                       wds)
+                               config_get ssid "$vif" ssid
+                               [ -z "$ssid" ] && continue
+
+                               config_set "$vif" wds 1
+                               config_set "$vif" mode sta
+                               mode="sta"
+                               addr="$ssid"
+                               ${addr:+append $mode "$vif"}
+                       ;;
+                       *) echo "$device($vif): Invalid mode, ignored."; continue;;
+               esac
+
+               ifidx=$(($ifidx + 1))
+       done
+
+       case "${adhoc:+1}:${sta:+1}:${ap:+1}" in
+               # valid mode combinations
+               1::) wds="";;
+               1::1);;
+               :1:1)config_set "$device" nosbeacon 1;; # AP+STA, can't use beacon timers for STA
+               :1:);;
+               ::1);;
+               ::);;
+               *) echo "$device: Invalid mode combination in config"; return 1;;
+       esac
+
+       config_set "$device" vifs "${sta:+$sta }${ap:+$ap }${adhoc:+$adhoc }${ahdemo:+$ahdemo }${wds:+$wds }${monitor:+$monitor}"
+}
+
+
+disable_atheros() (
+       local device="$1"
+
+       find_atheros_phy "$device" || return 0
+       config_get phy "$device" phy
+
+       set_wifi_down "$device"
+
+       include /lib/network
+       cd /proc/sys/net
+       for dev in *; do
+               grep "$phy" "$dev/%parent" >/dev/null 2>/dev/null && {
+                       [ -f "/var/run/wifi-${dev}.pid" ] &&
+                               kill "$(cat "/var/run/wifi-${dev}.pid")"
+                       ifconfig "$dev" down
+                       unbridge "$dev"
+                       wlanconfig "$dev" destroy
+               }
+       done
+       return 0
+)
+
+enable_atheros() {
+       local device="$1"
+
+       find_atheros_phy "$device" || return 0
+       config_get phy "$device" phy
+
+       config_get regdomain "$device" regdomain
+       [ -n "$regdomain" ] && echo "$regdomain" > /proc/sys/dev/$phy/regdomain
+
+       config_get country "$device" country
+       case "$country" in
+               [A-Za-z]*) country=`grep -i "$country" /lib/wifi/madwifi_countrycodes.txt |cut -d " " -f 2`;;
+               [0-9]*) ;;
+               *) country="" ;;
+       esac
+       [ -n "$country" ] && echo "$country" > /proc/sys/dev/$phy/countrycode
+
+       config_get_bool outdoor "$device" outdoor "0"
+       echo "$outdoor" > /proc/sys/dev/$phy/outdoor
+
+       config_get channel "$device" channel
+       config_get vifs "$device" vifs
+       config_get txpower "$device" txpower
+
+       [ auto = "$channel" ] && channel=0
+
+       config_get_bool antdiv "$device" diversity
+       config_get antrx "$device" rxantenna
+       config_get anttx "$device" txantenna
+       config_get_bool softled "$device" softled
+       config_get antenna "$device" antenna
+
+       devname="$(cat /proc/sys/dev/$phy/dev_name)"
+       local antgpio=
+       local invert=
+       case "$devname" in
+               NanoStation2) antgpio=7; invert=1;;
+               NanoStation5) antgpio=1; invert=1;;
+               "NanoStation Loco2") antgpio=2;;
+               "NanoStation Loco5")
+                       case "$antenna" in
+                               horizontal) antdiv=0; anttx=1; antrx=1;;
+                               vertical) antdiv=0; anttx=2; antrx=2;;
+                               *) antdiv=1; anttx=0; antrx=0;;
+                       esac
+               ;;
+       esac
+       if [ -n "$invert" ]; then
+               _set="clear"
+               _clear="set"
+       else
+               _set="set"
+               _clear="clear"
+       fi
+       if [ -n "$antgpio" ]; then
+               softled=0
+               case "$devname" in
+                       "NanoStation Loco2")
+                               antdiv=0
+                               antrx=1
+                               anttx=1
+                               case "$antenna" in
+                                       horizontal) gpioval=0;;
+                                       *) gpioval=1;;
+                               esac
+                       ;;
+                       *)
+                               case "$antenna" in
+                                       external) antdiv=0; antrx=1; anttx=1; gpioval=1;;
+                                       horizontal) antdiv=0; antrx=1; anttx=1; gpioval=0;;
+                                       vertical) antdiv=0; antrx=2; anttx=2; gpioval=0;;
+                                       auto) antdiv=1; antrx=0; anttx=0; gpioval=0;;
+                               esac
+                       ;;
+               esac
+
+               [ -x "$(which gpioctl 2>/dev/null)" ] || antenna=
+               gpioctl "dirout" "$antgpio" >/dev/null 2>&1
+               case "$gpioval" in
+                       0)
+                               gpioctl "$_clear" "$antgpio" >/dev/null 2>&1
+                       ;;
+                       1)
+                               gpioctl "$_set" "$antgpio" >/dev/null 2>&1
+                       ;;
+               esac
+       fi
+
+       [ -n "$antdiv" ] && sysctl -w dev."$phy".diversity="$antdiv" >&-
+       [ -n "$antrx" ] && sysctl -w dev."$phy".rxantenna="$antrx" >&-
+       [ -n "$anttx" ] && sysctl -w dev."$phy".txantenna="$anttx" >&-
+       [ -n "$softled" ] && sysctl -w dev."$phy".softled="$softled" >&-
+
+       config_get distance "$device" distance
+       [ -n "$distance" ] && sysctl -w dev."$phy".distance="$distance" >&-
+
+       for vif in $vifs; do
+               local start_hostapd= vif_txpower= nosbeacon=
+               config_get ifname "$vif" ifname
+               config_get enc "$vif" encryption
+               config_get eap_type "$vif" eap_type
+               config_get mode "$vif" mode
+
+               case "$mode" in
+                       sta) config_get_bool nosbeacon "$device" nosbeacon;;
+                       adhoc) config_get_bool nosbeacon "$vif" sw_merge 1;;
+               esac
+
+               [ "$nosbeacon" = 1 ] || nosbeacon=""
+               ifname=$(wlanconfig "$ifname" create nounit wlandev "$phy" wlanmode "$mode" ${nosbeacon:+nosbeacon})
+               [ $? -ne 0 ] && {
+                       echo "enable_atheros($device): Failed to set up $mode vif $ifname" >&2
+                       continue
+               }
+               config_set "$vif" ifname "$ifname"
+
+               config_get hwmode "$device" hwmode
+               [ -z "$hwmode" ] && config_get hwmode "$device" mode
+
+               pureg=0
+               case "$hwmode" in
+                       *b) hwmode=11b;;
+                       *bg) hwmode=11g;;
+                       *g) hwmode=11g; pureg=1;;
+                       *gdt) hwmode=11gdt;;
+                       *a) hwmode=11a;;
+                       *adt) hwmode=11adt;;
+                       *ast) hwmode=11ast;;
+                       *fh) hwmode=fh;;
+                       *) hwmode=auto;;
+               esac
+               iwpriv "$ifname" mode "$hwmode"
+               iwpriv "$ifname" pureg "$pureg"
+
+               iwconfig "$ifname" channel "$channel" >/dev/null 2>/dev/null 
+
+               config_get_bool hidden "$vif" hidden 0
+               iwpriv "$ifname" hide_ssid "$hidden"
+
+               config_get ff "$vif" ff
+               if [ -n "$ff" ]; then
+                       iwpriv "$ifname" ff "$ff"
+               fi
+
+               config_get wds "$vif" wds
+               case "$wds" in
+                       1|on|enabled) wds=1;;
+                       *) wds=0;;
+               esac
+               iwpriv "$ifname" wds "$wds" >/dev/null 2>&1
+
+               [ "$mode" = ap -a "$wds" = 1 ] && {
+                       config_get_bool wdssep "$vif" wdssep 1
+                       [ -n "$wdssep" ] && iwpriv "$ifname" wdssep "$wdssep"
+               }
+
+               case "$enc" in
+                       wep*)
+                               case "$enc" in
+                                       *shared*) iwpriv "$ifname" authmode 2;;
+                                       *)        iwpriv "$ifname" authmode 1;;
+                               esac
+                               for idx in 1 2 3 4; do
+                                       config_get key "$vif" "key${idx}"
+                                       iwconfig "$ifname" enc "[$idx]" "${key:-off}"
+                               done
+                               config_get key "$vif" key
+                               key="${key:-1}"
+                               case "$key" in
+                                       [1234]) iwconfig "$ifname" enc "[$key]";;
+                                       *) iwconfig "$ifname" enc "$key";;
+                               esac
+                       ;;
+                       psk*|wpa*)
+                               start_hostapd=1
+                               config_get key "$vif" key
+                       ;;
+               esac
+
+               case "$mode" in
+                       sta|adhoc|ahdemo)
+                               config_get addr "$vif" bssid
+                               [ -z "$addr" ] || { 
+                                       iwconfig "$ifname" ap "$addr"
+                               }
+                       ;;
+               esac
+
+               config_get_bool uapsd "$vif" uapsd 0
+               iwpriv "$ifname" uapsd "$uapsd"
+
+               config_get_bool bgscan "$vif" bgscan
+               [ -n "$bgscan" ] && iwpriv "$ifname" bgscan "$bgscan"
+
+               config_get rate "$vif" rate
+               [ -n "$rate" ] && iwconfig "$ifname" rate "${rate%%.*}"
+
+               config_get mcast_rate "$vif" mcast_rate
+               [ -n "$mcast_rate" ] && iwpriv "$ifname" mcast_rate "${mcast_rate%%.*}"
+
+               config_get frag "$vif" frag
+               [ -n "$frag" ] && iwconfig "$ifname" frag "${frag%%.*}"
+
+               config_get rts "$vif" rts
+               [ -n "$rts" ] && iwconfig "$ifname" rts "${rts%%.*}"
+
+               config_get_bool comp "$vif" compression 0
+               iwpriv "$ifname" compression "$comp" >/dev/null 2>&1
+
+               config_get minrate "$vif" minrate
+               [ -n "$minrate" ] && iwpriv "$ifname" minrate "$minrate"
+
+               config_get maxrate "$vif" maxrate
+               [ -n "$maxrate" ] && iwpriv "$ifname" maxrate "$maxrate"
+
+               config_get_bool burst "$vif" bursting
+               [ -n "$burst" ] && iwpriv "$ifname" burst "$burst"
+
+               config_get_bool wmm "$vif" wmm
+               [ -n "$wmm" ] && iwpriv "$ifname" wmm "$wmm"
+
+               config_get_bool xr "$vif" xr
+               [ -n "$xr" ] && iwpriv "$ifname" xr "$xr"
+
+               config_get_bool ar "$vif" ar
+               [ -n "$ar" ] && iwpriv "$ifname" ar "$ar"
+
+               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"
+
+               config_get_bool probereq "$vif" probereq
+               [ -n "$probereq" ] && iwpriv "$ifname" probereq "$probereq"
+
+               config_get maclist "$vif" maclist
+               [ -n "$maclist" ] && {
+                       # flush MAC list
+                       iwpriv "$ifname" maccmd 3
+                       for mac in $maclist; do
+                               iwpriv "$ifname" addmac "$mac"
+                       done
+               }
+
+               config_get macpolicy "$vif" macpolicy
+               case "$macpolicy" in
+                       allow)
+                               iwpriv "$ifname" maccmd 1
+                       ;;
+                       deny)
+                               iwpriv "$ifname" maccmd 2
+                       ;;
+                       *)
+                               # default deny policy if mac list exists
+                               [ -n "$maclist" ] && iwpriv "$ifname" maccmd 2
+                       ;;
+               esac
+
+               ifconfig "$ifname" up
+
+               local net_cfg bridge
+               net_cfg="$(find_net_config "$vif")"
+               [ -z "$net_cfg" ] || {
+                       bridge="$(bridge_interface "$net_cfg")"
+                       config_set "$vif" bridge "$bridge"
+                       start_net "$ifname" "$net_cfg"
+               }
+
+               config_get ssid "$vif" ssid
+               [ -n "$ssid" ] && {
+                       iwconfig "$ifname" essid on
+                       iwconfig "$ifname" essid ${ssid:+-- }"$ssid"
+               }
+
+               set_wifi_up "$vif" "$ifname"
+
+               # TXPower settings only work if device is up already
+               # while atheros hardware theoretically is capable of per-vif (even per-packet) txpower
+               # adjustment it does not work with the current atheros hal/madwifi driver
+
+               config_get vif_txpower "$vif" txpower
+               # use vif_txpower (from wifi-iface) instead of txpower (from wifi-device) if
+               # the latter doesn't exist
+               txpower="${txpower:-$vif_txpower}"
+               [ -z "$txpower" ] || iwconfig "$ifname" txpower "${txpower%%.*}"
+
+               case "$mode" in
+                       ap)
+                               config_get_bool isolate "$vif" isolate 0
+                               iwpriv "$ifname" ap_bridge "$((isolate^1))"
+
+                               if [ -n "$start_hostapd" ] && eval "type hostapd_setup_vif" 2>/dev/null >/dev/null; then
+                                       hostapd_setup_vif "$vif" madwifi || {
+                                               echo "enable_atheros($device): Failed to set up hostapd for interface $ifname" >&2
+                                               # make sure this wifi interface won't accidentally stay open without encryption
+                                               ifconfig "$ifname" down
+                                               wlanconfig "$ifname" destroy
+                                               continue
+                                       }
+                               fi
+                       ;;
+                       wds|sta)
+                               if eval "type wpa_supplicant_setup_vif" 2>/dev/null >/dev/null; then
+                                       wpa_supplicant_setup_vif "$vif" wext || {
+                                               echo "enable_atheros($device): Failed to set up wpa_supplicant for interface $ifname" >&2
+                                               ifconfig "$ifname" down
+                                               wlanconfig "$ifname" destroy
+                                               continue
+                                       }
+                               fi
+                       ;;
+                       adhoc)
+                               if eval "type wpa_supplicant_setup_vif" 2>/dev/null >/dev/null; then
+                                       wpa_supplicant_setup_vif "$vif" madwifi || {
+                                               echo "enable_atheros($device): Failed to set up wpa"
+                                               ifconfig "$ifname" down
+                                               wlanconfig "$ifname" destroy
+                                               continue
+                                       }
+                               fi
+               esac
+       done
+}
+
+check_atheros_device() {
+       [ ${1%[0-9]} = "wifi" ] && config_set "$1" phy "$1"
+       config_get phy "$1" phy
+       [ -z "$phy" ] && {
+               find_atheros_phy "$1" >/dev/null || return 0
+               config_get phy "$1" phy
+       }
+       [ "$phy" = "$dev" ] && found=1
+}
+
+
+detect_atheros() {
+       devidx=0
+       config_load wireless
+       while :; do
+               config_get type "radio$devidx" type
+               [ -n "$type" ] || break
+               devidx=$(($devidx + 1))
+       done
+       cd /proc/sys/dev
+       [ -d ath ] || return
+       for dev in $(ls -d wifi* 2>&-); do
+               found=0
+               config_foreach check_atheros_device wifi-device
+               [ "$found" -gt 0 ] && continue
+
+               devname="$(cat /proc/sys/dev/$dev/dev_name)"
+               case "$devname" in
+                       "NanoStation Loco2")
+                               EXTRA_DEV="
+# Ubiquiti NanoStation Loco2 features
+       option antenna  vertical # (horizontal|vertical)
+"
+                       ;;
+                       "NanoStation Loco5")
+                               EXTRA_DEV="
+# Ubiquiti NanoStation Loco5 features
+       option antenna  auto # (auto|horizontal|vertical)
+"
+                       ;;
+                       NanoStation*)
+                               EXTRA_DEV="
+# Ubiquiti NanoStation features
+       option antenna  auto # (auto|horizontal|vertical|external)
+"
+                       ;;
+               esac
+
+               cat <<EOF
+config wifi-device  radio$devidx
+       option type     atheros
+       option channel  auto
+       option macaddr  $(cat /sys/class/net/${dev}/address)
+$EXTRA_DEV
+       # REMOVE THIS LINE TO ENABLE WIFI:
+       option disabled 1
+
+config wifi-iface
+       option device   radio$devidx
+       option network  lan
+       option mode     ap
+       option ssid     OpenWrt
+       option encryption none
+
+EOF
+       devidx=$(($devidx + 1))
+       done
+}
diff --git a/net/madwifi/files/lib/wifi/madwifi_countrycodes.txt b/net/madwifi/files/lib/wifi/madwifi_countrycodes.txt
new file mode 100644 (file)
index 0000000..624048b
--- /dev/null
@@ -0,0 +1,239 @@
+AF 4
+AL 8
+DZ 12
+AS 16
+AD 20
+AO 24
+AI 660
+AQ 10
+AG 28
+AR 32
+AM 51
+AW 533
+AU 36
+AT 40
+AZ 31
+BS 44
+BH 48
+BD 50
+BB 52
+BY 112
+BE 56
+BZ 84
+BJ 204
+BM 60
+BT 64
+BO 68
+BA 70
+BW 72
+BV 74
+BR 76
+IO 86
+VG 92
+BN 96
+BG 100
+BF 854
+BI 108
+KH 116
+CM 120
+CA 124
+CV 132
+KY 136
+CF 140
+TD 148
+CL 152
+CN 156
+CX 162
+CC 166
+CO 170
+KM 174
+CD 180
+CG 178
+CK 184
+CR 188
+CI 384
+CU 192
+CY 196
+CZ 203
+DK 208
+DJ 262
+DM 212
+DO 214
+EC 218
+EG 818
+SV 222
+GQ 226
+ER 232
+EE 233
+ET 231
+FO 234
+FK 238
+FJ 242
+FI 246
+FR 250
+GF 254
+PF 258
+TF 260
+GA 266
+GM 270
+GE 268
+DE 276
+GH 288
+GI 292
+GR 300
+GL 304
+GD 308
+GP 312
+GU 316
+GT 320
+GN 324
+GW 624
+GY 328
+HT 332
+HM 334
+VA 336
+HN 340
+HK 344
+HR 191
+HU 348
+IS 352
+IN 356
+ID 360
+IR 364
+IQ 368
+IE 372
+IL 376
+IT 380
+JM 388
+JP 392
+JO 400
+KZ 398
+KE 404
+KI 296
+KP 408
+KR 410
+KW 414
+KG 417
+LA 418
+LV 428
+LB 422
+LS 426
+LR 430
+LY 434
+LI 438
+LT 440
+LU 442
+MO 446
+MK 807
+MG 450
+MW 454
+MY 458
+MV 462
+ML 466
+MT 470
+MH 584
+MQ 474
+MR 478
+MU 480
+YT 175
+MX 484
+FM 583
+MD 498
+MC 492
+MN 496
+MS 500
+MA 504
+MZ 508
+MM 104
+NA 516
+NR 520
+NP 524
+AN 530
+NL 528
+NC 540
+NZ 554
+NI 558
+NE 562
+NG 566
+NU 570
+NF 574
+MP 580
+NO 578
+OM 512
+PK 586
+PW 585
+PS 275
+PA 591
+PG 598
+PY 600
+PE 604
+PH 608
+PN 612
+PL 616
+PT 620
+PR 630
+QA 634
+RE 638
+RO 642
+RU 643
+RW 646
+SH 654
+KN 659
+LC 662
+PM 666
+VC 670
+WS 882
+SM 674
+ST 678
+SA 682
+SN 686
+CS 891
+SC 690
+SL 694
+SG 702
+SK 703
+SI 705
+SB 90
+SO 706
+ZA 710
+GS 239
+ES 724
+LK 144
+SD 736
+SR 740
+SJ 744
+SZ 748
+SE 752
+CH 756
+SY 760
+TW 158
+TJ 762
+TZ 834
+TH 764
+TL 626
+TG 768
+TK 772
+TO 776
+TT 780
+TN 788
+TR 792
+TM 795
+TC 796
+TV 798
+VI 850
+UG 800
+UA 804
+AE 784
+GB 826
+UM 581
+US 840
+UY 858
+UZ 860
+VU 548
+VE 862
+VN 704
+WF 876
+EH 732
+YE 887
+ZM 894
+ZW 716
diff --git a/net/madwifi/patches/102-multicall_binary.patch b/net/madwifi/patches/102-multicall_binary.patch
new file mode 100644 (file)
index 0000000..887a462
--- /dev/null
@@ -0,0 +1,315 @@
+--- a/tools/80211debug.c
++++ b/tools/80211debug.c
+@@ -48,6 +48,7 @@
+ #include <ctype.h>
+ #include <getopt.h>
+ #include <err.h>
++#include "do_multi.h"
+ #undef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+@@ -185,7 +186,7 @@ sysctlbyname(const char *oid0, void *old
+ #endif /* __linux__ */
+ int
+-main(int argc, char *argv[])
++CMD(a80211debug)(int argc, char *argv[])
+ {
+       const char *ifname = "ath0";
+       const char *cp, *tp;
+--- a/tools/80211stats.c
++++ b/tools/80211stats.c
+@@ -59,6 +59,7 @@
+ #include "net80211/ieee80211.h"
+ #include "net80211/ieee80211_crypto.h"
+ #include "net80211/ieee80211_ioctl.h"
++#include "do_multi.h"
+ #ifndef SIOCG80211STATS
+ #define       SIOCG80211STATS (SIOCDEVPRIVATE + 2)
+@@ -240,7 +241,7 @@ print_sta_stats(FILE *fd, const u_int8_t
+ }
+ int
+-main(int argc, char *argv[])
++CMD(a80211stats)(int argc, char *argv[])
+ {
+       int c, len;
+       struct ieee80211req_sta_info *si;
+--- a/tools/athchans.c
++++ b/tools/athchans.c
+@@ -58,6 +58,7 @@
+ #include "net80211/ieee80211.h"
+ #include "net80211/ieee80211_crypto.h"
+ #include "net80211/ieee80211_ioctl.h"
++#include "do_multi.h"
+ static        int s = -1;
+ static const char *progname;
+@@ -140,8 +141,9 @@ usage(void)
+ }
+ #define       MAXCHAN ((int)(sizeof(struct ieee80211req_chanlist) * NBBY))
++
+ int
+-main(int argc, char *argv[])
++CMD(athchans)(int argc, char *argv[])
+ {
+       const char *ifname = "wifi0";
+       struct ieee80211req_chanlist chanlist;
+--- a/tools/athctrl.c
++++ b/tools/athctrl.c
+@@ -52,6 +52,7 @@
+ #include <err.h>
+ #include <net/if.h>
++#include "do_multi.h"
+ static int
+ setsysctrl(const char *dev, const char *control , u_long value)
+@@ -88,7 +89,7 @@ static void usage(void)
+ }
+ int
+-main(int argc, char *argv[])
++CMD(athctrl)(int argc, char *argv[])
+ {
+       char device[IFNAMSIZ + 1];
+       int distance = -1;
+--- a/tools/athdebug.c
++++ b/tools/athdebug.c
+@@ -51,6 +51,7 @@
+ #include <ctype.h>
+ #include <getopt.h>
+ #include <err.h>
++#include "do_multi.h"
+ #undef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+@@ -194,7 +195,7 @@ sysctlbyname(const char *oid0, void *old
+ #endif /* __linux__ */
+ int
+-main(int argc, char *argv[])
++CMD(athdebug)(int argc, char *argv[])
+ {
+ #ifdef __linux__
+       const char *ifname = "wifi0";
+--- a/tools/athkey.c
++++ b/tools/athkey.c
+@@ -58,6 +58,7 @@
+ #include "net80211/ieee80211.h"
+ #include "net80211/ieee80211_crypto.h"
+ #include "net80211/ieee80211_ioctl.h"
++#include "do_multi.h"
+ static int s = -1;
+ static const char *progname;
+@@ -213,8 +214,7 @@ usage(void)
+       exit(-1);
+ }
+-int
+-main(int argc, char *argv[])
++int CMD(athkey)(int argc, char *argv[])
+ {
+       const char *ifname = "wifi0";
+       struct ieee80211req_key setkey;
+--- a/tools/athstats.c
++++ b/tools/athstats.c
+@@ -65,6 +65,7 @@
+ #undef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
++#include "do_multi.h"
+ static const struct {
+       u_int           phyerr;
+@@ -228,7 +229,7 @@ catchalarm(int signo)
+ }
+ int
+-main(int argc, char *argv[])
++CMD(athstats)(int argc, char *argv[])
+ {
+ #ifdef __linux__
+       const char *ifname = "wifi0";
+--- /dev/null
++++ b/tools/do_multi.c
+@@ -0,0 +1,33 @@
++#include <string.h>
++#include <libgen.h>
++#include "do_multi.h"
++
++int
++main(int argc, char *argv[])
++{
++    char *progname;
++    int ret = 0;
++
++    progname = basename(argv[0]);
++
++    if(strcmp(progname, "80211debug") == 0)
++      ret = a80211debug_init(argc, argv);
++    if(strcmp(progname, "80211stats") == 0)
++      ret = a80211stats_init(argc, argv);
++    if(strcmp(progname, "athchans") == 0)
++      ret = athchans_init(argc, argv);
++    if(strcmp(progname, "athctrl") == 0)
++      ret =  athctrl_init(argc, argv);
++    if(strcmp(progname, "athdebug") == 0)
++      ret =  athdebug_init(argc, argv);
++    if(strcmp(progname, "athkey") == 0)
++      ret =  athkey_init(argc, argv);
++    if(strcmp(progname, "athstats") == 0)
++      ret =  athstats_init(argc, argv);
++    if(strcmp(progname, "wlanconfig") == 0)
++      ret =  wlanconfig_init(argc, argv);
++    if(strcmp(progname, "ath_info") == 0)
++      ret =  athinfo_init(argc, argv);
++
++    return ret;
++}
+--- /dev/null
++++ b/tools/do_multi.h
+@@ -0,0 +1,15 @@
++#ifdef DO_MULTI
++int a80211debug_init(int argc, char *argv[]);
++int a80211stats_init(int argc, char *argv[]);
++int athchans_init(int argc, char *argv[]);
++int athctrl_init(int argc, char *argv[]);
++int athdebug_init(int argc, char *argv[]);
++int athkey_init(int argc, char *argv[]);
++int athstats_init(int argc, char *argv[]);
++int wlanconfig_init(int argc, char *argv[]);
++int athinfo_init(int argc, char *argv[]);
++
++#define CMD(name) name##_init
++#else
++#define CMD(name) main
++#endif
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -46,56 +46,55 @@ ifeq ($(HAL),)
+ HAL=   $(TOP)/hal
+ endif
++all: compile
+-ALL=  athstats 80211stats athkey athchans athctrl \
++ALLPROGS=     athstats 80211stats athkey athchans athctrl \
+       athdebug 80211debug wlanconfig ath_info
+-all:  $(ALL)
++OBJS= $(patsubst %,%.o,$(ALLPROGS))
+-INCS= -I. -I$(HAL) -I$(TOP) -I$(ATH_HAL)
++INCS= -I. -I../ath -I$(HAL) -I$(TOP) -I$(ATH_HAL)
+ CFLAGS=       -g -O2 -Wall
+ ALL_CFLAGS= $(CFLAGS) $(INCS)
+ LDFLAGS=
+-all:  $(ALL)
+-athstats: athstats.c
+-      $(CC) -o athstats $(ALL_CFLAGS) -I$(TOP)/ath $(LDFLAGS) athstats.c
+-80211stats: 80211stats.c
+-      $(CC) -o 80211stats $(ALL_CFLAGS) $(LDFLAGS) 80211stats.c
+-athkey: athkey.c
+-      $(CC) -o athkey $(ALL_CFLAGS) $(LDFLAGS) athkey.c
+-athchans: athchans.c
+-      $(CC) -o athchans $(ALL_CFLAGS) $(LDFLAGS) athchans.c
+-athctrl: athctrl.c
+-      $(CC) -o athctrl $(ALL_CFLAGS) $(LDFLAGS) athctrl.c
+-athdebug: athdebug.c
+-      $(CC) -o athdebug $(ALL_CFLAGS) $(LDFLAGS) athdebug.c
+-wlanconfig: wlanconfig.c
+-      $(CC) -o wlanconfig $(ALL_CFLAGS) $(LDFLAGS) wlanconfig.c
+-80211debug: 80211debug.c
+-      $(CC) -o 80211debug $(ALL_CFLAGS) $(LDFLAGS) 80211debug.c
+-ath_info: ath_info.c
+-      $(CC) -o ath_info $(CFLAGS) ath_info.c
++ifneq ($(DO_MULTI),)
++ALL_CFLAGS += -DDO_MULTI=1
++%.o: %.c
++      ${CC} $(ALL_CFLAGS) -c -o $@  $<
++
++madwifi_multi: $(OBJS) do_multi.o
++      $(CC) -o $@ $^
++
++compile: madwifi_multi
++      for i in $(ALLPROGS); do \
++              ln -s -f madwifi_multi $$i; \
++      done
++else
++$(ALLPROGS):
++      $(CC) $(ALL_CFLAGS) -o $@ $@.c
++
++compile: $(ALLPROGS)
++endif
+ install: $(ALL) 
+       install -d $(DESTDIR)$(BINDIR)
+-      for i in $(ALL); do \
++      for i in $(ALLPROGS) $(if $(DO_MULTI),madwifi_multi); do \
+               install $$i $(DESTDIR)$(BINDIR)/$$i; \
+-              $(STRIP) $(DESTDIR)$(BINDIR)/$$i; \
+       done
+       install -d $(DESTDIR)$(MANDIR)/man8
+       install -m 0644 man/*.8 $(DESTDIR)$(MANDIR)/man8
+       install $(TOP)/scripts/madwifi-unload $(DESTDIR)$(BINDIR)/madwifi-unload
+ uninstall:
+-      for i in $(ALL); do \
++      for i in $(ALLPROGS) $(if $(DO_MULTI),madwifi_multi); do \
+               rm -f $(DESTDIR)$(BINDIR)/$$i; \
+       done
+-      for i in $(ALL:=.8); do \
+-              rm -f $(DESTDIR)$(MANDIR)/man8/$$i; \
++      for i in $(ALLPROGS); do \
++              rm -f $(DESTDIR)$(MANDIR)/man8/$$i.8; \
+       done
+ clean:
+-      rm -f $(ALL) core a.out
++      rm -f $(ALLPROGS) madwifi_multi *.o core a.out
+--- a/tools/wlanconfig.c
++++ b/tools/wlanconfig.c
+@@ -61,6 +61,7 @@
+ #include "net80211/ieee80211.h"
+ #include "net80211/ieee80211_crypto.h"
+ #include "net80211/ieee80211_ioctl.h"
++#include "do_multi.h"
+ /*
+  * These are taken from ieee80211_node.h
+@@ -100,7 +101,7 @@ size_t strlcat(char *, const char *, siz
+ static int verbose = 0;
+ int
+-main(int argc, char *argv[])
++CMD(wlanconfig)(int argc, char *argv[])
+ {
+       const char *ifname, *cmd;
+       unsigned char bnounit = 0;
+--- a/tools/ath_info.c
++++ b/tools/ath_info.c
+@@ -98,6 +98,7 @@
+ #include <sys/mman.h>
+ #include <endian.h>
+ #include <byteswap.h>
++#include "do_multi.h"
+ #undef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+@@ -738,7 +739,8 @@ static void usage(const char *n)
+               "unlawful radio transmissions!\n\n");
+ }
+-int main(int argc, char *argv[])
++int
++CMD(athinfo)(int argc, char *argv[])
+ {
+       u_int32_t dev_addr;
+       u_int16_t eeprom_header, srev, phy_rev_5ghz, phy_rev_2ghz;
diff --git a/net/madwifi/patches/104-autocreate_none.patch b/net/madwifi/patches/104-autocreate_none.patch
new file mode 100644 (file)
index 0000000..b2181b6
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -516,7 +516,7 @@ ath_attach(u_int16_t devid, struct net_d
+       HAL_STATUS status;
+       int error = 0;
+       unsigned int i;
+-      int autocreatemode = IEEE80211_M_STA;
++      int autocreatemode = -1;
+       u_int8_t csz;
+       sc->devid = devid;
diff --git a/net/madwifi/patches/105-ratectl_attach.patch b/net/madwifi/patches/105-ratectl_attach.patch
new file mode 100644 (file)
index 0000000..80aad83
--- /dev/null
@@ -0,0 +1,23 @@
+--- a/net80211/ieee80211_rate.c
++++ b/net80211/ieee80211_rate.c
+@@ -100,8 +100,18 @@ struct ath_ratectrl *ieee80211_rate_atta
+               ieee80211_load_module(buf);
+       if (!ratectls[id].attach) {
+-              printk(KERN_ERR "Error loading module \"%s\"\n", buf);
+-              return NULL;
++              /* pick the first available rate control module */
++              printk(KERN_INFO "Rate control module \"%s\" not available\n", buf);
++              for (id = 0; id < IEEE80211_RATE_MAX - 1; id++) {
++                      if (ratectls[id].attach)
++                              break;
++              }
++              if (!ratectls[id].attach) {
++                      printk(KERN_ERR "No rate control module available");
++                      return NULL;
++              } else {
++                      printk(KERN_INFO "Using \"%s\" instead.\n", module_names[id]);
++              }
+       }
+       ctl = ratectls[id].attach(sc);
diff --git a/net/madwifi/patches/106-get_arch.patch b/net/madwifi/patches/106-get_arch.patch
new file mode 100644 (file)
index 0000000..3140f36
--- /dev/null
@@ -0,0 +1,21 @@
+--- a/scripts/get_arch.mk
++++ b/scripts/get_arch.mk
+@@ -36,11 +36,14 @@ ifeq (,$(ARCH-y))
+ $(Cannot determine ARCH)
+ endif
++# Allow ARCH to be x86
++ifneq (,$(CONFIG_X86))
++ifeq (x86,$(ARCH))
++ARCH-y = $(ARCH)
++endif
++endif
++
+ # Don't allow ARCH to be overridden by a different value.
+ ifeq (,$(ARCH))
+ ARCH = $(ARCH-y)
+-else
+-ifneq ($(ARCH),$(ARCH-y))
+-$(error ARCH mismatch: supplied "$(ARCH)", determined "$(ARCH-y)")
+-endif
+ endif
diff --git a/net/madwifi/patches/111-minstrel_crash.patch b/net/madwifi/patches/111-minstrel_crash.patch
new file mode 100644 (file)
index 0000000..975bc4e
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -393,6 +393,9 @@ ath_rate_get_mrr(struct ath_softc *sc, s
+               struct minstrel_node *sn = ATH_NODE_MINSTREL(an);
+               int rc1, rc2, rc3;         /* Index into the rate table, so for example, it is  0..11 */
++              if (sn->num_rates <= 0)
++                      return;
++
+               if (sn->is_sampling) {
+                       sn->is_sampling = 0;
+                       if (sn->rs_sample_rate_slower)
diff --git a/net/madwifi/patches/113-no_ibss_pwrsave.patch b/net/madwifi/patches/113-no_ibss_pwrsave.patch
new file mode 100644 (file)
index 0000000..af23ceb
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/net80211/ieee80211_scan.c
++++ b/net80211/ieee80211_scan.c
+@@ -291,7 +291,8 @@ scan_restart_pwrsav(unsigned long arg)
+       struct ieee80211com *ic = vap->iv_ic;
+       int delay;
+-      ieee80211_sta_pwrsave(vap, 1);
++      if (vap->iv_opmode != IEEE80211_M_IBSS)
++          ieee80211_sta_pwrsave(vap, 1);
+       /*
+        * Use an initial 1ms delay to ensure the null
+        * data frame has a chance to go out.
diff --git a/net/madwifi/patches/122-replayfail_workaround.patch b/net/madwifi/patches/122-replayfail_workaround.patch
new file mode 100644 (file)
index 0000000..c4eb28c
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -331,6 +331,9 @@ ieee80211_notify_replay_failure(struct i
+               k->wk_cipher->ic_name, k->wk_keyix,
+               (unsigned long long)rsc);
++      /* disabled for now due to bogus events for unknown reasons */
++      return;
++
+       /* TODO: needed parameters: count, keyid, key type, src address, TSC */
+       snprintf(buf, sizeof(buf), "%s(keyid=%d %scast addr=" MAC_FMT ")", tag,
+               k->wk_keyix,
diff --git a/net/madwifi/patches/123-ccmp_checks.patch b/net/madwifi/patches/123-ccmp_checks.patch
new file mode 100644 (file)
index 0000000..6178a3f
--- /dev/null
@@ -0,0 +1,95 @@
+--- a/net80211/ieee80211_crypto_ccmp.c
++++ b/net80211/ieee80211_crypto_ccmp.c
+@@ -115,6 +115,7 @@ ccmp_attach(struct ieee80211vap *vap, st
+ /* This function (crypto_alloc_foo might sleep. Therefore:
+  * Context: process
+  */
++#ifdef CONFIG_CRYPTO
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+       ctx->cc_tfm = crypto_alloc_tfm("aes", 0);
+ #else
+@@ -123,7 +124,8 @@ ccmp_attach(struct ieee80211vap *vap, st
+       if (IS_ERR(ctx->cc_tfm))
+               ctx->cc_tfm = NULL;
+ #endif
+-      
++#endif
++
+       if (ctx->cc_tfm == NULL) {
+               IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
+                               "%s: unable to load kernel AES crypto support\n",
+@@ -138,12 +140,14 @@ ccmp_detach(struct ieee80211_key *k)
+ {
+       struct ccmp_ctx *ctx = k->wk_private;
++#ifdef CONFIG_CRYPTO
+       if (ctx->cc_tfm != NULL)
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+               crypto_free_tfm(ctx->cc_tfm);
+ #else
+               crypto_free_cipher(ctx->cc_tfm);
+ #endif
++#endif
+       FREE(ctx, M_DEVBUF);
+       _MOD_DEC_USE(THIS_MODULE);
+@@ -169,7 +173,9 @@ ccmp_setkey(struct ieee80211_key *k)
+                       return 0;
+               }
++#ifdef CONFIG_CRYPTO
+               crypto_cipher_setkey(ctx->cc_tfm, k->wk_key, k->wk_keylen);
++#endif
+       }
+       return 1;
+@@ -324,6 +330,7 @@ xor_block(u8 *b, const u8 *a, size_t len
+ static void
+ rijndael_encrypt(struct crypto_cipher *tfm, const void *src, void *dst)
+ {
++#ifdef CONFIG_CRYPTO
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
+       crypto_cipher_encrypt_one(tfm, dst, src);
+ #else
+@@ -339,6 +346,7 @@ rijndael_encrypt(struct crypto_cipher *t
+       sg_dst.length = AES_BLOCK_LEN;
+       crypto_cipher_encrypt(tfm, &sg_dst, &sg_src, AES_BLOCK_LEN);
+ #endif
++#endif
+ }
+ /*
+@@ -475,6 +483,9 @@ ccmp_encrypt(struct ieee80211_key *key,
+       uint8_t *mic, *pos;
+       u_int space;
++      if (ctx->cc_tfm == NULL)
++              return 0;
++
+       ctx->cc_vap->iv_stats.is_crypto_ccmp++;
+       skb = skb0;
+@@ -589,6 +600,9 @@ ccmp_decrypt(struct ieee80211_key *key,
+       uint8_t *pos, *mic;
+       u_int space;
++      if (ctx->cc_tfm == NULL)
++              return 0;
++
+       ctx->cc_vap->iv_stats.is_crypto_ccmp++;
+       skb = skb0;
+--- a/Makefile
++++ b/Makefile
+@@ -192,11 +192,4 @@ endif
+           exit 1; \
+       fi
+       
+-      @# check crypto support is enabled
+-      @if [ -z "$(CONFIG_CRYPTO)" ]; then \
+-          echo "FAILED"; \
+-          echo "Please enable crypto API."; \
+-          exit 1; \
+-      fi
+-      
+       @echo "ok."
diff --git a/net/madwifi/patches/124-linux24_compat.patch b/net/madwifi/patches/124-linux24_compat.patch
new file mode 100644 (file)
index 0000000..88601a4
--- /dev/null
@@ -0,0 +1,202 @@
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -126,6 +126,11 @@ typedef void irqreturn_t;
+ #define ATH_GET_NETDEV_DEV(ndev)      ((ndev)->class_dev.dev)
+ #endif
++#ifndef NETDEV_TX_OK
++#define NETDEV_TX_OK    0
++#define NETDEV_TX_BUSY  1
++#endif
++
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
+ static inline struct net_device *_alloc_netdev(int sizeof_priv, const char *mask,
+                                              void (*setup)(struct net_device *))
+--- a/ath/if_ath_radar.c
++++ b/ath/if_ath_radar.c
+@@ -92,6 +92,13 @@
+ #define nofloat_pct(_value, _pct) \
+       ( (_value * (1000 + _pct)) / 1000 )
++#ifndef list_for_each_entry_reverse
++#define list_for_each_entry_reverse(pos, head, member)                        \
++      for (pos = list_entry((head)->prev, typeof(*pos), member);      \
++           prefetch(pos->member.prev), &pos->member != (head);        \
++           pos = list_entry(pos->member.prev, typeof(*pos), member))
++#endif
++
+ struct radar_pattern_specification {
+       /* The name of the rule/specification (i.e. what did we detect) */
+       const char *name;
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -4705,6 +4705,46 @@ ath_beacon_setup(struct ath_softc *sc, s
+ #undef USE_SHPREAMBLE
+ }
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
++static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
++{
++      int ret;
++      unsigned long flags;
++
++      local_irq_save(flags);
++      ret = v->counter;
++      if (likely(ret == old))
++              v->counter = new;
++      local_irq_restore(flags);
++
++      return ret;
++}
++
++/**
++ * atomic_add_unless - add unless the number is a given value
++ * @v: pointer of type atomic_t
++ * @a: the amount to add to v...
++ * @u: ...unless v is equal to u.
++ *
++ * Atomically adds @a to @v, so long as it was not @u.
++ * Returns non-zero if @v was not @u, and zero otherwise.
++ */
++static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
++{
++      int c, old;
++      c = atomic_read(v);
++      for (;;) {
++              if (unlikely(c == (u)))
++                      break;
++              old = atomic_cmpxchg((v), c, c + (a));
++              if (likely(old == c))
++                      break;
++              c = old;
++      }
++      return c != (u);
++}
++#endif
++
+ /*
+  * Generate beacon frame and queue cab data for a VAP.
+  */
+--- /dev/null
++++ b/net80211/sort.c
+@@ -0,0 +1,120 @@
++/*
++ * A fast, small, non-recursive O(nlog n) sort for the Linux kernel
++ *
++ * Jan 23 2005  Matt Mackall <mpm@selenic.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++
++static void u32_swap(void *a, void *b, int size)
++{
++      u32 t = *(u32 *)a;
++      *(u32 *)a = *(u32 *)b;
++      *(u32 *)b = t;
++}
++
++static void generic_swap(void *a, void *b, int size)
++{
++      char t;
++
++      do {
++              t = *(char *)a;
++              *(char *)a++ = *(char *)b;
++              *(char *)b++ = t;
++      } while (--size > 0);
++}
++
++/**
++ * sort - sort an array of elements
++ * @base: pointer to data to sort
++ * @num: number of elements
++ * @size: size of each element
++ * @cmp: pointer to comparison function
++ * @swap: pointer to swap function or NULL
++ *
++ * This function does a heapsort on the given array. You may provide a
++ * swap function optimized to your element type.
++ *
++ * Sorting time is O(n log n) both on average and worst-case. While
++ * qsort is about 20% faster on average, it suffers from exploitable
++ * O(n*n) worst-case behavior and extra memory requirements that make
++ * it less suitable for kernel use.
++ */
++
++static void sort(void *base, size_t num, size_t size,
++        int (*cmp)(const void *, const void *),
++        void (*swap)(void *, void *, int size))
++{
++      /* pre-scale counters for performance */
++      int i = (num/2 - 1) * size, n = num * size, c, r;
++
++      if (!swap)
++              swap = (size == 4 ? u32_swap : generic_swap);
++
++      /* heapify */
++      for ( ; i >= 0; i -= size) {
++              for (r = i; r * 2 + size < n; r  = c) {
++                      c = r * 2 + size;
++                      if (c < n - size && cmp(base + c, base + c + size) < 0)
++                              c += size;
++                      if (cmp(base + r, base + c) >= 0)
++                              break;
++                      swap(base + r, base + c, size);
++              }
++      }
++
++      /* sort */
++      for (i = n - size; i >= 0; i -= size) {
++              swap(base, base + i, size);
++              for (r = 0; r * 2 + size < i; r = c) {
++                      c = r * 2 + size;
++                      if (c < i - size && cmp(base + c, base + c + size) < 0)
++                              c += size;
++                      if (cmp(base + r, base + c) >= 0)
++                              break;
++                      swap(base + r, base + c, size);
++              }
++      }
++}
++
++EXPORT_SYMBOL(sort);
++
++#if 0
++/* a simple boot-time regression test */
++
++int cmpint(const void *a, const void *b)
++{
++      return *(int *)a - *(int *)b;
++}
++
++static int sort_test(void)
++{
++      int *a, i, r = 1;
++
++      a = kmalloc(1000 * sizeof(int), GFP_KERNEL);
++      BUG_ON(!a);
++
++      printk("testing sort()\n");
++
++      for (i = 0; i < 1000; i++) {
++              r = (r * 725861) % 6599;
++              a[i] = r;
++      }
++
++      sort(a, 1000, sizeof(int), cmpint, NULL);
++
++      for (i = 0; i < 999; i++)
++              if (a[i] > a[i+1]) {
++                      printk("sort() failed!\n");
++                      break;
++              }
++
++      kfree(a);
++
++      return 0;
++}
++
++module_init(sort_test);
++#endif
diff --git a/net/madwifi/patches/126-rxerr_frames.patch b/net/madwifi/patches/126-rxerr_frames.patch
new file mode 100644 (file)
index 0000000..762a7bc
--- /dev/null
@@ -0,0 +1,13 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6474,8 +6474,9 @@ ath_rx_tasklet(TQUEUE_ARG data)
+                       /*
+                        * Reject error frames if we have no vaps that
+                        * are operating in monitor mode.
++                       * Reject empty frames as well
+                        */
+-                      if (sc->sc_nmonvaps == 0)
++                      if ((sc->sc_nmonvaps == 0) || (rs->rs_datalen == 0))
+                               goto rx_next;
+               }
+ rx_accept:
diff --git a/net/madwifi/patches/200-no_debug.patch b/net/madwifi/patches/200-no_debug.patch
new file mode 100644 (file)
index 0000000..3f46ec8
--- /dev/null
@@ -0,0 +1,408 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -42,7 +42,6 @@
+  * This software is derived from work of Atsushi Onoe; his contribution
+  * is greatly appreciated.
+  */
+-#define       AR_DEBUG
+ #include "if_ath_debug.h"
+ #include "opt_ah.h"
+@@ -368,8 +367,10 @@ static unsigned int ath_get_dfs_cac_time
+ static void ath_set_dfs_cac_time(struct ieee80211com *, unsigned int seconds);
+ static unsigned int ath_test_radar(struct ieee80211com *);
+-static unsigned int ath_dump_hal_map(struct ieee80211com *ic);
++#ifdef AR_DEBUG
++static unsigned int ath_dump_hal_map(struct ieee80211com *ic);
++#endif
+ 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);
+@@ -520,9 +521,11 @@ ath_attach(u_int16_t devid, struct net_d
+       u_int8_t csz;
+       sc->devid = devid;
++#ifdef AR_DEBUG
+       ath_debug_global = (ath_debug & ATH_DEBUG_GLOBAL);
+       sc->sc_debug     = (ath_debug & ~ATH_DEBUG_GLOBAL);
+       DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid);
++#endif
+       /* Allocate space for dynamically determined maximum VAP count */
+       sc->sc_bslot = 
+@@ -1038,8 +1041,9 @@ ath_attach(u_int16_t devid, struct net_d
+       ic->ic_vap_delete = ath_vap_delete;
+       ic->ic_test_radar           = ath_test_radar;
++#ifdef AR_DEBUG
+       ic->ic_dump_hal_map         = ath_dump_hal_map;
+-
++#endif
+       ic->ic_set_dfs_testmode     = ath_set_dfs_testmode;
+       ic->ic_get_dfs_testmode     = ath_get_dfs_testmode;
+@@ -1297,12 +1301,14 @@ ath_vap_create(struct ieee80211com *ic,
+               /* If no default VAP debug flags are passed, allow a few to
+                * transfer down from the driver to new VAPs so we can have load
+                * time debugging for VAPs too. */
++#ifdef AR_DEBUG
+               vap->iv_debug = 0 |
+                       ((sc->sc_debug & ATH_DEBUG_RATE) ? IEEE80211_MSG_XRATE  : 0) | 
+                       ((sc->sc_debug & ATH_DEBUG_XMIT) ? IEEE80211_MSG_OUTPUT : 0) | 
+                       ((sc->sc_debug & ATH_DEBUG_RECV) ? IEEE80211_MSG_INPUT  : 0) |
+                       0
+                       ;
++#endif
+       }
+       ic->ic_debug = (sc->sc_default_ieee80211_debug & IEEE80211_MSG_IC);
+@@ -10496,9 +10502,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+                               /* XXX validate? */
+                               sc->sc_ledpin = val;
+                               break;
++#ifdef AR_DEBUG
+                       case ATH_DEBUG:
+                               sc->sc_debug     = (val & ~ATH_DEBUG_GLOBAL);
+                               ath_debug_global = (val &  ATH_DEBUG_GLOBAL);
++#endif
+                               break;
+                       case ATH_TXANTENNA:
+                               /*
+@@ -10918,9 +10926,11 @@ ath_dynamic_sysctl_register(struct ath_s
+       }
+       /* initialize values */
++#ifdef AR_DEBUG
+       ath_debug_global = (ath_debug & ATH_DEBUG_GLOBAL);
+       sc->sc_debug     = (ath_debug & ~ATH_DEBUG_GLOBAL);
+       sc->sc_default_ieee80211_debug = ieee80211_debug;
++#endif
+       sc->sc_txantenna = 0;           /* default to auto-selection */
+       sc->sc_txintrperiod = ATH_TXQ_INTR_PERIOD;
+ }
+@@ -11762,6 +11772,7 @@ ath_test_radar(struct ieee80211com *ic)
+ }
+ /* This is called by a private ioctl (iwpriv) to dump the HAL obfuscation table */
++#ifdef AR_DEBUG
+ static unsigned int
+ ath_dump_hal_map(struct ieee80211com *ic)
+ {
+@@ -11770,7 +11781,7 @@ ath_dump_hal_map(struct ieee80211com *ic
+       ath_hal_dump_map(sc->sc_ah);
+       return 0;
+ }
+-
++#endif
+ /* If we are shutting down or blowing off the DFS channel availability check
+  * then we call this to stop the behavior before we take the rest of the
+  * necessary actions (such as a DFS reaction to radar). */
+--- a/ath_rate/amrr/amrr.c
++++ b/ath_rate/amrr/amrr.c
+@@ -70,7 +70,9 @@
+ #include "amrr.h"
++#ifdef AR_DEBUG
+ #define       AMRR_DEBUG
++#endif
+ #ifdef AMRR_DEBUG
+ #define       DPRINTF(sc, _fmt, ...) do {                                     \
+       if (sc->sc_debug & 0x10)                                        \
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -117,7 +117,9 @@
+ #include "minstrel.h"
++#ifdef AR_DEBUG
+ #define       MINSTREL_DEBUG
++#endif
+ #ifdef MINSTREL_DEBUG
+ enum {
+               ATH_DEBUG_RATE          = 0x00000010    /* rate control */
+--- a/ath_rate/onoe/onoe.c
++++ b/ath_rate/onoe/onoe.c
+@@ -66,7 +66,9 @@
+ #include "onoe.h"
++#ifdef AR_DEBUG
+ #define       ONOE_DEBUG
++#endif
+ #ifdef ONOE_DEBUG
+ enum {
+       ATH_DEBUG_RATE  = 0x00000010,   /* rate control */
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -68,7 +68,9 @@
+ #include "sample.h"
+-#define       SAMPLE_DEBUG
++#ifdef AR_DEBUG
++#define SAMPLE_DEBUG
++#endif
+ #ifdef SAMPLE_DEBUG
+ enum {
+       ATH_DEBUG_RATE          = 0x00000010,   /* rate control */
+--- a/tools/do_multi.c
++++ b/tools/do_multi.c
+@@ -10,16 +10,20 @@ main(int argc, char *argv[])
+     progname = basename(argv[0]);
++#ifdef AR_DEBUG
+     if(strcmp(progname, "80211debug") == 0)
+       ret = a80211debug_init(argc, argv);
++#endif
+     if(strcmp(progname, "80211stats") == 0)
+       ret = a80211stats_init(argc, argv);
+     if(strcmp(progname, "athchans") == 0)
+       ret = athchans_init(argc, argv);
+     if(strcmp(progname, "athctrl") == 0)
+       ret =  athctrl_init(argc, argv);
++#ifdef AR_DEBUG
+     if(strcmp(progname, "athdebug") == 0)
+       ret =  athdebug_init(argc, argv);
++#endif
+     if(strcmp(progname, "athkey") == 0)
+       ret =  athkey_init(argc, argv);
+     if(strcmp(progname, "athstats") == 0)
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -48,14 +48,16 @@ endif
+ all: compile
++DEBUG = -DAR_DEBUG
++
+ ALLPROGS=     athstats 80211stats athkey athchans athctrl \
+-      athdebug 80211debug wlanconfig ath_info
++      $(if $(DEBUG),athdebug 80211debug) wlanconfig ath_info
+ OBJS= $(patsubst %,%.o,$(ALLPROGS))
+ INCS= -I. -I../ath -I$(HAL) -I$(TOP) -I$(ATH_HAL)
+ CFLAGS=       -g -O2 -Wall
+-ALL_CFLAGS= $(CFLAGS) $(INCS)
++ALL_CFLAGS= $(CFLAGS) $(INCS) $(DEBUG)
+ LDFLAGS=
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -29,8 +29,6 @@
+ #ifndef _NET80211_IEEE80211_LINUX_H_
+ #define _NET80211_IEEE80211_LINUX_H_
+-#define       IEEE80211_DEBUG
+-#define       IEEE80211_DEBUG_REFCNT                  /* Node reference count debugging */
+ /* #define ATH_DEBUG_SPINLOCKS */             /* announce before spinlocking */
+ #include <linux/wireless.h>
+--- a/Makefile.inc
++++ b/Makefile.inc
+@@ -147,8 +147,9 @@ ATH_RATE=  $(TOP)/ath_rate
+ # 
+ TOOLS=  $(TOP)/tools 
+-WARNINGS = -Werror
+-COPTS+= $(WARNINGS)
++WARNINGS = -Wno-unused
++# DEBUG = -DAR_DEBUG -DIEEE80211_DEBUG
++COPTS+= $(WARNINGS) $(DEBUG)
+ INCS= -include $(TOP)/include/compat.h -I$(TOP)/include
+ # TARGET defines the target platform architecture. It must match one of
+--- a/ath/if_ath_radar.c
++++ b/ath/if_ath_radar.c
+@@ -19,8 +19,6 @@
+  * $Id: if_ath_radar.c 2464 2007-06-15 22:51:56Z mtaylor $
+  */
+ #include "opt_ah.h"
+-
+-#define       AR_DEBUG
+ #include "if_ath_debug.h"
+ #ifndef AUTOCONF_INCLUDED
+@@ -56,8 +54,6 @@
+ #include <net80211/if_llc.h>
+ #endif
+-#define       AR_DEBUG
+-
+ #include "net80211/if_athproto.h"
+ #include "if_athvar.h"
+--- a/ath/if_ath_hal.h
++++ b/ath/if_ath_hal.h
+@@ -1081,6 +1081,7 @@ static inline HAL_BOOL ath_hal_disable(s
+            tail -f /var/log/messages | sed -f hal_unmangle.sed 
+  */
++#ifdef AR_DEBUG
+ static inline void ath_hal_dump_map(struct ath_hal *ah)
+ {
+ #ifdef CONFIG_KALLSYMS
+@@ -1345,7 +1346,7 @@ static inline void ath_hal_dump_map(stru
+ #endif                                /* #ifndef CONFIG_KALLSYMS */
+ }
+-
++#endif
+ #include "if_ath_hal_wrappers.h"
+ #endif                                /* #ifndef _IF_ATH_HAL_H_ */
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -492,9 +492,10 @@ struct ieee80211com {
+       /* inject a fake radar signal -- used while on a 802.11h DFS channels */
+       unsigned int (*ic_test_radar)(struct ieee80211com *);
++#ifdef AR_DEBUG
+       /* dump HAL */
+       unsigned int (*ic_dump_hal_map)(struct ieee80211com *);
+-
++#endif
+       /* DFS channel availability check time (in seconds) */
+       void (*ic_set_dfs_cac_time)(struct ieee80211com *, unsigned int);
+       unsigned int (*ic_get_dfs_cac_time)(struct ieee80211com *);
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -1548,6 +1548,7 @@ ieee80211_get_txcont_power(struct net_de
+       return 0;
+ }
++#ifdef AR_DEBUG
+ static int 
+ ieee80211_ioctl_hal_map(struct net_device *dev, struct iw_request_info *info,
+        void *w, char *extra)
+@@ -1558,7 +1559,7 @@ ieee80211_ioctl_hal_map(struct net_devic
+        params[0] = ic->ic_dump_hal_map(ic);
+        return 0;
+ }
+-
++#endif
+ static int
+ ieee80211_ioctl_radar(struct net_device *dev, struct iw_request_info *info,
+@@ -5258,8 +5259,10 @@ static const struct iw_priv_args ieee802
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,   "getwmmparams" },
+       { IEEE80211_IOCTL_RADAR,
+         0, 0, "doth_radar" },
++#ifdef AR_DEBUG
+       { IEEE80211_IOCTL_HALMAP,
+         0, 0, "dump_hal_map" },
++#endif
+       /*
+        * These depends on sub-ioctl support which added in version 12.
+        */
+@@ -5695,7 +5698,9 @@ static const iw_handler ieee80211_priv_h
+       set_priv(IEEE80211_IOCTL_SETMLME, ieee80211_ioctl_setmlme),
+       set_priv(IEEE80211_IOCTL_SETKEY, ieee80211_ioctl_setkey),
+       set_priv(IEEE80211_IOCTL_DELKEY, ieee80211_ioctl_delkey),
++#ifdef AR_DEBUG
+       set_priv(IEEE80211_IOCTL_HALMAP, ieee80211_ioctl_hal_map),
++#endif
+       set_priv(IEEE80211_IOCTL_ADDMAC, ieee80211_ioctl_addmac),
+       set_priv(IEEE80211_IOCTL_DELMAC, ieee80211_ioctl_delmac),
+       set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac),
+--- a/ath/if_ath_debug.h
++++ b/ath/if_ath_debug.h
+@@ -54,6 +54,10 @@ enum {
+       ATH_DEBUG_GLOBAL        = (ATH_DEBUG_SKB|ATH_DEBUG_SKB_REF)
+ };
++#define       EPRINTF(_sc, _fmt, ...) \
++              printk(KERN_ERR "%s: %s: " _fmt, \
++                      SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
++
+ #ifdef AR_DEBUG
+ /* DEBUG-ONLY DEFINITIONS */
+@@ -68,20 +72,9 @@ enum {
+               ath_keyprint((_sc), __func__, _ix, _hk, _mac);          \
+ } while (0)
+-#else /* #ifdef AR_DEBUG */
+-
+-#define       DFLAG_ISSET(sc, _m)             0
+-#define       DPRINTF(sc, _m, _fmt, ...)
+-#define       KEYPRINTF(sc, k, ix, mac)
+-
+-#endif /* #ifdef AR_DEBUG */
+ #define       IFF_DUMPPKTS(_sc, _m)   DFLAG_ISSET((_sc), (_m))
+-#define       EPRINTF(_sc, _fmt, ...) \
+-              printk(KERN_ERR "%s: %s: " _fmt, \
+-                      SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
+-
+ #define       WPRINTF(_sc, _fmt, ...) \
+               printk(KERN_WARNING "%s: %s: " _fmt, \
+                       SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
+@@ -89,5 +82,14 @@ enum {
+ #define       IPRINTF(_sc, _fmt, ...) \
+               printk(KERN_INFO "%s: %s: " _fmt, \
+                       SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
++#else
++#define       DFLAG_ISSET(sc, _m)             0
++#define       DPRINTF(sc, _m, _fmt, ...)
++#define       KEYPRINTF(sc, k, ix, mac)
++#define WPRINTF(...)
++#define IPRINTF(...)
++#define IFF_DUMPPKTS(...) 0
++
++#endif
+ #endif /* #ifndef _IF_ATH_DEBUG_H_ */
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -920,6 +920,9 @@ node_cleanup(struct ieee80211_node *ni)
+       ni->ni_rxkeyoff = 0;
+ }
++#ifndef IEEE80211_DEBUG
++#define node_print_message(...) do {} while(0)
++#else
+ static void node_print_message(
+               u_int32_t flags,
+               int show_counter, 
+@@ -972,7 +975,7 @@ static void node_print_message(
+                       adjusted_refcount);
+       va_end(args);
+ }
+-EXPORT_SYMBOL(node_print_message);
++#endif
+ static void
+ #ifdef IEEE80211_DEBUG_REFCNT
+--- a/ath/if_ath_pci.c
++++ b/ath/if_ath_pci.c
+@@ -134,8 +134,10 @@ ath_pci_probe(struct pci_dev *pdev, cons
+       u16 vdevice;
+       int i;
+-      if (pci_enable_device(pdev))
++      if (pci_enable_device(pdev)) {
++              printk(KERN_ERR "%s: failed to enable PCI device\n", dev_info);
+               return -EIO;
++      }
+       /* XXX 32-bit addressing only */
+       if (pci_set_dma_mask(pdev, 0xffffffff)) {
+@@ -244,8 +246,10 @@ ath_pci_probe(struct pci_dev *pdev, cons
+               sc->aps_sc.sc_ledpin = 1;
+       }
+-      if (ath_attach(vdevice, dev, NULL) != 0)
++      if ((i = ath_attach(vdevice, dev, NULL)) != 0) {
++              printk(KERN_ERR "%s: ath_attach failed: %d\n", dev_info, i);
+               goto bad4;
++      }
+       athname = ath_hal_probe(id->vendor, vdevice);
+       printk(KERN_INFO "%s: %s: %s: mem=0x%lx, irq=%d\n",
diff --git a/net/madwifi/patches/201-debug_fix.patch b/net/madwifi/patches/201-debug_fix.patch
new file mode 100644 (file)
index 0000000..bcfbba8
--- /dev/null
@@ -0,0 +1,20 @@
+--- a/ath_hal/ah_os.c
++++ b/ath_hal/ah_os.c
+@@ -65,7 +65,7 @@
+ #include <ah_os.h>
+ #ifdef AH_DEBUG
+-static        int ath_hal_debug = 0;
++static        int ath_hal_debug = 99;
+ #endif
+ int   ath_hal_dma_beacon_response_time = 2;   /* in TUs */
+@@ -327,6 +327,8 @@ EXPORT_SYMBOL(OS_MARK);
+  * useful for debugging and figuring out, which hal function sets which 
+  * registers */
+ char *ath_hal_func = NULL;
++EXPORT_SYMBOL(ath_hal_func);
++
+ #endif
+ /*
diff --git a/net/madwifi/patches/202-debug_variables.patch b/net/madwifi/patches/202-debug_variables.patch
new file mode 100644 (file)
index 0000000..33e6efa
--- /dev/null
@@ -0,0 +1,204 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -453,8 +453,8 @@ MODULE_PARM_DESC(autocreate, "Create ath
+ MODULE_PARM_DESC(ratectl, "Rate control algorithm [amrr|minstrel|onoe|sample], "
+               "defaults to '" DEF_RATE_CTL "'");
+-static int    ath_debug = 0;
+ #ifdef AR_DEBUG
++static int    ath_debug = 0;
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+ MODULE_PARM(ath_debug, "i");
+ #else
+@@ -465,8 +465,8 @@ static void ath_printrxbuf(const struct
+ static void ath_printtxbuf(const struct ath_buf *, int);
+ #endif /* defined(AR_DEBUG) */
+-static int    ieee80211_debug = 0;
+ #ifdef AR_DEBUG
++static int    ieee80211_debug = 0;
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+ MODULE_PARM(ieee80211_debug, "i");
+ #else
+@@ -1565,7 +1565,9 @@ ath_vap_delete(struct ieee80211vap *vap)
+ void
+ ath_suspend(struct net_device *dev)
+ {
++#ifdef AR_DEBUG
+       struct ath_softc *sc = dev->priv;
++#endif
+       DPRINTF(sc, ATH_DEBUG_ANY, "flags=%x\n", dev->flags);
+       ath_stop(dev);
+@@ -1574,7 +1576,9 @@ ath_suspend(struct net_device *dev)
+ void
+ ath_resume(struct net_device *dev)
+ {
++#ifdef AR_DEBUG
+       struct ath_softc *sc = dev->priv;
++#endif
+       DPRINTF(sc, ATH_DEBUG_ANY, "flags=%x\n", dev->flags);
+       ath_init(dev);
+@@ -4019,7 +4023,9 @@ static void
+ ath_key_update_begin(struct ieee80211vap *vap)
+ {
+       struct net_device *dev = vap->iv_ic->ic_dev;
++#ifdef AR_DEBUG
+       struct ath_softc *sc = dev->priv;
++#endif
+       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "Begin\n");
+       /*
+@@ -4040,7 +4046,9 @@ static void
+ ath_key_update_end(struct ieee80211vap *vap)
+ {
+       struct net_device *dev = vap->iv_ic->ic_dev;
++#ifdef AR_DEBUG
+       struct ath_softc *sc = dev->priv;
++#endif
+       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "End\n");
+       netif_wake_queue(dev);
+@@ -6218,7 +6226,9 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+       struct sk_buff *skb, int subtype, int rssi, u_int64_t rtsf)
+ {
+       struct ath_softc *sc = vap->iv_ic->ic_dev->priv;
++#ifdef AR_DEBUG
+         struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data;
++#endif
+       struct ieee80211_node * ni = ni_or_null;
+       u_int64_t hw_tsf, beacon_tsf;
+       u_int32_t hw_tu, beacon_tu, intval;
+@@ -8382,7 +8392,9 @@ ath_tx_timeout(struct net_device *dev)
+ static void
+ ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
+ {
++#ifdef AR_DEBUG
+       struct ath_hal *ah = sc->sc_ah;
++#endif
+       struct ath_buf *bf;
+       /*
+        * NB: this assumes output has been stopped and
+@@ -11002,6 +11014,7 @@ ath_announce(struct net_device *dev)
+               strncat(m, b, MLEN);
+       }
+       strncat(m, "\n", MLEN);
++#ifdef AR_DEBUG
+       if (1 /* bootverbose */) {
+               unsigned int i;
+               for (i = 0; i <= WME_AC_VO; i++) {
+@@ -11014,6 +11027,7 @@ ath_announce(struct net_device *dev)
+                       sc->sc_cabq->axq_qnum);
+               IPRINTF(sc, "Use hw queue %u for beacons\n", sc->sc_bhalq);
+       }
++#endif
+ #undef HAL_MODE_DUALBAND
+ }
+  
+--- a/ath/if_ath_radar.c
++++ b/ath/if_ath_radar.c
+@@ -156,7 +156,9 @@ static struct radar_pattern_specificatio
+ #endif
+ };
++#ifdef AR_DEBUG
+ static u_int32_t interval_to_frequency(u_int32_t pri);
++#endif
+ /* Returns true if radar detection is enabled. */
+ int ath_radar_is_enabled(struct ath_softc *sc)
+@@ -229,7 +231,9 @@ int ath_radar_update(struct ath_softc *s
+ {
+       struct ath_hal *ah = sc->sc_ah;
++#ifdef AR_DEBUG
+       struct net_device *dev = sc->sc_dev;
++#endif
+       struct ieee80211com *ic = &sc->sc_ic;
+       int required = 0;
+@@ -366,6 +370,7 @@ static struct ath_rp *pulse_prev(struct
+ #define MR_FAIL_MIN_PERIOD    4
+ #define MR_FAIL_MAX_PERIOD    5
++#ifdef AR_DEBUG
+ static const char* get_match_result_desc(u_int32_t code) {
+       switch (code) {
+       case MR_MATCH:
+@@ -384,6 +389,7 @@ static const char* get_match_result_desc
+               return "unknown";
+       }
+ }
++#endif
+ static int32_t match_radar(
+       u_int32_t matched, 
+@@ -775,7 +781,10 @@ static HAL_BOOL rp_analyse_short_pulse(
+       struct ath_softc *sc, struct ath_rp *last_pulse, 
+       u_int32_t *index, u_int32_t *pri, u_int32_t *matching_pulses, 
+       u_int32_t *missed_pulses, u_int32_t *noise_pulses)
+-{ struct net_device *dev = sc->sc_dev;
++{
++#ifdef AR_DEBUG
++      struct net_device *dev = sc->sc_dev;
++#endif
+       int i;
+       int best_index = -1;
+       unsigned int best_matched = 0;
+@@ -1217,6 +1226,7 @@ static HAL_BOOL rp_analyse_short_pulse(
+       return (-1 != best_index) ? AH_TRUE : AH_FALSE;
+ }
++#ifdef AR_DEBUG
+ static u_int32_t interval_to_frequency(u_int32_t interval)
+ {
+       /* Calculate BRI from PRI */
+@@ -1224,6 +1234,7 @@ static u_int32_t interval_to_frequency(u
+       /* Round to nearest multiple of 50 */
+       return frequency + ((frequency % 50) >= 25 ? 50 : 0) - (frequency % 50);
+ }
++#endif
+ #ifdef ATH_RADAR_LONG_PULSE
+ static const char* get_longpulse_desc(int lp) {
+@@ -1580,7 +1591,9 @@ void ath_rp_done(struct ath_softc *sc)
+ void ath_rp_record(struct ath_softc *sc, u_int64_t tsf, u_int8_t rssi, 
+                           u_int8_t width, HAL_BOOL is_simulated)
+ {
++#ifdef AR_DEBUG
+       struct net_device *dev = sc->sc_dev;
++#endif
+       struct ath_rp *pulse;
+       DPRINTF(sc, ATH_DEBUG_DOTHPULSES, "%s: ath_rp_record: "
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -931,7 +931,9 @@ ath_proc_read_nodes(struct ieee80211vap
+                           (struct ieee80211_node_table *) &vap->iv_ic->ic_sta;
+               unsigned int x = 0;
+               unsigned int this_tp, this_prob, this_eprob;
++#ifdef AR_DEBUG
+                       struct ath_softc *sc = vap->iv_ic->ic_dev->priv;;
++#endif
+               IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+               TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
+--- a/net80211/ieee80211_scan_ap.c
++++ b/net80211/ieee80211_scan_ap.c
+@@ -731,6 +731,7 @@ pick_channel(struct ieee80211_scan_state
+       sort(chans, ss_last, sizeof(*chans), pc_cmp, pc_swap);
++#ifdef IEEE80211_DEBUG
+       for (i = 0; i < ss_last; i++) {
+               int chan = ieee80211_chan2ieee(ic, chans[i].chan);
+@@ -742,6 +743,7 @@ pick_channel(struct ieee80211_scan_state
+                               !!IEEE80211_ARE_CHANS_SAME_MODE(chans[i].chan, 
+                                       ic->ic_bsschan));
+       }
++#endif
+       best = NULL;
+       best_rssi = 0xff; /* If signal is bigger than 0xff, we'd be melting. */
diff --git a/net/madwifi/patches/300-napi_polling.patch b/net/madwifi/patches/300-napi_polling.patch
new file mode 100644 (file)
index 0000000..bde7684
--- /dev/null
@@ -0,0 +1,536 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -184,7 +184,11 @@ static void ath_recv_mgmt(struct ieee802
+       struct sk_buff *, int, int, u_int64_t);
+ static void ath_setdefantenna(struct ath_softc *, u_int);
+ static struct ath_txq *ath_txq_setup(struct ath_softc *, int, int);
+-static void ath_rx_tasklet(TQUEUE_ARG);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++static int ath_rx_poll(struct napi_struct *napi, int budget);
++#else
++static int ath_rx_poll(struct net_device *dev, int *budget);
++#endif
+ static int ath_hardstart(struct sk_buff *, struct net_device *);
+ static int ath_mgtstart(struct ieee80211com *, struct sk_buff *);
+ #ifdef ATH_SUPERG_COMP
+@@ -376,6 +380,9 @@ static u_int32_t ath_set_clamped_maxtxpo
+               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);
++
+ /* calibrate every 30 secs in steady state but check every second at first. */
+ static int ath_calinterval = ATH_SHORT_CALINTERVAL;
+ static int ath_countrycode = CTRY_DEFAULT;    /* country code */
+@@ -547,7 +554,6 @@ ath_attach(u_int16_t devid, struct net_d
+       atomic_set(&sc->sc_txbuf_counter, 0);
+-      ATH_INIT_TQUEUE(&sc->sc_rxtq,     ath_rx_tasklet,       dev);
+       ATH_INIT_TQUEUE(&sc->sc_txtq,     ath_tx_tasklet,       dev);
+       ATH_INIT_TQUEUE(&sc->sc_bmisstq,  ath_bmiss_tasklet,    dev);
+       ATH_INIT_TQUEUE(&sc->sc_bstucktq, ath_bstuck_tasklet,   dev);
+@@ -821,6 +827,12 @@ ath_attach(u_int16_t devid, struct net_d
+       dev->set_mac_address = ath_set_mac_address;
+       dev->change_mtu = ath_change_mtu;
+       dev->tx_queue_len = ATH_TXBUF - ATH_TXBUF_MGT_RESERVED;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      netif_napi_add(dev, &sc->sc_napi, ath_rx_poll, 64);
++#else
++      dev->poll = ath_rx_poll;
++      dev->weight = 64;
++#endif
+ #ifdef USE_HEADERLEN_RESV
+       dev->hard_header_len += sizeof(struct ieee80211_qosframe) +
+                               sizeof(struct llc) +
+@@ -2220,6 +2232,7 @@ ath_intr(int irq, void *dev_id, struct p
+               (status & HAL_INT_GLOBAL)       ? " HAL_INT_GLOBAL"     : ""
+               );
++      sc->sc_isr = status;
+       status &= sc->sc_imask;                 /* discard unasked for bits */
+       /* 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. 
+@@ -2277,7 +2290,21 @@ ath_intr(int irq, void *dev_id, struct p
+               }
+               if (status & (HAL_INT_RX | HAL_INT_RXPHY)) {
+                       ath_uapsd_processtriggers(sc, hw_tsf);
+-                      ATH_SCHEDULE_TQUEUE(&sc->sc_rxtq, &needmark);
++                      sc->sc_isr &= ~HAL_INT_RX;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++                      if (netif_rx_schedule_prep(dev, &sc->sc_napi))
++#else
++                      if (netif_rx_schedule_prep(dev))
++#endif
++                      {
++                              sc->sc_imask &= ~HAL_INT_RX;
++                              ath_hal_intrset(ah, sc->sc_imask);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++                              __netif_rx_schedule(dev, &sc->sc_napi);
++#else
++                              __netif_rx_schedule(dev);
++#endif
++                      }
+               }
+               if (status & HAL_INT_TX) {
+ #ifdef ATH_SUPERG_DYNTURBO
+@@ -2303,6 +2330,11 @@ ath_intr(int irq, void *dev_id, struct p
+                               }
+                       }
+ #endif
++                      /* disable transmit interrupt */
++                      sc->sc_isr &= ~HAL_INT_TX;
++                      ath_hal_intrset(ah, sc->sc_imask & ~HAL_INT_TX);
++                      sc->sc_imask &= ~HAL_INT_TX;
++
+                       ATH_SCHEDULE_TQUEUE(&sc->sc_txtq, &needmark);
+               }
+               if (status & HAL_INT_BMISS) {
+@@ -2515,6 +2547,7 @@ ath_init(struct net_device *dev)
+       if (sc->sc_tx99 != NULL)
+               sc->sc_tx99->start(sc->sc_tx99);
+ #endif
++      ath_poll_enable(dev);
+ done:
+       ATH_UNLOCK(sc);
+@@ -2555,6 +2588,9 @@ ath_stop_locked(struct net_device *dev)
+               if (sc->sc_tx99 != NULL)
+                       sc->sc_tx99->stop(sc->sc_tx99);
+ #endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++              ath_poll_disable(dev);
++#endif
+               netif_stop_queue(dev);  /* XXX re-enabled by ath_newstate */
+               dev->flags &= ~IFF_RUNNING;     /* NB: avoid recursion */
+               ieee80211_stop_running(ic);     /* stop all VAPs */
+@@ -4013,12 +4049,47 @@ ath_key_set(struct ieee80211vap *vap, co
+       return ath_keyset(sc, k, mac, vap->iv_bss);
+ }
++static void ath_poll_disable(struct net_device *dev)
++{
++      struct ath_softc *sc = dev->priv;
++
++      /*
++       * XXX Using in_softirq is not right since we might
++       * be called from other soft irq contexts than
++       * ath_rx_poll
++       */
++      if (!in_softirq()) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++              napi_disable(&sc->sc_napi);
++#else
++              netif_poll_disable(dev);
++#endif
++      }
++}
++
++static void ath_poll_enable(struct net_device *dev)
++{
++      struct ath_softc *sc = dev->priv;
++
++      /* NB: see above */
++      if (!in_softirq()) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++              napi_enable(&sc->sc_napi);
++#else
++              netif_poll_enable(dev);
++#endif
++      }
++}
++
++
+ /*
+  * Block/unblock tx+rx processing while a key change is done.
+  * We assume the caller serializes key management operations
+  * so we only need to worry about synchronization with other
+  * uses that originate in the driver.
+  */
++#define       IS_UP(_dev) \
++      (((_dev)->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP))
+ static void
+ ath_key_update_begin(struct ieee80211vap *vap)
+ {
+@@ -4032,14 +4103,9 @@ ath_key_update_begin(struct ieee80211vap
+        * When called from the rx tasklet we cannot use
+        * tasklet_disable because it will block waiting
+        * for us to complete execution.
+-       *
+-       * XXX Using in_softirq is not right since we might
+-       * be called from other soft irq contexts than
+-       * ath_rx_tasklet.
+        */
+-      if (!in_softirq())
+-              tasklet_disable(&sc->sc_rxtq);
+-      netif_stop_queue(dev);
++      if (IS_UP(vap->iv_dev))
++              netif_stop_queue(dev);
+ }
+ static void
+@@ -4051,9 +4117,9 @@ ath_key_update_end(struct ieee80211vap *
+ #endif
+       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "End\n");
+-      netif_wake_queue(dev);
+-      if (!in_softirq())              /* NB: see above */
+-              tasklet_enable(&sc->sc_rxtq);
++
++      if (IS_UP(vap->iv_dev))
++              netif_wake_queue(dev);
+ }
+ /*
+@@ -6360,15 +6426,25 @@ ath_setdefantenna(struct ath_softc *sc,
+       sc->sc_rxotherant = 0;
+ }
+-static void
+-ath_rx_tasklet(TQUEUE_ARG data)
++static int
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++ath_rx_poll(struct napi_struct *napi, int budget)
++#else
++ath_rx_poll(struct net_device *dev, int *budget)
++#endif
+ {
+ #define       PA2DESC(_sc, _pa) \
+       ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
+               ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
+-      struct net_device *dev = (struct net_device *)data;
+-      struct ath_buf *bf;
++#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;
++#else
+       struct ath_softc *sc = dev->priv;
++      u_int rx_limit = min(dev->quota, *budget);
++#endif
++      struct ath_buf *bf;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc ? sc->sc_ah : NULL;
+       struct ath_desc *ds;
+@@ -6378,8 +6454,10 @@ ath_rx_tasklet(TQUEUE_ARG data)
+       unsigned int len;
+       int type;
+       u_int phyerr;
++      u_int processed = 0, early_stop = 0;
+       DPRINTF(sc, ATH_DEBUG_RX_PROC, "invoked\n");
++process_rx_again:
+       do {
+               bf = STAILQ_FIRST(&sc->sc_rxbuf);
+               if (bf == NULL) {               /* XXX ??? can this happen */
+@@ -6403,6 +6481,15 @@ ath_rx_tasklet(TQUEUE_ARG data)
+                       /* NB: never process the self-linked entry at the end */
+                       break;
+               }
++
++              if (rx_limit-- < 2) {
++                      early_stop = 1;
++                      break;
++              }
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++              processed++;
++#endif
++
+               skb = bf->bf_skb;
+               if (skb == NULL) {
+                       EPRINTF(sc, "Dropping; buffer contains NULL skbuff.\n");
+@@ -6450,6 +6537,7 @@ ath_rx_tasklet(TQUEUE_ARG data)
+                               sc->sc_stats.ast_rx_phyerr++;
+                               phyerr = rs->rs_phyerr & 0x1f;
+                               sc->sc_stats.ast_rx_phy[phyerr]++;
++                              goto rx_next;
+                       }
+                       if (rs->rs_status & HAL_RXERR_DECRYPT) {
+                               /*
+@@ -6645,9 +6733,39 @@ rx_next:
+               STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
+               ATH_RXBUF_UNLOCK_IRQ(sc);
+       } while (ath_rxbuf_init(sc, bf) == 0);
++      if (!early_stop) {
++              unsigned long flags;
++              /* Check if more data is received while we were
++               * processing the descriptor chain.
++               */
++              local_irq_save(flags);
++              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);
++                      goto process_rx_again;
++              }
++              local_irq_restore(flags);
++      }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      netif_rx_complete(dev, napi);
++#else
++      netif_rx_complete(dev);
++      *budget -= processed;
++      dev->quota -= processed;
++#endif
++      sc->sc_imask |= HAL_INT_RX;
++      ath_hal_intrset(ah, sc->sc_imask);
+       /* rx signal state monitoring */
+       ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      return processed;
++#else
++      return early_stop;
++#endif
+ #undef PA2DESC
+ }
+@@ -8298,12 +8416,24 @@ ath_tx_tasklet_q0(TQUEUE_ARG data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+       struct ath_softc *sc = dev->priv;
++      unsigned long flags;
++process_tx_again:
+       if (txqactive(sc->sc_ah, 0))
+               ath_tx_processq(sc, &sc->sc_txq[0]);
+       if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum))
+               ath_tx_processq(sc, sc->sc_cabq);
++      local_irq_save(flags);
++      if (sc->sc_isr & HAL_INT_TX) {
++              sc->sc_isr &= ~HAL_INT_TX;
++              local_irq_restore(flags);
++              goto process_tx_again;
++      }
++      sc->sc_imask |= HAL_INT_TX;
++      ath_hal_intrset(sc->sc_ah, sc->sc_imask);
++      local_irq_restore(flags);
++
+       netif_wake_queue(dev);
+       if (sc->sc_softled)
+@@ -8319,7 +8449,9 @@ ath_tx_tasklet_q0123(TQUEUE_ARG data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+       struct ath_softc *sc = dev->priv;
++      unsigned long flags;
++process_tx_again:
+       /*
+        * Process each active queue.
+        */
+@@ -8340,6 +8472,16 @@ ath_tx_tasklet_q0123(TQUEUE_ARG data)
+       if (sc->sc_uapsdq && txqactive(sc->sc_ah, sc->sc_uapsdq->axq_qnum))
+               ath_tx_processq(sc, sc->sc_uapsdq);
++      local_irq_save(flags);
++      if (sc->sc_isr & HAL_INT_TX) {
++              sc->sc_isr &= ~HAL_INT_TX;
++              local_irq_restore(flags);
++              goto process_tx_again;
++      }
++      sc->sc_imask |= HAL_INT_TX;
++      ath_hal_intrset(sc->sc_ah, sc->sc_imask);
++      local_irq_restore(flags);
++
+       netif_wake_queue(dev);
+       if (sc->sc_softled)
+@@ -8355,13 +8497,25 @@ ath_tx_tasklet(TQUEUE_ARG data)
+       struct net_device *dev = (struct net_device *)data;
+       struct ath_softc *sc = dev->priv;
+       unsigned int i;
++      unsigned long flags;
+       /* Process each active queue. This includes sc_cabq, sc_xrtq and
+        * sc_uapsdq */
++process_tx_again:
+       for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
+               if (ATH_TXQ_SETUP(sc, i) && txqactive(sc->sc_ah, i))
+                       ath_tx_processq(sc, &sc->sc_txq[i]);
++      local_irq_save(flags);
++      if (sc->sc_isr & HAL_INT_TX) {
++              sc->sc_isr &= ~HAL_INT_TX;
++              local_irq_restore(flags);
++              goto process_tx_again;
++      }
++      sc->sc_imask |= HAL_INT_TX;
++      ath_hal_intrset(sc->sc_ah, sc->sc_imask);
++      local_irq_restore(flags);
++
+       netif_wake_queue(dev);
+       if (sc->sc_softled)
+@@ -10296,9 +10450,9 @@ ath_change_mtu(struct net_device *dev, i
+       dev->mtu = mtu;
+       if ((dev->flags & IFF_RUNNING) && !sc->sc_invalid) {
+               /* NB: the rx buffers may need to be reallocated */
+-              tasklet_disable(&sc->sc_rxtq);
++              ath_poll_disable(dev);
+               error = ath_reset(dev);
+-              tasklet_enable(&sc->sc_rxtq);
++              ath_poll_enable(dev);
+       }
+       ATH_UNLOCK(sc);
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -53,6 +53,10 @@
+ # include     <asm/bitops.h>
+ #endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++#define irqs_disabled()                       0
++#endif
++
+ /*
+  * Deduce if tasklets are available.  If not then
+  * fall back to using the immediate work queue.
+@@ -616,6 +620,9 @@ struct ath_rp {
+ struct ath_softc {
+       struct ieee80211com sc_ic;              /* NB: must be first */
+       struct net_device *sc_dev;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      struct napi_struct sc_napi;
++#endif
+       void __iomem *sc_iobase;                /* address of the device */
+       struct semaphore sc_lock;               /* dev-level lock */
+       struct net_device_stats sc_devstats;    /* device statistics */
+@@ -730,7 +737,6 @@ struct ath_softc {
+       struct ath_buf *sc_rxbufcur;            /* current rx buffer */
+       u_int32_t *sc_rxlink;                   /* link ptr in last RX desc */
+       spinlock_t sc_rxbuflock;
+-      struct ATH_TQ_STRUCT sc_rxtq;           /* rx intr tasklet */
+       struct ATH_TQ_STRUCT sc_rxorntq;        /* rxorn intr tasklet */
+       u_int8_t sc_defant;                     /* current default antenna */
+       u_int8_t sc_rxotherant;                 /* RXs on non-default antenna */
+@@ -745,6 +751,7 @@ struct ath_softc {
+       u_int sc_txintrperiod;                  /* tx interrupt batching */
+       struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
+       struct ath_txq *sc_ac2q[WME_NUM_AC];    /* WME AC -> h/w qnum */
++      HAL_INT sc_isr;                         /* unmasked ISR state */
+       struct ATH_TQ_STRUCT sc_txtq;           /* tx intr tasklet */
+       u_int8_t sc_grppoll_str[GRPPOLL_RATE_STR_LEN];
+       struct ath_descdma sc_bdma;             /* beacon descriptors */
+@@ -858,6 +865,8 @@ typedef void (*ath_callback) (struct ath
+ #define       ATH_TXBUF_LOCK_CHECK(_sc)
+ #endif
++#define ATH_DISABLE_INTR              local_irq_disable
++#define ATH_ENABLE_INTR               local_irq_enable
+ #define       ATH_RXBUF_LOCK_INIT(_sc)        spin_lock_init(&(_sc)->sc_rxbuflock)
+ #define       ATH_RXBUF_LOCK_DESTROY(_sc)
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1198,7 +1198,7 @@ ieee80211_deliver_data(struct ieee80211_
+                       /* attach vlan tag */
+                       struct ieee80211_node *ni_tmp = SKB_CB(skb)->ni;
+                       if (vlan_hwaccel_receive_skb(skb, vap->iv_vlgrp, ni->ni_vlan) == NET_RX_DROP) {
+-                              /* If netif_rx dropped the packet because 
++                              /* If netif_receive_skb dropped the packet because
+                                * device was too busy */
+                               if (ni_tmp != NULL) {
+                                       /* node reference was leaked */
+@@ -1209,8 +1209,8 @@ ieee80211_deliver_data(struct ieee80211_
+                       skb = NULL; /* SKB is no longer ours */
+               } else {
+                       struct ieee80211_node *ni_tmp = SKB_CB(skb)->ni;
+-                      if (netif_rx(skb) == NET_RX_DROP) {
+-                              /* If netif_rx dropped the packet because 
++                      if (netif_receive_skb(skb) == NET_RX_DROP) {
++                              /* If netif_receive_skb dropped the packet because
+                                * device was too busy */
+                               if (ni_tmp != NULL) {
+                                       /* node reference was leaked */
+@@ -2322,8 +2322,8 @@ forward_mgmt_to_app(struct ieee80211vap
+               skb1->protocol = __constant_htons(0x0019);  /* ETH_P_80211_RAW */
+               ni_tmp = SKB_CB(skb1)->ni;
+-              if (netif_rx(skb1) == NET_RX_DROP) {
+-                      /* If netif_rx dropped the packet because 
++              if (netif_receive_skb(skb1) == NET_RX_DROP) {
++                      /* If netif_receive_skb dropped the packet because
+                        * device was too busy */
+                       if (ni_tmp != NULL) {
+                               /* node reference was leaked */
+--- a/net80211/ieee80211_monitor.c
++++ b/net80211/ieee80211_monitor.c
+@@ -584,8 +584,8 @@ ieee80211_input_monitor(struct ieee80211
+                       skb1->protocol = 
+                               __constant_htons(0x0019); /* ETH_P_80211_RAW */
+-                      if (netif_rx(skb1) == NET_RX_DROP) {
+-                              /* If netif_rx dropped the packet because 
++                      if (netif_receive_skb(skb1) == NET_RX_DROP) {
++                              /* If netif_receive_skb dropped the packet because
+                                * device was too busy, reclaim the ref. in 
+                                * the skb. */
+                               if (SKB_CB(skb1)->ni != NULL)
+--- a/net80211/ieee80211_skb.c
++++ b/net80211/ieee80211_skb.c
+@@ -73,7 +73,7 @@
+ #undef dev_queue_xmit
+ #undef kfree_skb
+ #undef kfree_skb_fast
+-#undef netif_rx
++#undef netif_receive_skb
+ #undef pskb_copy
+ #undef skb_clone
+ #undef skb_copy
+@@ -638,8 +638,8 @@ int  vlan_hwaccel_receive_skb_debug(stru
+               grp, vlan_tag);
+ }
+-int netif_rx_debug(struct sk_buff *skb, const char* func, int line) {
+-      return netif_rx(untrack_skb(skb, 0, func, line, __func__, __LINE__));
++int netif_receive_skb_debug(struct sk_buff *skb, const char* func, int line) {
++      return netif_receive_skb(untrack_skb(skb, 0, func, line, __func__, __LINE__));
+ }
+ struct sk_buff * alloc_skb_debug(unsigned int length, gfp_t gfp_mask,
+@@ -760,7 +760,7 @@ struct sk_buff * skb_copy_expand_debug(c
+ }
+ EXPORT_SYMBOL(vlan_hwaccel_receive_skb_debug);
+-EXPORT_SYMBOL(netif_rx_debug);
++EXPORT_SYMBOL(netif_receive_skb_debug);
+ EXPORT_SYMBOL(alloc_skb_debug);
+ EXPORT_SYMBOL(dev_alloc_skb_debug);
+ EXPORT_SYMBOL(skb_clone_debug);
+--- a/net80211/ieee80211_skb.h
++++ b/net80211/ieee80211_skb.h
+@@ -116,7 +116,7 @@ int ieee80211_skb_references(void);
+ int  vlan_hwaccel_receive_skb_debug(struct sk_buff *skb, 
+                                   struct vlan_group *grp, unsigned short vlan_tag, 
+                                   const char* func, int line);
+-int netif_rx_debug(struct sk_buff *skb, const char* func, int line);
++int netif_receive_skb_debug(struct sk_buff *skb, const char* func, int line);
+ struct sk_buff * alloc_skb_debug(unsigned int length, gfp_t gfp_mask,
+                                const char *func, int line);
+ struct sk_buff * dev_alloc_skb_debug(unsigned int length,
+@@ -151,7 +151,7 @@ struct sk_buff * skb_copy_expand_debug(c
+ #undef dev_queue_xmit
+ #undef kfree_skb
+ #undef kfree_skb_fast
+-#undef netif_rx
++#undef netif_receive_skb
+ #undef pskb_copy
+ #undef skb_clone
+ #undef skb_copy
+@@ -168,8 +168,8 @@ struct sk_buff * skb_copy_expand_debug(c
+       skb_copy_expand_debug(_skb, _newheadroom, _newtailroom, _gfp_mask, __func__, __LINE__)
+ #define vlan_hwaccel_receive_skb(_skb, _grp, _tag) \
+       vlan_hwaccel_receive_skb_debug(_skb, _grp, _tag, __func__, __LINE__)
+-#define netif_rx(_skb) \
+-      netif_rx_debug(_skb, __func__, __LINE__)
++#define netif_receive_skb(_skb) \
++      netif_receive_skb_debug(_skb, __func__, __LINE__)
+ #define       alloc_skb(_length, _gfp_mask) \
+       alloc_skb_debug(_length, _gfp_mask, __func__, __LINE__)
+ #define       dev_alloc_skb(_length) \
diff --git a/net/madwifi/patches/305-pureg_fix.patch b/net/madwifi/patches/305-pureg_fix.patch
new file mode 100644 (file)
index 0000000..8adb8a7
--- /dev/null
@@ -0,0 +1,168 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -4158,7 +4158,9 @@ ath_calcrxfilter(struct ath_softc *sc)
+               rfilt |= HAL_RX_FILTER_PROM;
+       if (ic->ic_opmode == IEEE80211_M_STA ||
+           sc->sc_opmode == HAL_M_IBSS ||      /* NB: AHDEMO too */
+-          (sc->sc_nostabeacons) || sc->sc_scanning)
++          (sc->sc_nostabeacons) || sc->sc_scanning ||
++              ((ic->ic_opmode == IEEE80211_M_HOSTAP) &&
++               (ic->ic_protmode != IEEE80211_PROT_NONE)))
+               rfilt |= HAL_RX_FILTER_BEACON;
+       if (sc->sc_nmonvaps > 0)
+               rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -346,11 +346,12 @@ ieee80211_input(struct ieee80211vap * va
+                               bssid = wh->i_addr3;
+                       }
+                       /*
+-                       * Validate the bssid.
++                       * Validate the bssid. Let beacons get through though for 11g protection mode.
+                        */
+-#ifdef ATH_SUPERG_XR
+                       if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bssid) &&
+-                          !IEEE80211_ADDR_EQ(bssid, dev->broadcast)) {
++                          !IEEE80211_ADDR_EQ(bssid, dev->broadcast) &&
++                              (subtype != IEEE80211_FC0_SUBTYPE_BEACON)) {
++#ifdef ATH_SUPERG_XR
+                               /*
+                                * allow MGT frames to vap->iv_xrvap.
+                                * this will allow roaming between  XR and normal vaps
+@@ -366,18 +367,14 @@ ieee80211_input(struct ieee80211vap * va
+                                       vap->iv_stats.is_rx_wrongbss++;
+                                       goto out;
+                               }
+-                      }
+ #else
+-                      if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bssid) &&
+-                          !IEEE80211_ADDR_EQ(bssid, dev->broadcast)) {
+                               /* not interested in */
+                               IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
+                                       bssid, NULL, "%s", "not to bss");
+                               vap->iv_stats.is_rx_wrongbss++;
+                               goto out;
+-                      }
+-
+ #endif
++                      }
+                       break;
+               case IEEE80211_M_WDS:
+                       if (skb->len < sizeof(struct ieee80211_frame_addr4)) {
+@@ -3066,7 +3063,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
+       u_int8_t *frm, *efrm;
+       u_int8_t *ssid, *rates, *xrates, *suppchan, *wpa, *rsn, *wme, *ath;
+       u_int8_t rate;
+-      int reassoc, resp, allocbs = 0;
++      int reassoc, resp, allocbs = 0, has_erp = 0;
+       u_int8_t qosinfo;
+       if (ni_or_null == NULL)
+@@ -3096,11 +3093,15 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                *    o station mode when associated (to collect state
+                *      updates such as 802.11g slot time), or
+                *    o adhoc mode (to discover neighbors)
++               *    o ap mode in protection mode (beacons only)
+                * Frames otherwise received are discarded.
+                */
+               if (!((ic->ic_flags & IEEE80211_F_SCAN) ||
+                   (vap->iv_opmode == IEEE80211_M_STA && ni->ni_associd) ||
+-                  vap->iv_opmode == IEEE80211_M_IBSS)) {
++                  (vap->iv_opmode == IEEE80211_M_IBSS) ||
++                      ((subtype == IEEE80211_FC0_SUBTYPE_BEACON) &&
++                       (vap->iv_opmode == IEEE80211_M_HOSTAP) &&
++                       (ic->ic_protmode != IEEE80211_PROT_NONE)))) {
+                       vap->iv_stats.is_rx_mgtdiscard++;
+                       return;
+               }
+@@ -3184,6 +3185,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                                       break;
+                               }
+                               scan.erp = frm[2];
++                              has_erp = 1;
+                               break;
+                       case IEEE80211_ELEMID_RSN:
+                               scan.rsn = frm;
+@@ -3421,6 +3423,20 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                               ieee80211_bg_scan(vap);
+                       return;
+               }
++
++              /* Update AP protection mode when in 11G mode */
++              if ((vap->iv_opmode == IEEE80211_M_HOSTAP) &&
++                      IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
++
++                      /* Assume no ERP IE == 11b AP */
++                      if ((!has_erp || (has_erp && (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
++                              !(ic->ic_flags & IEEE80211_F_USEPROT)) {
++
++                              ic->ic_flags |= IEEE80211_F_USEPROT;
++                              ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++                      }
++              }
++
+               /*
+                * If scanning, just pass information to the scan module.
+                */
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -383,10 +383,16 @@ ieee80211_create_ibss(struct ieee80211va
+       /* Update country ie information */
+       ieee80211_build_countryie(ic);
+-      if (IEEE80211_IS_CHAN_HALF(chan))
++      if (IEEE80211_IS_CHAN_HALF(chan)) {
+               ni->ni_rates = ic->ic_sup_half_rates;
+-      else if (IEEE80211_IS_CHAN_QUARTER(chan))
++      } else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
+               ni->ni_rates = ic->ic_sup_quarter_rates;
++      }
++
++      if ((vap->iv_flags & IEEE80211_F_PUREG) &&
++              IEEE80211_IS_CHAN_ANYG(chan)) {
++              ieee80211_setpuregbasicrates(&ni->ni_rates);
++      }
+       (void) ieee80211_sta_join1(PASS_NODE(ni));
+ }
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -595,6 +595,28 @@ static const struct ieee80211_rateset ba
+       { 4, { 2, 4, 11, 22 } },        /* IEEE80211_MODE_TURBO_G (mixed b/g) */
+ };
++static const struct ieee80211_rateset basicpureg[] = {
++    { 7, {2, 4, 11, 22, 12, 24, 48 } },
++};
++
++/*
++ * Mark basic rates for the 11g rate table based on the pureg setting
++ */
++void
++ieee80211_setpuregbasicrates(struct ieee80211_rateset *rs)
++{
++      int i, j;
++
++      for (i = 0; i < rs->rs_nrates; i++) {
++              rs->rs_rates[i] &= IEEE80211_RATE_VAL;
++              for (j = 0; j < basicpureg[0].rs_nrates; j++)
++                      if (basicpureg[0].rs_rates[j] == rs->rs_rates[i]) {
++                              rs->rs_rates[i] |= IEEE80211_RATE_BASIC;
++                              break;
++                      }
++      }
++}
++
+ /*
+  * Mark the basic rates for the 11g rate table based on the
+  * specified mode.  For 11b compatibility we mark only 11b
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -708,6 +708,7 @@ int ieee80211_media_setup(struct ieee802
+ void ieee80211_build_sc_ie(struct ieee80211com *);
+ void ieee80211_dfs_action(struct ieee80211com *);
+ void ieee80211_expire_channel_excl_restrictions(struct ieee80211com *);
++void ieee80211_setpuregbasicrates(struct ieee80211_rateset *rs);
+ /*
+  * Iterate through ic_channels to enumerate all distinct ic_ieee channel numbers.
diff --git a/net/madwifi/patches/309-micfail_detect.patch b/net/madwifi/patches/309-micfail_detect.patch
new file mode 100644 (file)
index 0000000..ca4103a
--- /dev/null
@@ -0,0 +1,321 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6457,6 +6457,7 @@ ath_rx_poll(struct net_device *dev, int
+       int type;
+       u_int phyerr;
+       u_int processed = 0, early_stop = 0;
++      u_int mic_fail = 0;
+       DPRINTF(sc, ATH_DEBUG_RX_PROC, "invoked\n");
+ process_rx_again:
+@@ -6558,24 +6559,8 @@ process_rx_again:
+                       }
+                       if (rs->rs_status & HAL_RXERR_MIC) {
+                               sc->sc_stats.ast_rx_badmic++;
+-                              /*
+-                               * Do minimal work required to hand off
+-                               * the 802.11 header for notification.
+-                               */
+-                              /* XXX frag's and QoS frames */
+-                              if (len >= sizeof (struct ieee80211_frame)) {
+-                                      bus_dma_sync_single(sc->sc_bdev,
+-                                          bf->bf_skbaddr, len,
+-                                          BUS_DMA_FROMDEVICE);
+-#if 0
+-/* XXX revalidate MIC, lookup ni to find VAP */
+-                                      ieee80211_notify_michael_failure(ic,
+-                                          (struct ieee80211_frame *)skb->data,
+-                                          sc->sc_splitmic ?
+-                                              rs->rs_keyix - 32 : rs->rs_keyix
+-                                      );
+-#endif
+-                              }
++                              mic_fail = 1;
++                              goto rx_accept;
+                       }
+                       /*
+                        * Reject error frames if we have no vaps that
+@@ -6614,8 +6599,9 @@ rx_accept:
+               /*
+                * Finished monitor mode handling, now reject
+                * error frames before passing to other vaps
++               * Ignore MIC failures here, as we need to recheck them
+                */
+-              if (rs->rs_status != 0) {
++              if (rs->rs_status & ~(HAL_RXERR_MIC | HAL_RXERR_DECRYPT)) {
+                       ieee80211_dev_kfree_skb(&skb);
+                       goto rx_next;
+               }
+@@ -6623,6 +6609,26 @@ rx_accept:
+               /* remove the CRC */
+               skb_trim(skb, skb->len - IEEE80211_CRC_LEN);
++              if (mic_fail) {
++                      /* Ignore control frames which are reported with mic error */
++                  if ((((struct ieee80211_frame *)skb->data)->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);
++
++                      if (ni && ni->ni_table) {
++                              ieee80211_check_mic(ni, skb);
++                              ieee80211_unref_node(&ni);
++                      }
++
++drop_micfail:
++                      dev_kfree_skb_any(skb);
++                      skb = NULL;
++                      mic_fail = 0;
++                      goto rx_next;
++              }
++
+               /*
+                * From this point on we assume the frame is at least
+                * as large as ieee80211_frame_min; verify that.
+@@ -6635,6 +6641,7 @@ rx_accept:
+                       goto rx_next;
+               }
++              /* MIC failure. Drop the packet in any case */
+               /*
+                * Normal receive.
+                */
+--- a/net80211/ieee80211_crypto_ccmp.c
++++ b/net80211/ieee80211_crypto_ccmp.c
+@@ -73,7 +73,7 @@ static int ccmp_setkey(struct ieee80211_
+ static int ccmp_encap(struct ieee80211_key *, struct sk_buff *, u_int8_t);
+ static int ccmp_decap(struct ieee80211_key *, struct sk_buff *, int);
+ static int ccmp_enmic(struct ieee80211_key *, struct sk_buff *, int);
+-static int ccmp_demic(struct ieee80211_key *, struct sk_buff *, int);
++static int ccmp_demic(struct ieee80211_key *, struct sk_buff *, int, int);
+ static const struct ieee80211_cipher ccmp = {
+       .ic_name        = "AES-CCM",
+@@ -314,7 +314,7 @@ ccmp_decap(struct ieee80211_key *k, stru
+  * Verify and strip MIC from the frame.
+  */
+ static int
+-ccmp_demic(struct ieee80211_key *k, struct sk_buff *skb, int hdrlen)
++ccmp_demic(struct ieee80211_key *k, struct sk_buff *skb, int hdrlen, int force)
+ {
+       return 1;
+ }
+--- a/net80211/ieee80211_crypto.h
++++ b/net80211/ieee80211_crypto.h
+@@ -145,7 +145,7 @@ struct ieee80211_cipher {
+       int (*ic_encap)(struct ieee80211_key *, struct sk_buff *, u_int8_t);
+       int (*ic_decap)(struct ieee80211_key *, struct sk_buff *, int);
+       int (*ic_enmic)(struct ieee80211_key *, struct sk_buff *, int);
+-      int (*ic_demic)(struct ieee80211_key *, struct sk_buff *, int);
++      int (*ic_demic)(struct ieee80211_key *, struct sk_buff *, int, int);
+ };
+ extern const struct ieee80211_cipher ieee80211_cipher_none;
+@@ -163,10 +163,10 @@ struct ieee80211_key *ieee80211_crypto_d
+  */
+ static __inline int
+ ieee80211_crypto_demic(struct ieee80211vap *vap, struct ieee80211_key *k,
+-      struct sk_buff *skb, int hdrlen)
++      struct sk_buff *skb, int hdrlen, int force)
+ {
+       const struct ieee80211_cipher *cip = k->wk_cipher;
+-      return (cip->ic_miclen > 0 ? cip->ic_demic(k, skb, hdrlen) : 1);
++      return (cip->ic_miclen > 0 ? cip->ic_demic(k, skb, hdrlen, force) : 1);
+ }
+ /*
+--- a/net80211/ieee80211_crypto_none.c
++++ b/net80211/ieee80211_crypto_none.c
+@@ -52,7 +52,7 @@ static int none_setkey(struct ieee80211_
+ static int none_encap(struct ieee80211_key *, struct sk_buff *, u_int8_t);
+ static int none_decap(struct ieee80211_key *, struct sk_buff *, int);
+ static int none_enmic(struct ieee80211_key *, struct sk_buff *, int);
+-static int none_demic(struct ieee80211_key *, struct sk_buff *, int);
++static int none_demic(struct ieee80211_key *, struct sk_buff *, int, int);
+ const struct ieee80211_cipher ieee80211_cipher_none = {
+       .ic_name        = "NONE",
+@@ -137,7 +137,7 @@ none_enmic(struct ieee80211_key *k, stru
+ }
+ static int
+-none_demic(struct ieee80211_key *k, struct sk_buff *skb, int hdrlen)
++none_demic(struct ieee80211_key *k, struct sk_buff *skb, int hdrlen, int force)
+ {
+       struct ieee80211vap *vap = k->wk_private;
+--- a/net80211/ieee80211_crypto_tkip.c
++++ b/net80211/ieee80211_crypto_tkip.c
+@@ -57,7 +57,7 @@ static int tkip_setkey(struct ieee80211_
+ static int tkip_encap(struct ieee80211_key *, struct sk_buff *, u_int8_t);
+ static int tkip_enmic(struct ieee80211_key *, struct sk_buff *, int);
+ static int tkip_decap(struct ieee80211_key *, struct sk_buff *, int);
+-static int tkip_demic(struct ieee80211_key *, struct sk_buff *, int);
++static int tkip_demic(struct ieee80211_key *, struct sk_buff *, int, int);
+ static const struct ieee80211_cipher tkip  = {
+       .ic_name        = "TKIP",
+@@ -339,7 +339,7 @@ tkip_decap(struct ieee80211_key *k, stru
+  * Verify and strip MIC from the frame.
+  */
+ static int
+-tkip_demic(struct ieee80211_key *k, struct sk_buff *skb0, int hdrlen)
++tkip_demic(struct ieee80211_key *k, struct sk_buff *skb0, int hdrlen, int force)
+ {
+       struct tkip_ctx *ctx = k->wk_private;
+       struct sk_buff *skb;
+@@ -355,7 +355,7 @@ tkip_demic(struct ieee80211_key *k, stru
+       }
+       wh = (struct ieee80211_frame *) skb0->data;
+       /* NB: skb left pointing at last in chain */
+-      if (k->wk_flags & IEEE80211_KEY_SWMIC) {
++      if ((k->wk_flags & IEEE80211_KEY_SWMIC) || force) {
+               struct ieee80211vap *vap = ctx->tc_vap;
+               u8 mic[IEEE80211_WEP_MICLEN];
+               u8 mic0[IEEE80211_WEP_MICLEN];
+--- a/net80211/ieee80211_crypto_wep.c
++++ b/net80211/ieee80211_crypto_wep.c
+@@ -54,7 +54,7 @@ static int wep_setkey(struct ieee80211_k
+ static int wep_encap(struct ieee80211_key *, struct sk_buff *, u_int8_t);
+ static int wep_decap(struct ieee80211_key *, struct sk_buff *, int);
+ static int wep_enmic(struct ieee80211_key *, struct sk_buff *, int);
+-static int wep_demic(struct ieee80211_key *, struct sk_buff *, int);
++static int wep_demic(struct ieee80211_key *, struct sk_buff *, int, int);
+ static const struct ieee80211_cipher wep = {
+       .ic_name        = "WEP",
+@@ -244,7 +244,7 @@ wep_decap(struct ieee80211_key *k, struc
+  * Verify and strip MIC from the frame.
+  */
+ static int
+-wep_demic(struct ieee80211_key *k, struct sk_buff *skb, int hdrlen)
++wep_demic(struct ieee80211_key *k, struct sk_buff *skb, int hdrlen, int force)
+ {
+       return 1;
+ }
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -669,7 +669,7 @@ ieee80211_input(struct ieee80211vap * va
+                * Next strip any MSDU crypto bits.
+                */
+               if (key != NULL &&
+-                  !ieee80211_crypto_demic(vap, key, skb, hdrspace)) {
++                  !ieee80211_crypto_demic(vap, key, skb, hdrspace, 0)) {
+                       IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
+                               ni->ni_macaddr, "data", "%s", "demic error");
+                       IEEE80211_NODE_STAT(ni, rx_demicfail);
+@@ -4293,6 +4293,47 @@ ath_eth_type_trans(struct sk_buff *skb,
+ }
+ #endif
++/*
++ * Process a frame w/ hw detected MIC failure.
++ * The frame will be dropped in any case.
++ */
++void
++ieee80211_check_mic(struct ieee80211_node *ni, struct sk_buff *skb)
++{
++      struct ieee80211vap *vap = ni->ni_vap;
++
++      struct ieee80211_frame *wh;
++      struct ieee80211_key *key;
++      int hdrspace;
++      struct ieee80211com *ic = vap->iv_ic;
++
++      if (skb->len < sizeof(struct ieee80211_frame_min)) {
++              IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
++                  ni->ni_macaddr, NULL,
++                  "too short (1): len %u", skb->len);
++              vap->iv_stats.is_rx_tooshort++;
++              return;
++      }
++
++      wh = (struct ieee80211_frame *)skb->data;
++
++      hdrspace = ieee80211_hdrspace(ic, wh);
++      key = ieee80211_crypto_decap(ni, skb, hdrspace);
++      if (key == NULL) {
++              /* NB: stats+msgs handled in crypto_decap */
++              IEEE80211_NODE_STAT(ni, rx_wepfail);
++              return;
++      }
++
++      if (!ieee80211_crypto_demic(vap, key, skb, hdrspace, 1)) {
++              IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
++                      ni->ni_macaddr, "data", "%s", "demic error");
++                      IEEE80211_NODE_STAT(ni, rx_demicfail);
++      }
++      return;
++}
++EXPORT_SYMBOL(ieee80211_check_mic);
++
+ #ifdef IEEE80211_DEBUG
+ /*
+  * Debugging support.
+--- a/net80211/ieee80211_proto.h
++++ b/net80211/ieee80211_proto.h
+@@ -90,6 +90,7 @@ int ieee80211_iserp_rateset(struct ieee8
+ void ieee80211_set11gbasicrates(struct ieee80211_rateset *, enum ieee80211_phymode);
+ enum ieee80211_phymode ieee80211_get11gbasicrates(struct ieee80211_rateset *);
+ void ieee80211_send_pspoll(struct ieee80211_node *);
++void ieee80211_check_mic(struct ieee80211_node *, struct sk_buff *);
+ /*
+  * Return the size of the 802.11 header for a management or data frame.
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -337,8 +337,8 @@ ieee80211_notify_replay_failure(struct i
+       /* TODO: needed parameters: count, keyid, key type, src address, TSC */
+       snprintf(buf, sizeof(buf), "%s(keyid=%d %scast addr=" MAC_FMT ")", tag,
+               k->wk_keyix,
+-              IEEE80211_IS_MULTICAST(wh->i_addr1) ?  "broad" : "uni",
+-              MAC_ADDR(wh->i_addr1));
++              IEEE80211_IS_MULTICAST(wh->i_addr2) ?  "broad" : "uni",
++              MAC_ADDR(wh->i_addr2));
+       memset(&wrqu, 0, sizeof(wrqu));
+       wrqu.data.length = strlen(buf);
+       wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -1074,13 +1074,16 @@ ieee80211_encap(struct ieee80211_node *n
+                       cip = (struct ieee80211_cipher *) key->wk_cipher;
+                       ciphdrsize = cip->ic_header;
+                       tailsize += (cip->ic_trailer + cip->ic_miclen);
++
++                      /* add the 8 bytes MIC length */
++                      if (cip->ic_cipher == IEEE80211_CIPHER_TKIP)
++                              pktlen += IEEE80211_WEP_MICLEN;
+               }
+               pdusize = vap->iv_fragthreshold - (hdrsize_nopad + ciphdrsize);
+               fragcnt = *framecnt =
+-                      ((pktlen - (hdrsize_nopad + ciphdrsize)) / pdusize) +
+-                      (((pktlen - (hdrsize_nopad + ciphdrsize)) %
+-                              pdusize == 0) ? 0 : 1);
++                      ((pktlen - hdrsize_nopad) / pdusize) +
++                      (((pktlen - hdrsize_nopad) % pdusize == 0) ? 0 : 1);
+               /*
+                * Allocate sk_buff for each subsequent fragment; First fragment
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -2264,11 +2264,13 @@ ieee80211_node_leave(struct ieee80211_no
+       /* From this point onwards we can no longer find the node,
+        * so no more references are generated
+        */
+-      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);
++      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);
++      }
+       /*
+        * If node wasn't previously associated all
diff --git a/net/madwifi/patches/310-noise_get.patch b/net/madwifi/patches/310-noise_get.patch
new file mode 100644 (file)
index 0000000..d882158
--- /dev/null
@@ -0,0 +1,55 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1699,8 +1699,6 @@ ath_uapsd_processtriggers(struct ath_sof
+        * get to reality.  This value is used in monitor mode and by tools like
+        * Wireshark and Kismet.
+        */
+-      ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
+-
+       ATH_RXBUF_LOCK_IRQ(sc);
+       if (sc->sc_rxbufcur == NULL)
+               sc->sc_rxbufcur = STAILQ_FIRST(&sc->sc_rxbuf);
+@@ -8975,6 +8973,7 @@ ath_calibrate(unsigned long arg)
+                       sc->sc_curchan.channel);
+               sc->sc_stats.ast_per_calfail++;
+       }
++      ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
+       ath_hal_process_noisefloor(ah);
+       if (isIQdone == AH_TRUE) {
+@@ -9043,6 +9042,7 @@ ath_set_channel(struct ieee80211com *ic)
+       struct ath_softc *sc = dev->priv;
+       (void) ath_chan_set(sc, ic->ic_curchan);
++      ic->ic_channoise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan));
+       /*
+        * If we are returning to our bss channel then mark state
+        * so the next recv'd beacon's TSF will be used to sync the
+@@ -9311,6 +9311,7 @@ ath_newstate(struct ieee80211vap *vap, e
+               }
+               ath_hal_process_noisefloor(ah);
++              ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
+               /*
+                * Reset rssi stats; maybe not the best place...
+                */
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -4358,6 +4358,7 @@ get_sta_info(void *arg, struct ieee80211
+       si->isi_state = ni->ni_flags;
+       si->isi_authmode = ni->ni_authmode;
+       si->isi_rssi = ic->ic_node_getrssi(ni);
++      si->isi_noise = ic->ic_channoise;
+       si->isi_capinfo = ni->ni_capinfo;
+       si->isi_athflags = ni->ni_ath_flags;
+       si->isi_erp = ni->ni_erp;
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -311,6 +311,7 @@ struct ieee80211req_sta_info {
+       u_int16_t isi_state;            /* state flags */
+       u_int8_t isi_authmode;          /* authentication algorithm */
+       u_int8_t isi_rssi;
++      int8_t isi_noise;
+       u_int16_t isi_capinfo;          /* capabilities */
+       u_int8_t isi_athflags;          /* Atheros capabilities */
+       u_int8_t isi_erp;               /* ERP element */
diff --git a/net/madwifi/patches/311-bssid_alloc.patch b/net/madwifi/patches/311-bssid_alloc.patch
new file mode 100644 (file)
index 0000000..005a677
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1354,7 +1354,7 @@ ath_vap_create(struct ieee80211com *ic,
+               TAILQ_FOREACH(v, &ic->ic_vaps, iv_next)
+                       id_mask |= (1 << ATH_GET_VAP_ID(v->iv_myaddr));
+-              for (id = 1; id < ath_maxvaps; id++) {
++              for (id = 0; id < ath_maxvaps; id++) {
+                       /* get the first available slot */
+                       if ((id_mask & (1 << id)) == 0) {
+                               ATH_SET_VAP_BSSID(vap->iv_myaddr, id);
diff --git a/net/madwifi/patches/312-erpupdate.patch b/net/madwifi/patches/312-erpupdate.patch
new file mode 100644 (file)
index 0000000..f878acd
--- /dev/null
@@ -0,0 +1,68 @@
+--- a/net80211/ieee80211_beacon.c
++++ b/net80211/ieee80211_beacon.c
+@@ -542,10 +542,10 @@ ieee80211_beacon_update(struct ieee80211
+                       vap->iv_flags &= ~IEEE80211_F_XRUPDATE;
+               }
+ #endif
+-              if ((ic->ic_flags_ext & IEEE80211_FEXT_ERPUPDATE) && 
++              if ((vap->iv_flags_ext & IEEE80211_FEXT_ERPUPDATE) &&
+                               (bo->bo_erp != NULL)) {
+                       (void)ieee80211_add_erp(bo->bo_erp, ic);
+-                      ic->ic_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE;
++                      vap->iv_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE;
+               }
+       }
+       /* if it is a mode change beacon for dynamic turbo case */
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3431,9 +3431,12 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                       /* Assume no ERP IE == 11b AP */
+                       if ((!has_erp || (has_erp && (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
+                               !(ic->ic_flags & IEEE80211_F_USEPROT)) {
++                              struct ieee80211vap *tmpvap;
+                               ic->ic_flags |= IEEE80211_F_USEPROT;
+-                              ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++                              TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
++                                      tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++                              }
+                       }
+               }
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -2025,8 +2025,12 @@ ieee80211_node_join_11g(struct ieee80211
+               }
+               /* Update ERP element if this is first non ERP station */
+-              if (ic->ic_nonerpsta == 1)
+-                      ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++              if (ic->ic_nonerpsta == 1) {
++                      struct ieee80211vap *tmpvap;
++                      TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
++                              tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++                      }
++              }
+       } else
+               ni->ni_flags |= IEEE80211_NODE_ERP;
+ }
+@@ -2229,6 +2233,8 @@ ieee80211_node_leave_11g(struct ieee8021
+               IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
+                       "non-ERP station leaves, count now %d", ic->ic_nonerpsta);
+               if (ic->ic_nonerpsta == 0) {
++                      struct ieee80211vap *tmpvap;
++
+                       IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
+                               "%s: disable use of protection\n", __func__);
+                       ic->ic_flags &= ~IEEE80211_F_USEPROT;
+@@ -2240,7 +2246,9 @@ ieee80211_node_leave_11g(struct ieee8021
+                               ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
+                               ic->ic_flags &= ~IEEE80211_F_USEBARKER;
+                       }
+-                      ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++                      TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
++                              tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++                      }
+               }
+       }
+ }
diff --git a/net/madwifi/patches/317-bmask.patch b/net/madwifi/patches/317-bmask.patch
new file mode 100644 (file)
index 0000000..3355dc7
--- /dev/null
@@ -0,0 +1,13 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -8689,6 +8689,10 @@ ath_startrecv(struct ath_softc *sc)
+       sc->sc_rxbufcur = NULL;
++      /* configure bssid mask */
++      if (sc->sc_hasbmask)
++              ath_hal_setbssidmask(ah, sc->sc_bssidmask);
++
+       bf = STAILQ_FIRST(&sc->sc_rxbuf);
+       ath_hal_putrxbuf(ah, bf->bf_daddr);
+       ath_hal_rxena(ah);              /* enable recv descriptors */
diff --git a/net/madwifi/patches/323-dfs_optional.patch b/net/madwifi/patches/323-dfs_optional.patch
new file mode 100644 (file)
index 0000000..2336d74
--- /dev/null
@@ -0,0 +1,38 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1778,17 +1778,14 @@ ath_uapsd_processtriggers(struct ath_sof
+                        * may have occurred in the intervening timeframe. */
+                       bf->bf_channoise = ic->ic_channoise;
+-                      if (rs->rs_status) {
+-                              if ((HAL_RXERR_PHY == rs->rs_status) &&
+-                                  (HAL_PHYERR_RADAR ==
+-                                   (rs->rs_phyerr & 0x1f)) &&
+-                                  (0 == (bf->bf_status &
+-                                         ATH_BUFSTATUS_RADAR_DONE))) {
+-                                      check_for_radar = 1;
+-                              }
+-                              /* Skip past the error now */
++                      if ((HAL_RXERR_PHY == rs->rs_status) &&
++                          (HAL_PHYERR_RADAR == (rs->rs_phyerr & 0x1f)) &&
++                          (0 == (bf->bf_status & ATH_BUFSTATUS_RADAR_DONE)) &&
++                          (ic->ic_flags & IEEE80211_F_DOTH))
++                              check_for_radar = 1;
++
++                      if (rs->rs_status) /* Skip past the error now */
+                               continue;
+-                      }
+                       /* Prepare wireless header for examination */
+                       bus_dma_sync_single(sc->sc_bdev, bf->bf_skbaddr,
+--- a/ath/if_ath_radar.c
++++ b/ath/if_ath_radar.c
+@@ -265,7 +265,7 @@ int ath_radar_update(struct ath_softc *s
+               unsigned int new_rxfilt = old_rxfilt;
+               ath_hal_intrset(ah, old_ier & ~HAL_INT_GLOBAL);
+-              if (required) {
++              if ((required) && (ic->ic_flags & IEEE80211_F_DOTH)) {
+                       new_radar |= AR5K_PHY_RADAR_ENABLE;
+                       new_filter |= AR5K_AR5212_PHY_ERR_FIL_RADAR;
+                       new_rxfilt |= (HAL_RX_FILTER_PHYERR | 
diff --git a/net/madwifi/patches/324-alignment.patch b/net/madwifi/patches/324-alignment.patch
new file mode 100644 (file)
index 0000000..c01135f
--- /dev/null
@@ -0,0 +1,19 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1275,14 +1275,8 @@ ieee80211_decap(struct ieee80211vap *vap
+               eh->ether_type = ether_type;
+       if (!ALIGNED_POINTER(skb->data + sizeof(*eh), u_int32_t)) {
+-              struct sk_buff *tskb;
+-
+-              /* XXX: does this always work? */
+-              tskb = skb_copy(skb, GFP_ATOMIC);
+-              if (tskb)
+-                      ieee80211_skb_copy_noderef(skb, tskb);
+-              ieee80211_dev_kfree_skb(&skb);
+-              skb = tskb;
++              memmove(skb->data - 2, skb->data, skb->len);
++              skb->data -= 2;
+       }
+       return skb;
+ }
diff --git a/net/madwifi/patches/325-channel_spam.patch b/net/madwifi/patches/325-channel_spam.patch
new file mode 100644 (file)
index 0000000..e34b7a4
--- /dev/null
@@ -0,0 +1,28 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -9792,7 +9792,9 @@ ath_getchannels(struct net_device *dev,
+       /*
+        * Convert HAL channels to ieee80211 ones.
+        */
++#ifdef AR_DEBUG
+       IPRINTF(sc, "HAL returned %d channels.\n", nchan);
++#endif
+       for (i = 0; i < nchan; i++) {
+               HAL_CHANNEL *c = &chans[i];
+               struct ieee80211_channel *ichan = &ic->ic_channels[i];
+@@ -9819,6 +9821,7 @@ ath_getchannels(struct net_device *dev,
+               ic->ic_chan_non_occupy[i].tv_sec  = 0;
+               ic->ic_chan_non_occupy[i].tv_usec = 0;
++#ifdef AR_DEBUG
+               IPRINTF(sc, "Channel %3d (%4d MHz) Max Tx Power %d dBm%s "
+                               "[%d hw %d reg] Flags%s%s%s%s%s%s%s%s%s%s%s%s%"
+                               "s%s%s%s%s%s%s%s%s%s%s%s\n",
+@@ -9907,6 +9910,7 @@ ath_getchannels(struct net_device *dev,
+                               (c->privFlags & 0x0080 ? 
+                                " PF & (1 << 7)" : "")
+                               );
++#endif
+       }
+       ic->ic_nchans = nchan;
+       kfree(chans);
diff --git a/net/madwifi/patches/327-queue.patch b/net/madwifi/patches/327-queue.patch
new file mode 100644 (file)
index 0000000..228aae3
--- /dev/null
@@ -0,0 +1,40 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -8438,8 +8438,6 @@ process_tx_again:
+       ath_hal_intrset(sc->sc_ah, sc->sc_imask);
+       local_irq_restore(flags);
+-      netif_wake_queue(dev);
+-
+       if (sc->sc_softled)
+               ath_led_event(sc, ATH_LED_TX);
+ }
+@@ -8486,8 +8484,6 @@ process_tx_again:
+       ath_hal_intrset(sc->sc_ah, sc->sc_imask);
+       local_irq_restore(flags);
+-      netif_wake_queue(dev);
+-
+       if (sc->sc_softled)
+               ath_led_event(sc, ATH_LED_TX);
+ }
+@@ -8520,8 +8516,6 @@ process_tx_again:
+       ath_hal_intrset(sc->sc_ah, sc->sc_imask);
+       local_irq_restore(flags);
+-      netif_wake_queue(dev);
+-
+       if (sc->sc_softled)
+               ath_led_event(sc, ATH_LED_TX);
+ }
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1132,7 +1132,7 @@ ieee80211_deliver_data(struct ieee80211_
+           (vap->iv_flags & IEEE80211_F_NOBRIDGE) == 0) {
+               struct sk_buff *skb1 = NULL;
+-              if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
++              if (ETHER_IS_MULTICAST(eh->ether_dhost) && !netif_queue_stopped(dev)) {
+                       /* Create a SKB for the BSS to send out. */
+                       skb1 = skb_copy(skb, GFP_ATOMIC);
+                       if (skb1)
diff --git a/net/madwifi/patches/330-beaconcal.patch b/net/madwifi/patches/330-beaconcal.patch
new file mode 100644 (file)
index 0000000..a338dc7
--- /dev/null
@@ -0,0 +1,166 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -397,6 +397,7 @@ static int countrycode = -1;
+ static int maxvaps = -1;
+ static int outdoor = -1;
+ static int xchanmode = -1;
++static int beacon_cal = 1;
+ static const char *hal_status_desc[] = {
+       "No error",
+@@ -422,6 +423,7 @@ static struct notifier_block ath_event_b
+ };
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
++MODULE_PARM(beacon_cal, "i");
+ MODULE_PARM(countrycode, "i");
+ MODULE_PARM(maxvaps, "i");
+ MODULE_PARM(outdoor, "i");
+@@ -434,6 +436,7 @@ MODULE_PARM(autocreate, "s");
+ MODULE_PARM(ratectl, "s");
+ #else
+ #include <linux/moduleparam.h>
++module_param(beacon_cal, int, 0600);
+ module_param(countrycode, int, 0600);
+ module_param(maxvaps, int, 0600);
+ module_param(outdoor, int, 0600);
+@@ -2600,7 +2603,8 @@ ath_stop_locked(struct net_device *dev)
+               }
+               if (!sc->sc_invalid) {
+                       del_timer_sync(&sc->sc_dfs_cac_timer);
+-                      del_timer_sync(&sc->sc_cal_ch);
++                      if (!sc->sc_beacon_cal)
++                              del_timer_sync(&sc->sc_cal_ch);
+               }
+               ath_draintxq(sc);
+               if (!sc->sc_invalid) {
+@@ -2617,6 +2621,20 @@ ath_stop_locked(struct net_device *dev)
+       return 0;
+ }
++static void ath_set_beacon_cal(struct ath_softc *sc, int val)
++{
++      if (sc->sc_beacon_cal == !!val)
++              return;
++
++      if (val) {
++              del_timer_sync(&sc->sc_cal_ch);
++      } else {
++              sc->sc_cal_ch.expires = jiffies + (ath_calinterval * HZ);
++              add_timer(&sc->sc_cal_ch);
++      }
++      sc->sc_beacon_cal = !!val && beacon_cal;
++}
++
+ /*
+  * Stop the device, grabbing the top-level lock to protect
+  * against concurrent entry through ath_init (which can happen
+@@ -2742,6 +2760,12 @@ ath_reset(struct net_device *dev)
+       HAL_STATUS status;
+       /*
++       * XXX: starting the calibration too early seems to lead to
++       * problems with the beacons.
++       */
++      sc->sc_lastcal = jiffies;
++
++      /*
+        * Convert to a HAL channel description with the flags
+        * constrained to reflect the current operating mode.
+        */
+@@ -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))) {
++                      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 +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);
++              ath_set_beacon_cal(sc, 0);
+       } else {
+               ath_hal_intrset(ah, 0);
+               if (reset_tsf)
+@@ -5414,8 +5443,11 @@ ath_beacon_config(struct ath_softc *sc,
+                        */
+                       intval |= HAL_BEACON_ENA;
+                       sc->sc_imask |= HAL_INT_SWBA;
++                      ath_set_beacon_cal(sc, 1);
+                       ath_beaconq_config(sc);
+-              }
++              } else
++                      ath_set_beacon_cal(sc, 0);
++
+ #ifdef ATH_SUPERG_DYNTURBO
+               ath_beacon_dturbo_config(vap, intval &
+                               ~(HAL_BEACON_RESET_TSF | HAL_BEACON_ENA));
+@@ -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));
++
++                      /* This is a good time to start a calibration */
++                      ath_set_beacon_cal(sc, 1);
+               }
+               /*
+                * re configure beacons when it is a turbo mode switch.
+@@ -8988,8 +9023,11 @@ ath_calibrate(unsigned long arg)
+               sc->sc_curchan.channel, sc->sc_curchan.channelFlags,
+               isIQdone ? "done" : "not done");
+-      sc->sc_cal_ch.expires = jiffies + (ath_calinterval * HZ);
+-      add_timer(&sc->sc_cal_ch);
++      sc->sc_lastcal = jiffies;
++      if (!sc->sc_beacon_cal) {
++              sc->sc_cal_ch.expires = jiffies + (ath_calinterval * HZ);
++              add_timer(&sc->sc_cal_ch);
++      }
+ }
+ static void
+@@ -9096,7 +9134,8 @@ ath_newstate(struct ieee80211vap *vap, e
+               ieee80211_state_name[vap->iv_state],
+               ieee80211_state_name[nstate]);
+-      del_timer(&sc->sc_cal_ch);              /* periodic calibration timer */
++      if (!sc->sc_beacon_cal)
++              del_timer(&sc->sc_cal_ch);              /* periodic calibration timer */
+       ath_hal_setledstate(ah, leds[nstate]);  /* set LED */
+       netif_stop_queue(dev);                  /* before we do anything else */
+@@ -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 */
+-                      mod_timer(&sc->sc_cal_ch, jiffies + (HZ/10));
++                      if (!sc->sc_beacon_cal)
++                              mod_timer(&sc->sc_cal_ch, jiffies + (HZ/10));
+                       /* wake the receiver */
+                       netif_wake_queue(dev);
+                       /* don't do the other usual stuff... */
+@@ -9364,7 +9404,7 @@ done:
+       error = avp->av_newstate(vap, nstate, arg);
+       /* Finally, start any timers. */
+-      if (nstate == IEEE80211_S_RUN) {
++      if (nstate == IEEE80211_S_RUN && !sc->sc_beacon_cal) {
+               /* start periodic recalibration timer */
+               mod_timer(&sc->sc_cal_ch, jiffies + (ath_calinterval * HZ));
+       }
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -778,6 +778,8 @@ struct ath_softc {
+       struct ieee80211vap **sc_bslot;         /* beacon xmit slots */
+       int sc_bnext;                           /* next slot for beacon xmit */
++      int sc_beacon_cal;                      /* use beacon timer for calibration */
++      u_int64_t sc_lastcal;                   /* last time the calibration was performed */
+       struct timer_list sc_cal_ch;            /* calibration timer */
+       HAL_NODE_STATS sc_halstats;             /* station-mode rssi stats */
diff --git a/net/madwifi/patches/331-memory_alloc.patch b/net/madwifi/patches/331-memory_alloc.patch
new file mode 100644 (file)
index 0000000..6b01d79
--- /dev/null
@@ -0,0 +1,36 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -3320,17 +3320,18 @@ ath_hardstart(struct sk_buff *skb, struc
+        * without affecting any other bridge ports. */
+       if (skb_cloned(skb)) {
+               /* Remember the original SKB so we can free up our references */
+-              struct sk_buff *skb_orig = skb;
+-              skb = skb_copy(skb, GFP_ATOMIC);
+-              if (skb == NULL) {
++              struct sk_buff *skb_new;
++              skb_new = skb_copy(skb, GFP_ATOMIC);
++              if (skb_new == NULL) {
+                       DPRINTF(sc, ATH_DEBUG_XMIT,
+                               "Dropping; skb_copy failure.\n");
+                       /* No free RAM, do not requeue! */
+                       goto hardstart_fail;
+               }
+-              ieee80211_skb_copy_noderef(skb_orig, skb);
+-              ieee80211_dev_kfree_skb(&skb_orig);
+-      } 
++              ieee80211_skb_copy_noderef(skb, skb_new);
++              ieee80211_dev_kfree_skb(&skb);
++              skb = skb_new;
++      }
+       eh = (struct ether_header *)skb->data;
+ #ifdef ATH_SUPERG_FF
+@@ -3601,6 +3602,8 @@ ath_mgtstart(struct ieee80211com *ic, st
+       sc->sc_stats.ast_tx_mgmt++;
+       return 0;
+ bad:
++      if (skb)
++              ieee80211_dev_kfree_skb(&skb);
+       ath_return_txbuf(sc, &bf);
+       return error;
+ }
diff --git a/net/madwifi/patches/332-reset_beacons.patch b/net/madwifi/patches/332-reset_beacons.patch
new file mode 100644 (file)
index 0000000..b776426
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -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.
+                */
+-              if (sc->sc_beacons && tswitch && !sc->sc_dfs_cac)
++              if (sc->sc_beacons && !sc->sc_dfs_cac)
+                       ath_beacon_config(sc, NULL);
+               /*
+                * Re-enable interrupts.
diff --git a/net/madwifi/patches/333-apscan_mode.patch b/net/madwifi/patches/333-apscan_mode.patch
new file mode 100644 (file)
index 0000000..877eea6
--- /dev/null
@@ -0,0 +1,15 @@
+--- a/net80211/ieee80211_scan_ap.c
++++ b/net80211/ieee80211_scan_ap.c
+@@ -783,12 +783,6 @@ pick_channel(struct ieee80211_scan_state
+                               /* break the loop as the subsequent chans won't be 
+                                * better */
+                               break;
+-
+-                      if (!IEEE80211_ARE_CHANS_SAME_MODE(c->chan,
+-                              ic->ic_bsschan))
+-                              /* break the loop as the subsequent chans won't be 
+-                               * better */
+-                              break;
+               }
+               if (sta_assoc != 0) {
diff --git a/net/madwifi/patches/334-input.patch b/net/madwifi/patches/334-input.patch
new file mode 100644 (file)
index 0000000..7c13367
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -950,6 +950,9 @@ ieee80211_input_all(struct ieee80211com
+       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+               struct sk_buff *skb1;
++              if ((vap->iv_dev->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
++                      continue;
++
+               if (TAILQ_NEXT(vap, iv_next) != NULL) {
+                       skb1 = skb_copy(skb, GFP_ATOMIC);
+                       if (skb1 == NULL) {
diff --git a/net/madwifi/patches/340-maxrate.patch b/net/madwifi/patches/340-maxrate.patch
new file mode 100644 (file)
index 0000000..ae93f02
--- /dev/null
@@ -0,0 +1,98 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1307,6 +1307,7 @@ ath_vap_create(struct ieee80211com *ic,
+       vap->iv_key_set = ath_key_set;
+       vap->iv_key_update_begin = ath_key_update_begin;
+       vap->iv_key_update_end = ath_key_update_end;
++      vap->iv_maxrateindex = 0;
+       if (sc->sc_default_ieee80211_debug) {
+               /* User specified defaults for new VAPs were provided, so
+                * use those (only). */
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -622,8 +622,12 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+                       return;
+               }
+               sn->static_rate_ndx = -1;
++              if (vap->iv_maxrateindex == 0 || ni->ni_rates.rs_nrates <= 0
++                  || vap->iv_maxrateindex > ni->ni_rates.rs_nrates)
++                      sn->num_rates = ni->ni_rates.rs_nrates;
++              else
++                      sn->num_rates = vap->iv_maxrateindex;
+-              sn->num_rates = ni->ni_rates.rs_nrates;
+               for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+                       sn->rs_rateattempts     [x] = 0;
+                       sn->rs_thisprob         [x] = 0;
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -835,7 +835,12 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+       }
+       sn->static_rate_ndx = -1;
+-      sn->num_rates = ni->ni_rates.rs_nrates;
++      if (vap->iv_maxrateindex == 0 || ni->ni_rates.rs_nrates <= 0
++          || vap->iv_maxrateindex > ni->ni_rates.rs_nrates)
++              sn->num_rates = ni->ni_rates.rs_nrates;
++      else
++              sn->num_rates = vap->iv_maxrateindex;
++
+       for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+               sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
+               sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -641,6 +641,7 @@ enum {
+                                                          FCC requires 30m, so that is the default. */
+       IEEE80211_PARAM_BEACON_MISS_THRESH      = 73,   /* Beacon miss threshold (in beacons) */
+       IEEE80211_PARAM_BEACON_MISS_THRESH_MS   = 74,   /* Beacon miss threshold (in ms) */
++      IEEE80211_PARAM_MAXRATE                 = 75,   /* Maximum rate (by table index) */
+ };
+ #define       SIOCG80211STATS                 (SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -281,6 +281,7 @@ struct ieee80211vap {
+       struct ieee80211_spy iv_spy;                    /* IWSPY support */
+       struct ieee80211_app_ie app_ie[IEEE80211_APPIE_NUM_OF_FRAME]; /* app-specified IEs by frame type */
+       u_int32_t app_filter;                           /* filters which management frames are forwarded to app */
++      u_int iv_maxrateindex;
+ };
+ /* Debug functions need the defintion of struct ieee80211vap because iv_debug 
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2839,6 +2839,12 @@ ieee80211_ioctl_setparam(struct net_devi
+               else
+                       ic->ic_flags_ext &= ~IEEE80211_FEXT_MARKDFS;
+               break;
++      case IEEE80211_PARAM_MAXRATE:
++              if (value > 0)
++                      vap->iv_maxrateindex = value;
++              else
++                      vap->iv_maxrateindex = 0;
++              break;
+ #ifdef ATH_REVERSE_ENGINEERING
+       case IEEE80211_PARAM_DUMPREGS:
+               ieee80211_dump_registers(dev, info, w, extra);
+@@ -3174,6 +3180,9 @@ ieee80211_ioctl_getparam(struct net_devi
+               else
+                       param[0] = 0;
+               break;
++      case IEEE80211_PARAM_MAXRATE:
++              param[0] = vap->iv_maxrateindex;
++              break;
+       default:
+               return -EOPNOTSUPP;
+       }
+@@ -5610,6 +5619,10 @@ static const struct iw_priv_args ieee802
+         0, IW_PRIV_TYPE_APPIEBUF, "getiebuf" },
+       { IEEE80211_IOCTL_FILTERFRAME,
+         IW_PRIV_TYPE_FILTER , 0, "setfilter" },
++      {IEEE80211_PARAM_MAXRATE,
++       IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maxrate"},
++      {IEEE80211_PARAM_MAXRATE,
++       0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_maxrate"},
+ #ifdef ATH_REVERSE_ENGINEERING
+       /*
diff --git a/net/madwifi/patches/341-minrate.patch b/net/madwifi/patches/341-minrate.patch
new file mode 100644 (file)
index 0000000..cc04ae0
--- /dev/null
@@ -0,0 +1,114 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1308,6 +1308,7 @@ ath_vap_create(struct ieee80211com *ic,
+       vap->iv_key_update_begin = ath_key_update_begin;
+       vap->iv_key_update_end = ath_key_update_end;
+       vap->iv_maxrateindex = 0;
++      vap->iv_minrateindex = 0;
+       if (sc->sc_default_ieee80211_debug) {
+               /* User specified defaults for new VAPs were provided, so
+                * use those (only). */
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -638,9 +638,15 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+                       sn->rs_succ_hist        [x] = 0;
+                       sn->rs_att_hist         [x] = 0;
+                       sn->rs_this_tp          [x] = 0;
+-
++                      if (vap->iv_minrateindex && vap->iv_minrateindex<ni->ni_rates.rs_nrates)
++                      {
++                      int idx = vap->iv_minrateindex; 
++                      sn->rates[x].rate = ni->ni_rates.rs_rates[idx] & IEEE80211_RATE_VAL;
++                      sn->rates[x].rix = sc->sc_rixmap[sn->rates[idx].rate];
++                      }else{
+                       sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
+                       sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
++                      }
+                       if (sn->rates[x].rix == 0xff) {
+                               DPRINTF(sc, "%s: %s ignore bogus rix at %d\n",
+                                       dev_info, __func__, x);
+@@ -649,7 +655,7 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+                       sn->rates[x].rateCode = rt->info[sn->rates[x].rix].rateCode;
+                       sn->rates[x].shortPreambleRateCode =
+                               rt->info[sn->rates[x].rix].rateCode |
+-                              rt->info[sn->rates[x].rix].shortPreamble;
++                              rt->info[sn->rates[x].rix].shortPreamble;                       
+               }
+               ath_fill_sample_table(sn);
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -842,8 +842,15 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+               sn->num_rates = vap->iv_maxrateindex;
+       for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+-              sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
+-              sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
++              if (vap->iv_minrateindex && vap->iv_minrateindex<ni->ni_rates.rs_nrates)
++                      {
++                      int idx = vap->iv_minrateindex; 
++                      sn->rates[x].rate = ni->ni_rates.rs_rates[idx] & IEEE80211_RATE_VAL;
++                      sn->rates[x].rix = sc->sc_rixmap[sn->rates[idx].rate];
++                      }else{
++                      sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
++                      sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
++                      }
+               if (sn->rates[x].rix == 0xff) {
+                       DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s ignore bogus rix at %u\n",
+                               dev_info, __func__, x);
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -642,6 +642,7 @@ enum {
+       IEEE80211_PARAM_BEACON_MISS_THRESH      = 73,   /* Beacon miss threshold (in beacons) */
+       IEEE80211_PARAM_BEACON_MISS_THRESH_MS   = 74,   /* Beacon miss threshold (in ms) */
+       IEEE80211_PARAM_MAXRATE                 = 75,   /* Maximum rate (by table index) */
++      IEEE80211_PARAM_MINRATE                 = 76,   /* Minimum rate (by table index) */
+ };
+ #define       SIOCG80211STATS                 (SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -282,6 +282,7 @@ struct ieee80211vap {
+       struct ieee80211_app_ie app_ie[IEEE80211_APPIE_NUM_OF_FRAME]; /* app-specified IEs by frame type */
+       u_int32_t app_filter;                           /* filters which management frames are forwarded to app */
+       u_int iv_maxrateindex;
++      u_int iv_minrateindex;
+ };
+ /* Debug functions need the defintion of struct ieee80211vap because iv_debug 
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2845,6 +2845,12 @@ ieee80211_ioctl_setparam(struct net_devi
+               else
+                       vap->iv_maxrateindex = 0;
+               break;
++      case IEEE80211_PARAM_MINRATE:
++              if (value > 0)
++                      vap->iv_minrateindex = value;
++              else
++                      vap->iv_minrateindex = 0;
++              break;
+ #ifdef ATH_REVERSE_ENGINEERING
+       case IEEE80211_PARAM_DUMPREGS:
+               ieee80211_dump_registers(dev, info, w, extra);
+@@ -3183,6 +3189,9 @@ ieee80211_ioctl_getparam(struct net_devi
+       case IEEE80211_PARAM_MAXRATE:
+               param[0] = vap->iv_maxrateindex;
+               break;
++      case IEEE80211_PARAM_MINRATE:
++              param[0] = vap->iv_minrateindex;
++              break;
+       default:
+               return -EOPNOTSUPP;
+       }
+@@ -5623,6 +5632,10 @@ static const struct iw_priv_args ieee802
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maxrate"},
+       {IEEE80211_PARAM_MAXRATE,
+        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_maxrate"},
++      {IEEE80211_PARAM_MINRATE,
++       IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "minrate"},
++      {IEEE80211_PARAM_MINRATE,
++       0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"},
+ #ifdef ATH_REVERSE_ENGINEERING
+       /*
diff --git a/net/madwifi/patches/342-performance.patch b/net/madwifi/patches/342-performance.patch
new file mode 100644 (file)
index 0000000..88cec18
--- /dev/null
@@ -0,0 +1,263 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -3239,7 +3239,6 @@ ath_hardstart(struct sk_buff *skb, struc
+       struct ath_softc *sc = dev->priv;
+       struct ieee80211_node *ni = NULL;
+       struct ath_buf *bf = NULL;
+-      struct ether_header *eh;
+       ath_bufhead bf_head;
+       struct ath_buf *tbf, *tempbf;
+       struct sk_buff *tskb;
+@@ -3251,6 +3250,7 @@ ath_hardstart(struct sk_buff *skb, struc
+       */
+       int requeue = 0;
+ #ifdef ATH_SUPERG_FF
++      struct ether_header *eh;
+       unsigned int pktlen;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_node *an;
+@@ -3316,27 +3316,9 @@ ath_hardstart(struct sk_buff *skb, struc
+               requeue = 1;
+               goto hardstart_fail;
+       }
+-#endif
+-      /* If the skb data is shared, we will copy it so we can strip padding
+-       * without affecting any other bridge ports. */
+-      if (skb_cloned(skb)) {
+-              /* Remember the original SKB so we can free up our references */
+-              struct sk_buff *skb_new;
+-              skb_new = skb_copy(skb, GFP_ATOMIC);
+-              if (skb_new == NULL) {
+-                      DPRINTF(sc, ATH_DEBUG_XMIT,
+-                              "Dropping; skb_copy failure.\n");
+-                      /* No free RAM, do not requeue! */
+-                      goto hardstart_fail;
+-              }
+-              ieee80211_skb_copy_noderef(skb, skb_new);
+-              ieee80211_dev_kfree_skb(&skb);
+-              skb = skb_new;
+-      }
+       eh = (struct ether_header *)skb->data;
+-#ifdef ATH_SUPERG_FF
+       /* NB: use this lock to protect an->an_tx_ffbuf (and txq->axq_stageq)
+        *     in athff_can_aggregate() call too. */
+       ATH_TXQ_LOCK_IRQ(txq);
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -283,7 +283,7 @@ ieee80211_hardstart(struct sk_buff *skb,
+        * normal vap. */
+       if (vap->iv_xrvap && (ni == vap->iv_bss) &&
+           vap->iv_xrvap->iv_sta_assoc) {
+-              struct sk_buff *skb1 = skb_copy(skb, GFP_ATOMIC);
++              struct sk_buff *skb1 = skb_clone(skb, GFP_ATOMIC);
+               if (skb1) {
+                       memset(SKB_CB(skb1), 0, sizeof(struct ieee80211_cb));
+ #ifdef IEEE80211_DEBUG_REFCNT
+@@ -566,7 +566,7 @@ ieee80211_skbhdr_adjust(struct ieee80211
+       struct ieee80211_key *key, struct sk_buff *skb, int ismulticast)
+ {
+       /* XXX pre-calculate per node? */
+-      int need_headroom = LLC_SNAPFRAMELEN + hdrsize + IEEE80211_ADDR_LEN;
++      int need_headroom = LLC_SNAPFRAMELEN + hdrsize;
+       int need_tailroom = 0;
+ #ifdef ATH_SUPERG_FF
+       int isff = ATH_FF_MAGIC_PRESENT(skb);
+@@ -608,109 +608,56 @@ ieee80211_skbhdr_adjust(struct ieee80211
+                               need_tailroom += cip->ic_miclen;
+       }
+-      if (skb_shared(skb)) {
+-              /* Take our own reference to the node in the clone */
+-              ieee80211_ref_node(SKB_CB(skb)->ni);
+-              /* Unshare the node, decrementing users in the old skb */
+-              skb = skb_unshare(skb, GFP_ATOMIC);
+-      }
++      need_headroom -= skb_headroom(skb);
++      if (isff)
++              need_tailroom -= skb_tailroom(skb2);
++      else
++              need_tailroom -= skb_tailroom(skb);
++
++      if (need_headroom < 0)
++              need_headroom = 0;
++      if (need_tailroom < 0)
++              need_tailroom = 0;
+-#ifdef ATH_SUPERG_FF
+-      if (isff) {
+-              if (skb == NULL) {
+-                      IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-                              "%s: cannot unshare for encapsulation\n",
+-                              __func__);
+-                      vap->iv_stats.is_tx_nobuf++;
+-                      ieee80211_dev_kfree_skb(&skb2);
++      if (skb_cloned(skb) || (need_headroom > 0) ||
++              (!isff && (need_tailroom > 0))) {
+-                      return NULL;
++              if (pskb_expand_head(skb, need_headroom, need_tailroom, GFP_ATOMIC)) {
++                      IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
++                              "%s: cannot expand storage (tail)\n", __func__);
++                      goto error;
+               }
++      }
+-              /* first skb header */
+-              if (skb_headroom(skb) < need_headroom) {
+-                      struct sk_buff *tmp = skb;
+-                      skb = skb_realloc_headroom(skb, need_headroom);
+-                      if (skb == NULL) {
+-                              IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-                                      "%s: cannot expand storage (head1)\n",
+-                                      __func__);
+-                              vap->iv_stats.is_tx_nobuf++;
+-                              ieee80211_dev_kfree_skb(&skb2);
+-                              return NULL;
+-                      } else
+-                              ieee80211_skb_copy_noderef(tmp, skb);
+-                      ieee80211_dev_kfree_skb(&tmp);
+-                      /* NB: cb[] area was copied, but not next ptr. must do that
+-                       *     prior to return on success. */
+-              }
++#ifdef ATH_SUPERG_FF
++      if (isff) {
++              inter_headroom -= skb_headroom(skb2);
++              if (inter_headroom < 0)
++                      inter_headroom = 0;
++              if ((skb_cloned(skb2) ||
++                      (inter_headroom > 0) || (need_tailroom > 0))) {
+-              /* second skb with header and tail adjustments possible */
+-              if (skb_tailroom(skb2) < need_tailroom) {
+-                      int n = 0;
+-                      if (inter_headroom > skb_headroom(skb2))
+-                              n = inter_headroom - skb_headroom(skb2);
+-                      if (pskb_expand_head(skb2, n,
+-                          need_tailroom - skb_tailroom(skb2), GFP_ATOMIC)) {
+-                              ieee80211_dev_kfree_skb(&skb2);
++                      if (pskb_expand_head(skb2, inter_headroom,
++                              need_tailroom, GFP_ATOMIC)) {
+                               IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-                                      "%s: cannot expand storage (tail2)\n",
+-                                      __func__);
+-                              vap->iv_stats.is_tx_nobuf++;
+-                              /* this shouldn't happen, but don't send first ff either */
+-                              ieee80211_dev_kfree_skb(&skb);
++                                      "%s: cannot expand storage (tail)\n", __func__);
++                              goto error;
+                       }
+-              } else if (skb_headroom(skb2) < inter_headroom) {
+-                      struct sk_buff *tmp = skb2;
+-
+-                      skb2 = skb_realloc_headroom(skb2, inter_headroom);
+-                      if (skb2 == NULL) {
+-                              IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-                                      "%s: cannot expand storage (head2)\n",
+-                                      __func__);
+-                              vap->iv_stats.is_tx_nobuf++;
+-                              /* this shouldn't happen, but don't send first ff either */
+-                              ieee80211_dev_kfree_skb(&skb);
+-                              skb = NULL;
+-                      } else
+-                              ieee80211_skb_copy_noderef(tmp, skb);
+-                      ieee80211_dev_kfree_skb(&tmp);
+-              }
+-              if (skb) {
+-                      skb->next = skb2;
+               }
+-              return skb;
++              skb->next = skb2;
+       }
+ #endif /* ATH_SUPERG_FF */
+-      if (skb == NULL) {
+-              IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-                      "%s: cannot unshare for encapsulation\n", __func__);
+-              vap->iv_stats.is_tx_nobuf++;
+-      } else if (skb_tailroom(skb) < need_tailroom) {
+-              int n = 0;
+-              if (need_headroom > skb_headroom(skb))
+-                      n = need_headroom - skb_headroom(skb);
+-              if (pskb_expand_head(skb, n, need_tailroom - 
+-                                      skb_tailroom(skb), GFP_ATOMIC)) {
+-                      IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-                              "%s: cannot expand storage (tail)\n", __func__);
+-                      vap->iv_stats.is_tx_nobuf++;
+-                      ieee80211_dev_kfree_skb(&skb);
+-              }
+-      } else if (skb_headroom(skb) < need_headroom) {
+-              struct sk_buff *tmp = skb;
+-              skb = skb_realloc_headroom(skb, need_headroom);
+-              /* Increment reference count after copy */
+-              if (skb == NULL) {
+-                      IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-                              "%s: cannot expand storage (head)\n", __func__);
+-                      vap->iv_stats.is_tx_nobuf++;
+-              } else
+-                      ieee80211_skb_copy_noderef(tmp, skb);
+-              ieee80211_dev_kfree_skb(&tmp);
+-      }
+       return skb;
++
++error:
++      vap->iv_stats.is_tx_nobuf++;
++      ieee80211_dev_kfree_skb(&skb);
++#ifdef ATH_SUPERG_FF
++      if (skb2)
++              ieee80211_dev_kfree_skb(&skb2);
++#endif
++      return NULL;
+ }
+ #define       KEY_UNDEFINED(k)        ((k).wk_cipher == &ieee80211_cipher_none)
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -204,7 +204,6 @@ ieee80211_input(struct ieee80211vap * va
+       struct ieee80211_frame *wh;
+       struct ieee80211_key *key;
+       struct ether_header *eh;
+-      struct sk_buff *skb2;
+ #ifdef ATH_SUPERG_FF
+       struct llc *llc;
+ #endif
+@@ -244,20 +243,6 @@ ieee80211_input(struct ieee80211vap * va
+               vap->iv_stats.is_rx_tooshort++;
+               goto out;
+       }
+-      /* Clone the SKB... we assume somewhere in this driver that we 'own'
+-       * the skbuff passed into hard start and we do a lot of messing with it
+-       * but bridges under some cases will not clone for the first pass of skb
+-       * to a bridge port, but will then clone for subsequent ones.  This is 
+-       * odd behavior but it means that if we have trashed the skb we are given
+-       * then other ports get clones of the residual garbage.
+-       */
+-      if ((skb2 = skb_copy(skb, GFP_ATOMIC)) == NULL) {
+-              vap->iv_devstats.tx_dropped++;
+-              goto out;
+-      }
+-      ieee80211_skb_copy_noderef(skb, skb2);
+-      ieee80211_dev_kfree_skb(&skb);
+-      skb = skb2;
+       /*
+        * Bit of a cheat here, we use a pointer for a 3-address
+@@ -738,7 +723,7 @@ ieee80211_input(struct ieee80211vap * va
+                       /* ether_type must be length as FF frames are always LLC/SNAP encap'd */ 
+                       frame_len = ntohs(eh_tmp->ether_type); 
+-                      skb1 = skb_copy(skb, GFP_ATOMIC);
++                      skb1 = skb_clone(skb, GFP_ATOMIC);
+                       if (skb1 == NULL)
+                               goto err;
+                       ieee80211_skb_copy_noderef(skb, skb1);
+@@ -1137,7 +1122,7 @@ ieee80211_deliver_data(struct ieee80211_
+               if (ETHER_IS_MULTICAST(eh->ether_dhost) && !netif_queue_stopped(dev)) {
+                       /* Create a SKB for the BSS to send out. */
+-                      skb1 = skb_copy(skb, GFP_ATOMIC);
++                      skb1 = skb_clone(skb, GFP_ATOMIC);
+                       if (skb1)
+                               SKB_CB(skb1)->ni = ieee80211_ref_node(vap->iv_bss); 
+               }
diff --git a/net/madwifi/patches/343-txqueue_races.patch b/net/madwifi/patches/343-txqueue_races.patch
new file mode 100644 (file)
index 0000000..a2b14d6
--- /dev/null
@@ -0,0 +1,34 @@
+Merged from madwifi trunk r3551, r3552
+
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -8253,6 +8253,17 @@ ath_tx_processq(struct ath_softc *sc, st
+                       goto bf_fail;
+               }
++              /* We make sure we don't remove the TX descriptor on
++               * which the HW is pointing since it contains the
++               * ds_link field, except if this is the last TX
++               * descriptor in the queue */
++
++              if ((txq->axq_depth > 1) &&
++                  (bf->bf_daddr == ath_hal_gettxbuf(ah, txq->axq_qnum))) {
++                      ATH_TXQ_UNLOCK_IRQ_EARLY(txq);
++                      goto bf_fail;
++              }
++
+               ATH_TXQ_REMOVE_HEAD(txq, bf_list);
+               ATH_TXQ_UNLOCK_IRQ(txq);
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -586,7 +586,8 @@ struct ath_vap {
+ } while (0)
+ #define ATH_TXQ_REMOVE_HEAD(_tq, _field) do { \
+       STAILQ_REMOVE_HEAD(&(_tq)->axq_q, _field); \
+-      (_tq)->axq_depth--; \
++      if (--(_tq)->axq_depth <= 0) \
++              (_tq)->axq_link = NULL; \
+ } while (0)
+ /* move buffers from MCASTQ to CABQ */
+ #define ATH_TXQ_MOVE_MCASTQ(_tqs,_tqd) do { \
diff --git a/net/madwifi/patches/344-minstrel_failcnt.patch b/net/madwifi/patches/344-minstrel_failcnt.patch
new file mode 100644 (file)
index 0000000..ea92dc4
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -475,7 +475,7 @@ ath_rate_tx_complete(struct ath_softc *s
+               /* 'tries' is the total number of times we have endeavoured to
+                * send this packet, and is a sum of the #attempts at each
+                * level in the multi-rate retry chain */
+-              tries = ts->ts_shortretry + ts->ts_longretry + 1;
++              tries = ts->ts_longretry + 1;
+               if (sn->num_rates <= 0) {
+                       DPRINTF(sc, "%s: " MAC_FMT " %s no rates yet\n", dev_info,
diff --git a/net/madwifi/patches/345-minstrel_sampling.patch b/net/madwifi/patches/345-minstrel_sampling.patch
new file mode 100644 (file)
index 0000000..63fcb8a
--- /dev/null
@@ -0,0 +1,80 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -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);
++              bf->rcflags = mrr.privflags;
+       }
+ #ifndef ATH_SUPERG_FF
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -446,6 +446,7 @@ struct ath_buf {
+       u_int16_t bf_flags;                             /* tx descriptor flags */
+       u_int64_t bf_tsf;
+       int16_t bf_channoise;
++      unsigned int rcflags;
+ #ifdef ATH_SUPERG_FF
+       /* XXX: combine this with bf_skbaddr if it ever changes to accommodate
+        *      multiple segments.
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -333,15 +333,19 @@ ath_rate_findrate(struct ath_softc *sc,
+               if (sn->static_rate_ndx >= 0) {
+                           ndx = sn->static_rate_ndx;
+               } else {
++                      int delta;
+                       sn->packet_count++;
+                       sn->random_n = (sn->a * sn->random_n) + sn->b;
+                       offset = sn->random_n & 0xf;
+-                      if ((((100 * sn->sample_count) / (sn->sample_count + sn->packet_count)) < ath_lookaround_rate) && (offset < 2)) {
++                      delta = (sn->packet_count * ath_lookaround_rate / 100) - sn->sample_count;
++                      if ((delta > 0) && (offset < 2)) {
+                               sn->sample_count++;
+                               sn->is_sampling = 1;
+                               if (sn->packet_count >= 10000) {
+                                       sn->sample_count = 0;
+                                       sn->packet_count = 0;
++                              } else if (delta > sn->num_rates * 2) {
++                                      sn->sample_count += ((delta - sn->num_rates * 2) * ath_lookaround_rate) / 100;
+                               }
+                               /* Don't look for slowest rate (i.e. slowest
+@@ -398,11 +402,14 @@ ath_rate_get_mrr(struct ath_softc *sc, s
+               if (sn->num_rates <= 0)
+                       return;
++              mrr->privflags = sn->is_sampling;
+               if (sn->is_sampling) {
+                       sn->is_sampling = 0;
+-                      if (sn->rs_sample_rate_slower)
++                      if (sn->rs_sample_rate_slower) {
+                               rc1 = sn->rs_sample_rate;
+-                      else
++                              if (sn->sample_count > 0)
++                                      sn->sample_count--;
++                      } else
+                               rc1 = sn->max_tp_rate;
+               } else {
+                       rc1 = sn->max_tp_rate2;
+@@ -525,6 +532,9 @@ ath_rate_tx_complete(struct ath_softc *s
+               if (tries <= tries1)
+                       return;
++              if (bf->rcflags)
++                      sn->sample_count++;
++
+               if  (tries2 < 0)
+                       return;
+               tries = tries - tries1;
+--- a/net80211/ieee80211_rate.h
++++ b/net80211/ieee80211_rate.h
+@@ -87,6 +87,7 @@ struct ieee80211_mrr {
+       int retries2;
+       int rate3;
+       int retries3;
++      int privflags;
+ };
+ struct ieee80211_rate_ops {
diff --git a/net/madwifi/patches/346-protmode_trig.patch b/net/madwifi/patches/346-protmode_trig.patch
new file mode 100644 (file)
index 0000000..5b5cec6
--- /dev/null
@@ -0,0 +1,135 @@
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -333,7 +333,9 @@ ieee80211_ifattach(struct ieee80211com *
+                       IEEE80211_MS_TO_TU(IEEE80211_BMISSTHRESH_DEFAULT_MS), 
+                       ic->ic_lintval), ic->ic_lintval);
+       }
+-              
++      ic->ic_protmode_timeout = IEEE80211_PROTMODE_TIMEOUT;
++      ic->ic_protmode_rssi = IEEE80211_PROTMODE_RSSITHR;
++
+       IEEE80211_LOCK_INIT(ic, "ieee80211com");
+       IEEE80211_VAPS_LOCK_INIT(ic, "ieee80211com_vaps");
+       TAILQ_INIT(&ic->ic_vaps);
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3411,14 +3411,18 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                       IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
+                       /* Assume no ERP IE == 11b AP */
+-                      if ((!has_erp || (has_erp && (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
+-                              !(ic->ic_flags & IEEE80211_F_USEPROT)) {
++                      if ((!has_erp || (has_erp &&
++                              (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
++                              (rssi > ic->ic_protmode_rssi)) {
+                               struct ieee80211vap *tmpvap;
+-                              ic->ic_flags |= IEEE80211_F_USEPROT;
+-                              TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
+-                                      tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++                              if (!(ic->ic_flags & IEEE80211_F_USEPROT)) {
++                                      ic->ic_flags |= IEEE80211_F_USEPROT;
++                                      TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
++                                              tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++                                      }
+                               }
++                              ic->ic_protmode_lasttrig = jiffies;
+                       }
+               }
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -643,6 +643,8 @@ enum {
+       IEEE80211_PARAM_BEACON_MISS_THRESH_MS   = 74,   /* Beacon miss threshold (in ms) */
+       IEEE80211_PARAM_MAXRATE                 = 75,   /* Maximum rate (by table index) */
+       IEEE80211_PARAM_MINRATE                 = 76,   /* Minimum rate (by table index) */
++      IEEE80211_PARAM_PROTMODE_RSSI           = 77,   /* RSSI Threshold for enabling protection mode */
++      IEEE80211_PARAM_PROTMODE_TIMEOUT        = 78,   /* Timeout for expiring protection mode */
+ };
+ #define       SIOCG80211STATS                 (SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -128,6 +128,9 @@
+ #define       IEEE80211_APPIE_MAX     1024
++#define IEEE80211_PROTMODE_RSSITHR    15      /* default rssi threshold for protection mode trigger */
++#define IEEE80211_PROTMODE_TIMEOUT    30      /* timeout for keeping protection mode alive */
++
+ #define IEEE80211_PWRCONSTRAINT_VAL(ic) \
+       (((ic)->ic_bsschan->ic_maxregpower > (ic)->ic_curchanmaxpwr) ? \
+           (ic)->ic_bsschan->ic_maxregpower - (ic)->ic_curchanmaxpwr : 0)
+@@ -324,6 +327,9 @@ struct ieee80211com {
+       u_int16_t ic_newtxpowlimit;             /* tx power limit to change to (in 0.5 dBm) */
+       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 */
++      u_int64_t ic_protmode_lasttrig;         /* last trigger for protection mode */
++      u_int16_t ic_protmode_timeout;          /* protection mode timeout */
+       /* Channel state:
+        *
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2312,6 +2312,12 @@ ieee80211_ioctl_setparam(struct net_devi
+                   IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
+                       retv = ENETRESET;
+               break;
++      case IEEE80211_PARAM_PROTMODE_TIMEOUT:
++              ic->ic_protmode_timeout = value;
++              break;
++      case IEEE80211_PARAM_PROTMODE_RSSI:
++              ic->ic_protmode_rssi = value;
++              break;
+       case IEEE80211_PARAM_MCASTCIPHER:
+               if ((vap->iv_caps & cipher2cap(value)) == 0 &&
+                   !ieee80211_crypto_available(vap, value))
+@@ -2955,6 +2961,12 @@ ieee80211_ioctl_getparam(struct net_devi
+       case IEEE80211_PARAM_PROTMODE:
+               param[0] = ic->ic_protmode;
+               break;
++      case IEEE80211_PARAM_PROTMODE_TIMEOUT:
++              param[0] = ic->ic_protmode_timeout;
++              break;
++      case IEEE80211_PARAM_PROTMODE_RSSI:
++              param[0] = ic->ic_protmode_rssi;
++              break;
+       case IEEE80211_PARAM_MCASTCIPHER:
+               param[0] = rsn->rsn_mcastcipher;
+               break;
+@@ -5346,6 +5358,14 @@ static const struct iw_priv_args ieee802
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "protmode" },
+       { IEEE80211_PARAM_PROTMODE,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_protmode" },
++      { IEEE80211_PARAM_PROTMODE_RSSI,
++        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "protrssi" },
++      { IEEE80211_PARAM_PROTMODE_RSSI,
++        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_protrssi" },
++      { IEEE80211_PARAM_PROTMODE_TIMEOUT,
++        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "prottime" },
++      { IEEE80211_PARAM_PROTMODE_TIMEOUT,
++        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_prottime" },
+       { IEEE80211_PARAM_MCASTCIPHER,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "mcastcipher" },
+       { IEEE80211_PARAM_MCASTCIPHER,
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -1877,6 +1877,17 @@ ieee80211_node_timeout(unsigned long arg
+       ieee80211_scan_timeout(ic);
+       ieee80211_timeout_stations(&ic->ic_sta);
++      if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
++              (ic->ic_protmode_lasttrig + ic->ic_protmode_timeout * HZ <
++                      jiffies)) {
++              struct ieee80211vap *tmpvap;
++
++              /* expire protection mode */
++              ic->ic_flags &= ~IEEE80211_F_USEPROT;
++              TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
++                      tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++              }
++      }
+       ic->ic_inact.expires = jiffies + IEEE80211_INACT_WAIT * HZ;
+       add_timer(&ic->ic_inact);
diff --git a/net/madwifi/patches/347-tuning.patch b/net/madwifi/patches/347-tuning.patch
new file mode 100644 (file)
index 0000000..1a73c42
--- /dev/null
@@ -0,0 +1,99 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -10276,11 +10276,11 @@ ath_setcurmode(struct ath_softc *sc, enu
+       sc->sc_currates = rt;
+       sc->sc_curmode = mode;
+       /*
+-       * All protection frames are transmitted at 2Mb/s for
+-       * 11g, otherwise at 1Mb/s.
++       * All protection frames are transmitted at 11Mb/s for
++       * 11g, otherwise at 2Mb/s.
+        * XXX select protection rate index from rate table.
+        */
+-      sc->sc_protrix = (mode == IEEE80211_MODE_11G ? 1 : 0);
++      sc->sc_protrix = (mode == IEEE80211_MODE_11G ? 3 : 1);
+       /* rate index used to send mgt frames */
+       sc->sc_minrateix = 0;
+ }
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -272,6 +272,10 @@ static inline struct net_device *_alloc_
+ #define AES_ICV_FIELD_SIZE      8       /* AES ICV field size */
+ #define EXT_IV_FIELD_SIZE       4       /* ext IV field size */
++/* This is what the HAL uses by default for 11a+g */
++#define ATH_DEFAULT_CWMIN     15
++#define ATH_DEFAULT_CWMAX     1023
++
+ /* XR specific macros */
+ #define XR_DEFAULT_GRPPOLL_RATE_STR   "0.25 1 1 3 3 6 6 20"
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -197,7 +197,7 @@ calc_usecs_unicast_packet(struct ath_sof
+               unsigned int x = 0, tt = 0;
+               unsigned int cix = rt->info[rix].controlRate;
+               int rts = 0, cts = 0;
+-              int cw = WIFI_CW_MIN;
++              int cw = ATH_DEFAULT_CWMIN;
+               KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+@@ -281,7 +281,7 @@ calc_usecs_unicast_packet(struct ath_sof
+               tt += (long_retries + 1) * ath_hal_computetxtime(sc->sc_ah, rt, length,
+                                                       rix, AH_TRUE);
+               for (x = 0; x <= short_retries + long_retries; x++) {
+-                      cw = MIN(WIFI_CW_MAX, (cw + 1) * 2);
++                      cw = MIN(ATH_DEFAULT_CWMAX, (cw + 1) * 2);
+                       tt += (t_slot * cw / 2);
+               }
+               return tt;
+--- a/ath_rate/minstrel/minstrel.h
++++ b/ath_rate/minstrel/minstrel.h
+@@ -180,14 +180,6 @@ struct minstrel_node {
+ #define MAX(a,b)        ((a) > (b) ? (a) : (b))
+ #endif
+-#if 0
+-#define WIFI_CW_MIN 31
+-#define WIFI_CW_MAX 1023
+-#else
+-#define WIFI_CW_MIN 3
+-#define WIFI_CW_MAX 10
+-#endif
+-
+ /*
+  * Definitions for pulling the rate and trie counts from
+  * a 5212 h/w descriptor. These Don't belong here; the
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -170,7 +170,7 @@ calc_usecs_unicast_packet(struct ath_sof
+       struct ieee80211com *ic = &sc->sc_ic;
+       unsigned int tt = 0;
+       unsigned int x;
+-      unsigned int cw = WIFI_CW_MIN;
++      unsigned int cw = ATH_DEFAULT_CWMIN;
+       unsigned int cix = rt->info[rix].controlRate;
+       KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+@@ -254,7 +254,7 @@ calc_usecs_unicast_packet(struct ath_sof
+       tt += (long_retries+1)*ath_hal_computetxtime(sc->sc_ah, rt, length,
+                                               rix, AH_TRUE);
+       for (x = 0; x <= short_retries + long_retries; x++) {
+-              cw = MIN(WIFI_CW_MAX, (cw + 1) * 2);
++              cw = MIN(ATH_DEFAULT_CWMAX, (cw + 1) * 2);
+               tt += (t_slot * cw / 2);
+       }
+       return tt;
+--- a/ath_rate/sample/sample.h
++++ b/ath_rate/sample/sample.h
+@@ -106,9 +106,6 @@ struct sample_node {
+ #define MAX(a,b)        ((a) > (b) ? (a) : (b))
+ #endif
+-#define WIFI_CW_MIN 31
+-#define WIFI_CW_MAX 1023
+-
+ /*
+  * Definitions for pulling the rate and trie counts from
+  * a 5212 h/w descriptor. These Don't belong here; the
diff --git a/net/madwifi/patches/348-ackcts.patch b/net/madwifi/patches/348-ackcts.patch
new file mode 100644 (file)
index 0000000..42b6fe2
--- /dev/null
@@ -0,0 +1,38 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -2723,6 +2723,9 @@ ar_device(int devid)
+ static int
+ ath_set_ack_bitrate(struct ath_softc *sc, int high)
+ {
++      if (!sc->sc_ackrate_override)
++              return 0;
++
+       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 */
+@@ -10791,8 +10794,13 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+                               break;
+ #endif
+                       case ATH_ACKRATE:
+-                              sc->sc_ackrate = val;
+-                              ath_set_ack_bitrate(sc, sc->sc_ackrate);
++                              if (val == -1)
++                                      sc->sc_ackrate_override = 0;
++                              else {
++                                      sc->sc_ackrate_override = 1;
++                                      sc->sc_ackrate = val;
++                                      ath_set_ack_bitrate(sc, sc->sc_ackrate);
++                              }
+                               break;
+                       case ATH_RP:
+                               ath_rp_record(sc,
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -681,6 +681,7 @@ struct ath_softc {
+       unsigned int    sc_devstopped:1;        /* stopped due to of no tx bufs */
+       unsigned int    sc_stagbeacons:1;       /* use staggered beacons */
+       unsigned int    sc_dfswait:1;           /* waiting on channel for radar detect */
++      unsigned int    sc_ackrate_override:1;  /* override ack rate */
+       unsigned int    sc_ackrate:1;           /* send acks at high bitrate */
+       unsigned int    sc_dfs_cac:1;           /* waiting on channel for radar detect */
+       unsigned int    sc_hasintmit:1;         /* Interference mitigation */
diff --git a/net/madwifi/patches/349-reset.patch b/net/madwifi/patches/349-reset.patch
new file mode 100644 (file)
index 0000000..06e3fa8
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -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. */
+-              if (!ath_hal_reset(ah, sc->sc_opmode, &hchan, AH_TRUE, &status)   ||
+-                  !ath_hal_reset(ah, sc->sc_opmode, &hchan, AH_FALSE, &status)) {
++              if (!ath_hal_reset(ah, sc->sc_opmode, &hchan, AH_TRUE, &status)) {
+                       EPRINTF(sc, "Unable to reset channel %u (%u MHz) "
+                               "flags 0x%x '%s' (HAL status %u)\n",
+                               ieee80211_chan2ieee(ic, chan), chan->ic_freq,
diff --git a/net/madwifi/patches/350-wisoc_softled.patch b/net/madwifi/patches/350-wisoc_softled.patch
new file mode 100644 (file)
index 0000000..dae9f21
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/ath/if_ath_ahb.c
++++ b/ath/if_ath_ahb.c
+@@ -245,6 +245,8 @@ init_ath_wmac(u_int16_t devid, u_int16_t
+       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;
+       return 0;
diff --git a/net/madwifi/patches/351-scanlist.patch b/net/madwifi/patches/351-scanlist.patch
new file mode 100644 (file)
index 0000000..c11f28e
--- /dev/null
@@ -0,0 +1,904 @@
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -317,147 +317,6 @@ found:
+ #undef ISPROBE
+ }
+-static struct ieee80211_channel *
+-find11gchannel(struct ieee80211com *ic, int i, int freq)
+-{
+-      struct ieee80211_channel *c;
+-      int j;
+-
+-      /*
+-       * The normal ordering in the channel list is b channel
+-       * immediately followed by g so optimize the search for
+-       * this.  We'll still do a full search just in case.
+-       */
+-      for (j = i+1; j < ic->ic_nchans; j++) {
+-              c = &ic->ic_channels[j];
+-              if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
+-                      return c;
+-      }
+-      for (j = 0; j < i; j++) {
+-              c = &ic->ic_channels[j];
+-              if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
+-                      return c;
+-      }
+-      return NULL;
+-}
+-static const u_int chanflags[] = {
+-      IEEE80211_CHAN_B,       /* IEEE80211_MODE_AUTO */
+-      IEEE80211_CHAN_A,       /* IEEE80211_MODE_11A */
+-      IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
+-      IEEE80211_CHAN_PUREG,   /* IEEE80211_MODE_11G */
+-      IEEE80211_CHAN_FHSS,    /* IEEE80211_MODE_FH */
+-      IEEE80211_CHAN_A,       /* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */
+-      IEEE80211_CHAN_PUREG,   /* IEEE80211_MODE_TURBO_G */
+-      IEEE80211_CHAN_ST,      /* IEEE80211_MODE_TURBO_STATIC_A */
+-};
+-
+-static void
+-add_channels(struct ieee80211com *ic,
+-      struct ieee80211_scan_state *ss,
+-      enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq)
+-{
+-      struct ieee80211_channel *c, *cg;
+-      u_int modeflags;
+-      int i;
+-
+-      KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
+-      modeflags = chanflags[mode];
+-      for (i = 0; i < nfreq; i++) {
+-              c = ieee80211_find_channel(ic, freq[i], modeflags);
+-              if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))
+-                      continue;
+-              if (mode == IEEE80211_MODE_AUTO) {
+-                      /*
+-                       * XXX special-case 11b/g channels so we select
+-                       *     the g channel if both are present.
+-                       */
+-                      if (IEEE80211_IS_CHAN_B(c) &&
+-                          (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
+-                              c = cg;
+-              }
+-              if (ss->ss_last >= IEEE80211_SCAN_MAX)
+-                      break;
+-              ss->ss_chans[ss->ss_last++] = c;
+-      }
+-}
+-
+-static const u_int16_t rcl1[] =               /* 8 FCC channel: 52, 56, 60, 64, 36, 40, 44, 48 */
+-{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 };
+-static const u_int16_t rcl2[] =               /* 4 MKK channels: 34, 38, 42, 46 */
+-{ 5170, 5190, 5210, 5230 };
+-static const u_int16_t rcl3[] =               /* 2.4Ghz ch: 1,6,11,7,13 */
+-{ 2412, 2437, 2462, 2442, 2472 };
+-static const u_int16_t rcl4[] =               /* 5 FCC channel: 149, 153, 161, 165 */
+-{ 5745, 5765, 5785, 5805, 5825 };
+-static const u_int16_t rcl7[] =               /* 11 ETSI channel: 100,104,108,112,116,120,124,128,132,136,140 */
+-{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 };
+-static const u_int16_t rcl8[] =               /* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */
+-{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 };
+-static const u_int16_t rcl9[] =               /* 2.4Ghz ch: 14 */
+-{ 2484 };
+-static const u_int16_t rcl10[] =      /* Added Korean channels 2312-2372 */
+-{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 };
+-static const u_int16_t rcl11[] =      /* Added Japan channels in 4.9/5.0 spectrum */
+-{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 };
+-#ifdef ATH_TURBO_SCAN
+-static const u_int16_t rcl5[] =               /* 3 static turbo channels */
+-{ 5210, 5250, 5290 };
+-static const u_int16_t rcl6[] =               /* 2 static turbo channels */
+-{ 5760, 5800 };
+-static const u_int16_t rcl6x[] =              /* 4 FCC3 turbo channels */
+-{ 5540, 5580, 5620, 5660 };
+-static const u_int16_t rcl12[] =              /* 2.4Ghz Turbo channel 6 */
+-{ 2437 };
+-static const u_int16_t rcl13[] =              /* dynamic Turbo channels */
+-{ 5200, 5240, 5280, 5765, 5805 };
+-#endif /* ATH_TURBO_SCAN */
+-
+-struct scanlist {
+-      u_int16_t       mode;
+-      u_int16_t       count;
+-      const u_int16_t *list;
+-};
+-
+-#define       IEEE80211_MODE_TURBO_STATIC_A   IEEE80211_MODE_MAX
+-#define       X(a)    .count = sizeof(a)/sizeof(a[0]), .list = a
+-
+-static const struct scanlist staScanTable[] = {
+-      { IEEE80211_MODE_11B,                   X(rcl3) },
+-      { IEEE80211_MODE_11A,                   X(rcl1) },
+-      { IEEE80211_MODE_11A,                   X(rcl2) },
+-      { IEEE80211_MODE_11B,                   X(rcl8) },
+-      { IEEE80211_MODE_11B,                   X(rcl9) },
+-      { IEEE80211_MODE_11A,                   X(rcl4) },
+-#ifdef ATH_TURBO_SCAN
+-      { IEEE80211_MODE_TURBO_STATIC_A,        X(rcl5) },
+-      { IEEE80211_MODE_TURBO_STATIC_A,        X(rcl6) },
+-      { IEEE80211_MODE_TURBO_A,               X(rcl6x) },
+-      { IEEE80211_MODE_TURBO_A,               X(rcl13) },
+-#endif /* ATH_TURBO_SCAN */
+-      { IEEE80211_MODE_11A,                   X(rcl7) },
+-      { IEEE80211_MODE_11B,                   X(rcl10) },
+-      { IEEE80211_MODE_11A,                   X(rcl11) },
+-#ifdef ATH_TURBO_SCAN
+-      { IEEE80211_MODE_TURBO_G,               X(rcl12) },
+-#endif /* ATH_TURBO_SCAN */
+-      { .list = NULL }
+-};
+-
+-#undef X
+-
+-static int
+-checktable(const struct scanlist *scan, const struct ieee80211_channel *c)
+-{
+-      int i;
+-
+-      for (; scan->list != NULL; scan++) {
+-              for (i = 0; i < scan->count; i++)
+-                      if (scan->list[i] == c->ic_freq)
+-                              return 1;
+-      }
+-      return 0;
+-}
+-
+ /*
+  * Start a station-mode scan by populating the channel list.
+  */
+@@ -466,81 +325,14 @@ sta_start(struct ieee80211_scan_state *s
+ {
+       struct ieee80211com *ic = vap->iv_ic;
+       struct sta_table *st = ss->ss_priv;
+-      const struct scanlist *scan;
+       enum ieee80211_phymode mode;
+       struct ieee80211_channel *c;
+       int i;
+       ss->ss_last = 0;
+-      /*
+-       * Use the table of ordered channels to construct the list
+-       * of channels for scanning.  Any channels in the ordered
+-       * list not in the master list will be discarded.
+-       */
+-      for (scan = staScanTable; scan->list != NULL; scan++) {
+-              mode = scan->mode;
+-              if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
+-                      /*
+-                       * If a desired mode was specified, scan only 
+-                       * channels that satisfy that constraint.
+-                       */
+-                      if (vap->iv_des_mode != mode) {
+-                              /*
+-                               * The scan table marks 2.4Ghz channels as b
+-                               * so if the desired mode is 11g, then use
+-                               * the 11b channel list but upgrade the mode.
+-                               */
+-                              if (vap->iv_des_mode != IEEE80211_MODE_11G ||
+-                                  mode != IEEE80211_MODE_11B)
+-                                      continue;
+-                              mode = IEEE80211_MODE_11G;      /* upgrade */
+-                      }
+-              } else {
+-                      /*
+-                       * This lets ieee80211_scan_add_channels
+-                       * upgrade an 11b channel to 11g if available.
+-                       */
+-                      if (mode == IEEE80211_MODE_11B)
+-                              mode = IEEE80211_MODE_AUTO;
+-              }
+-              /* XR does not operate on turbo channels */
+-              if ((vap->iv_flags & IEEE80211_F_XR) &&
+-                  (mode == IEEE80211_MODE_TURBO_A ||
+-                   mode == IEEE80211_MODE_TURBO_G))
+-                      continue;
+-              /*
+-               * Add the list of the channels; any that are not
+-               * in the master channel list will be discarded.
+-               */
+-              add_channels(ic, ss, mode, scan->list, scan->count);
+-      }
+-
+-      /*
+-       * Add the channels from the ic (from HAL) that are not present
+-       * in the staScanTable.
+-       */
+-      for (i = 0; i < ic->ic_nchans; i++) {
+-              c = &ic->ic_channels[i];
+-              /*
+-               * scan dynamic turbo channels in normal mode.
+-               */
+-              if (IEEE80211_IS_CHAN_DTURBO(c))
+-                      continue;
+-              mode = ieee80211_chan2mode(c);
+-              if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
+-                      /*
+-                       * If a desired mode was specified, scan only 
+-                       * channels that satisfy that constraint.
+-                       */
+-                      if (vap->iv_des_mode != mode)
+-                              continue;
+-
+-              }
+-              if (!checktable(staScanTable, c))
+-                      ss->ss_chans[ss->ss_last++] = c;
+-      }
+-
++      ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode);
+       ss->ss_next = 0;
++
+       /* XXX tunables */
+       /* 
+        * The scanner will stay on station for ss_maxdwell ms (using a 
+@@ -749,17 +541,7 @@ match_bss(struct ieee80211vap *vap,
+       fail = 0;
+       if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, se->se_chan)))
+               fail |= 0x01;
+-      /*
+-       * NB: normally the desired mode is used to construct
+-       * the channel list, but it's possible for the scan
+-       * cache to include entries for stations outside this
+-       * list so we check the desired mode here to weed them
+-       * out.
+-       */
+-      if (vap->iv_des_mode != IEEE80211_MODE_AUTO &&
+-          (se->se_chan->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
+-          chanflags[vap->iv_des_mode])
+-              fail |= 0x01;
++
+       if (vap->iv_opmode == IEEE80211_M_IBSS) {
+               if ((se->se_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
+                       fail |= 0x02;
+@@ -1168,78 +950,6 @@ static const struct ieee80211_scanner st
+       .scan_default           = ieee80211_sta_join,
+ };
+-/*
+- * Start an adhoc-mode scan by populating the channel list.
+- */
+-static int
+-adhoc_start(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
+-{
+-      struct ieee80211com *ic = vap->iv_ic;
+-      struct sta_table *st = ss->ss_priv;
+-      const struct scanlist *scan;
+-      enum ieee80211_phymode mode;
+-
+-      ss->ss_last = 0;
+-      /*
+-       * Use the table of ordered channels to construct the list
+-       * of channels for scanning.  Any channels in the ordered
+-       * list not in the master list will be discarded.
+-       */
+-      for (scan = staScanTable; scan->list != NULL; scan++) {
+-              mode = scan->mode;
+-              if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
+-                      /*
+-                       * If a desired mode was specified, scan only 
+-                       * channels that satisfy that constraint.
+-                       */
+-                      if (vap->iv_des_mode != mode) {
+-                              /*
+-                               * The scan table marks 2.4Ghz channels as b
+-                               * so if the desired mode is 11g, then use
+-                               * the 11b channel list but upgrade the mode.
+-                               */
+-                              if (vap->iv_des_mode != IEEE80211_MODE_11G ||
+-                                  mode != IEEE80211_MODE_11B)
+-                                      continue;
+-                              mode = IEEE80211_MODE_11G;      /* upgrade */
+-                      }
+-              } else {
+-                      /*
+-                       * This lets ieee80211_scan_add_channels
+-                       * upgrade an 11b channel to 11g if available.
+-                       */
+-                      if (mode == IEEE80211_MODE_11B)
+-                              mode = IEEE80211_MODE_AUTO;
+-              }
+-              /* XR does not operate on turbo channels */
+-              if ((vap->iv_flags & IEEE80211_F_XR) &&
+-                  (mode == IEEE80211_MODE_TURBO_A ||
+-                   mode == IEEE80211_MODE_TURBO_G))
+-                      continue;
+-              /*
+-               * Add the list of the channels; any that are not
+-               * in the master channel list will be discarded.
+-               */
+-              add_channels(ic, ss, mode, scan->list, scan->count);
+-      }
+-      ss->ss_next = 0;
+-      /* XXX tunables */
+-      ss->ss_mindwell = msecs_to_jiffies(200);        /* 200ms */
+-      ss->ss_maxdwell = msecs_to_jiffies(200);        /* 200ms */
+-
+-#ifdef IEEE80211_DEBUG
+-      if (ieee80211_msg_scan(vap)) {
+-              printk("%s: scan set ", vap->iv_dev->name);
+-              ieee80211_scan_dump_channels(ss);
+-              printk(" dwell min %ld max %ld\n",
+-                      ss->ss_mindwell, ss->ss_maxdwell);
+-      }
+-#endif /* IEEE80211_DEBUG */
+-
+-      st->st_newscan = 1;
+-
+-      return 0;
+-}
+ /*
+  * Select a channel to start an adhoc network on.
+@@ -1405,7 +1115,7 @@ static const struct ieee80211_scanner ad
+       .scan_name              = "default",
+       .scan_attach            = sta_attach,
+       .scan_detach            = sta_detach,
+-      .scan_start             = adhoc_start,
++      .scan_start             = sta_start,
+       .scan_restart           = sta_restart,
+       .scan_cancel            = sta_cancel,
+       .scan_end               = adhoc_pick_bss,
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -278,6 +278,11 @@ ieee80211_ifattach(struct ieee80211com *
+                       ("channel with bogus ieee number %u", c->ic_ieee));
+               setbit(ic->ic_chan_avail, c->ic_ieee);
++              if (c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT)
++                      c->ic_scanflags |= IEEE80211_NOSCAN_SET;
++              else
++                      c->ic_scanflags &= ~IEEE80211_NOSCAN_SET;
++
+               /* Identify mode capabilities. */
+               if (IEEE80211_IS_CHAN_A(c))
+                       ic->ic_modecaps |= 1 << IEEE80211_MODE_11A;
+@@ -1447,10 +1452,6 @@ ieee80211_media_change(struct net_device
+               vap->iv_fixed_rate = newrate;           /* fixed TX rate */
+               error = -ENETRESET;
+       }
+-      if (vap->iv_des_mode != newmode) {
+-              vap->iv_des_mode = newmode;             /* desired PHY mode */
+-              error = -ENETRESET;
+-      }
+       return error;
+ }
+ EXPORT_SYMBOL(ieee80211_media_change);
+--- a/net80211/_ieee80211.h
++++ b/net80211/_ieee80211.h
+@@ -132,6 +132,11 @@ enum ieee80211_scanmode {
+       IEEE80211_SCAN_FIRST    = 2,    /* take first suitable candidate */
+ };
++enum ieee80211_scanflags {
++      IEEE80211_NOSCAN_DEFAULT = (1 << 0),
++      IEEE80211_NOSCAN_SET     = (1 << 1),
++};
++
+ /*
+  * Channels are specified by frequency and attributes.
+  */
+@@ -142,6 +147,7 @@ struct ieee80211_channel {
+       int8_t ic_maxregpower;  /* maximum regulatory tx power in dBm */
+       int8_t ic_maxpower;     /* maximum tx power in dBm */
+       int8_t ic_minpower;     /* minimum tx power in dBm */
++      u_int8_t ic_scanflags;
+ };
+ #define       IEEE80211_CHAN_MAX      255
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -555,6 +555,7 @@ struct ieee80211req_scan_result {
+ #define       IEEE80211_IOCTL_WDSADDMAC       (SIOCIWFIRSTPRIV+26)
+ #define       IEEE80211_IOCTL_WDSDELMAC       (SIOCIWFIRSTPRIV+28)
+ #define       IEEE80211_IOCTL_KICKMAC         (SIOCIWFIRSTPRIV+30)
++#define       IEEE80211_IOCTL_SETSCANLIST     (SIOCIWFIRSTPRIV+31)
+ enum {
+       IEEE80211_WMMPARAMS_CWMIN       = 1,
+--- a/net80211/ieee80211_scan_ap.c
++++ b/net80211/ieee80211_scan_ap.c
+@@ -105,11 +105,6 @@ struct scan_entry {
+ };
+ struct ap_state {
+-      unsigned int as_vap_desired_mode;       /* Used for channel selection, 
+-                                               * vap->iv_des_mode */
+-      unsigned int as_required_mode;          /* Used for channel selection, 
+-                                               * filtered version of 
+-                                               * as_vap_desired_mode */
+       int as_maxrssi[IEEE80211_CHAN_MAX];     /* Used for channel selection */
+       /* These fields are just for scan caching for returning responses to
+@@ -129,131 +124,7 @@ struct ap_state {
+ static int ap_flush(struct ieee80211_scan_state *);
+ static void action_tasklet(IEEE80211_TQUEUE_ARG);
+-static struct ieee80211_channel *find11gchannel(struct ieee80211com *ic, 
+-              int i, int freq);
+-static const u_int chanflags[] = {
+-      IEEE80211_CHAN_B,       /* IEEE80211_MODE_AUTO */
+-      IEEE80211_CHAN_A,       /* IEEE80211_MODE_11A */
+-      IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
+-      IEEE80211_CHAN_PUREG,   /* IEEE80211_MODE_11G */
+-      IEEE80211_CHAN_FHSS,    /* IEEE80211_MODE_FH */
+-      IEEE80211_CHAN_A,       /* IEEE80211_MODE_TURBO_A */ /* for turbo mode 
+-                                                            * look for AP in 
+-                                                            * normal channel 
+-                                                            */
+-      IEEE80211_CHAN_PUREG,   /* IEEE80211_MODE_TURBO_G */
+-      IEEE80211_CHAN_ST,      /* IEEE80211_MODE_TURBO_STATIC_A */
+-};
+-
+-static const u_int16_t rcl1[] =               /* 8 FCC channel: 52, 56, 60, 64, 
+-                                       *                36, 40, 44, 48 */
+-{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 };
+-static const u_int16_t rcl2[] =               /* 4 MKK channels: 34, 38, 42, 46 */
+-{ 5170, 5190, 5210, 5230 };
+-static const u_int16_t rcl3[] =               /* 2.4Ghz ch: 1,6,11,7,13 */
+-{ 2412, 2437, 2462, 2442, 2472 };
+-static const u_int16_t rcl4[] =               /* 5 FCC channel: 149, 153, 161, 165 */
+-{ 5745, 5765, 5785, 5805, 5825 };
+-static const u_int16_t rcl7[] =               /* 11 ETSI channel: 100, 104, 108, 112,
+-                                       *                  116, 120, 124, 128, 
+-                                       *                  132, 136, 140 */
+-{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 };
+-static const u_int16_t rcl8[] =               /* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */
+-{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 };
+-static const u_int16_t rcl9[] =               /* 2.4Ghz ch: 14 */
+-{ 2484 };
+-static const u_int16_t rcl10[] =      /* Added Korean channels 2312-2372 */
+-{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 };
+-static const u_int16_t rcl11[] =      /* Added Japan channels in 4.9/5.0 spectrum */
+-{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 };
+-#ifdef ATH_TURBO_SCAN
+-static const u_int16_t rcl5[] =               /* 3 static turbo channels */
+-{ 5210, 5250, 5290 };
+-static const u_int16_t rcl6[] =               /* 2 static turbo channels */
+-{ 5760, 5800 };
+-static const u_int16_t rcl6x[] =              /* 4 FCC3 turbo channels */
+-{ 5540, 5580, 5620, 5660 };
+-static const u_int16_t rcl12[] =              /* 2.4Ghz Turbo channel 6 */
+-{ 2437 };
+-static const u_int16_t rcl13[] =              /* dynamic Turbo channels */
+-{ 5200, 5240, 5280, 5765, 5805 };
+-#endif /* ATH_TURBO_SCAN */
+-
+-struct scanlist {
+-      u_int16_t       mode;
+-      u_int16_t       count;
+-      const u_int16_t *list;
+-};
+-
+-#define       IEEE80211_MODE_TURBO_STATIC_A   IEEE80211_MODE_MAX
+-#define       X(a)    .count = ARRAY_SIZE(a), .list = a
+-
+-static const struct scanlist staScanTable[] = {
+-      { IEEE80211_MODE_11B,                   X(rcl3)  },
+-      { IEEE80211_MODE_11A,                   X(rcl1)  },
+-      { IEEE80211_MODE_11A,                   X(rcl2)  },
+-      { IEEE80211_MODE_11B,                   X(rcl8)  },
+-      { IEEE80211_MODE_11B,                   X(rcl9)  },
+-      { IEEE80211_MODE_11A,                   X(rcl4)  },
+-#ifdef ATH_TURBO_SCAN
+-      { IEEE80211_MODE_TURBO_STATIC_A,        X(rcl5)  },
+-      { IEEE80211_MODE_TURBO_STATIC_A,        X(rcl6)  },
+-      { IEEE80211_MODE_TURBO_A,               X(rcl6x) },
+-      { IEEE80211_MODE_TURBO_A,               X(rcl13) },
+-#endif /* ATH_TURBO_SCAN */
+-      { IEEE80211_MODE_11A,                   X(rcl7)  },
+-      { IEEE80211_MODE_11B,                   X(rcl10) },
+-      { IEEE80211_MODE_11A,                   X(rcl11) },
+-#ifdef ATH_TURBO_SCAN
+-      { IEEE80211_MODE_TURBO_G,               X(rcl12) },
+-#endif /* ATH_TURBO_SCAN */
+-      { .list = NULL }
+-};
+-
+-#undef X
+-/* This function must be invoked with locks acquired */
+-static void
+-add_channels(struct ieee80211com *ic,
+-      struct ieee80211_scan_state *ss,
+-      enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq)
+-{
+-      struct ieee80211_channel *c, *cg;
+-      u_int modeflags;
+-      int i;
+-
+-      KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
+-      modeflags = chanflags[mode];
+-      for (i = 0; i < nfreq; i++) {
+-              c = ieee80211_find_channel(ic, freq[i], modeflags);
+-              if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee))
+-                      continue;
+-              if (mode == IEEE80211_MODE_AUTO) {
+-                      /* XXX special-case 11b/g channels so we select
+-                       *     the g channel if both are present. */
+-                      if (IEEE80211_IS_CHAN_B(c) &&
+-                          (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
+-                              c = cg;
+-              }
+-              if (ss->ss_last >= IEEE80211_SCAN_MAX)
+-                      break;
+-              ss->ss_chans[ss->ss_last++] = c;
+-      }
+-}
+-
+-/* This function must be invoked with locks acquired */
+-static int
+-checktable(const struct scanlist *scan, const struct ieee80211_channel *c)
+-{
+-      int i;
+-
+-      for (; scan->list != NULL; scan++) {
+-              for (i = 0; i < scan->count; i++)
+-                      if (scan->list[i] == c->ic_freq)
+-                              return 1;
+-      }
+-      return 0;
+-}
+ /*
+  * Attach prior to any scanning work.
+@@ -327,29 +198,6 @@ saveie(u_int8_t **iep, const u_int8_t *i
+               ieee80211_saveie(iep, ie);
+ }
+-/* This function must be invoked with locks acquired */
+-static struct ieee80211_channel *
+-find11gchannel(struct ieee80211com *ic, int i, int freq)
+-{
+-      struct ieee80211_channel *c;
+-      int j;
+-
+-      /* The normal ordering in the channel list is b channel
+-       * immediately followed by g so optimize the search for
+-       * this.  We'll still do a full search just in case. */
+-      for (j = i + 1; j < ic->ic_nchans; j++) {
+-              c = &ic->ic_channels[j];
+-              if ((c->ic_freq == freq) && IEEE80211_IS_CHAN_ANYG(c))
+-                      return c;
+-      }
+-      for (j = 0; j < i; j++) {
+-              c = &ic->ic_channels[j];
+-              if ((c->ic_freq == freq) && IEEE80211_IS_CHAN_ANYG(c))
+-                      return c;
+-      }
+-      return NULL;
+-}
+-
+ /*
+  * Start an ap scan by populating the channel list.
+  */
+@@ -358,90 +206,15 @@ ap_start(struct ieee80211_scan_state *ss
+ {
+       struct ap_state *as         = ss->ss_priv;
+       struct ieee80211com *ic     = NULL;
+-      const struct scanlist *sl   = NULL;
+-      struct ieee80211_channel *c = NULL;
+       int i;
+       unsigned int mode = 0;
+       SCAN_AP_LOCK_IRQ(as);
+       ic = vap->iv_ic;
+       /* 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;
+-      if (as->as_vap_desired_mode != IEEE80211_MODE_AUTO) {
+-              as->as_required_mode = chanflags[as->as_vap_desired_mode];
+-              if ((vap->iv_ath_cap & IEEE80211_ATHC_TURBOP) && 
+-                  (as->as_required_mode != IEEE80211_CHAN_ST)) {
+-                      /* Fixup for dynamic turbo flags */
+-                      if (as->as_vap_desired_mode == IEEE80211_MODE_11G)
+-                              as->as_required_mode = IEEE80211_CHAN_108G;
+-                      else
+-                              as->as_required_mode = IEEE80211_CHAN_108A;
+-              }
+-      }
+-
+       ss->ss_last = 0;
+-      /* Use the table of ordered channels to construct the list
+-       * of channels for scanning.  Any channels in the ordered
+-       * list not in the master list will be discarded. */
+-      for (sl = staScanTable; sl->list != NULL; sl++) {
+-              mode = sl->mode;
+-
+-              /* The scan table marks 2.4Ghz channels as b
+-               * so if the desired mode is 11g, then use
+-               * the 11b channel list but upgrade the mode. */
+-              if (as->as_vap_desired_mode &&
+-                  (as->as_vap_desired_mode != mode) && 
+-                  (as->as_vap_desired_mode == IEEE80211_MODE_11G) && 
+-                  (mode == IEEE80211_MODE_11B))
+-                      mode = IEEE80211_MODE_11G;
+-
+-              /* If we are in "AUTO" mode, upgrade the mode to auto. 
+-               * This lets add_channels upgrade an 11b channel to 
+-               * 11g if available. */
+-              if (!as->as_vap_desired_mode && (mode == IEEE80211_MODE_11B))
+-                      mode = IEEE80211_MODE_AUTO;
+-
+-              /* Add the list of the channels; any that are not
+-               * in the master channel list will be discarded. */
+-              add_channels(ic, ss, mode, sl->list, sl->count);
+-      }
+-
+-      /* Add the channels from the ic (from HAL) that are not present
+-       * in the staScanTable, assuming they pass the sanity checks... */
+-      for (i = 0; i < ic->ic_nchans; i++) {
+-              c = &ic->ic_channels[i];
+-
+-              /* XR is not supported on turbo channels */
+-              if (IEEE80211_IS_CHAN_TURBO(c) && vap->iv_flags & IEEE80211_F_XR)
+-                      continue;
+-
+-              /* Dynamic channels are scanned in base mode */
+-              if (!as->as_required_mode && !IEEE80211_IS_CHAN_ST(c))
+-                      continue;
+-
+-              /* Use any 11g channel instead of 11b one. */
+-              if (vap->iv_des_mode == IEEE80211_MODE_AUTO && 
+-                  IEEE80211_IS_CHAN_B(c) &&
+-                  find11gchannel(ic, i, c->ic_freq))
+-                      continue;
+-
+-              /* Do not add channels already put into the scan list by the
+-               * scan table - these have already been filtered by mode
+-               * and for whether they are in the active channel list. */
+-              if (checktable(staScanTable, c))
+-                      continue;
+-
+-              /* Make sure the channel is active */
+-              if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee))
+-                      continue;
++      ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode);
+-              /* Don't overrun */
+-              if (ss->ss_last >= IEEE80211_SCAN_MAX)
+-                      break;
+-
+-              ss->ss_chans[ss->ss_last++] = c;
+-      }
+       ss->ss_next = 0;
+       /* XXX tunables */
+       ss->ss_mindwell = msecs_to_jiffies(200);        /* 200ms */
+@@ -761,18 +534,6 @@ pick_channel(struct ieee80211_scan_state
+               if (IEEE80211_IS_CHAN_RADAR(c->chan))
+                       continue;
+-              /* Do not select 802.11a ST if mode is specified and is not 
+-               * 802.11a ST */
+-              if (as->as_required_mode &&
+-                  IEEE80211_IS_CHAN_STURBO(c->chan) &&
+-                  (as->as_vap_desired_mode != IEEE80211_MODE_TURBO_STATIC_A))
+-                      continue;
+-
+-              /* Verify mode matches any fixed mode specified */
+-              if((c->chan->ic_flags & as->as_required_mode) != 
+-                              as->as_required_mode)
+-                      continue;
+-
+               if ((ic->ic_bsschan != NULL) &&
+                       (ic->ic_bsschan != IEEE80211_CHAN_ANYC)) {
+--- a/net80211/ieee80211_scan.c
++++ b/net80211/ieee80211_scan.c
+@@ -958,6 +958,80 @@ ieee80211_scan_flush(struct ieee80211com
+       }
+ }
++static const u_int chanflags[] = {
++      0,      /* IEEE80211_MODE_AUTO */
++      IEEE80211_CHAN_A,       /* IEEE80211_MODE_11A */
++      IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
++      IEEE80211_CHAN_PUREG,   /* IEEE80211_MODE_11G */
++      IEEE80211_CHAN_FHSS,    /* IEEE80211_MODE_FH */
++      IEEE80211_CHAN_A,       /* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */
++      IEEE80211_CHAN_PUREG,   /* IEEE80211_MODE_TURBO_G */
++      IEEE80211_CHAN_ST,      /* IEEE80211_MODE_TURBO_STATIC_A */
++};
++
++static struct ieee80211_channel *
++find11gchannel(struct ieee80211com *ic, int i, int freq)
++{
++      struct ieee80211_channel *c;
++      int j;
++
++      /*
++       * The normal ordering in the channel list is b channel
++       * immediately followed by g so optimize the search for
++       * this.  We'll still do a full search just in case.
++       */
++      for (j = i+1; j < ic->ic_nchans; j++) {
++              c = &ic->ic_channels[j];
++              if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
++                      return c;
++      }
++      for (j = 0; j < i; j++) {
++              c = &ic->ic_channels[j];
++              if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
++                      return c;
++      }
++      return NULL;
++}
++
++
++void
++ieee80211_scan_add_channels(struct ieee80211com *ic,
++      struct ieee80211_scan_state *ss,
++      enum ieee80211_phymode mode)
++{
++      struct ieee80211_channel *c, *cg;
++      u_int modeflags;
++      int i;
++
++      KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
++      modeflags = chanflags[mode];
++      for (i = 0; i < ic->ic_nchans; i++) {
++              c = &ic->ic_channels[i];
++              if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))
++                      continue;
++              if (c->ic_scanflags & IEEE80211_NOSCAN_SET)
++                      continue;
++              if (modeflags &&
++                      ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
++                       (modeflags & IEEE80211_CHAN_ALLTURBO)))
++                      continue;
++              if (mode == IEEE80211_MODE_AUTO) {
++                      /*
++                       * XXX special-case 11b/g channels so we select
++                       *     the g channel if both are present.
++                       */
++                      if (IEEE80211_IS_CHAN_B(c) &&
++                          (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
++                              continue;
++              }
++              if (ss->ss_last >= IEEE80211_SCAN_MAX)
++                      break;
++              ss->ss_chans[ss->ss_last++] = c;
++      }
++}
++EXPORT_SYMBOL(ieee80211_scan_add_channels);
++
++
+ /*
+  * Execute radar channel change. This is called when a radar/dfs
+  * signal is detected.  AP mode only.  Return 1 on success, 0 on
+--- a/net80211/ieee80211_scan.h
++++ b/net80211/ieee80211_scan.h
+@@ -219,4 +219,7 @@ void ieee80211_scanner_register(enum iee
+ void ieee80211_scanner_unregister(enum ieee80211_opmode,
+       const struct ieee80211_scanner *);
+ void ieee80211_scanner_unregister_all(const struct ieee80211_scanner *);
++void ieee80211_scan_add_channels(struct ieee80211com *ic,
++      struct ieee80211_scan_state *ss,
++      enum ieee80211_phymode mode);
+ #endif /* _NET80211_IEEE80211_SCAN_H_ */
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -3873,6 +3873,106 @@ ieee80211_ioctl_kickmac(struct net_devic
+       return ieee80211_ioctl_setmlme(dev, info, w, (char *)&mlme);
+ }
++static inline void setflag(struct ieee80211_channel *c, int flag)
++{
++      if (flag)
++              c->ic_scanflags |= IEEE80211_NOSCAN_SET;
++      else
++              c->ic_scanflags &= ~IEEE80211_NOSCAN_SET;
++}
++
++static void setscanflag(struct ieee80211com *ic, int min, int max, int set)
++{
++      int i;
++
++      for (i = 0; i < ic->ic_nchans; i++) {
++              struct ieee80211_channel *c = &ic->ic_channels[i];
++
++              if (min == -1) {
++                      if (!(c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT))
++                              setflag(c, set);
++              } else if ((c->ic_freq >= min) && (c->ic_freq <= max)) {
++                      setflag(c, set);
++              }
++      }
++}
++
++static int
++ieee80211_ioctl_setscanlist(struct net_device *dev,
++      struct iw_request_info *info,
++      struct iw_point *data, char *extra)
++{
++      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211com *ic = vap->iv_ic;
++      char *s, *next;
++      int val = 1;
++
++      if (data->length <= 0)
++              return -EINVAL;
++
++      s = kmalloc(data->length + 1, GFP_KERNEL);
++      if (!s)
++              return -ENOMEM;
++
++      memset(s, 0, data->length + 1);
++      if (copy_from_user(s, data->pointer, data->length))
++              return -EFAULT;
++
++      s[data->length - 1] = '\0';             /* ensure null termination */
++
++      switch(*s) {
++              case '-':
++                      val = 1;
++                      break;
++              case '+':
++                      val = 0;
++                      break;
++              default:
++                      goto error;
++      }
++      s++;
++      next = s;
++      do {
++              next = strchr(s, ',');
++              if (next) {
++                      *next = 0;
++                      next++;
++              }
++              if (!strcmp(s, "ALL")) {
++                      setscanflag(ic, 0, 10000, val);
++              } else if (!strcmp(s, "REG")) {
++                      setscanflag(ic, -1, -1, val);
++              } else {
++                      int min, max;
++                      char *n, *end = NULL;
++
++                      n = strchr(s, '-');
++                      if (n) {
++                              *n = 0;
++                              n++;
++                      }
++                      min = simple_strtoul(s, &end, 10);
++                      if (end && *end)
++                              goto error;
++                      if (n) {
++                              max = simple_strtoul(n, &end, 10);
++                              if (end && *end)
++                                      goto error;
++                      } else {
++                              max = min;
++                      }
++                      setscanflag(ic, min, max, val);
++              }
++              s = next;
++      } while (next);
++      return 0;
++
++error:
++      if (s)
++              kfree(s);
++      return -EINVAL;
++}
++
+ static int
+ ieee80211_ioctl_addmac(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+@@ -5656,6 +5756,8 @@ static const struct iw_priv_args ieee802
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "minrate"},
+       {IEEE80211_PARAM_MINRATE,
+        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"},
++      { IEEE80211_IOCTL_SETSCANLIST,
++       IW_PRIV_TYPE_CHAR | 255, 0, "setscanlist"},
+ #ifdef ATH_REVERSE_ENGINEERING
+       /*
+@@ -5753,6 +5855,7 @@ static const iw_handler ieee80211_priv_h
+       set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac),
+       set_priv(IEEE80211_IOCTL_WDSDELMAC, ieee80211_ioctl_wdsdelmac),
+       set_priv(IEEE80211_IOCTL_KICKMAC, ieee80211_ioctl_kickmac),
++      set_priv(IEEE80211_IOCTL_SETSCANLIST, ieee80211_ioctl_setscanlist),
+ #ifdef ATH_REVERSE_ENGINEERING
+       set_priv(IEEE80211_IOCTL_READREG, ieee80211_ioctl_readreg),
+       set_priv(IEEE80211_IOCTL_WRITEREG, ieee80211_ioctl_writereg),
diff --git a/net/madwifi/patches/352-ani_fix.patch b/net/madwifi/patches/352-ani_fix.patch
new file mode 100644 (file)
index 0000000..938d11c
--- /dev/null
@@ -0,0 +1,265 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1014,9 +1014,7 @@ ath_attach(u_int16_t devid, struct net_d
+        */
+       sc->sc_hasveol = ath_hal_hasveol(ah);
+-      /* Interference mitigation/ambient noise immunity (ANI).
+-       * In modes other than HAL_M_STA, it causes receive sensitivity
+-       * problems for OFDM. */
++      /* Interference mitigation/ambient noise immunity (ANI). */
+       sc->sc_hasintmit = ath_hal_hasintmit(ah);
+       /* get mac address from hardware */
+@@ -1144,6 +1142,11 @@ ath_attach(u_int16_t devid, struct net_d
+       sc->sc_rp_lasttsf       = 0;
+       sc->sc_last_tsf         = 0;
++      /* set all 3 to auto */
++      sc->sc_intmit = -1;
++      sc->sc_noise_immunity = -1;
++      sc->sc_ofdm_weak_det = -1;
++
+       return 0;
+ bad3:
+       ieee80211_ifdetach(ic);
+@@ -2428,6 +2431,43 @@ ath_chan2flags(struct ieee80211_channel
+       return flags;
+ }
++static int ath_setintmit(struct ath_softc *sc)
++{
++      struct ath_hal *ah = sc->sc_ah;
++      int ret;
++      int val;
++
++      if (!sc->sc_hasintmit)
++              return 0;
++
++      switch(sc->sc_intmit) {
++              case -1:
++                      if (sc->sc_opmode != IEEE80211_M_MONITOR)
++                              val = 1;
++                      else
++                              val = 0;
++                      break;
++              case 0: /* disabled */
++              case 1: /* enabled */
++                      val = sc->sc_intmit;
++                      break;
++              default:
++                      return 0;
++      }
++      ret = ath_hal_setintmit(ah, val);
++      if (val)
++              goto done;
++
++      /* manual settings */
++      if ((sc->sc_noise_immunity >= 0) && (sc->sc_noise_immunity <= 5))
++              ath_hal_setcapability(ah, HAL_CAP_INTMIT, 2, sc->sc_noise_immunity, NULL);
++      if ((sc->sc_ofdm_weak_det == 0) || (sc->sc_ofdm_weak_det == 1))
++              ath_hal_setcapability(ah, HAL_CAP_INTMIT, 3, sc->sc_ofdm_weak_det, NULL);
++
++done:
++      return ret;
++}
++
+ /*
+  * Context: process context
+  */
+@@ -2493,8 +2533,7 @@ ath_init(struct net_device *dev)
+       if (sc->sc_softled)
+               ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
+-      if ((sc->sc_opmode != HAL_M_STA) && sc->sc_hasintmit)
+-              ath_hal_setintmit(ah, 0);
++      ath_setintmit(sc);
+       /*
+        * This is needed only to setup initial state
+@@ -2530,7 +2569,7 @@ ath_init(struct net_device *dev)
+        * Enable MIB interrupts when there are hardware phy counters.
+        * Note we only do this (at the moment) for station mode.
+        */
+-      if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA)
++      if (sc->sc_needmib && ath_hal_getintmit(ah, NULL))
+               sc->sc_imask |= HAL_INT_MIB;
+       ath_hal_intrset(ah, sc->sc_imask);
+@@ -2787,9 +2826,7 @@ ath_reset(struct net_device *dev)
+               EPRINTF(sc, "Unable to reset hardware: '%s' (HAL status %u)\n",
+                       ath_get_hal_status_desc(status), status);
+-      if ((sc->sc_opmode != HAL_M_STA) && sc->sc_hasintmit)
+-              ath_hal_setintmit(ah, 0);
+-
++      ath_setintmit(sc);
+       ath_update_txpow(sc);           /* update tx power state */
+       ath_radar_update(sc);
+       ath_setdefantenna(sc, sc->sc_defant);
+@@ -4174,6 +4211,8 @@ ath_calcrxfilter(struct ath_softc *sc)
+       if (sc->sc_nmonvaps > 0)
+               rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
+                         HAL_RX_FILTER_PROBEREQ | HAL_RX_FILTER_PROM);
++      if (sc->sc_hasintmit && !sc->sc_needmib && ath_hal_getintmit(ah, NULL))
++              rfilt |= HAL_RX_FILTER_PHYERR;
+       if (sc->sc_curchan.privFlags & CHANNEL_DFS)
+               rfilt |= (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR);
+       return rfilt;
+@@ -6526,9 +6565,6 @@ process_rx_again:
+                       rs->rs_rssi = 0;
+               len = rs->rs_datalen;
+-              /* DMA sync. dies spectacularly if len == 0 */
+-              if (len == 0)
+-                      goto rx_next;
+               if (rs->rs_more) {
+                       /*
+@@ -8876,9 +8912,7 @@ ath_chan_set(struct ath_softc *sc, struc
+               if (sc->sc_softled)
+                       ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
+-              if ((sc->sc_opmode != HAL_M_STA) && sc->sc_hasintmit)
+-                      ath_hal_setintmit(ah, 0);
+-
++              ath_setintmit(sc);
+               sc->sc_curchan = hchan;
+               ath_update_txpow(sc);           /* update tx power state */
+               ath_radar_update(sc);
+@@ -10655,9 +10689,54 @@ enum {
+       ATH_RP_IGNORED          = 24,
+       ATH_RADAR_IGNORED       = 25,
+       ATH_MAXVAPS             = 26,
++      ATH_INTMIT                      = 27,
++      ATH_NOISE_IMMUNITY      = 28,
++      ATH_OFDM_WEAK_DET       = 29
+ };
+ static int
++ath_sysctl_set_intmit(struct ath_softc *sc, long ctl, u_int val)
++{
++      int ret;
++
++      switch(ctl) {
++      case ATH_INTMIT:
++              sc->sc_intmit = val;
++              break;
++      case ATH_NOISE_IMMUNITY:
++              sc->sc_noise_immunity = val;
++              break;
++      case ATH_OFDM_WEAK_DET:
++              sc->sc_ofdm_weak_det = val;
++              break;
++      default:
++              return -EINVAL;
++      }
++      ret = ath_setintmit(sc);
++      ath_calcrxfilter(sc);
++      return ret;
++}
++
++static int
++ath_sysctl_get_intmit(struct ath_softc *sc, long ctl, u_int *val)
++{
++      struct ath_hal *ah = sc->sc_ah;
++
++      switch(ctl) {
++      case ATH_INTMIT:
++              *val = (ath_hal_getcapability(ah, HAL_CAP_INTMIT, 1, NULL) == HAL_OK);
++              break;
++      case ATH_NOISE_IMMUNITY:
++              return ath_hal_getcapability(ah, HAL_CAP_INTMIT, 2, val);
++      case ATH_OFDM_WEAK_DET:
++              return ath_hal_getcapability(ah, HAL_CAP_INTMIT, 3, val);
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++static int
+ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
+ {
+       struct ath_softc *sc = ctl->extra1;
+@@ -10843,6 +10922,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+                       case ATH_RADAR_IGNORED:
+                               sc->sc_radar_ignored = val;
+                               break;
++                      case ATH_INTMIT:
++                      case ATH_NOISE_IMMUNITY:
++                      case ATH_OFDM_WEAK_DET:
++                              ret = ath_sysctl_set_intmit(sc, (long)ctl->extra2, val);
++                              break;
+                       default:
+                               ret = -EINVAL;
+                               break;
+@@ -10909,6 +10993,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+               case ATH_RADAR_IGNORED:
+                       val = sc->sc_radar_ignored;
+                       break;
++              case ATH_INTMIT:
++              case ATH_NOISE_IMMUNITY:
++              case ATH_OFDM_WEAK_DET:
++                      ret = ath_sysctl_get_intmit(sc, (long)ctl->extra2, &val);
++                      break;
+               default:
+                       ret = -EINVAL;
+                       break;
+@@ -11086,6 +11175,24 @@ static const ctl_table ath_sysctl_templa
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_RADAR_IGNORED,
+       },
++      { .ctl_name     = CTL_AUTO,
++        .procname     = "intmit",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_halparam,
++        .extra2       = (void *)ATH_INTMIT,
++      },
++      { .ctl_name     = CTL_AUTO,
++        .procname     = "noise_immunity",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_halparam,
++        .extra2       = (void *)ATH_NOISE_IMMUNITY,
++      },
++      { .ctl_name     = CTL_AUTO,
++        .procname     = "ofdm_weak_det",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_halparam,
++        .extra2       = (void *)ATH_OFDM_WEAK_DET,
++      },
+       { 0 }
+ };
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -693,6 +693,10 @@ struct ath_softc {
+       unsigned int sc_txcont_power; /* Continuous transmit power in 0.5dBm units */
+       unsigned int sc_txcont_rate;  /* Continuous transmit rate in Mbps */
++      int8_t sc_intmit; /* Interference mitigation enabled, -1 = auto, based on mode, 0/1 = off/on */
++      int8_t sc_noise_immunity; /* Noise immunity level, 0-4, -1 == auto) */
++      int8_t sc_ofdm_weak_det; /* OFDM weak frames detection, -1 == auto */
++
+       /* rate tables */
+       const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX];
+       const HAL_RATE_TABLE *sc_currates;      /* current rate table */
+--- a/ath/if_ath_hal.h
++++ b/ath/if_ath_hal.h
+@@ -67,14 +67,14 @@ static inline HAL_POWER_MODE ath_hal_get
+ static inline HAL_BOOL ath_hal_getdiagstate(struct ath_hal *ah, int request,
+                                           const void *args, u_int32_t argsize,
+-                                          void **result,
++                                          void *result,
+                                           u_int32_t *resultsize)
+ {
+       HAL_BOOL ret;
+       ATH_HAL_LOCK_IRQ(ah->ah_sc);
+       ath_hal_set_function(__func__);
+       ret =
+-          ah->ah_getDiagState(ah, request, args, argsize, *result,
++          ah->ah_getDiagState(ah, request, args, argsize, result,
+                               resultsize);
+       ath_hal_set_function(NULL);
+       ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
diff --git a/net/madwifi/patches/353-devid.patch b/net/madwifi/patches/353-devid.patch
new file mode 100644 (file)
index 0000000..ee149ff
--- /dev/null
@@ -0,0 +1,19 @@
+--- a/ath/if_ath_pci.c
++++ b/ath/if_ath_pci.c
+@@ -114,11 +114,15 @@ static struct pci_device_id ath_pci_id_t
+       { 0x168c, 0x0023, PCI_ANY_ID, PCI_ANY_ID },
+       { 0x168c, 0x0024, PCI_ANY_ID, PCI_ANY_ID },
+       { 0x168c, 0x9013, PCI_ANY_ID, PCI_ANY_ID }, /* sonicwall */
++      { 0x168c, 0xff16, PCI_ANY_ID, PCI_ANY_ID },
++      { 0x168c, 0xff1a, PCI_ANY_ID, PCI_ANY_ID },
+       { 0 }
+ };
+ static u16 ath_devidmap[][2] = {
+-      { 0x9013, 0x0013 }
++      { 0x9013, 0x0013 },
++      { 0xff16, 0x0013 },
++      { 0xff1a, 0x001a }
+ };
+ static int
diff --git a/net/madwifi/patches/354-lantiq_eeprom.patch b/net/madwifi/patches/354-lantiq_eeprom.patch
new file mode 100644 (file)
index 0000000..59036b1
--- /dev/null
@@ -0,0 +1,95 @@
+--- a/ath_hal/ah_os.c
++++ b/ath_hal/ah_os.c
+@@ -343,6 +343,46 @@ EXPORT_SYMBOL(ath_hal_func);
+  * NB: see the comments in ah_osdep.h about byte-swapping register
+  *     reads and writes to understand what's going on below.
+  */
++
++#ifdef CONFIG_LANTIQ
++extern int lantiq_emulate_madwifi_eep;
++extern unsigned long long lantiq_madwifi_eep_addr;
++#define EEPROM_EMULATION 1
++#endif
++
++#ifdef EEPROM_EMULATION
++static int ath_hal_eeprom(struct ath_hal *ah, unsigned long addr, int val, int write)
++{
++      static int addrsel = 0;
++      static int rc = 0;
++
++      if (write) {
++              if(addr == 0x6000) {
++                      addrsel = val * 2;
++                      rc = 0;
++              }
++      } else {
++              switch(addr)
++              {
++              case 0x600c:
++                      if(rc++ < 2)
++                              val = 0x00000000;
++                      else
++                              val = 0x00000002;
++                      break;
++              case 0x6004:
++                      val = cpu_to_le16(__raw_readw((u16 *) KSEG1ADDR(lantiq_madwifi_eep_addr + addrsel)));
++                      /* this forces the regdomain to 0x00 (worldwide), as the original setting
++                       * causes issues with the HAL */
++                      if (addrsel == 0x17e)
++                              val = 0;
++                      break;
++              }
++      }
++      return val;
++}
++#endif
++
+ void __ahdecl
+ ath_hal_reg_write(struct ath_hal *ah, u_int reg, u_int32_t val)
+ {
+@@ -351,20 +391,33 @@ ath_hal_reg_write(struct ath_hal *ah, u_
+               ath_hal_printf(ah, "%s: WRITE 0x%x <= 0x%x\n", 
+                               (ath_hal_func ?: "unknown"), reg, val);
+ #endif
+-      _OS_REG_WRITE(ah, reg, val);
++#ifdef EEPROM_EMULATION
++      if((reg >= 0x6000) && (reg <= 0x6010) && lantiq_emulate_madwifi_eep)
++      {
++              val = ath_hal_eeprom(ah, reg, val, 1);
++      } else
++#endif
++              _OS_REG_WRITE(ah, reg, val);
+ }
+ EXPORT_SYMBOL(ath_hal_reg_write);
++
+ /* This should only be called while holding the lock, sc->sc_hal_lock. */
+ u_int32_t __ahdecl
+ ath_hal_reg_read(struct ath_hal *ah, u_int reg)
+ {
+-      u_int32_t val;
++      u_int32_t val;
++#ifdef EEPROM_EMULATION
++      if((reg >= 0x6000) && (reg <= 0x6010) && lantiq_emulate_madwifi_eep)
++      {
++              val = ath_hal_eeprom(ah, reg, 0, 0);
++      } else
++#endif
++              val = _OS_REG_READ(ah, reg);
+-      val = _OS_REG_READ(ah, reg);
+ #ifdef AH_DEBUG
+       if (ath_hal_debug > 1)
+-              ath_hal_printf(ah, "%s: READ 0x%x => 0x%x\n", 
++              ath_hal_printf(ah, "%s: READ 0x%x => 0x%x\n",
+                               (ath_hal_func ?: "unknown"), reg, val);
+ #endif
+       return val;
+@@ -581,7 +634,6 @@ init_ath_hal(void)
+ {
+       const char *sep;
+       int i;
+-
+       printk(KERN_INFO "%s: %s (", dev_info, ath_hal_version);
+       sep = "";
+       for (i = 0; ath_hal_buildopts[i] != NULL; i++) {
diff --git a/net/madwifi/patches/355-eap_auth_disassoc.patch b/net/madwifi/patches/355-eap_auth_disassoc.patch
new file mode 100644 (file)
index 0000000..8bb1e93
--- /dev/null
@@ -0,0 +1,77 @@
+This patch causes STA mode interfaces to disassociate if transmission of assoc/auth
+critical packets failed.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -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++;
++                                      if (SKB_CB(bf->bf_skb)->auth_pkt &&
++                                              (ni->ni_vap->iv_opmode == IEEE80211_M_STA)) {
++                                              struct ieee80211vap *vap = ni->ni_vap;
++
++                                              /* if roaming is enabled, try reassociating, otherwise
++                                               * disassociate and go back to the scan state */
++                                              vap->iv_mgtsend.function(vap->iv_mgtsend.data);
++                                      }
+                                       if (ni->ni_flags & IEEE80211_NODE_UAPSD_TRIG) {
+                                               ni->ni_stats.ns_tx_eosplost++;
+                                               DPRINTF(sc, ATH_DEBUG_UAPSD,
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -156,6 +156,7 @@ ieee80211_getmgtframe(u_int8_t **frm, u_
+               if (off != 0)
+                       skb_reserve(skb, align - off);
++              SKB_CB(skb)->auth_pkt = 0;
+               SKB_CB(skb)->ni = NULL;
+               SKB_CB(skb)->flags = 0;
+               SKB_CB(skb)->next = NULL;
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -393,6 +393,7 @@ typedef spinlock_t acl_lock_t;
+       void            (*next_destructor)(struct sk_buff *skb);
+ #endif
+       struct sk_buff *next;                   /* fast frame sk_buf chain */
++      u_int8_t auth_pkt;
+ };
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -778,6 +778,8 @@ ieee80211_encap(struct ieee80211_node *n
+       else
+               hdrsize = sizeof(struct ieee80211_frame);
++      SKB_CB(skb)->auth_pkt = (eh.ether_type == __constant_htons(ETHERTYPE_PAE));
++
+       switch (vap->iv_opmode) {
+       case IEEE80211_M_IBSS:
+       case IEEE80211_M_AHDEMO:
+@@ -1622,6 +1624,7 @@ ieee80211_add_xr_param(u_int8_t *frm, st
+       ie->param_len = frm - &ie->param_oui[0];
+       return frm;
+ }
++
+ #endif
+ /*
+  * Send a probe request frame with the specified ssid
+@@ -1886,6 +1889,7 @@ ieee80211_send_mgmt(struct ieee80211_nod
+                               sizeof(u_int16_t)+IEEE80211_CHALLENGE_LEN : 0));
+               if (skb == NULL)
+                       senderr(ENOMEM, is_tx_nobuf);
++              SKB_CB(skb)->auth_pkt = 1;
+               ((__le16 *)frm)[0] =
+                       (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED)
+@@ -1960,6 +1964,7 @@ ieee80211_send_mgmt(struct ieee80211_nod
+                       vap->app_ie[IEEE80211_APPIE_FRAME_ASSOC_REQ].length);
+               if (skb == NULL)
+                       senderr(ENOMEM, is_tx_nobuf);
++              SKB_CB(skb)->auth_pkt = 1;
+               capinfo = 0;
+               if (vap->iv_opmode == IEEE80211_M_IBSS)
diff --git a/net/madwifi/patches/356-hidden_ssid.patch b/net/madwifi/patches/356-hidden_ssid.patch
new file mode 100644 (file)
index 0000000..b87569e
--- /dev/null
@@ -0,0 +1,49 @@
+This patch fixes the detection of hidden SSIDs as transmitted
+by some cisco systems.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -209,6 +209,19 @@ saveie(u_int8_t **iep, const u_int8_t *i
+               ieee80211_saveie(iep, ie);
+ }
++
++static inline int is_empty_ssid(u_int8_t *ssid)
++{
++      if (!ssid)
++              return 1;
++      if (ssid[1] == 0)
++              return 1;
++      if ((ssid[1] == 1) && (ssid[2] == 0))
++              return 1;
++      return 0;
++}
++
++
+ /*
+  * Process a beacon or probe response frame; create an
+  * entry in the scan cache or update any previous entry.
+@@ -233,8 +246,8 @@ sta_add(struct ieee80211_scan_state *ss,
+       SCAN_STA_LOCK_IRQ(st);
+       LIST_FOREACH(se, &st->st_hash[hash], se_hash)
+               if (IEEE80211_ADDR_EQ(se->base.se_macaddr, macaddr) &&
+-                  sp->ssid[1] == se->base.se_ssid[1] &&
+-                  !memcmp(se->base.se_ssid+2, sp->ssid+2, se->base.se_ssid[1]))
++                  (is_empty_ssid(sp->ssid) || (sp->ssid[1] == se->base.se_ssid[1] &&
++                  !memcmp(se->base.se_ssid+2, sp->ssid+2, se->base.se_ssid[1]))))
+                       goto found;
+       MALLOC(se, struct sta_entry *, sizeof(struct sta_entry),
+@@ -252,8 +265,8 @@ found:
+       ise = &se->base;
+       /* XXX ap beaconing multiple ssid w/ same bssid */
+-      if (sp->ssid[1] != 0 &&
+-          (ISPROBE(subtype) || ise->se_ssid[1] == 0))
++      if (!is_empty_ssid(sp->ssid) &&
++          (ISPROBE(subtype) || is_empty_ssid(ise->se_ssid)))
+               memcpy(ise->se_ssid, sp->ssid, 2 + sp->ssid[1]);
+       memcpy(ise->se_rates, sp->rates, 
diff --git a/net/madwifi/patches/357-bgscan_thresh.patch b/net/madwifi/patches/357-bgscan_thresh.patch
new file mode 100644 (file)
index 0000000..bf34837
--- /dev/null
@@ -0,0 +1,160 @@
+Add an optional background scanning threshold triggered by low rssi
+(useful for passing updated scan results to the supplicant ahead of
+time, before losing connectivity entirely)
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -646,6 +646,7 @@ enum {
+       IEEE80211_PARAM_MINRATE                 = 76,   /* Minimum rate (by table index) */
+       IEEE80211_PARAM_PROTMODE_RSSI           = 77,   /* RSSI Threshold for enabling protection mode */
+       IEEE80211_PARAM_PROTMODE_TIMEOUT        = 78,   /* Timeout for expiring protection mode */
++      IEEE80211_PARAM_BGSCAN_THRESH           = 79,   /* bg scan rssi threshold */
+ };
+ #define       SIOCG80211STATS                 (SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -92,6 +92,8 @@
+ #define       IEEE80211_BGSCAN_IDLE_MIN       100     /* min idle time (ms) */
+ #define       IEEE80211_BGSCAN_IDLE_DEFAULT   250     /* default idle time (ms) */
++#define IEEE80211_BGSCAN_TRIGGER_INTVL 20 /* min trigger interval for thresh based bgscan (secs) */
++
+ #define IEEE80211_COVERAGE_CLASS_MAX  31      /* max coverage class */
+ #define IEEE80211_REGCLASSIDS_MAX     10      /* max regclass id list */
+@@ -219,6 +221,10 @@ struct ieee80211vap {
+       u_int8_t iv_nickname[IEEE80211_NWID_LEN];
+       u_int iv_bgscanidle;                            /* bg scan idle threshold */
+       u_int iv_bgscanintvl;                           /* bg scan min interval */
++      u_int iv_bgscanthr;                                     /* bg scan rssi threshold */
++      u_int iv_bgscantrintvl;                         /* bg scan trigger interval */
++      unsigned long iv_bgscanthr_next;                /* last trigger for bgscan */
++      unsigned long iv_lastconnect;   /* time of last connect attempt */
+       u_int iv_scanvalid;                             /* scan cache valid threshold */
+       struct ieee80211_roam iv_roam;                  /* sta-mode roaming state */
+@@ -608,6 +614,7 @@ MALLOC_DECLARE(M_80211_VAP);
+ #define IEEE80211_FEXT_SWBMISS                0x00000400      /* CONF: use software beacon timer */
+ #define IEEE80211_FEXT_DROPUNENC_EAPOL        0x00000800      /* CONF: drop unencrypted eapol frames */
+ #define IEEE80211_FEXT_APPIE_UPDATE   0x00001000      /* STATE: beacon APP IE updated */
++#define IEEE80211_FEXT_BGSCAN_THR     0x00002000      /* bgscan due to low rssi */
+ #define IEEE80211_COM_UAPSD_ENABLE(_ic)               ((_ic)->ic_flags_ext |= IEEE80211_FEXT_UAPSD)
+ #define IEEE80211_COM_UAPSD_DISABLE(_ic)      ((_ic)->ic_flags_ext &= ~IEEE80211_FEXT_UAPSD)
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2744,6 +2744,9 @@ ieee80211_ioctl_setparam(struct net_devi
+               else
+                       retv = EINVAL;
+               break;
++      case IEEE80211_PARAM_BGSCAN_THRESH:
++              vap->iv_bgscanthr = value;
++              break;
+       case IEEE80211_PARAM_MCAST_RATE:
+               /* units are in KILObits per second */
+               if (value >= 256 && value <= 54000)
+@@ -3144,6 +3147,9 @@ ieee80211_ioctl_getparam(struct net_devi
+       case IEEE80211_PARAM_BGSCAN_INTERVAL:
+               param[0] = vap->iv_bgscanintvl / HZ;    /* seconds */
+               break;
++      case IEEE80211_PARAM_BGSCAN_THRESH:
++              param[0] = vap->iv_bgscanthr;   /* rssi */
++              break;
+       case IEEE80211_PARAM_MCAST_RATE:
+               param[0] = vap->iv_mcast_rate;  /* seconds */
+               break;
+@@ -5666,6 +5672,10 @@ static const struct iw_priv_args ieee802
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bgscanintvl" },
+       { IEEE80211_PARAM_BGSCAN_INTERVAL,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bgscanintvl" },
++      { IEEE80211_PARAM_BGSCAN_THRESH,
++        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bgscanthr" },
++      { IEEE80211_PARAM_BGSCAN_THRESH,
++        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bgscanthr" },
+       { IEEE80211_PARAM_MCAST_RATE,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "mcast_rate" },
+       { IEEE80211_PARAM_MCAST_RATE,
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3013,8 +3013,10 @@ contbgscan(struct ieee80211vap *vap)
+ {
+       struct ieee80211com *ic = vap->iv_ic;
++      vap->iv_bgscantrintvl = (vap->iv_bgscantrintvl + 1) % 4;
+       return ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) &&
+-              time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle));
++              (((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN_THR) && !vap->iv_bgscantrintvl) ||
++                      time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle)));
+ }
+ static __inline int
+@@ -3258,6 +3260,25 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                       /* record tsf of last beacon */
+                       memcpy(ni->ni_tstamp.data, scan.tstamp,
+                               sizeof(ni->ni_tstamp));
++
++                      /* When rssi is low, start doing bgscans more frequently to allow
++                       * the supplicant to make a better switching decision */
++                      if (!(ic->ic_flags & IEEE80211_F_SCAN) && (rssi < vap->iv_bgscanthr) &&
++                                      (!vap->iv_bgscanthr_next ||
++                                              !time_before(jiffies, vap->iv_bgscanthr_next)) &&
++                                      (vap->iv_state == IEEE80211_S_RUN) &&
++                                      time_after(jiffies, vap->iv_lastconnect +
++                                              msecs_to_jiffies(IEEE80211_BGSCAN_INTVAL_MIN * 1000))) {
++                              int ret;
++
++                              ic->ic_lastdata = 0;
++                              ic->ic_lastscan = 0;
++                              ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN_THR;
++                              ret = ieee80211_bg_scan(vap);
++                              if (ret)
++                                      vap->iv_bgscanthr_next = jiffies + msecs_to_jiffies(IEEE80211_BGSCAN_TRIGGER_INTVL * 1000);
++                      }
++
+                       if (ni->ni_intval != scan.bintval) {
+                               IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
+                                               "beacon interval divergence: "
+--- a/net80211/ieee80211_scan.c
++++ b/net80211/ieee80211_scan.c
+@@ -616,6 +616,7 @@ ieee80211_cancel_scan(struct ieee80211va
+               /* clear bg scan NOPICK and mark cancel request */
+               ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
++              ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN_THR;
+               SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL;
+               ss->ss_ops->scan_cancel(ss, vap);
+               /* force it to fire asap */
+@@ -782,7 +783,7 @@ again:
+                               ieee80211_sta_pwrsave(vap, 0);
+                               if (ss->ss_next >= ss->ss_last) {
+                                       ieee80211_notify_scan_done(vap);
+-                                      ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
++                                      ic->ic_flags_ext &= ~(IEEE80211_FEXT_BGSCAN|IEEE80211_FEXT_BGSCAN_THR);
+                               }
+                       }
+                       SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_CANCEL;
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -1450,6 +1450,7 @@ __ieee80211_newstate(struct ieee80211vap
+               }
+               break;
+       case IEEE80211_S_AUTH:
++              vap->iv_lastconnect = jiffies;
+               /* auth frames are possible between IBSS nodes, 
+                * see 802.11-1999, chapter 5.7.6 */
+               KASSERT(vap->iv_opmode == IEEE80211_M_STA || 
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -238,7 +238,8 @@ ieee80211_hardstart(struct sk_buff *skb,
+       }
+       
+       /* Cancel any running BG scan */
+-      ieee80211_cancel_scan(vap);
++      if (!(ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN_THR) && (vap->iv_state == IEEE80211_S_RUN))
++              ieee80211_cancel_scan(vap);
+       /* 
+        * Find the node for the destination so we can do
diff --git a/net/madwifi/patches/358-ignore_broken_bssid.patch b/net/madwifi/patches/358-ignore_broken_bssid.patch
new file mode 100644 (file)
index 0000000..b549272
--- /dev/null
@@ -0,0 +1,18 @@
+Some misconfigured APs broadcast NULL BSSIDs, which can confuse the STA
+Ignore those when scanning.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -242,6 +242,10 @@ sta_add(struct ieee80211_scan_state *ss,
+       struct ieee80211_scan_entry *ise;
+       int hash;
++      /* workaround for broken APs that broadcast NULL BSSIDs */
++      if (memcmp(wh->i_addr3, "\x00\x00\x00\x00\x00\x00", 6) == 0)
++              return 0;
++
+       hash = STA_HASH(macaddr);
+       SCAN_STA_LOCK_IRQ(st);
+       LIST_FOREACH(se, &st->st_hash[hash], se_hash)
diff --git a/net/madwifi/patches/359-disable_reassoc.patch b/net/madwifi/patches/359-disable_reassoc.patch
new file mode 100644 (file)
index 0000000..8d25dc2
--- /dev/null
@@ -0,0 +1,31 @@
+Add a preliminary fix for the reassoc check, but disable reassoc entirely for now
+until we've figured out why it fails frequently.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -599,10 +599,9 @@ ieee80211_ibss_merge(struct ieee80211_no
+ EXPORT_SYMBOL(ieee80211_ibss_merge);
+ static __inline int
+-ssid_equal(const struct ieee80211_node *a, const struct ieee80211_node *b)
++bssid_equal(const struct ieee80211_node *a, const struct ieee80211_node *b)
+ {
+-      return (a->ni_esslen == b->ni_esslen &&
+-              memcmp(a->ni_essid, b->ni_essid, a->ni_esslen) == 0);
++      return (memcmp(a->ni_bssid, b->ni_bssid, IEEE80211_ADDR_LEN) == 0);
+ }
+ /*
+@@ -634,8 +633,8 @@ ieee80211_sta_join1(struct ieee80211_nod
+        * Check if old+new node have the same ssid in which
+        * case we can reassociate when operating in sta mode.
+        */
+-      canreassoc = ((obss != NULL) &&
+-              (vap->iv_state == IEEE80211_S_RUN) && ssid_equal(obss, selbs));
++      canreassoc = 0; /* ((obss != NULL) &&
++              (vap->iv_state == IEEE80211_S_RUN) && bssid_equal(obss, selbs)); */
+       vap->iv_bss = selbs;
+       IEEE80211_ADDR_COPY(vap->iv_bssid, selbs->ni_bssid);
+       if (obss != NULL)
diff --git a/net/madwifi/patches/360-sta_nodes.patch b/net/madwifi/patches/360-sta_nodes.patch
new file mode 100644 (file)
index 0000000..8d2dd9d
--- /dev/null
@@ -0,0 +1,242 @@
+Drop stale AP nodes from the client list when disconnecting.
+Fixes some reassoc issues.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -1348,7 +1348,7 @@ __ieee80211_newstate(struct ieee80211vap
+                               IEEE80211_SEND_MGMT(ni,
+                                       IEEE80211_FC0_SUBTYPE_DISASSOC,
+                                       IEEE80211_REASON_ASSOC_LEAVE);
+-                              ieee80211_sta_leave(ni);
++                              ieee80211_node_leave(ni);
+                               break;
+                       case IEEE80211_M_HOSTAP:
+                               ieee80211_iterate_nodes(&ic->ic_sta,
+@@ -1358,12 +1358,14 @@ __ieee80211_newstate(struct ieee80211vap
+                               break;
+                       }
+                       goto reset;
++              case IEEE80211_S_AUTH:
+               case IEEE80211_S_ASSOC:
+                       switch (vap->iv_opmode) {
+                       case IEEE80211_M_STA:
+                               IEEE80211_SEND_MGMT(ni,
+                                       IEEE80211_FC0_SUBTYPE_DEAUTH,
+                                       IEEE80211_REASON_AUTH_LEAVE);
++                              ieee80211_node_leave(ni);
+                               break;
+                       case IEEE80211_M_HOSTAP:
+                               ieee80211_iterate_nodes(&ic->ic_sta,
+@@ -1376,7 +1378,6 @@ __ieee80211_newstate(struct ieee80211vap
+               case IEEE80211_S_SCAN:
+                       ieee80211_cancel_scan(vap);
+                       goto reset;
+-              case IEEE80211_S_AUTH:
+               reset:
+                       ieee80211_reset_bss(vap);
+                       break;
+@@ -1429,10 +1430,12 @@ __ieee80211_newstate(struct ieee80211vap
+                                       IEEE80211_SCAN_FOREVER,
+                                       vap->iv_des_nssid, vap->iv_des_ssid,
+                                       NULL);
++                      else
++                              ieee80211_node_leave(vap->iv_bss);
+                       break;
+               case IEEE80211_S_RUN:           /* beacon miss */
+                       if (vap->iv_opmode == IEEE80211_M_STA) {
+-                              ieee80211_sta_leave(ni);
++                              ieee80211_node_leave(ni);
+                               vap->iv_flags &= ~IEEE80211_F_SIBSS;    /* XXX */
+                               if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
+                                       ieee80211_check_scan(vap,
+@@ -1511,7 +1514,7 @@ __ieee80211_newstate(struct ieee80211vap
+                               IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
+                       break;
+               case IEEE80211_S_RUN:
+-                      ieee80211_sta_leave(ni);
++                      ieee80211_node_leave(ni);
+                       if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
+                               /* NB: caller specifies ASSOC/REASSOC by arg */
+                               IEEE80211_SEND_MGMT(ni, arg ?
+@@ -1779,6 +1782,7 @@ ieee80211_newstate(struct ieee80211vap *
+                         ieee80211_state_name[nstate], 
+                         ieee80211_state_name[dstate]);
++      ieee80211_update_link_status(vap, nstate, ostate);
+       switch (nstate) {
+       case IEEE80211_S_AUTH:
+       case IEEE80211_S_ASSOC:
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -233,33 +233,59 @@ ieee80211_vlan_vdetach(struct ieee80211v
+ }
+ void
+-ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc)
++ieee80211_update_link_status(struct ieee80211vap *vap, int nstate, int ostate)
+ {
+-      struct ieee80211vap *vap = ni->ni_vap;
+       struct net_device *dev = vap->iv_dev;
+       union iwreq_data wreq;
++      int active;
++
++      if (vap->iv_opmode != IEEE80211_M_STA)
++              return;
++
++      if (ostate == nstate)
++              return;
++
++      if (nstate == IEEE80211_S_RUN)
++              active = 1;
++      else if ((ostate >= IEEE80211_S_AUTH) && (nstate < ostate))
++              active = 0;
++      else
++              return;
++
++      if (active && !vap->iv_bss)
++              return;
++
++      memset(&wreq, 0, sizeof(wreq));
++      wreq.ap_addr.sa_family = ARPHRD_ETHER;
+-      if (ni == vap->iv_bss) {
+-              if (newassoc)
+-                      netif_carrier_on(dev);
+-              memset(&wreq, 0, sizeof(wreq));
++      if (active) {
++              //netif_carrier_on(vap->iv_dev);
+               IEEE80211_ADDR_COPY(wreq.addr.sa_data, vap->iv_bssid);
+-              wreq.addr.sa_family = ARPHRD_ETHER;
+-#ifdef ATH_SUPERG_XR
+-              if (vap->iv_xrvap && vap->iv_flags & IEEE80211_F_XR)
+-                      dev = vap->iv_xrvap->iv_dev;
+-#endif
+-              wireless_send_event(dev, SIOCGIWAP, &wreq, NULL);
+       } else {
+-              memset(&wreq, 0, sizeof(wreq));
+-              IEEE80211_ADDR_COPY(wreq.addr.sa_data, ni->ni_macaddr);
+-              wreq.addr.sa_family = ARPHRD_ETHER;
++              //netif_carrier_off(vap->iv_dev);
++              memset(wreq.ap_addr.sa_data, 0, ETHER_ADDR_LEN);
++      }
++      wireless_send_event(dev, SIOCGIWAP, &wreq, NULL);
++}
++
++void
++ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc)
++{
++      struct ieee80211vap *vap = ni->ni_vap;
++      struct net_device *dev = vap->iv_dev;
++      union iwreq_data wreq;
++
++      if (ni == vap->iv_bss)
++              return;
++
++      memset(&wreq, 0, sizeof(wreq));
++      IEEE80211_ADDR_COPY(wreq.addr.sa_data, ni->ni_macaddr);
++      wreq.addr.sa_family = ARPHRD_ETHER;
+ #ifdef ATH_SUPERG_XR
+-              if (vap->iv_xrvap && vap->iv_flags & IEEE80211_F_XR)
+-                      dev = vap->iv_xrvap->iv_dev;
++      if (vap->iv_xrvap && vap->iv_flags & IEEE80211_F_XR)
++              dev = vap->iv_xrvap->iv_dev;
+ #endif
+-              wireless_send_event(dev, IWEVREGISTERED, &wreq, NULL);
+-      }
++      wireless_send_event(dev, IWEVREGISTERED, &wreq, NULL);
+ }
+ void
+@@ -269,18 +295,14 @@ ieee80211_notify_node_leave(struct ieee8
+       struct net_device *dev = vap->iv_dev;
+       union iwreq_data wreq;
+-      if (ni == vap->iv_bss) {
+-              netif_carrier_off(dev);
+-              memset(wreq.ap_addr.sa_data, 0, ETHER_ADDR_LEN);
+-              wreq.ap_addr.sa_family = ARPHRD_ETHER;
+-              wireless_send_event(dev, SIOCGIWAP, &wreq, NULL);
+-      } else {
+-              /* fire off wireless event station leaving */
+-              memset(&wreq, 0, sizeof(wreq));
+-              IEEE80211_ADDR_COPY(wreq.addr.sa_data, ni->ni_macaddr);
+-              wreq.addr.sa_family = ARPHRD_ETHER;
+-              wireless_send_event(dev, IWEVEXPIRED, &wreq, NULL);
+-      }
++      if (ni == vap->iv_bss)
++              return;
++
++      /* fire off wireless event station leaving */
++      memset(&wreq, 0, sizeof(wreq));
++      IEEE80211_ADDR_COPY(wreq.addr.sa_data, ni->ni_macaddr);
++      wreq.addr.sa_family = ARPHRD_ETHER;
++      wireless_send_event(dev, IWEVEXPIRED, &wreq, NULL);
+ }
+ void
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -2332,6 +2332,7 @@ ieee80211_node_leave(struct ieee80211_no
+               count_suppchans(ic, ni, -1);
+       IEEE80211_UNLOCK_IRQ(ic);
++done:
+       /*
+        * Cleanup station state.  In particular clear various
+        * state that might otherwise be reused if the node
+@@ -2339,7 +2340,7 @@ ieee80211_node_leave(struct ieee80211_no
+        * (and memory is reclaimed).
+        */
+       ieee80211_sta_leave(ni);
+-done:
++
+       /* Run a cleanup */
+ #ifdef IEEE80211_DEBUG_REFCNT
+       ic->ic_node_cleanup_debug(ni, __func__, __LINE__);
+--- a/net80211/ieee80211_node.h
++++ b/net80211/ieee80211_node.h
+@@ -60,7 +60,7 @@
+ #define       IEEE80211_INACT_PROBE   (30/IEEE80211_INACT_WAIT)       /* probe */
+ #define       IEEE80211_INACT_SCAN    (300/IEEE80211_INACT_WAIT)      /* scanned */
+-#define       IEEE80211_TRANS_WAIT    5                               /* mgt frame tx timer (secs) */
++#define       IEEE80211_TRANS_WAIT    300                             /* mgt frame tx timer (msecs) */
+ #define       IEEE80211_NODE_HASHSIZE 32
+ /* simple hash is enough for variation of macaddr */
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -2141,7 +2141,7 @@ ieee80211_send_mgmt(struct ieee80211_nod
+       ieee80211_mgmt_output(ieee80211_ref_node(ni), skb, type);
+       if (timer)
+-              mod_timer(&vap->iv_mgtsend, jiffies + timer * HZ);
++              mod_timer(&vap->iv_mgtsend, jiffies + msecs_to_jiffies(timer));
+       return 0;
+ bad:
+       return ret;
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -514,8 +514,9 @@ ieee80211_ioctl_siwap(struct net_device
+                       vap->iv_flags |= IEEE80211_F_DESBSSID;
+               IEEE80211_ADDR_COPY(vap->iv_des_bssid, &ap_addr->sa_data);
+-              if (IS_UP_AUTO(vap))
++              if (IS_UP(vap->iv_dev)) {
+                       ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
++              }
+       }
+       return 0;
+ }
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -643,6 +643,7 @@ void ieee80211_vlan_vdetach(struct ieee8
+ #define       free_netdev(dev)        kfree(dev)
+ #endif
++void ieee80211_update_link_status(struct ieee80211vap *vap, int nstate, int ostate);
+ void ieee80211_ioctl_vattach(struct ieee80211vap *);
+ void ieee80211_ioctl_vdetach(struct ieee80211vap *);
+ struct ifreq;
diff --git a/net/madwifi/patches/361-bmiss_handling.patch b/net/madwifi/patches/361-bmiss_handling.patch
new file mode 100644 (file)
index 0000000..15d238f
--- /dev/null
@@ -0,0 +1,102 @@
+Improve the beacon miss handling. Instead of just dropping the connection,
+send a directed probe request to the AP to see if it's still responding.
+Schedule a software beacon miss timer in this case, which adds a timeout
+for the APs probe response.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3400,12 +3400,17 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                       }
+                       /* WDS/Repeater: re-schedule software beacon timer for 
+-                       * STA. */
+-                      if ((vap->iv_state == IEEE80211_S_RUN) &&
+-                          (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) {
+-                              mod_timer(&vap->iv_swbmiss, 
++                       * STA. Reset consecutive bmiss counter as well */
++                      IEEE80211_LOCK_IRQ(ic);
++                      if (vap->iv_state == IEEE80211_S_RUN) {
++                              vap->iv_bmiss_count = 0;
++                              if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)
++                                      mod_timer(&vap->iv_swbmiss,
+                                               jiffies + vap->iv_swbmiss_period);
++                              else
++                                      del_timer(&vap->iv_swbmiss);
+                       }
++                      IEEE80211_UNLOCK_IRQ(ic);
+                       /* If scanning, pass the info to the scan module.
+                        * Otherwise, check if it's the right time to do
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -1209,6 +1209,8 @@ ieee80211_beacon_miss(struct ieee80211co
+       }
+       /* XXX locking */
+       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++              int count;
++
+               IEEE80211_DPRINTF(vap,
+                       IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
+                       "%s\n", "beacon miss");
+@@ -1221,6 +1223,29 @@ ieee80211_beacon_miss(struct ieee80211co
+               if (vap->iv_opmode != IEEE80211_M_STA ||
+                   vap->iv_state != IEEE80211_S_RUN)
+                       continue;
++
++              IEEE80211_LOCK_IRQ(ic);
++              count = vap->iv_bmiss_count++;
++              if (count) {
++                      /* if the counter was already above zero, reset it
++                       * here, since we're going to do the bmiss handling
++                       * in any case */
++                      vap->iv_bmiss_count = 0;
++              } else {
++                      /* schedule the software beacon miss timer, it will be
++                       * cancelled, if the probe request is acked */
++                      mod_timer(&vap->iv_swbmiss, jiffies + vap->iv_swbmiss_period);
++              }
++              IEEE80211_UNLOCK_IRQ(ic);
++
++              if (!count) {
++                      ieee80211_send_probereq(vap->iv_bss, vap->iv_myaddr,
++                              vap->iv_bss->ni_bssid, vap->iv_bss->ni_bssid,
++                              vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen,
++                              NULL, 0);
++                      continue;
++              }
++
+               if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
+ #ifdef ATH_SUPERG_DYNTURBO
+                       /* 
+@@ -1621,14 +1646,14 @@ __ieee80211_newstate(struct ieee80211vap
+               }
+               /* WDS/Repeater: Start software beacon timer for STA */
++              vap->iv_swbmiss.function = ieee80211_sta_swbmiss;
++              vap->iv_swbmiss.data = (unsigned long) vap;
++              vap->iv_swbmiss_period = IEEE80211_TU_TO_JIFFIES(
++                      vap->iv_ic->ic_bmissthreshold * ni->ni_intval);
++
+               if (ostate != IEEE80211_S_RUN &&
+                   (vap->iv_opmode == IEEE80211_M_STA &&
+                    vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) {
+-                      vap->iv_swbmiss.function = ieee80211_sta_swbmiss;
+-                      vap->iv_swbmiss.data = (unsigned long) vap;
+-                      vap->iv_swbmiss_period = IEEE80211_TU_TO_JIFFIES(
+-                              vap->iv_ic->ic_bmissthreshold * ni->ni_intval);
+-
+                       mod_timer(&vap->iv_swbmiss, jiffies + vap->iv_swbmiss_period);
+               }
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -283,6 +283,7 @@ struct ieee80211vap {
+       struct timer_list iv_swbmiss;                   /* software beacon miss timer */
+       u_int16_t iv_swbmiss_period;                    /* software beacon miss timer period */
++      u_int16_t iv_bmiss_count;                       /* consecutive beacon miss counter */
+       struct ieee80211_nsparams iv_nsparams;          /* new state parameters for tasklet for stajoin1 */
+       struct IEEE80211_TQ_STRUCT iv_stajoin1tq;       /* tasklet for newstate action called from stajoin1tq */
+       unsigned int iv_nsdone;                         /* Done with scheduled newstate tasklet */
diff --git a/net/madwifi/patches/362-rssithr.patch b/net/madwifi/patches/362-rssithr.patch
new file mode 100644 (file)
index 0000000..5a86833
--- /dev/null
@@ -0,0 +1,93 @@
+Add an optional threshold for low-rssi disconnection. This can be useful
+when letting wpa_supplicant control roaming.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -647,6 +647,8 @@ enum {
+       IEEE80211_PARAM_PROTMODE_RSSI           = 77,   /* RSSI Threshold for enabling protection mode */
+       IEEE80211_PARAM_PROTMODE_TIMEOUT        = 78,   /* Timeout for expiring protection mode */
+       IEEE80211_PARAM_BGSCAN_THRESH           = 79,   /* bg scan rssi threshold */
++      IEEE80211_PARAM_RSSI_DIS_THR    = 80,   /* rssi threshold for disconnection */
++      IEEE80211_PARAM_RSSI_DIS_COUNT  = 81,   /* counter for rssi threshold */
+ };
+ #define       SIOCG80211STATS                 (SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2799,6 +2799,12 @@ ieee80211_ioctl_setparam(struct net_devi
+       case IEEE80211_PARAM_ROAM_RATE_11G:
+               vap->iv_roam.rate11b = value;
+               break;
++      case IEEE80211_PARAM_RSSI_DIS_THR:
++              vap->iv_rssi_dis_thr = value;
++              break;
++      case IEEE80211_PARAM_RSSI_DIS_COUNT:
++              vap->iv_rssi_dis_max = value;
++              break;
+       case IEEE80211_PARAM_UAPSDINFO:
+               if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+                       if (ic->ic_caps & IEEE80211_C_UAPSD) {
+@@ -3184,6 +3190,12 @@ ieee80211_ioctl_getparam(struct net_devi
+       case IEEE80211_PARAM_ROAM_RATE_11G:
+               param[0] = vap->iv_roam.rate11b;
+               break;
++      case IEEE80211_PARAM_RSSI_DIS_THR:
++              param[0] = vap->iv_rssi_dis_thr;
++              break;
++      case IEEE80211_PARAM_RSSI_DIS_COUNT:
++              param[0] = vap->iv_rssi_dis_max;
++              break;
+       case IEEE80211_PARAM_UAPSDINFO:
+               if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+                       if (IEEE80211_VAP_UAPSD_ENABLED(vap))
+@@ -5733,6 +5745,14 @@ static const struct iw_priv_args ieee802
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rate11g" },
+       { IEEE80211_PARAM_ROAM_RATE_11G,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rate11g" },
++      { IEEE80211_PARAM_RSSI_DIS_THR,
++        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rssi_disthr" },
++      { IEEE80211_PARAM_RSSI_DIS_THR,
++        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rssi_disthr" },
++      { IEEE80211_PARAM_RSSI_DIS_COUNT,
++        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rssi_discnt" },
++      { IEEE80211_PARAM_RSSI_DIS_COUNT,
++        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rssi_discnt" },
+       { IEEE80211_PARAM_UAPSDINFO,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "uapsd" },
+       { IEEE80211_PARAM_UAPSDINFO,
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3261,6 +3261,19 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                       memcpy(ni->ni_tstamp.data, scan.tstamp,
+                               sizeof(ni->ni_tstamp));
++                      /* when rssi falls below the disconnection threshold, drop the connection */
++                      if ((vap->iv_rssi_dis_thr > 0) && (vap->iv_rssi_dis_max > 0)) {
++                              if ((rssi > 0) && (rssi < vap->iv_rssi_dis_thr)) {
++                                      if (++vap->iv_rssi_dis_trig > vap->iv_rssi_dis_max) {
++                                              vap->iv_rssi_dis_trig = 0;
++                                              ieee80211_node_leave(ni);
++                                              return;
++                                      }
++                              } else {
++                                      vap->iv_rssi_dis_trig = 0;
++                              }
++                      }
++
+                       /* When rssi is low, start doing bgscans more frequently to allow
+                        * the supplicant to make a better switching decision */
+                       if (!(ic->ic_flags & IEEE80211_F_SCAN) && (rssi < vap->iv_bgscanthr) &&
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -223,6 +223,9 @@ struct ieee80211vap {
+       u_int iv_bgscanintvl;                           /* bg scan min interval */
+       u_int iv_bgscanthr;                                     /* bg scan rssi threshold */
+       u_int iv_bgscantrintvl;                         /* bg scan trigger interval */
++      u_int iv_rssi_dis_thr;                          /* rssi disassoc threshold */
++      u_int iv_rssi_dis_max;                          /* max beacons below disconnect threshold */
++      u_int iv_rssi_dis_trig;                         /* rssi disassoc trigger count */
+       unsigned long iv_bgscanthr_next;                /* last trigger for bgscan */
+       unsigned long iv_lastconnect;   /* time of last connect attempt */
+       u_int iv_scanvalid;                             /* scan cache valid threshold */
diff --git a/net/madwifi/patches/363-fix_turbo.patch b/net/madwifi/patches/363-fix_turbo.patch
new file mode 100644 (file)
index 0000000..880f2d6
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -4925,7 +4925,7 @@ ath_beacon_generate(struct ath_softc *sc
+        * capability info and arrange for a mode change
+        * if needed.
+        */
+-      if (sc->sc_dturbo) {
++      if (sc->sc_dturbo && NULL != avp->av_boff.bo_tim) {
+               u_int8_t dtim;
+               dtim = ((avp->av_boff.bo_tim[2] == 1) ||
+                       (avp->av_boff.bo_tim[3] == 1));
diff --git a/net/madwifi/patches/364-memory_alloc.patch b/net/madwifi/patches/364-memory_alloc.patch
new file mode 100644 (file)
index 0000000..53fbc77
--- /dev/null
@@ -0,0 +1,13 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -539,8 +539,8 @@ ath_attach(u_int16_t devid, struct net_d
+       /* Allocate space for dynamically determined maximum VAP count */
+       sc->sc_bslot = 
+-              kmalloc(ath_maxvaps * sizeof(struct ieee80211vap), GFP_KERNEL);
+-      memset(sc->sc_bslot, 0, ath_maxvaps * sizeof(struct ieee80211vap));
++              kmalloc(ath_maxvaps * sizeof(struct ieee80211vap*), GFP_KERNEL);
++      memset(sc->sc_bslot, 0, ath_maxvaps * sizeof(struct ieee80211vap*));
+       /*
+        * Cache line size is used to size and align various
diff --git a/net/madwifi/patches/365-turbo_channelsearch.patch b/net/madwifi/patches/365-turbo_channelsearch.patch
new file mode 100644 (file)
index 0000000..df4306b
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -684,6 +684,7 @@ ieee80211_find_channel(struct ieee80211c
+       int i;
+       /* Brute force search */
++      flags &= IEEE80211_CHAN_ALLTURBO;
+       for (i = 0; i < ic->ic_nchans; i++) {
+               c = &ic->ic_channels[i];
+               if (c->ic_freq == freq &&
diff --git a/net/madwifi/patches/366-bstuck_thresh.patch b/net/madwifi/patches/366-bstuck_thresh.patch
new file mode 100644 (file)
index 0000000..cde1f5c
--- /dev/null
@@ -0,0 +1,52 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -389,6 +389,7 @@ static int ath_countrycode = CTRY_DEFAUL
+ static int ath_outdoor = AH_FALSE;            /* enable outdoor use */
+ static int ath_xchanmode = AH_TRUE;           /* enable extended channels */
+ static int ath_maxvaps = ATH_MAXVAPS_DEFAULT;   /* set default maximum vaps */
++static int bstuck_thresh = BSTUCK_THRESH;       /* Stuck beacon count required for reset */
+ static char *autocreate = NULL;
+ static char *ratectl = DEF_RATE_CTL;
+ static int rfkill = 0;
+@@ -432,6 +433,7 @@ MODULE_PARM(rfkill, "i");
+ #ifdef ATH_CAP_TPC
+ MODULE_PARM(tpc, "i");
+ #endif
++MODULE_PARM(bstuck_thresh, "i");
+ MODULE_PARM(autocreate, "s");
+ MODULE_PARM(ratectl, "s");
+ #else
+@@ -445,6 +447,7 @@ module_param(rfkill, int, 0600);
+ #ifdef ATH_CAP_TPC
+ module_param(tpc, int, 0600);
+ #endif
++module_param(bstuck_thresh, int, 0600);
+ module_param(autocreate, charp, 0600);
+ module_param(ratectl, charp, 0600);
+ #endif
+@@ -457,6 +460,7 @@ MODULE_PARM_DESC(rfkill, "Enable/disable
+ MODULE_PARM_DESC(tpc, "Enable/disable per-packet transmit power control (TPC) "
+               "capability");
+ #endif
++MODULE_PARM_DESC(bstuck_thresh, "Override default stuck beacon threshold");
+ MODULE_PARM_DESC(autocreate, "Create ath device in "
+               "[sta|ap|wds|adhoc|ahdemo|monitor] mode. defaults to sta, use "
+               "'none' to disable");
+@@ -5072,7 +5076,7 @@ ath_beacon_send(struct ath_softc *sc, in
+               DPRINTF(sc, ATH_DEBUG_BEACON_PROC,
+                       "Missed %u consecutive beacons (n_beacon=%u)\n",
+                       sc->sc_bmisscount, n_beacon);
+-              if (sc->sc_bmisscount > BSTUCK_THRESH)
++              if (sc->sc_bmisscount > bstuck_thresh)
+                       ATH_SCHEDULE_TQUEUE(&sc->sc_bstucktq, needmark);
+               return;
+       }
+@@ -5230,7 +5234,7 @@ ath_bstuck_tasklet(TQUEUE_ARG data)
+        *     check will be true, in which case return
+        *     without resetting the driver.
+        */
+-      if (sc->sc_bmisscount <= BSTUCK_THRESH)
++      if (sc->sc_bmisscount <= bstuck_thresh)
+               return;
+       EPRINTF(sc, "Stuck beacon; resetting (beacon miss count: %u)\n",
+               sc->sc_bmisscount);
diff --git a/net/madwifi/patches/367-roaming.patch b/net/madwifi/patches/367-roaming.patch
new file mode 100644 (file)
index 0000000..5950f9f
--- /dev/null
@@ -0,0 +1,77 @@
+Patch adapted from ubnt madwifi patchset
+
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -659,7 +659,7 @@ ieee80211_sta_join1(struct ieee80211_nod
+                */
+               if (canreassoc) {
+                       vap->iv_nsparams.newstate = IEEE80211_S_ASSOC;
+-                      vap->iv_nsparams.arg = 0;
++                      vap->iv_nsparams.arg = IEEE80211_FC0_SUBTYPE_REASSOC_REQ;
+                       IEEE80211_SCHEDULE_TQUEUE(&vap->iv_stajoin1tq);
+               } else {
+                       vap->iv_nsparams.newstate = IEEE80211_S_AUTH;
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -748,14 +748,17 @@ notfound:
+  * a reference to an entry w/o holding the lock on the table.
+  */
+ static struct sta_entry *
+-sta_lookup(struct sta_table *st, const u_int8_t macaddr[IEEE80211_ADDR_LEN])
++sta_lookup(struct sta_table *st, const u_int8_t macaddr[IEEE80211_ADDR_LEN], struct ieee80211_scan_ssid* essid)
+ {
+       struct sta_entry *se;
+       int hash = STA_HASH(macaddr);
+       SCAN_STA_LOCK_IRQ(st);
+       LIST_FOREACH(se, &st->st_hash[hash], se_hash)
+-              if (IEEE80211_ADDR_EQ(se->base.se_macaddr, macaddr))
++              if (IEEE80211_ADDR_EQ(se->base.se_macaddr, macaddr) &&
++                  (essid->len == se->base.se_ssid[1] &&
++                   !memcmp(se->base.se_ssid+2, essid->ssid,
++                           se->base.se_ssid[1])))
+                       break;
+       SCAN_STA_UNLOCK_IRQ(st);
+@@ -772,7 +775,7 @@ sta_roam_check(struct ieee80211_scan_sta
+       u_int8_t roamRate, curRate;
+       int8_t roamRssi, curRssi;
+-      se = sta_lookup(st, ni->ni_macaddr);
++      se = sta_lookup(st, ni->ni_macaddr, ss->ss_ssid);
+       if (se == NULL) {
+               /* XXX something is wrong */
+               return;
+@@ -866,8 +869,8 @@ sta_age(struct ieee80211_scan_state *ss)
+        */
+       KASSERT(vap->iv_opmode == IEEE80211_M_STA,
+               ("wrong mode %u", vap->iv_opmode));
+-      /* XXX turn this off until the ap release is cut */
+-      if (0 && vap->iv_ic->ic_roaming == IEEE80211_ROAMING_AUTO &&
++      if (vap->iv_opmode == IEEE80211_M_STA &&
++          vap->iv_ic->ic_roaming == IEEE80211_ROAMING_AUTO &&
+           vap->iv_state >= IEEE80211_S_RUN)
+               /* XXX vap is implicit */
+               sta_roam_check(ss, vap);
+@@ -922,7 +925,11 @@ sta_assoc_fail(struct ieee80211_scan_sta
+       struct sta_table *st = ss->ss_priv;
+       struct sta_entry *se;
+-      se = sta_lookup(st, macaddr);
++      /* Let outside apps to decide what peer is blacklisted */
++      if (ss->ss_vap->iv_ic->ic_roaming == IEEE80211_ROAMING_MANUAL)
++              return;
++
++      se = sta_lookup(st, macaddr, ss->ss_ssid);
+       if (se != NULL) {
+               se->se_fails++;
+               se->se_lastfail = jiffies;
+@@ -939,7 +946,7 @@ sta_assoc_success(struct ieee80211_scan_
+       struct sta_table *st = ss->ss_priv;
+       struct sta_entry *se;
+-      se = sta_lookup(st, macaddr);
++      se = sta_lookup(st, macaddr, ss->ss_ssid);
+       if (se != NULL) {
+ #if 0
+               se->se_fails = 0;
diff --git a/net/madwifi/patches/368-sta_ie_preserve.patch b/net/madwifi/patches/368-sta_ie_preserve.patch
new file mode 100644 (file)
index 0000000..fbd779e
--- /dev/null
@@ -0,0 +1,49 @@
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -201,8 +201,10 @@ sta_flush_table(struct sta_table *st)
+ }
+ static void
+-saveie(u_int8_t **iep, const u_int8_t *ie)
++saveie(u_int8_t **iep, const u_int8_t *ie, int preserve)
+ {
++      if (preserve && *iep)
++              return;
+       if (ie == NULL)
+               *iep = NULL;
+       else
+@@ -304,10 +306,10 @@ found:
+                   (const struct ieee80211_tim_ie *) sp->tim;
+               ise->se_dtimperiod = tim->tim_period;
+       }
+-      saveie(&ise->se_wme_ie, sp->wme);
+-      saveie(&ise->se_wpa_ie, sp->wpa);
+-      saveie(&ise->se_rsn_ie, sp->rsn);
+-      saveie(&ise->se_ath_ie, sp->ath);
++      saveie(&ise->se_wme_ie, sp->wme, 0);
++      saveie(&ise->se_wpa_ie, sp->wpa, !sp->isprobe);
++      saveie(&ise->se_rsn_ie, sp->rsn, !sp->isprobe);
++      saveie(&ise->se_ath_ie, sp->ath, 0);
+       /* clear failure count after STA_FAIL_AGE passes */
+       if (se->se_fails && (jiffies - se->se_lastfail) > STA_FAILS_AGE*HZ) {
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3106,6 +3106,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                */
+               IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
+               memset(&scan, 0, sizeof(scan));
++              scan.isprobe = (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) && IEEE80211_ADDR_EQ(wh->i_addr2, vap->iv_myaddr);
+               scan.tstamp  = frm;
+               frm += 8;
+               scan.bintval = le16toh(*(__le16 *)frm);
+--- a/net80211/ieee80211_scan.h
++++ b/net80211/ieee80211_scan.h
+@@ -133,6 +133,7 @@ struct ieee80211_scanparams {
+       u_int8_t erp;
+       u_int16_t bintval;
+       u_int8_t timoff;
++      u_int8_t isprobe;
+       u_int8_t *tim;
+       u_int8_t *tstamp;
+       u_int8_t *country;
diff --git a/net/madwifi/patches/369-mlme_assoc.patch b/net/madwifi/patches/369-mlme_assoc.patch
new file mode 100644 (file)
index 0000000..43aac66
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -3723,6 +3723,7 @@ ieee80211_ioctl_setmlme(struct net_devic
+               if (vap->iv_opmode == IEEE80211_M_STA) {
+                       struct scanlookup lookup;
++                      preempt_scan(dev, 100, 100);
+                       lookup.se = NULL;
+                       lookup.mac = mlme->im_macaddr;
+                       /* XXX use revised api w/ explicit ssid */
diff --git a/net/madwifi/patches/370-wdsvap.patch b/net/madwifi/patches/370-wdsvap.patch
new file mode 100644 (file)
index 0000000..8a0e823
--- /dev/null
@@ -0,0 +1,1665 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -124,7 +124,7 @@ enum {
+ };
+ static struct ieee80211vap *ath_vap_create(struct ieee80211com *,
+-      const char *, int, int, struct net_device *);
++      const char *, int, int, struct net_device *, struct ieee80211vap *);
+ static void ath_vap_delete(struct ieee80211vap *);
+ static int ath_init(struct net_device *);
+ static int ath_set_ack_bitrate(struct ath_softc *, int);
+@@ -1123,8 +1123,6 @@ ath_attach(u_int16_t devid, struct net_d
+                       autocreatemode = IEEE80211_M_IBSS;
+               else if (!strcmp(autocreate, "ahdemo"))
+                       autocreatemode = IEEE80211_M_AHDEMO;
+-              else if (!strcmp(autocreate, "wds"))
+-                      autocreatemode = IEEE80211_M_WDS;
+               else if (!strcmp(autocreate, "monitor"))
+                       autocreatemode = IEEE80211_M_MONITOR;
+               else {
+@@ -1137,7 +1135,7 @@ ath_attach(u_int16_t devid, struct net_d
+       if (autocreatemode != -1) {
+               rtnl_lock();
+               vap = ieee80211_create_vap(ic, "ath%d", dev,
+-                              autocreatemode, 0);
++                              autocreatemode, 0, NULL);
+               rtnl_unlock();
+               if (vap == NULL)
+                       EPRINTF(sc, "Autocreation of %s VAP failed.", autocreate);
+@@ -1230,14 +1228,14 @@ ath_detach(struct net_device *dev)
+ static struct ieee80211vap *
+ ath_vap_create(struct ieee80211com *ic, const char *name,
+-      int opmode, int flags, struct net_device *mdev)
++      int opmode, int flags, struct net_device *mdev, struct ieee80211vap *master)
+ {
+       struct ath_softc *sc = ic->ic_dev->priv;
+       struct ath_hal *ah = sc->sc_ah;
+       struct net_device *dev;
+       struct ath_vap *avp;
+       struct ieee80211vap *vap;
+-      int ic_opmode;
++      int ic_opmode = IEEE80211_M_STA;
+       if (ic->ic_dev->flags & IFF_RUNNING) {
+               /* needs to disable hardware too */
+@@ -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;
++      case IEEE80211_M_HOSTAP:
+               /* 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 +1306,7 @@ ath_vap_create(struct ieee80211com *ic,
+       }
+       avp = dev->priv;
+-      ieee80211_vap_setup(ic, dev, name, opmode, flags);
++      ieee80211_vap_setup(ic, dev, name, opmode, flags, master);
+       /* override with driver methods */
+       vap = &avp->av_vap;
+       avp->av_newstate = vap->iv_newstate;
+@@ -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 ||
+-              ((ic->ic_opmode == IEEE80211_M_HOSTAP) &&
+-               (ic->ic_protmode != IEEE80211_PROT_NONE)))
++              (ic->ic_opmode == IEEE80211_M_HOSTAP))
+               rfilt |= HAL_RX_FILTER_BEACON;
+       if (sc->sc_nmonvaps > 0)
+               rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
+@@ -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 &&
+-                              (TAILQ_FIRST(&ic->ic_vaps)->iv_opmode != 
+-                               IEEE80211_M_WDS) &&
+                               !txcont_was_active &&
+                               !sc->sc_dfs_cac) {
+                       sc->sc_beacons = 1;
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -373,10 +373,25 @@ void
+ ieee80211_ifdetach(struct ieee80211com *ic)
+ {
+       struct ieee80211vap *vap;
++      int count;
++
++      /* bring down all vaps */
++      TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++              ieee80211_stop(vap->iv_dev);
++      }
++
++      /* wait for all subifs to disappear */
++      do {
++              schedule();
++              rtnl_lock();
++              count = ic->ic_subifs;
++              rtnl_unlock();
++      } while (count > 0);
+       rtnl_lock();
+-      while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL)
++      while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL) {
+               ic->ic_vap_delete(vap);
++      }
+       rtnl_unlock();
+       del_timer(&ic->ic_dfs_excl_timer);
+@@ -396,7 +411,7 @@ EXPORT_SYMBOL(ieee80211_ifdetach);
+ int
+ ieee80211_vap_setup(struct ieee80211com *ic, struct net_device *dev,
+-      const char *name, int opmode, int flags)
++      const char *name, int opmode, int flags, struct ieee80211vap *master)
+ {
+ #define       IEEE80211_C_OPMODE \
+       (IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | IEEE80211_C_AHDEMO | \
+@@ -510,9 +525,18 @@ ieee80211_vap_setup(struct ieee80211com
+       vap->iv_monitor_crc_errors = 0;
+       vap->iv_monitor_phy_errors = 0;
++      TAILQ_INIT(&vap->iv_wdslinks);
+-      IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_myaddr);
+-      IEEE80211_ADDR_COPY(vap->iv_bssid, ic->ic_myaddr);
++      if (master && (vap->iv_opmode == IEEE80211_M_WDS)) {
++              vap->iv_master = master;
++              TAILQ_INSERT_TAIL(&master->iv_wdslinks, vap, iv_wdsnext);
++              /* use the same BSSID as the master interface */
++              IEEE80211_ADDR_COPY(vap->iv_myaddr, vap->iv_master->iv_myaddr);
++              IEEE80211_ADDR_COPY(vap->iv_bssid, vap->iv_master->iv_myaddr);
++      } else {
++              IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_myaddr);
++              IEEE80211_ADDR_COPY(vap->iv_bssid, ic->ic_myaddr);
++      }
+       /* NB: Defer setting dev_addr so driver can override */
+       ieee80211_crypto_vattach(vap);
+@@ -547,7 +571,8 @@ ieee80211_vap_attach(struct ieee80211vap
+       ifmedia_set(&vap->iv_media, imr.ifm_active);
+       IEEE80211_LOCK_IRQ(ic);
+-      TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next);
++      if (vap->iv_opmode != IEEE80211_M_WDS)
++              TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next);
+       IEEE80211_UNLOCK_IRQ(ic);
+       IEEE80211_ADDR_COPY(dev->dev_addr, vap->iv_myaddr);
+@@ -579,10 +604,27 @@ ieee80211_vap_detach(struct ieee80211vap
+ {
+       struct ieee80211com *ic = vap->iv_ic;
+       struct net_device *dev = vap->iv_dev;
++      struct ieee80211vap *avp;
++
++      /* Drop all WDS links that belong to this vap */
++      while ((avp = TAILQ_FIRST(&vap->iv_wdslinks)) != NULL) {
++              if (avp->iv_state != IEEE80211_S_INIT)
++                      ieee80211_stop(avp->iv_dev);
++              ic->ic_vap_delete(avp);
++      }
+       IEEE80211_CANCEL_TQUEUE(&vap->iv_stajoin1tq);
+       IEEE80211_LOCK_IRQ(ic);
+-      TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next);
++      if (vap->iv_wdsnode) {
++              vap->iv_wdsnode->ni_subif = NULL;
++              ieee80211_unref_node(&vap->iv_wdsnode);
++      }
++      if ((vap->iv_opmode == IEEE80211_M_WDS) &&
++              (vap->iv_master != NULL))
++              TAILQ_REMOVE(&vap->iv_master->iv_wdslinks, vap, iv_wdsnext);
++      else
++              TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next);
++
+       if (TAILQ_EMPTY(&ic->ic_vaps))          /* reset to supported mode */
+               ic->ic_opmode = IEEE80211_M_STA;
+       IEEE80211_UNLOCK_IRQ(ic);
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -474,7 +474,7 @@ struct ieee80211req {
+ #define       IEEE80211_IOC_DTIM_PERIOD       52      /* DTIM period (beacons) */
+ #define       IEEE80211_IOC_BEACON_INTERVAL   53      /* beacon interval (ms) */
+ #define       IEEE80211_IOC_ADDMAC            54      /* add sta to MAC ACL table */
+-#define       IEEE80211_IOC_DELMAC            55      /* del sta from MAC ACL table */
++#define       IEEE80211_IOC_SETMAC            55      /* set interface wds mac addr */
+ #define       IEEE80211_IOC_FF                56      /* ATH fast frames (on, off) */
+ #define       IEEE80211_IOC_TURBOP            57      /* ATH turbo' (on, off) */
+ #define       IEEE80211_IOC_APPIEBUF          58      /* IE in the management frame */
+@@ -552,8 +552,8 @@ struct ieee80211req_scan_result {
+ #define       IEEE80211_IOCTL_HALMAP          (SIOCIWFIRSTPRIV+21)
+ #define       IEEE80211_IOCTL_ADDMAC          (SIOCIWFIRSTPRIV+22)
+ #define       IEEE80211_IOCTL_DELMAC          (SIOCIWFIRSTPRIV+24)
+-#define       IEEE80211_IOCTL_WDSADDMAC       (SIOCIWFIRSTPRIV+26)
+-#define       IEEE80211_IOCTL_WDSDELMAC       (SIOCIWFIRSTPRIV+28)
++#define       IEEE80211_IOCTL_WDSADDMAC       (SIOCIWFIRSTPRIV+25)
++#define       IEEE80211_IOCTL_WDSSETMAC       (SIOCIWFIRSTPRIV+26)
+ #define       IEEE80211_IOCTL_KICKMAC         (SIOCIWFIRSTPRIV+30)
+ #define       IEEE80211_IOCTL_SETSCANLIST     (SIOCIWFIRSTPRIV+31)
+@@ -649,6 +649,7 @@ enum {
+       IEEE80211_PARAM_BGSCAN_THRESH           = 79,   /* bg scan rssi threshold */
+       IEEE80211_PARAM_RSSI_DIS_THR    = 80,   /* rssi threshold for disconnection */
+       IEEE80211_PARAM_RSSI_DIS_COUNT  = 81,   /* counter for rssi threshold */
++      IEEE80211_PARAM_WDS_SEP                 = 82,   /* move wds stations into separate interfaces */
+ };
+ #define       SIOCG80211STATS                 (SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -81,6 +81,12 @@ set_quality(struct iw_quality *iq, u_int
+ #endif
+ }
++#ifndef container_of
++#define container_of(ptr, type, member) ({          \
++    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
++          (type *)( (char *)__mptr - offsetof(type,member) );})
++#endif
++
+ /*
+  * Task deferral
+  *
+@@ -113,6 +119,29 @@ typedef void *IEEE80211_TQUEUE_ARG;
+ #define       IEEE80211_RESCHEDULE    schedule
++#include <linux/sched.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41)
++#include <linux/tqueue.h>
++#define work_struct                   tq_struct
++#define schedule_work(t)              schedule_task((t))
++#define flush_scheduled_work()                flush_scheduled_tasks()
++#define IEEE80211_INIT_WORK(t, f) do {                        \
++      memset((t), 0, sizeof(struct tq_struct)); \
++      (t)->routine = (void (*)(void*)) (f);   \
++      (t)->data=(void *) (t);                 \
++} while (0)
++#else
++#include <linux/workqueue.h>
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++#define IEEE80211_INIT_WORK(_t, _f)   INIT_WORK((_t), (void (*)(void *))(_f), (_t));
++#else
++#define IEEE80211_INIT_WORK(_t, _f)   INIT_WORK((_t), (_f));
++#endif
++
++#endif /* KERNEL_VERSION < 2.5.41 */
++
++
+ /* Locking */
+ /* NB: beware, spin_is_locked() is not usefully defined for !(DEBUG || SMP)
+  * because spinlocks do not exist in this configuration. Instead IRQs 
+@@ -167,6 +196,14 @@ typedef spinlock_t ieee80211com_lock_t;
+       IEEE80211_VAPS_LOCK_ASSERT(_ic);                \
+       spin_unlock_bh(&(_ic)->ic_vapslock);            \
+ } while (0)
++#define       IEEE80211_VAPS_LOCK_IRQ(_ic) do {                                       \
++      unsigned long __ilockflags;                                     \
++      IEEE80211_VAPS_LOCK_CHECK(_ic);                                 \
++      spin_lock_irqsave(&(_ic)->ic_vapslock, __ilockflags);
++#define       IEEE80211_VAPS_UNLOCK_IRQ(_ic)                                  \
++      IEEE80211_VAPS_LOCK_ASSERT(_ic);                                        \
++      spin_unlock_irqrestore(&(_ic)->ic_vapslock, __ilockflags);      \
++} while (0)
+ #if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked)
+ #define IEEE80211_VAPS_LOCK_ASSERT(_ic) \
+@@ -650,5 +687,5 @@ struct ifreq;
+ int ieee80211_ioctl_create_vap(struct ieee80211com *, struct ifreq *,
+       struct net_device *);
+ struct ieee80211vap *ieee80211_create_vap(struct ieee80211com *, char *,
+-      struct net_device *, int, int);
++      struct net_device *, int, int, struct ieee80211vap *);
+ #endif /* _NET80211_IEEE80211_LINUX_H_ */
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -187,6 +187,12 @@ struct ieee80211vap {
+       struct ieee80211_proc_entry *iv_proc_entries;
+       struct vlan_group *iv_vlgrp;                    /* vlan group state */
++      /* list of wds links */
++      TAILQ_HEAD(, ieee80211vap) iv_wdslinks;
++      TAILQ_ENTRY(ieee80211vap) iv_wdsnext;
++      struct ieee80211vap *iv_master;
++      struct ieee80211_node *iv_wdsnode;
++
+       TAILQ_ENTRY(ieee80211vap) iv_next;              /* list of vap instances */
+       struct ieee80211com *iv_ic;                     /* back ptr to common state */
+       u_int32_t iv_debug;                             /* debug msg flags */
+@@ -316,6 +322,7 @@ struct ieee80211com {
+       u_int8_t ic_myaddr[IEEE80211_ADDR_LEN];
+       struct timer_list ic_inact;             /* mgmt/inactivity timer */
++      unsigned int ic_subifs;
+       u_int32_t ic_flags;                     /* state flags */
+       u_int32_t ic_flags_ext;                 /* extension of state flags */
+       u_int32_t ic_caps;                      /* capabilities */
+@@ -447,7 +454,7 @@ struct ieee80211com {
+       atomic_t ic_node_counter;
+       /* Virtual AP create/delete */
+       struct ieee80211vap *(*ic_vap_create)(struct ieee80211com *,
+-              const char *, int, int, struct net_device *);
++              const char *, int, int, struct net_device *, struct ieee80211vap *);
+       void (*ic_vap_delete)(struct ieee80211vap *);
+       /* Send/recv 802.11 management frame */
+@@ -619,6 +626,7 @@ MALLOC_DECLARE(M_80211_VAP);
+ #define IEEE80211_FEXT_DROPUNENC_EAPOL        0x00000800      /* CONF: drop unencrypted eapol frames */
+ #define IEEE80211_FEXT_APPIE_UPDATE   0x00001000      /* STATE: beacon APP IE updated */
+ #define IEEE80211_FEXT_BGSCAN_THR     0x00002000      /* bgscan due to low rssi */
++#define IEEE80211_FEXT_WDSSEP         0x00004000      /* move wds clients into separate interfaces */
+ #define IEEE80211_COM_UAPSD_ENABLE(_ic)               ((_ic)->ic_flags_ext |= IEEE80211_FEXT_UAPSD)
+ #define IEEE80211_COM_UAPSD_DISABLE(_ic)      ((_ic)->ic_flags_ext &= ~IEEE80211_FEXT_UAPSD)
+@@ -703,7 +711,7 @@ MALLOC_DECLARE(M_80211_VAP);
+ int ieee80211_ifattach(struct ieee80211com *);
+ void ieee80211_ifdetach(struct ieee80211com *);
+ int ieee80211_vap_setup(struct ieee80211com *, struct net_device *,
+-      const char *, int, int);
++      const char *, int, int, struct ieee80211vap *);
+ int ieee80211_vap_attach(struct ieee80211vap *, ifm_change_cb_t, ifm_stat_cb_t);
+ void ieee80211_vap_detach(struct ieee80211vap *);
+ void ieee80211_mark_dfs(struct ieee80211com *, struct ieee80211_channel *);
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2190,7 +2190,7 @@ ieee80211_setupxr(struct ieee80211vap *v
+                       ieee80211_scan_flush(ic);       /* NB: could optimize */
+                       if (!(xrvap = ic->ic_vap_create(ic, name, IEEE80211_M_HOSTAP,
+-                              IEEE80211_VAP_XR | IEEE80211_CLONE_BSSID, dev)))
++                              IEEE80211_VAP_XR | IEEE80211_CLONE_BSSID, dev, NULL)))
+                               return;
+                       /* We use iv_xrvap to link to the parent VAP as well */
+@@ -2867,6 +2867,14 @@ ieee80211_ioctl_setparam(struct net_devi
+               else
+                       vap->iv_minrateindex = 0;
+               break;
++      case IEEE80211_PARAM_WDS_SEP:
++              if (vap->iv_opmode != IEEE80211_M_HOSTAP)
++                      retv = -EINVAL;
++              else if (value)
++                      vap->iv_flags_ext |= IEEE80211_FEXT_WDSSEP;
++              else
++                      vap->iv_flags_ext &= ~IEEE80211_FEXT_WDSSEP;
++              break;
+ #ifdef ATH_REVERSE_ENGINEERING
+       case IEEE80211_PARAM_DUMPREGS:
+               ieee80211_dump_registers(dev, info, w, extra);
+@@ -3223,6 +3231,9 @@ ieee80211_ioctl_getparam(struct net_devi
+       case IEEE80211_PARAM_MINRATE:
+               param[0] = vap->iv_minrateindex;
+               break;
++      case IEEE80211_PARAM_WDS_SEP:
++              param[0] = !!(vap->iv_flags_ext & IEEE80211_FEXT_WDSSEP);
++              break;
+       default:
+               return -EOPNOTSUPP;
+       }
+@@ -3801,74 +3812,54 @@ ieee80211_ioctl_setmlme(struct net_devic
+       return 0;
+ }
++#define WDSNAME ".wds%d"
+ static int
+-ieee80211_ioctl_wdsmac(struct net_device *dev, struct iw_request_info *info,
++ieee80211_ioctl_wdsaddmac(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+       struct ieee80211vap *vap = dev->priv;
+       struct sockaddr *sa = (struct sockaddr *)extra;
++      struct ieee80211com *ic = vap->iv_ic;
++      struct ieee80211vap *avp;
++      char *name;
+-      if (!IEEE80211_ADDR_NULL(vap->wds_mac)) {
+-              printk("%s: Failed to add WDS MAC: " MAC_FMT "\n", dev->name,
+-                      MAC_ADDR(sa->sa_data));
+-              printk("%s: Device already has WDS mac address attached,"
+-                      " remove first\n", dev->name);
+-              return -1;
+-      }
+-
+-      memcpy(vap->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN);
++      if (vap->iv_opmode != IEEE80211_M_HOSTAP)
++              return -EINVAL;
+-      printk("%s: Added WDS MAC: " MAC_FMT "\n", dev->name,
+-              MAC_ADDR(vap->wds_mac));
++      name = kmalloc(strlen(vap->iv_dev->name) + sizeof(WDSNAME) + 1, GFP_KERNEL);
++      if (!name)
++              return -ENOMEM;
+-      if (IS_UP(vap->iv_dev)) {
+-              /* Force us back to scan state to force us to go back through RUN
+-               * state and create/pin the WDS peer node into memory. */
+-              return ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
+-      }
++      strcpy(name, vap->iv_dev->name);
++      strcat(name, WDSNAME);
++      avp = ieee80211_create_vap(ic, name, ic->ic_dev, IEEE80211_M_WDS, 0, vap);
++      kfree(name);
++      if (!avp)
++              return -ENOMEM;
++      memcpy(avp->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN);
+       return 0;
+ }
++#undef WDSNAME
+ static int
+-ieee80211_ioctl_wdsdelmac(struct net_device *dev, struct iw_request_info *info,
++ieee80211_ioctl_wdssetmac(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+       struct ieee80211vap *vap = dev->priv;
+       struct sockaddr *sa = (struct sockaddr *)extra;
+-      struct ieee80211com *ic = vap->iv_ic;
+-      struct ieee80211_node *wds_ni;
+-      /* WDS Mac address filed already? */
+-      if (IEEE80211_ADDR_NULL(vap->wds_mac))
+-              return 0;
++      if (vap->iv_opmode != IEEE80211_M_WDS)
++              return -EINVAL;
+-      /* Compare suplied MAC address with WDS MAC of this interface 
+-       * remove when mac address is known
+-       */
+-      if (memcmp(vap->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN) == 0) {
+-              if (IS_UP(vap->iv_dev)) {
+-                      wds_ni = ieee80211_find_txnode(vap, vap->wds_mac);
+-                      if (wds_ni != NULL) {
+-                              /* Release reference created by find node */
+-                              ieee80211_unref_node(&wds_ni);
+-                              /* Release reference created by transition to RUN state,
+-                               * [pinning peer node into the table] */
+-                              ieee80211_unref_node(&wds_ni);
+-                      }
+-              }
+-              memset(vap->wds_mac, 0x00, IEEE80211_ADDR_LEN);
+-              if (IS_UP(vap->iv_dev)) {
+-                      /* This leaves a dead WDS node, until started again */
+-                      return ic->ic_reset(ic->ic_dev);
+-              }
+-              return 0;
++      memcpy(vap->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN);
++      if (IS_UP(vap->iv_dev)) {
++              /* Force us back to scan state to force us to go back through RUN
++               * state and create/pin the WDS peer node into memory. */
++              return ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
+       }
+-      printk("%s: WDS MAC address " MAC_FMT " is not known by this interface\n",
+-              dev->name, MAC_ADDR(sa->sa_data));
+-
+-      return -1;
++      return 0;
+ }
+ /*
+@@ -4470,6 +4461,8 @@ get_sta_space(void *arg, struct ieee8021
+       struct ieee80211vap *vap = ni->ni_vap;
+       size_t ielen;
++      if (req->vap->iv_wdsnode && ni->ni_subif)
++              vap = ni->ni_subif;
+       if (vap != req->vap && vap != req->vap->iv_xrvap)       /* only entries for this vap */
+               return;
+       if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
+@@ -4489,6 +4482,8 @@ get_sta_info(void *arg, struct ieee80211
+       size_t ielen, len;
+       u_int8_t *cp;
++      if (req->vap->iv_wdsnode && ni->ni_subif)
++              vap = ni->ni_subif;
+       if (vap != req->vap && vap != req->vap->iv_xrvap)       /* only entries for this vap (or) xrvap */
+               return;
+       if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
+@@ -5391,8 +5386,8 @@ static const struct iw_priv_args ieee802
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac"},
+       { IEEE80211_IOCTL_WDSADDMAC,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,"wds_add" },
+-      { IEEE80211_IOCTL_WDSDELMAC,
+-        IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,"wds_del" },
++      { IEEE80211_IOCTL_WDSSETMAC,
++        IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,"wds_set" },
+       { IEEE80211_IOCTL_SETCHANLIST,
+         IW_PRIV_TYPE_CHANLIST | IW_PRIV_SIZE_FIXED, 0,"setchanlist" },
+       { IEEE80211_IOCTL_GETCHANLIST,
+@@ -5790,6 +5785,10 @@ static const struct iw_priv_args ieee802
+        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"},
+       { IEEE80211_IOCTL_SETSCANLIST,
+        IW_PRIV_TYPE_CHAR | 255, 0, "setscanlist"},
++      { IEEE80211_PARAM_WDS_SEP,
++       IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wdssep"},
++      { IEEE80211_PARAM_WDS_SEP,
++       0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_wdssep"},
+ #ifdef ATH_REVERSE_ENGINEERING
+       /*
+@@ -5884,8 +5883,8 @@ static const iw_handler ieee80211_priv_h
+ #endif
+       set_priv(IEEE80211_IOCTL_ADDMAC, ieee80211_ioctl_addmac),
+       set_priv(IEEE80211_IOCTL_DELMAC, ieee80211_ioctl_delmac),
+-      set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac),
+-      set_priv(IEEE80211_IOCTL_WDSDELMAC, ieee80211_ioctl_wdsdelmac),
++      set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsaddmac),
++      set_priv(IEEE80211_IOCTL_WDSSETMAC, ieee80211_ioctl_wdssetmac),
+       set_priv(IEEE80211_IOCTL_KICKMAC, ieee80211_ioctl_kickmac),
+       set_priv(IEEE80211_IOCTL_SETSCANLIST, ieee80211_ioctl_setscanlist),
+ #ifdef ATH_REVERSE_ENGINEERING
+@@ -5913,6 +5912,8 @@ static int
+ ieee80211_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+       struct ieee80211vap *vap = dev->priv;
++      struct ieee80211com *ic = vap->iv_ic;
++      struct ieee80211_node *ni;
+       switch (cmd) {
+       case SIOCG80211STATS:
+@@ -5921,8 +5922,20 @@ ieee80211_ioctl(struct net_device *dev,
+       case SIOC80211IFDESTROY:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
++              /* drop all node subifs */
++              TAILQ_FOREACH(ni, &ic->ic_sta.nt_node, ni_list) {
++                      struct ieee80211vap *avp = ni->ni_subif;
++
++                      if (ni->ni_vap != vap)
++                              continue;
++                      if (!avp)
++                              continue;
++                      ni->ni_subif = NULL;
++                      ieee80211_stop(avp->iv_dev);
++                      ic->ic_vap_delete(avp);
++              }
+               ieee80211_stop(vap->iv_dev);    /* force state before cleanup */
+-              vap->iv_ic->ic_vap_delete(vap);
++              ic->ic_vap_delete(vap);
+               return 0;
+       case IEEE80211_IOCTL_GETKEY:
+               return ieee80211_ioctl_getkey(dev, (struct iwreq *) ifr);
+@@ -5956,7 +5969,7 @@ ieee80211_ioctl_create_vap(struct ieee80
+       strncpy(name, cp.icp_name, sizeof(name));
+-      vap = ieee80211_create_vap(ic, name, mdev, cp.icp_opmode, cp.icp_flags);
++      vap = ieee80211_create_vap(ic, name, mdev, cp.icp_opmode, cp.icp_flags, NULL);
+       if (vap == NULL)
+               return -EIO;
+@@ -5973,9 +5986,9 @@ EXPORT_SYMBOL(ieee80211_ioctl_create_vap
+  */
+ struct ieee80211vap*
+ ieee80211_create_vap(struct ieee80211com *ic, char *name,
+-      struct net_device *mdev, int opmode, int opflags)
++      struct net_device *mdev, int opmode, int opflags, struct ieee80211vap *master)
+ {
+-      return ic->ic_vap_create(ic, name, opmode, opflags, mdev);
++      return ic->ic_vap_create(ic, name, opmode, opflags, mdev, master);
+ }
+ EXPORT_SYMBOL(ieee80211_create_vap);
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -199,8 +199,10 @@ ieee80211_input(struct ieee80211vap * va
+ {
+ #define       HAS_SEQ(type)   ((type & 0x4) == 0)
+       struct ieee80211_node * ni = ni_or_null;
+-      struct ieee80211com *ic = vap->iv_ic;
+-      struct net_device *dev = vap->iv_dev;
++      struct ieee80211com *ic;
++      struct net_device *dev;
++      struct ieee80211_node *ni_wds = NULL;
++      struct net_device_stats *stats;
+       struct ieee80211_frame *wh;
+       struct ieee80211_key *key;
+       struct ether_header *eh;
+@@ -212,6 +214,19 @@ ieee80211_input(struct ieee80211vap * va
+       u_int8_t *bssid;
+       u_int16_t rxseq;
++      type = -1;                      /* undefined */
++
++      if (!vap)
++              goto out;
++
++      ic = vap->iv_ic;
++      if (!ic)
++              goto out;
++
++      dev = vap->iv_dev;
++      if (!dev)
++              goto out;
++
+       /* initialize ni as in the previous API */
+       if (ni_or_null == NULL) {
+                /* This function does not 'own' vap->iv_bss, so we cannot
+@@ -227,7 +242,6 @@ ieee80211_input(struct ieee80211vap * va
+       /* XXX adjust device in sk_buff? */
+-      type = -1;                      /* undefined */
+       /*
+        * In monitor mode, send everything directly to bpf.
+        * Also do not process frames w/o i_addr2 any further.
+@@ -434,7 +448,7 @@ ieee80211_input(struct ieee80211vap * va
+       switch (type) {
+       case IEEE80211_FC0_TYPE_DATA:
+-              hdrspace = ieee80211_hdrspace(ic, wh);
++              hdrspace = ieee80211_hdrsize(wh);
+               if (skb->len < hdrspace) {
+                       IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
+                               wh, "data", "too short: len %u, expecting %u",
+@@ -444,16 +458,24 @@ ieee80211_input(struct ieee80211vap * va
+               }
+               switch (vap->iv_opmode) {
+               case IEEE80211_M_STA:
+-                      if ((dir != IEEE80211_FC1_DIR_FROMDS) &&
+-                          (!((vap->iv_flags_ext & IEEE80211_FEXT_WDS) &&
+-                          (dir == IEEE80211_FC1_DIR_DSTODS)))) {
++                      switch(dir) {
++                      case IEEE80211_FC1_DIR_FROMDS:
++                              break;
++                      case IEEE80211_FC1_DIR_DSTODS:
++                              if (vap->iv_flags_ext & IEEE80211_FEXT_WDS)
++                                      break;
++                      default:
+                               IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
+                                       wh, "data", "invalid dir 0x%x", dir);
+                               vap->iv_stats.is_rx_wrongdir++;
+                               goto out;
+                       }
+-                      if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
++                      if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
++                              /* ignore 3-addr mcast if we're WDS STA */
++                              if (vap->iv_flags_ext & IEEE80211_FEXT_WDS)
++                                      goto out;
++
+                               /* Discard multicast if IFF_MULTICAST not set */
+                               if ((0 != memcmp(wh->i_addr3, dev->broadcast, ETH_ALEN)) && 
+                                       (0 == (dev->flags & IFF_MULTICAST))) {
+@@ -481,24 +503,10 @@ ieee80211_input(struct ieee80211vap * va
+                                       vap->iv_stats.is_rx_mcastecho++;
+                                       goto out;
+                               }
+-                              /* 
+-                               * if it is brodcasted by me on behalf of
+-                               * a station behind me, drop it.
+-                               */
+-                              if (vap->iv_flags_ext & IEEE80211_FEXT_WDS) {
+-                                      struct ieee80211_node_table *nt;
+-                                      struct ieee80211_node *ni_wds;
+-                                      nt = &ic->ic_sta;
+-                                      ni_wds = ieee80211_find_wds_node(nt, wh->i_addr3);
+-                                      if (ni_wds) {
+-                                              ieee80211_unref_node(&ni_wds);
+-                                              IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
+-                                                      wh, NULL, "%s",
+-                                                      "multicast echo originated from node behind me");
+-                                              vap->iv_stats.is_rx_mcastecho++;
+-                                              goto out;
+-                                      }
+-                              }
++                      } else {
++                              /* Same BSSID, but not meant for us to receive */
++                              if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr))
++                                      goto out;
+                       }
+                       break;
+               case IEEE80211_M_IBSS:
+@@ -540,16 +548,28 @@ ieee80211_input(struct ieee80211vap * va
+                               vap->iv_stats.is_rx_notassoc++;
+                               goto err;
+                       }
++
+                       /*
+                        * If we're a 4 address packet, make sure we have an entry in
+                        * the node table for the packet source address (addr4).
+                        * If not, add one.
+                        */
++                      /* check for wds link first */
++                      if ((dir == IEEE80211_FC1_DIR_DSTODS) && !ni->ni_subif) {
++                              if (vap->iv_flags_ext & IEEE80211_FEXT_WDSSEP) {
++                                      ieee80211_wds_addif(ni);
++                                      /* we must drop frames here until the interface has
++                                       * been fully separated, otherwise a bridge might get
++                                       * confused */
++                                      goto err;
++                              }
++                      }
++
+                       /* XXX: Useless node mgmt API; make better */
+-                      if (dir == IEEE80211_FC1_DIR_DSTODS) {
+-                              struct ieee80211_node_table *nt;
++                      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;
+-                              struct ieee80211_node *ni_wds;
+                               if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS)) {
+                                       IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
+@@ -557,7 +577,6 @@ ieee80211_input(struct ieee80211vap * va
+                                       goto err;
+                               }
+                               wh4 = (struct ieee80211_frame_addr4 *)skb->data;
+-                              nt = &ic->ic_sta;
+                               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 +627,11 @@ ieee80211_input(struct ieee80211vap * va
+                       goto out;
+               }
++              /* check if there is any data left */
++              hdrspace = ieee80211_hdrspace(ic, wh);
++              if (skb->len < hdrspace)
++                      goto out;
++
+               /*
+                * Handle privacy requirements.  Note that we
+                * must not be preempted from here until after
+@@ -680,8 +704,12 @@ ieee80211_input(struct ieee80211vap * va
+               if (! accept_data_frame(vap, ni, key, skb, eh))
+                       goto out;
+-              vap->iv_devstats.rx_packets++;
+-              vap->iv_devstats.rx_bytes += skb->len;
++              if (ni->ni_subif && ((eh)->ether_type != __constant_htons(ETHERTYPE_PAE)))
++                      stats = &ni->ni_subif->iv_devstats;
++              else
++                      stats = &vap->iv_devstats;
++              stats->rx_packets++;
++              stats->rx_bytes += skb->len;
+               IEEE80211_NODE_STAT(ni, rx_data);
+               IEEE80211_NODE_STAT_ADD(ni, rx_bytes, skb->len);
+               ic->ic_lastdata = jiffies;
+@@ -1114,6 +1142,18 @@ 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))) {
++              if (ni->ni_vap == ni->ni_subif) {
++                      ieee80211_dev_kfree_skb(&skb);
++                      return;
++              } else {
++                      vap = ni->ni_subif;
++                      dev = vap->iv_dev;
++              }
++      }
++
+       /* perform as a bridge within the vap */
+       /* XXX intra-vap bridging only */
+       if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
+@@ -1139,7 +1179,16 @@ ieee80211_deliver_data(struct ieee80211_
+                       if (ni1 != NULL) {
+                               if (ni1->ni_vap == vap &&
+                                   ieee80211_node_is_authorized(ni1) &&
++                                      !ni1->ni_subif &&
+                                   ni1 != vap->iv_bss) {
++
++                                      /* tried to bridge to a subif, drop the packet */
++                                      if (ni->ni_subif) {
++                                              ieee80211_unref_node(&ni1);
++                                              ieee80211_dev_kfree_skb(&skb);
++                                              return;
++                                      }
++
+                                       skb1 = skb;
+                                       skb = NULL;
+                               }
+@@ -3084,8 +3133,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                   (vap->iv_opmode == IEEE80211_M_STA && ni->ni_associd) ||
+                   (vap->iv_opmode == IEEE80211_M_IBSS) ||
+                       ((subtype == IEEE80211_FC0_SUBTYPE_BEACON) &&
+-                       (vap->iv_opmode == IEEE80211_M_HOSTAP) &&
+-                       (ic->ic_protmode != IEEE80211_PROT_NONE)))) {
++                       (vap->iv_opmode == IEEE80211_M_HOSTAP)))) {
+                       vap->iv_stats.is_rx_mgtdiscard++;
+                       return;
+               }
+@@ -3471,13 +3519,56 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                */
+               if (ic->ic_flags & IEEE80211_F_SCAN) {
+                       ieee80211_add_scan(vap, &scan, wh, subtype, rssi, rtsf);
+-                      return;
+               }
+-              if ((vap->iv_opmode == IEEE80211_M_IBSS) && 
+-                              (scan.capinfo & IEEE80211_CAPINFO_IBSS)) {
++              /* NB: Behavior of WDS-Link and Ad-Hoc is very similar here:
++               * When we receive a beacon that belongs to the AP that we're
++               * connected to, use it to refresh the local node info.
++               * If no node is found, go through the vap's wds link table
++               * and try to find the sub-vap that is interested in this address
++               */
++              if (((vap->iv_opmode == IEEE80211_M_IBSS) &&
++                              (scan.capinfo & IEEE80211_CAPINFO_IBSS)) ||
++                              (((vap->iv_opmode == IEEE80211_M_HOSTAP) ||
++                               (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) {
++                              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)
++                                                      continue;
++                                              if (!avp->iv_wdsnode)
++                                                      continue;
++                                              found = 1;
++                                              break;
++                                      }
++                              }
++                              if (found)
++                                      ni = ni_or_null = avp->iv_wdsnode;
++                      } else if ((vap->iv_opmode == IEEE80211_M_WDS) && vap->iv_wdsnode) {
++                              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. */
+-                              ni = ieee80211_add_neighbor(vap, wh, &scan);
++                              if (avp) {
++                                      IEEE80211_LOCK_IRQ(ic);
++                                      ni = ieee80211_add_neighbor(avp, wh, &scan);
++                                      /* force assoc */
++                                      ni->ni_associd |= 0xc000;
++                                      avp->iv_wdsnode = ieee80211_ref_node(ni);
++                                      IEEE80211_UNLOCK_IRQ(ic);
++                              } else if (vap->iv_opmode == IEEE80211_M_IBSS) {
++                                      /* Create a new entry in the neighbor table. */
++                                      ni = ieee80211_add_neighbor(vap, wh, &scan);
++                              }
+                       } else {
+                               /*
+                                * Copy data from beacon to neighbor table.
+@@ -3490,6 +3581,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                               IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
+                               memcpy(ni->ni_tstamp.data, scan.tstamp,
+                                       sizeof(ni->ni_tstamp));
++                              ni->ni_inact = ni->ni_inact_reload;
+                               ni->ni_intval = 
+                                       IEEE80211_BINTVAL_SANITISE(scan.bintval);
+                               ni->ni_capinfo = scan.capinfo;
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -47,6 +47,7 @@
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/random.h>
++#include <linux/rtnetlink.h>
+ #include "if_media.h"
+@@ -236,7 +237,11 @@ void
+ ieee80211_node_vdetach(struct ieee80211vap *vap)
+ {
+       struct ieee80211com *ic = vap->iv_ic;
++      struct ieee80211_node *ni;
++      ni = vap->iv_wdsnode;
++      if (ni)
++              ni->ni_subif = NULL;
+       ieee80211_node_table_reset(&ic->ic_sta, vap);
+       if (vap->iv_bss != NULL) {
+               ieee80211_unref_node(&vap->iv_bss);
+@@ -309,7 +314,7 @@ ieee80211_create_ibss(struct ieee80211va
+       /* Check to see if we already have a node for this mac
+        * NB: we gain a node reference here
+        */
+-      ni = ieee80211_find_node(&ic->ic_sta, vap->iv_myaddr);
++      ni = ieee80211_find_txnode(vap, vap->iv_myaddr);
+       if (ni == NULL) {
+               ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr);
+               IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
+@@ -831,12 +836,18 @@ node_table_leave_locked(struct ieee80211
+               LIST_REMOVE(ni, ni_hash);
+       }
+       ni->ni_table = NULL;
++      if (ni->ni_vap->iv_wdsnode == ni) {
++#ifdef IEEE80211_DEBUG_REFCNT
++              ieee80211_unref_node_debug(&ni->ni_vap->iv_wdsnode, func, line);
++#else
++              ieee80211_unref_node(&ni->ni_vap->iv_wdsnode);
++#endif
++      }
+ #ifdef IEEE80211_DEBUG_REFCNT
+       ieee80211_unref_node_debug(&ni, func, line);
+ #else
+       ieee80211_unref_node(&ni);
+ #endif
+-      
+ }
+ /* This is overridden by ath_node_alloc in ath/if_ath.c, and so
+@@ -1134,6 +1145,65 @@ ieee80211_alloc_node(struct ieee80211vap
+       return ni;
+ }
++#define WDSIFNAME ".sta%d"
++static void
++ieee80211_wds_do_addif(struct work_struct *work)
++{
++      struct ieee80211_node *ni = container_of(work, struct ieee80211_node, ni_create);
++      struct ieee80211vap *vap = ni->ni_vap;
++      struct ieee80211com *ic = vap->iv_ic;
++      struct ieee80211vap *avp = NULL;
++      char *name;
++
++      rtnl_lock();
++      /* did we get cancelled by the destroy call? */
++      if (!ni->ni_subif)
++              goto done;
++
++      ni->ni_subif = NULL;
++      name = kmalloc(strlen(vap->iv_dev->name) + sizeof(WDSIFNAME) + 1, GFP_KERNEL);
++      if (!name)
++              goto done;
++
++      strcpy(name, vap->iv_dev->name);
++      strcat(name, WDSIFNAME);
++      avp = ieee80211_create_vap(ic, name, ic->ic_dev, IEEE80211_M_WDS, 0, vap);
++      kfree(name);
++      if (!avp)
++              goto done;
++
++      memcpy(avp->wds_mac, ni->ni_bssid, IEEE80211_ADDR_LEN);
++      avp->iv_wdsnode = ieee80211_ref_node(ni);
++      ni->ni_subif = avp;
++      ic->ic_subifs++;
++
++done:
++      if (avp) {
++              IEEE80211_VAPS_LOCK_IRQ(ic);
++              avp->iv_newstate(vap, IEEE80211_S_RUN, -1);
++              IEEE80211_VAPS_UNLOCK_IRQ(ic);
++      }
++      rtnl_unlock();
++      ieee80211_unref_node(&ni);
++}
++#undef WDSIFNAME
++
++void ieee80211_wds_addif(struct ieee80211_node *ni)
++{
++      /* check if the node is split out already,
++       * or if we're in progress of setting up a new interface already */
++      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);
++      schedule_work(&ni->ni_create);
++}
++
+ /* Add wds address to the node table */
+ int
+ #ifdef IEEE80211_DEBUG_REFCNT
+@@ -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;
++      struct ieee80211vap *vap, *avp;
++      const u_int8_t *addr;
++
++      if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/)
++              addr = wh->i_addr1;
++      else
++              addr = wh->i_addr2;
++
++      if (IEEE80211_IS_MULTICAST(addr))
++              return NULL;
+       /* XXX check ic_bss first in station mode */
+       /* XXX 4-address frames? */
+       nt = &ic->ic_sta;
+       IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-      if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/)
+-#ifdef IEEE80211_DEBUG_REFCNT
+-              ni = ieee80211_find_node_locked_debug(nt, wh->i_addr1, func, line);
+-#else
+-              ni = ieee80211_find_node_locked(nt, wh->i_addr1);
+-#endif
+-      else
++      if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) {
++              TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++                      TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
++                              if (!IEEE80211_ADDR_EQ(addr, avp->wds_mac))
++                                      continue;
++
++                              if (avp->iv_wdsnode)
++                                      return ieee80211_ref_node(avp->iv_wdsnode);
++                              else
++                                      return NULL;
++                      }
++              }
++      }
++
+ #ifdef IEEE80211_DEBUG_REFCNT
+-              ni = ieee80211_find_node_locked_debug(nt, wh->i_addr2, func, line);
++      ni = ieee80211_find_node_locked_debug(nt, addr, func, line);
+ #else
+-              ni = ieee80211_find_node_locked(nt, wh->i_addr2);
++      ni = ieee80211_find_node_locked(nt, addr);
+ #endif
+       IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+@@ -1596,9 +1683,19 @@ ieee80211_find_txnode_debug(struct ieee8
+ ieee80211_find_txnode(struct ieee80211vap *vap, const u_int8_t *mac)
+ #endif
+ {
++      struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_node_table *nt;
+       struct ieee80211_node *ni = NULL;
++      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
+        * unless we are operating in station mode or this is a
+@@ -1669,6 +1766,11 @@ ieee80211_free_node(struct ieee80211_nod
+ {
+       struct ieee80211vap *vap = ni->ni_vap;
++      IEEE80211_LOCK_IRQ(ni->ni_ic);
++      if (vap && ni == vap->iv_wdsnode)
++              vap->iv_wdsnode = NULL;
++      IEEE80211_UNLOCK_IRQ(ni->ni_ic);
++
+       atomic_dec(&ni->ni_ic->ic_node_counter);
+       node_print_message(IEEE80211_MSG_NODE|IEEE80211_MSG_NODE_REF,
+                          1 /* show counter */, 
+@@ -1781,22 +1883,6 @@ restart:
+                   jiffies > ni->ni_rxfragstamp + HZ) {
+                       ieee80211_dev_kfree_skb(&ni->ni_rxfrag);
+               }
+-              /*
+-               * Special case ourself; we may be idle for extended periods
+-               * of time and regardless reclaiming our state is wrong.
+-               * Special case a WDS link: it may be dead or idle, but it is 
+-               * never ok to reclaim it, as this will block transmissions
+-               * and nobody will recreate the node when the WDS peer is
+-               * available again. */
+-              if ((ni == ni->ni_vap->iv_bss) ||
+-                  (ni->ni_vap->iv_opmode == IEEE80211_M_WDS && 
+-                   !memcmp(ni->ni_macaddr, ni->ni_vap->wds_mac, ETH_ALEN)))
+-              {
+-                      /* NB: don't permit it to go negative */
+-                      if (ni->ni_inact > 0)
+-                              ni->ni_inact--;
+-                      continue;
+-              }
+               ni->ni_inact--;
+               if (ni->ni_associd != 0 || isadhoc) {
+                       struct ieee80211vap *vap = ni->ni_vap;
+@@ -2263,6 +2349,35 @@ ieee80211_node_leave_11g(struct ieee8021
+       }
+ }
++static void
++ieee80211_subif_destroy(struct work_struct *work)
++{
++      struct ieee80211_node *ni = container_of(work, struct ieee80211_node, ni_destroy);
++      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 (!vap)
++              goto done;
++
++      ic = vap->iv_ic;
++      ni->ni_subif = NULL;
++      ieee80211_stop(vap->iv_dev);
++      ic->ic_vap_delete(vap);
++      ic->ic_subifs--;
++
++done:
++      ieee80211_unref_node(&ni);
++      rtnl_unlock();
++}
++
+ /*
+  * Handle bookkeeping for a station/neighbor leaving
+  * the bss when operating in ap or adhoc modes.
+@@ -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));
++      if (ni->ni_subif) {
++              ieee80211_ref_node(ni);
++              IEEE80211_INIT_WORK(&ni->ni_destroy, ieee80211_subif_destroy);
++              schedule_work(&ni->ni_destroy);
++      }
++
+       /* From this point onwards we can no longer find the node,
+        * so no more references are generated
+        */
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -246,15 +246,16 @@ ieee80211_hardstart(struct sk_buff *skb,
+        * things like power save.
+        */
+       eh = (struct ether_header *)skb->data;
+-      if (vap->iv_opmode == IEEE80211_M_WDS)
+-              ni = ieee80211_find_txnode(vap, vap->wds_mac);
+-      else
+-              ni = ieee80211_find_txnode(vap, eh->ether_dhost);
++      ni = ieee80211_find_txnode(vap, eh->ether_dhost);
+       if (ni == NULL) {
+               /* NB: ieee80211_find_txnode does stat+msg */
+               goto bad;
+       }
++      if (ni->ni_subif && (vap != ni->ni_subif) &&
++              ((eh)->ether_type != __constant_htons(ETHERTYPE_PAE)))
++              goto bad;
++
+       /* calculate priority so drivers can find the TX queue */
+       if (ieee80211_classify(ni, skb)) {
+               IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
+@@ -334,20 +335,33 @@ void ieee80211_parent_queue_xmit(struct
+  * constructing a frame as it sets i_fc[1]; other bits can
+  * then be or'd in.
+  */
+-static void
++static struct ieee80211_frame *
+ ieee80211_send_setup(struct ieee80211vap *vap,
+       struct ieee80211_node *ni,
+-      struct ieee80211_frame *wh,
++      struct sk_buff *skb,
+       int type,
+       const u_int8_t sa[IEEE80211_ADDR_LEN],
+       const u_int8_t da[IEEE80211_ADDR_LEN],
+       const u_int8_t bssid[IEEE80211_ADDR_LEN])
+ {
+ #define       WH4(wh) ((struct ieee80211_frame_addr4 *)wh)
++      struct ieee80211_frame *wh;
++      int len = sizeof(struct ieee80211_frame);
++      int opmode = vap->iv_opmode;
++
++      if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
++              if ((opmode == IEEE80211_M_STA) &&
++                      (vap->iv_flags_ext & IEEE80211_FEXT_WDS))
++                      opmode = IEEE80211_M_WDS;
++              if (opmode == IEEE80211_M_WDS)
++                      len = sizeof(struct ieee80211_frame_addr4);
++      }
++
++      wh = (struct ieee80211_frame *)skb_push(skb, len);
+       wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
+       if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
+-              switch (vap->iv_opmode) {
++              switch (opmode) {
+               case IEEE80211_M_STA:
+                       wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
+                       IEEE80211_ADDR_COPY(wh->i_addr1, bssid);
+@@ -389,6 +403,8 @@ ieee80211_send_setup(struct ieee80211vap
+       *(__le16 *)&wh->i_seq[0] =
+           htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
+       ni->ni_txseqs[0]++;
++
++      return wh;
+ #undef WH4
+ }
+@@ -410,9 +426,7 @@ ieee80211_mgmt_output(struct ieee80211_n
+       SKB_CB(skb)->ni = ni;
+-      wh = (struct ieee80211_frame *)
+-              skb_push(skb, sizeof(struct ieee80211_frame));
+-      ieee80211_send_setup(vap, ni, wh,
++      wh = ieee80211_send_setup(vap, ni, skb,
+               IEEE80211_FC0_TYPE_MGT | type,
+               vap->iv_myaddr, ni->ni_macaddr, vap->iv_bssid);
+       /* XXX power management */
+@@ -458,6 +472,9 @@ ieee80211_send_nulldata(struct ieee80211
+       struct ieee80211_frame *wh;
+       u_int8_t *frm;
++      if (ni->ni_subif)
++              vap = ni->ni_subif;
++
+       skb = ieee80211_getmgtframe(&frm, 0);
+       if (skb == NULL) {
+               /* XXX debug msg */
+@@ -466,9 +483,7 @@ ieee80211_send_nulldata(struct ieee80211
+               return -ENOMEM;
+       }
+-      wh = (struct ieee80211_frame *)
+-              skb_push(skb, sizeof(struct ieee80211_frame));
+-      ieee80211_send_setup(vap, ni, wh,
++      wh = ieee80211_send_setup(vap, ni, skb,
+               IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
+               vap->iv_myaddr, ni->ni_macaddr, vap->iv_bssid);
+       /* NB: power management bit is never sent by an AP */
+@@ -506,6 +521,7 @@ ieee80211_send_qosnulldata(struct ieee80
+       struct sk_buff *skb;
+       struct ieee80211_qosframe *qwh;
+       u_int8_t *frm;
++      u_int8_t *i_qos;
+       int tid;
+       skb = ieee80211_getmgtframe(&frm, 2);
+@@ -517,11 +533,12 @@ ieee80211_send_qosnulldata(struct ieee80
+       SKB_CB(skb)->ni = ieee80211_ref_node(ni);
+       skb->priority = ac;
+-      qwh = (struct ieee80211_qosframe *)skb_push(skb, sizeof(struct ieee80211_qosframe));
+-      qwh = (struct ieee80211_qosframe *)skb->data;
++      /* grab a pointer to QoS control and also compensate for the header length
++       * difference between QoS and non-QoS frame */
++      i_qos = skb_push(skb, sizeof(struct ieee80211_qosframe) - sizeof(struct ieee80211_frame));
+-      ieee80211_send_setup(vap, ni, (struct ieee80211_frame *)qwh,
++      qwh = (struct ieee80211_qosframe *) ieee80211_send_setup(vap, ni, skb,
+               IEEE80211_FC0_TYPE_DATA,
+               vap->iv_myaddr, /* SA */
+               ni->ni_macaddr, /* DA */
+@@ -535,10 +552,10 @@ ieee80211_send_qosnulldata(struct ieee80
+       /* map from access class/queue to 11e header priority value */
+       tid = WME_AC_TO_TID(ac);
+-      qwh->i_qos[0] = tid & IEEE80211_QOS_TID;
++      i_qos[0] = tid & IEEE80211_QOS_TID;
+       if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy)
+               qwh->i_qos[0] |= (1 << IEEE80211_QOS_ACKPOLICY_S) & IEEE80211_QOS_ACKPOLICY;
+-      qwh->i_qos[1] = 0;
++      i_qos[1] = 0;
+       IEEE80211_NODE_STAT(ni, tx_data);
+@@ -780,6 +797,8 @@ ieee80211_encap(struct ieee80211_node *n
+               hdrsize = sizeof(struct ieee80211_frame);
+       SKB_CB(skb)->auth_pkt = (eh.ether_type == __constant_htons(ETHERTYPE_PAE));
++      if (ni->ni_subif)
++              vap = ni->ni_subif;
+       switch (vap->iv_opmode) {
+       case IEEE80211_M_IBSS:
+@@ -788,7 +807,7 @@ ieee80211_encap(struct ieee80211_node *n
+               break;
+       case IEEE80211_M_WDS:
+               use4addr = 1;
+-              ismulticast = IEEE80211_IS_MULTICAST(ni->ni_macaddr);
++              ismulticast = 0;
+               break;
+       case IEEE80211_M_HOSTAP:
+               if (!IEEE80211_IS_MULTICAST(eh.ether_dhost) &&
+@@ -799,20 +818,9 @@ ieee80211_encap(struct ieee80211_node *n
+                       ismulticast = IEEE80211_IS_MULTICAST(eh.ether_dhost);
+               break;
+       case IEEE80211_M_STA:
+-              if ((vap->iv_flags_ext & IEEE80211_FEXT_WDS) &&
+-                  !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
++              if (vap->iv_flags_ext & IEEE80211_FEXT_WDS) {
+                       use4addr = 1;
+-                      ismulticast = IEEE80211_IS_MULTICAST(ni->ni_macaddr);
+-                      /* Add a WDS entry to the station VAP */
+-                      if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
+-                              struct ieee80211_node_table *nt = &ic->ic_sta;
+-                              struct ieee80211_node *ni_wds 
+-                                      = ieee80211_find_wds_node(nt, eh.ether_shost);
+-                              if (ni_wds)
+-                                      ieee80211_unref_node(&ni_wds);
+-                              else
+-                                      ieee80211_add_wds_addr(nt, ni, eh.ether_shost, 0);
+-                      }
++                      ismulticast = 0;
+               } else
+                       ismulticast = IEEE80211_IS_MULTICAST(vap->iv_bssid);
+               break;
+@@ -973,7 +981,7 @@ ieee80211_encap(struct ieee80211_node *n
+                       break;
+               case IEEE80211_M_WDS:
+                       wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
+-                      IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
++                      IEEE80211_ADDR_COPY(wh->i_addr1, vap->wds_mac);
+                       IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
+                       IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
+                       IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost);
+@@ -1683,9 +1691,7 @@ ieee80211_send_probereq(struct ieee80211
+       SKB_CB(skb)->ni = ieee80211_ref_node(ni);
+-      wh = (struct ieee80211_frame *)
+-              skb_push(skb, sizeof(struct ieee80211_frame));
+-      ieee80211_send_setup(vap, ni, wh,
++      wh = ieee80211_send_setup(vap, ni, skb,
+               IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
+               sa, da, bssid);
+       /* XXX power management? */
+--- a/tools/athkey.c
++++ b/tools/athkey.c
+@@ -118,7 +118,7 @@ set80211priv(const char *dev, int op, vo
+                               IOCTL_ERR(IEEE80211_IOCTL_ADDMAC),
+                               IOCTL_ERR(IEEE80211_IOCTL_DELMAC),
+                               IOCTL_ERR(IEEE80211_IOCTL_WDSADDMAC),
+-                              IOCTL_ERR(IEEE80211_IOCTL_WDSDELMAC),
++                              IOCTL_ERR(IEEE80211_IOCTL_WDSSETMAC),
+                               IOCTL_ERR(IEEE80211_IOCTL_READREG),
+                               IOCTL_ERR(IEEE80211_IOCTL_WRITEREG),
+                       };
+--- a/tools/athchans.c
++++ b/tools/athchans.c
+@@ -118,7 +118,7 @@ set80211priv(const char *dev, int op, vo
+                               IOCTL_ERR(IEEE80211_IOCTL_ADDMAC),
+                               IOCTL_ERR(IEEE80211_IOCTL_DELMAC),
+                               IOCTL_ERR(IEEE80211_IOCTL_WDSADDMAC),
+-                              IOCTL_ERR(IEEE80211_IOCTL_WDSDELMAC),
++                              IOCTL_ERR(IEEE80211_IOCTL_WDSSETMAC),
+                               IOCTL_ERR(IEEE80211_IOCTL_READREG),
+                               IOCTL_ERR(IEEE80211_IOCTL_WRITEREG),
+                       };
+--- a/tools/wlanconfig.c
++++ b/tools/wlanconfig.c
+@@ -968,7 +968,7 @@ do80211priv(struct iwreq *iwr, const cha
+                       IOCTL_ERR(IEEE80211_IOCTL_ADDMAC),
+                       IOCTL_ERR(IEEE80211_IOCTL_DELMAC),
+                       IOCTL_ERR(IEEE80211_IOCTL_WDSADDMAC),
+-                      IOCTL_ERR(IEEE80211_IOCTL_WDSDELMAC),
++                      IOCTL_ERR(IEEE80211_IOCTL_WDSSETMAC),
+                       IOCTL_ERR(IEEE80211_IOCTL_READREG),
+                       IOCTL_ERR(IEEE80211_IOCTL_WRITEREG),
+               };
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -979,6 +979,12 @@ ieee80211_init(struct net_device *dev, i
+               "start running (state=%d)\n", vap->iv_state);
++      if (vap->iv_master && vap->iv_master->iv_state == IEEE80211_S_INIT) {
++              int ret = ieee80211_init(vap->iv_master->iv_dev, forcescan);
++              if (ret < 0)
++                      return ret;
++      }
++
+       if ((dev->flags & IFF_RUNNING) == 0) {
+               if (ic->ic_nopened++ == 0 &&
+                   (parent->flags & IFF_RUNNING) == 0)
+@@ -1081,6 +1087,8 @@ ieee80211_init(struct net_device *dev, i
+ int
+ ieee80211_open(struct net_device *dev)
+ {
++      struct ieee80211vap *vap = dev->priv;
++
+       return ieee80211_init(dev, 0);
+ }
+@@ -1090,7 +1098,7 @@ ieee80211_open(struct net_device *dev)
+ void
+ ieee80211_start_running(struct ieee80211com *ic)
+ {
+-      struct ieee80211vap *vap;
++      struct ieee80211vap *vap, *avp;
+       struct net_device *dev;
+       /* XXX locking */
+@@ -1099,6 +1107,16 @@ ieee80211_start_running(struct ieee80211
+               /* NB: avoid recursion */
+               if ((dev->flags & IFF_UP) && !(dev->flags & IFF_RUNNING))
+                       ieee80211_open(dev);
++
++              TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
++                      if (avp->iv_wdsnode && avp->iv_wdsnode->ni_subif == avp)
++                              continue;
++
++                      dev = avp->iv_dev;
++                      /* NB: avoid recursion */
++                      if ((dev->flags & IFF_UP) && !(dev->flags & IFF_RUNNING))
++                              ieee80211_open(dev);
++              }
+       }
+ }
+ EXPORT_SYMBOL(ieee80211_start_running);
+@@ -1116,11 +1134,43 @@ ieee80211_stop(struct net_device *dev)
+       struct ieee80211vap *vap = dev->priv;
+       struct ieee80211com *ic = vap->iv_ic;
+       struct net_device *parent = ic->ic_dev;
++      struct ieee80211_node *tni, *ni;
++      struct ieee80211vap *avp;
+       IEEE80211_DPRINTF(vap,
+               IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
+               "%s\n", "stop running");
++      if (vap->iv_wdsnode && !vap->iv_wdsnode->ni_subif)
++              ieee80211_unref_node(&vap->iv_wdsnode);
++
++      /* stop wds interfaces */
++      TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_next) {
++              if (avp->iv_state != IEEE80211_S_INIT)
++                      ieee80211_stop(avp->iv_dev);
++      }
++
++      /* get rid of all wds nodes while we're still locked */
++      do {
++              ni = NULL;
++
++              IEEE80211_NODE_TABLE_LOCK_IRQ(&ic->ic_sta);
++              TAILQ_FOREACH(tni, &ic->ic_sta.nt_node, ni_list) {
++                      if (tni->ni_vap != vap)
++                              continue;
++                      if (!tni->ni_subif)
++                              continue;
++                      ni = tni;
++                      break;
++              }
++              IEEE80211_NODE_TABLE_UNLOCK_IRQ(&ic->ic_sta);
++
++              if (!ni)
++                      break;
++
++              ieee80211_node_leave(ni);
++      } while (1);
++
+       ieee80211_new_state(vap, IEEE80211_S_INIT, -1);
+       if (dev->flags & IFF_RUNNING) {
+               dev->flags &= ~IFF_RUNNING;             /* mark us stopped */
+@@ -1148,7 +1198,7 @@ EXPORT_SYMBOL(ieee80211_stop);
+ void
+ ieee80211_stop_running(struct ieee80211com *ic)
+ {
+-      struct ieee80211vap *vap;
++      struct ieee80211vap *vap, *avp;
+       struct net_device *dev;
+       /* XXX locking */
+@@ -1156,6 +1206,12 @@ ieee80211_stop_running(struct ieee80211c
+               dev = vap->iv_dev;
+               if (dev->flags & IFF_RUNNING)   /* NB: avoid recursion */
+                       ieee80211_stop(dev);
++
++              TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
++                      dev = avp->iv_dev;
++                      if (dev->flags & IFF_RUNNING)   /* NB: avoid recursion */
++                              ieee80211_stop(dev);
++              }
+       }
+ }
+ EXPORT_SYMBOL(ieee80211_stop_running);
+@@ -1342,9 +1398,9 @@ ieee80211_new_state(struct ieee80211vap
+       struct ieee80211com *ic = vap->iv_ic;
+       int rc;
+-      IEEE80211_VAPS_LOCK_BH(ic);
++      IEEE80211_VAPS_LOCK_IRQ(ic);
+       rc = vap->iv_newstate(vap, nstate, arg);
+-      IEEE80211_VAPS_UNLOCK_BH(ic);
++      IEEE80211_VAPS_UNLOCK_IRQ(ic);
+       return rc;
+ }
+@@ -1557,57 +1613,12 @@ __ieee80211_newstate(struct ieee80211vap
+               switch (ostate) {
+               case IEEE80211_S_INIT:
+                       if (vap->iv_opmode == IEEE80211_M_MONITOR ||
+-                          vap->iv_opmode == IEEE80211_M_WDS ||
+                           vap->iv_opmode == IEEE80211_M_HOSTAP) {
+                               /*
+                                * Already have a channel; bypass the
+                                * scan and startup immediately.
+                                */
+                               ieee80211_create_ibss(vap, ic->ic_curchan);
+-
+-                              /* In WDS mode, allocate and initialize peer node. */
+-                              if (vap->iv_opmode == IEEE80211_M_WDS) {
+-                                      /* XXX: This is horribly non-atomic. */
+-                                      struct ieee80211_node *wds_ni =
+-                                              ieee80211_find_node(&ic->ic_sta,
+-                                                              vap->wds_mac);
+-
+-                                      if (wds_ni == NULL) {
+-                                              wds_ni = ieee80211_alloc_node_table(
+-                                                              vap,
+-                                                              vap->wds_mac);
+-                                              if (wds_ni != NULL) {
+-                                                      ieee80211_add_wds_addr(
+-                                                                      &ic->ic_sta,
+-                                                                      wds_ni,
+-                                                                      vap->wds_mac,
+-                                                                      1);
+-                                                      ieee80211_ref_node(wds_ni); /* pin in memory */
+-                                              }
+-                                              else
+-                                                      IEEE80211_DPRINTF(
+-                                                                      vap,
+-                                                                      IEEE80211_MSG_NODE,
+-                                                                      "%s: Unable to "
+-                                                                      "allocate node for "
+-                                                                      "WDS: " MAC_FMT "\n",
+-                                                                      __func__,
+-                                                                      MAC_ADDR(
+-                                                                              vap->wds_mac)
+-                                                                      );
+-                                      }
+-
+-                                      if (wds_ni != NULL) {
+-                                              ieee80211_node_authorize(wds_ni);
+-                                              wds_ni->ni_chan =
+-                                                      vap->iv_bss->ni_chan;
+-                                              wds_ni->ni_capinfo =
+-                                                      ni->ni_capinfo;
+-                                              wds_ni->ni_associd = 1;
+-                                              wds_ni->ni_ath_flags =
+-                                                      vap->iv_ath_cap;
+-                                      }
+-                              }
+                               break;
+                       }
+                       /* fall thru... */
+@@ -1675,6 +1686,7 @@ __ieee80211_newstate(struct ieee80211vap
+                */
+               if (ni->ni_authmode != IEEE80211_AUTH_8021X)
+                       ieee80211_node_authorize(ni);
++
+ #ifdef ATH_SUPERG_XR
+               /*
+                * fire a timer to bring up XR vap if configured.
+@@ -1808,6 +1820,11 @@ ieee80211_newstate(struct ieee80211vap *
+                         ieee80211_state_name[dstate]);
+       ieee80211_update_link_status(vap, nstate, ostate);
++
++      if ((nstate != IEEE80211_S_RUN) && vap->iv_wdsnode &&
++                      !vap->iv_wdsnode->ni_subif)
++              ieee80211_unref_node(&vap->iv_wdsnode);
++
+       switch (nstate) {
+       case IEEE80211_S_AUTH:
+       case IEEE80211_S_ASSOC:
+@@ -1930,8 +1947,15 @@ ieee80211_newstate(struct ieee80211vap *
+               if (ostate == IEEE80211_S_SCAN || 
+                   ostate == IEEE80211_S_AUTH ||
+                   ostate == IEEE80211_S_ASSOC) {
++
+                       /* Transition (S_SCAN|S_AUTH|S_ASSOC) -> S_RUN */
+                       __ieee80211_newstate(vap, nstate, arg);
++
++                      /* if we're in wds, let the ap know that we're doing this */
++                      if ((vap->iv_opmode == IEEE80211_M_STA) &&
++                              (vap->iv_flags_ext & IEEE80211_FEXT_WDS))
++                                      ieee80211_send_nulldata(ieee80211_ref_node(vap->iv_bss));
++
+                       /* Then bring up all other vaps pending on the scan */
+                       dstate = get_dominant_state(ic);
+                       if (dstate == IEEE80211_S_RUN) {
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -79,28 +79,6 @@ typedef void *TQUEUE_ARG;
+ #define       tasklet_enable(t)       do { (void) t; local_bh_enable(); } while (0)
+ #endif /* !DECLARE_TASKLET */
+-#include <linux/sched.h>
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41)
+-#include <linux/tqueue.h>
+-#define work_struct                   tq_struct
+-#define schedule_work(t)              schedule_task((t))
+-#define flush_scheduled_work()                flush_scheduled_tasks()
+-#define ATH_INIT_WORK(t, f) do {                      \
+-      memset((t), 0, sizeof(struct tq_struct)); \
+-      (t)->routine = (void (*)(void*)) (f);   \
+-      (t)->data=(void *) (t);                 \
+-} while (0)
+-#else
+-#include <linux/workqueue.h>
+-
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+-#define ATH_INIT_WORK(_t, _f) INIT_WORK((_t), (void (*)(void *))(_f), (_t));
+-#else
+-#define ATH_INIT_WORK(_t, _f) INIT_WORK((_t), (_f));
+-#endif
+-
+-#endif /* KERNEL_VERSION < 2.5.41 */
+-
+ /*
+  * Guess how the interrupt handler should work.
+  */
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -145,7 +145,7 @@ ieee80211_getmgtframe(u_int8_t **frm, u_
+       struct sk_buff *skb;
+       u_int len;
+-      len = roundup(sizeof(struct ieee80211_frame) + pktlen, 4);
++      len = roundup(sizeof(struct ieee80211_frame_addr4) + pktlen, 4);
+ #ifdef IEEE80211_DEBUG_REFCNT
+       skb = ieee80211_dev_alloc_skb_debug(len + align - 1, func, line);
+ #else
+@@ -161,7 +161,7 @@ ieee80211_getmgtframe(u_int8_t **frm, u_
+               SKB_CB(skb)->flags = 0;
+               SKB_CB(skb)->next = NULL;
+-              skb_reserve(skb, sizeof(struct ieee80211_frame));
++              skb_reserve(skb, sizeof(struct ieee80211_frame_addr4));
+               *frm = skb_put(skb, pktlen);
+       }
+       return skb;
+--- a/net80211/ieee80211_node.h
++++ b/net80211/ieee80211_node.h
+@@ -92,11 +92,13 @@ struct ath_softc;
+  * the ieee80211com structure.
+  */
+ struct ieee80211_node {
+-      struct ieee80211vap *ni_vap;
++      struct ieee80211vap *ni_vap, *ni_subif;
+       struct ieee80211com *ni_ic;
+       struct ieee80211_node_table *ni_table;
+       TAILQ_ENTRY(ieee80211_node) ni_list;
+       LIST_ENTRY(ieee80211_node) ni_hash;
++      struct work_struct ni_create;   /* task for creating a subif */
++      struct work_struct ni_destroy;  /* task for destroying a subif */
+       atomic_t ni_refcnt;
+       u_int ni_scangen;                       /* gen# for timeout scan */
+       u_int8_t ni_authmode;                   /* authentication algorithm */
+@@ -430,5 +432,6 @@ void ieee80211_node_join(struct ieee8021
+ void ieee80211_node_leave(struct ieee80211_node *);
+ u_int8_t ieee80211_getrssi(struct ieee80211com *);
+ int32_t ieee80211_get_node_count(struct ieee80211com *);
++void ieee80211_wds_addif(struct ieee80211_node *ni);
+ #endif /* _NET80211_IEEE80211_NODE_H_ */
diff --git a/net/madwifi/patches/372-queue_vif.patch b/net/madwifi/patches/372-queue_vif.patch
new file mode 100644 (file)
index 0000000..8b13abc
--- /dev/null
@@ -0,0 +1,39 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1198,6 +1198,7 @@ ieee80211_deliver_data(struct ieee80211_
+               }
+               if (skb1 != NULL) {
+                       struct ieee80211_node *ni_tmp;
++                      int ret;
+                       skb1->dev = dev;
+                       skb_reset_mac_header(skb1);
+                       skb_set_network_header(skb1, sizeof(struct ether_header));
+@@ -1205,7 +1206,12 @@ ieee80211_deliver_data(struct ieee80211_
+                       skb1->protocol = __constant_htons(ETH_P_802_2);
+                       /* XXX insert vlan tag before queue it? */
+                       ni_tmp = SKB_CB(skb1)->ni; /* remember node so we can free it */
+-                      if (dev_queue_xmit(skb1) == NET_XMIT_DROP) {
++                      ret = dev->hard_start_xmit(skb1, dev);
++
++                      if (ret == NETDEV_TX_BUSY)
++                              ieee80211_dev_kfree_skb(&skb1);
++
++                      else if (ret != NETDEV_TX_OK) {
+                               /* If queue dropped the packet because device was
+                                * too busy */
+                               vap->iv_devstats.tx_dropped++;
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -324,9 +324,10 @@ void ieee80211_parent_queue_xmit(struct
+       /* Dispatch the packet to the parent device */
+       skb->dev = vap->iv_ic->ic_dev;
+-      if (dev_queue_xmit(skb) == NET_XMIT_DROP)
++      if (netif_queue_stopped(skb->dev))
++              ieee80211_dev_kfree_skb(&skb);
++      else if (dev_queue_xmit(skb) == NET_XMIT_DROP)
+               vap->iv_devstats.tx_dropped++;
+-
+ }
+ /*
diff --git a/net/madwifi/patches/373-sanity_check.patch b/net/madwifi/patches/373-sanity_check.patch
new file mode 100644 (file)
index 0000000..06c6acf
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -250,6 +250,9 @@ ieee80211_input(struct ieee80211vap * va
+       if (vap->iv_opmode == IEEE80211_M_MONITOR)
+               goto out;
++      if (!skb->data)
++              goto out;
++
+       if (skb->len < sizeof(struct ieee80211_frame_min)) {
+               IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
+                       ni->ni_macaddr, NULL,
diff --git a/net/madwifi/patches/374-nbtt_fix.patch b/net/madwifi/patches/374-nbtt_fix.patch
new file mode 100644 (file)
index 0000000..38a1c59
--- /dev/null
@@ -0,0 +1,22 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -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
++              if ((nexttbtt & HAL_BEACON_PERIOD) - (ath_hal_gettsf32(ah) >> 10)
++                              <= ath_hal_sw_beacon_response_time)
++                      nexttbtt += intval;
+               sc->sc_nexttbtt = nexttbtt;
+               ath_hal_beaconinit(ah, nexttbtt, intval);
+               if (intval & HAL_BEACON_RESET_TSF) {
+--- a/ath_hal/ah_os.c
++++ b/ath_hal/ah_os.c
+@@ -71,6 +71,7 @@ static       int ath_hal_debug = 99;
+ int   ath_hal_dma_beacon_response_time = 2;   /* in TUs */
+ int   ath_hal_sw_beacon_response_time = 10;   /* in TUs */
+ int   ath_hal_additional_swba_backoff = 0;    /* in TUs */
++EXPORT_SYMBOL(ath_hal_sw_beacon_response_time);
+ struct ath_hal *
+ _ath_hal_attach(u_int16_t devid, HAL_SOFTC sc,
diff --git a/net/madwifi/patches/375-atim_tsf_update.patch b/net/madwifi/patches/375-atim_tsf_update.patch
new file mode 100644 (file)
index 0000000..d1313aa
--- /dev/null
@@ -0,0 +1,141 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -161,6 +161,7 @@ static void ath_beacon_send(struct ath_s
+ static void ath_beacon_return(struct ath_softc *, struct ath_buf *);
+ static void ath_beacon_free(struct ath_softc *);
+ static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *);
++static void ath_hw_beacon_stop(struct ath_softc *sc);
+ static int ath_desc_alloc(struct ath_softc *);
+ static void ath_desc_free(struct ath_softc *);
+ static void ath_desc_swap(struct ath_desc *);
+@@ -2793,6 +2794,72 @@ ath_set_ack_bitrate(struct ath_softc *sc
+       return 1;
+ }
++static void
++ath_hw_beacon_stop(struct ath_softc *sc)
++{
++      HAL_BEACON_TIMERS btimers;
++
++      btimers.bt_intval = 0;
++      btimers.bt_nexttbtt = 0;
++      btimers.bt_nextdba = 0xffffffff;
++      btimers.bt_nextswba = 0xffffffff;
++      btimers.bt_nextatim = 0;
++
++      ath_hal_setbeacontimers(sc->sc_ah, &btimers);
++}
++
++/* Fix up the ATIM window after TSF resync */
++static int
++ath_hw_check_atim(struct ath_softc *sc, int window, int intval)
++{
++#define AR5K_TIMER0_5210       0x802c  /* Next beacon time register */
++#define AR5K_TIMER0_5211       0x8028
++#define AR5K_TIMER3_5210       0x8038  /* End of ATIM window time register */
++#define AR5K_TIMER3_5211       0x8034
++      struct ath_hal *ah = sc->sc_ah;
++      int dev = sc->sc_ah->ah_macType;
++      unsigned int nbtt, atim;
++      int is_5210 = 0;
++
++      /*
++       * check if the ATIM window is still correct:
++       *   1.) usually ATIM should be NBTT + window
++       *   2.) nbtt already updated
++       *   3.) nbtt already updated and has wrapped around
++       *   4.) atim has wrapped around
++       */
++      switch(dev) {
++      case 5210:
++              nbtt = OS_REG_READ(ah, AR5K_TIMER0_5210);
++              atim = OS_REG_READ(ah, AR5K_TIMER3_5210);
++              is_5210 = 1;
++              break;
++      case 5211:
++      case 5212:
++              nbtt = OS_REG_READ(ah, AR5K_TIMER0_5211);
++              atim = OS_REG_READ(ah, AR5K_TIMER3_5211);
++              break;
++      /* NB: 5416+ doesn't do ATIM in hw */
++      case 5416:
++      default:
++              return 0;
++      }
++
++      if ((atim - nbtt != window) &&                          /* 1.) */
++          (nbtt - atim != intval - window) &&                 /* 2.) */
++          ((nbtt | 0x10000) - atim != intval - window) &&     /* 3.) */
++          ((atim | 0x10000) - nbtt != window)) {              /* 4.) */
++              if (is_5210)
++                      OS_REG_WRITE(ah, AR5K_TIMER3_5210, nbtt + window );
++              else
++                      OS_REG_WRITE(ah, AR5K_TIMER3_5211, nbtt + window );
++              return atim - nbtt;
++      }
++
++      return 0;
++}
++
++
+ /*
+  * Reset the hardware w/o losing operational state.  This is
+  * basically a more efficient way of doing ath_stop, ath_init,
+@@ -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;
++      unsigned long flags;
+       int reset_tsf = 0;
+       if (vap == NULL)
+@@ -5301,6 +5369,9 @@ ath_beacon_config(struct ath_softc *sc,
+       ni = vap->iv_bss;
++      /* TSF calculation is timing critical - we don't want to be interrupted here */
++      local_irq_save(flags);
++
+       hw_tsf = ath_hal_gettsf64(ah);
+       tsf = le64_to_cpu(ni->ni_tstamp.tsf);
+       hw_tsftu = hw_tsf >> 10;
+@@ -5490,15 +5561,27 @@ ath_beacon_config(struct ath_softc *sc,
+                               <= ath_hal_sw_beacon_response_time)
+                       nexttbtt += intval;
+               sc->sc_nexttbtt = nexttbtt;
++
++              /* stop beacons before reconfiguring the timers to avoid race
++               * conditions. ath_hal_beaconinit will start them again */
++              ath_hw_beacon_stop(sc);
++
+               ath_hal_beaconinit(ah, nexttbtt, intval);
+               if (intval & HAL_BEACON_RESET_TSF) {
+                       sc->sc_last_tsf = 0;
+               }
+               sc->sc_bmisscount = 0;
+               ath_hal_intrset(ah, sc->sc_imask);
++
++              if ((sc->sc_opmode == HAL_M_IBSS) && ath_hw_check_atim(sc, 1, intval & HAL_BEACON_PERIOD)) {
++                      DPRINTF(sc, ATH_DEBUG_BEACON,
++                              "fixed atim window after beacon init\n");
++              }
+       }
+ ath_beacon_config_debug:
++      local_irq_restore(flags);
++
+       /* We print all debug messages here, in order to preserve the
+        * time critical aspect of this function */
+       DPRINTF(sc, ATH_DEBUG_BEACON,
+@@ -6401,6 +6484,11 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+                       DPRINTF(sc, ATH_DEBUG_BEACON, 
+                               "Updated beacon timers\n");
+               }
++              if ((sc->sc_opmode == HAL_M_IBSS) &&
++                              IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid) &&
++                              ath_hw_check_atim(sc, 1, vap->iv_bss->ni_intval)) {
++                      DPRINTF(sc, ATH_DEBUG_ANY, "Fixed ATIM window after beacon recv\n");
++              }
+               /* NB: Fall Through */
+       case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
+               if (vap->iv_opmode == IEEE80211_M_IBSS &&
diff --git a/net/madwifi/patches/377-disable_vlan_code.patch b/net/madwifi/patches/377-disable_vlan_code.patch
new file mode 100644 (file)
index 0000000..8a13248
--- /dev/null
@@ -0,0 +1,25 @@
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -657,22 +657,7 @@ int ieee80211_proc_vcreate(struct ieee80
+              char *);
+ void ieee80211_proc_cleanup(struct ieee80211vap *);
+-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+-#define IEEE80211_VLAN_TAG_USED 1
+-
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)
+-#define       vlan_hwaccel_receive_skb(skb, grp, tag) vlan_hwaccel_rx(skb, grp, tag)
+-#endif
+-
+-#ifndef VLAN_GROUP_ARRAY_PART_LEN
+-#define vlan_group_set_device(group, vid, dev) do { \
+-      group->vlan_devices[vid] = dev; \
+-} while (0);
+-#endif
+-
+-#else
+ #define IEEE80211_VLAN_TAG_USED 0
+-#endif
+ void ieee80211_vlan_vattach(struct ieee80211vap *);
+ void ieee80211_vlan_vdetach(struct ieee80211vap *);
diff --git a/net/madwifi/patches/378-adhoc_crash_fix.patch b/net/madwifi/patches/378-adhoc_crash_fix.patch
new file mode 100644 (file)
index 0000000..5b91683
--- /dev/null
@@ -0,0 +1,14 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3529,6 +3529,11 @@ ieee80211_recv_mgmt(struct ieee80211vap
+               if (ic->ic_flags & IEEE80211_F_SCAN) {
+                       ieee80211_add_scan(vap, &scan, wh, subtype, rssi, rtsf);
+               }
++
++              /* stop processing if the bss channel is not set up yet */
++              if (!ic->ic_bsschan || ic->ic_bsschan == IEEE80211_CHAN_ANYC)
++                      break;
++
+               /* NB: Behavior of WDS-Link and Ad-Hoc is very similar here:
+                * When we receive a beacon that belongs to the AP that we're
+                * connected to, use it to refresh the local node info.
diff --git a/net/madwifi/patches/379-invalid_rate_fix.patch b/net/madwifi/patches/379-invalid_rate_fix.patch
new file mode 100644 (file)
index 0000000..c96c04d
--- /dev/null
@@ -0,0 +1,405 @@
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -111,27 +111,13 @@
+ #include <net80211/ieee80211_var.h>
+ #include <net80211/ieee80211_rate.h>
++#include "if_ath_debug.h"
+ #include "if_athvar.h"
+ #include "if_ath_hal.h"
+ #include "ah_desc.h"
+ #include "minstrel.h"
+-#ifdef AR_DEBUG
+-#define       MINSTREL_DEBUG
+-#endif
+-#ifdef MINSTREL_DEBUG
+-enum {
+-              ATH_DEBUG_RATE          = 0x00000010    /* rate control */
+-};
+-#define       DPRINTF(sc, _fmt, ...) do {             \
+-              if (sc->sc_debug & ATH_DEBUG_RATE)      \
+-                      printk(_fmt, __VA_ARGS__);              \
+-} while (0)
+-#else
+-#define       DPRINTF(sc, _fmt, ...)
+-#endif
+-
+ #define ONE_SECOND (1000 * 1000)  /* 1 second, or 1000 milliseconds; eternity, in other words */
+ #include "release.h"
+@@ -471,11 +457,11 @@ ath_rate_tx_complete(struct ath_softc *s
+               final_rate = sc->sc_hwmap[ts->ts_rate & ~HAL_TXSTAT_ALTRATE].ieeerate;
+               final_ndx = rate_to_ndx(sn, final_rate);
+               if (final_ndx >= sn->num_rates) {
+-                      DPRINTF(sc, "%s: final ndx too high\n", __func__);
++                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: final ndx too high\n", __func__);
+                       final_ndx = 0;
+               }
+               if (final_ndx < 0) {
+-                      DPRINTF(sc, "%s: final ndx too low\n", __func__);
++                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: final ndx too low\n", __func__);
+                       final_ndx = 0;
+               }
+@@ -485,7 +471,7 @@ ath_rate_tx_complete(struct ath_softc *s
+               tries = ts->ts_longretry + 1;
+               if (sn->num_rates <= 0) {
+-                      DPRINTF(sc, "%s: " MAC_FMT " %s no rates yet\n", dev_info,
++                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: " MAC_FMT " %s no rates yet\n", dev_info,
+                               MAC_ADDR(an->an_node.ni_macaddr), __func__);
+                       return;
+               }
+@@ -551,7 +537,7 @@ ath_rate_tx_complete(struct ath_softc *s
+ static void
+ ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
+ {
+-              DPRINTF(sc, "%s: " MAC_FMT " %s\n", dev_info,
++              DPRINTF(sc, ATH_DEBUG_RATE, "%s: " MAC_FMT " %s\n", dev_info,
+                       MAC_ADDR(an->an_node.ni_macaddr), __func__);
+               if (isnew)
+                       ath_rate_ctl_reset(sc, &an->an_node);
+@@ -601,7 +587,7 @@ ath_fill_sample_table(struct minstrel_no
+                           p = rates + sprintf(rates, "rates :: %d ", column_index);
+                           for (i = 0; i < num_sample_rates; i++)
+                                   p += sprintf(p, "%2u ", sn->rs_sampleTable[i][column_index]);
+-                          DPRINTF(sc, "%s\n", rates);
++                          DPRINTF(sc, ATH_DEBUG_RATE, "%s\n", rates);
+               };
+ #endif
+ }
+@@ -628,7 +614,7 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+               sn->is_sampling = 0;
+               if (rt == NULL) {
+-                      DPRINTF(sc, "no rates yet! mode %u\n", sc->sc_curmode);
++                      DPRINTF(sc, ATH_DEBUG_RATE, "no rates yet! mode %u\n", sc->sc_curmode);
+                       return;
+               }
+               sn->static_rate_ndx = -1;
+@@ -658,7 +644,7 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+                       sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
+                       }
+                       if (sn->rates[x].rix == 0xff) {
+-                              DPRINTF(sc, "%s: %s ignore bogus rix at %d\n",
++                              DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s ignore bogus rix at %d\n",
+                                       dev_info, __func__, x);
+                               continue;
+                       }
+@@ -673,7 +659,7 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+               ni->ni_txrate = 0;
+               if (sn->num_rates <= 0) {
+-                      DPRINTF(sc, "%s: %s " MAC_FMT " no rates (fixed %d) \n",
++                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s " MAC_FMT " no rates (fixed %d) \n",
+                               dev_info, __func__, MAC_ADDR(ni->ni_macaddr),
+                               vap->iv_fixed_rate);
+                       /* There are no rates yet; we're done */
+@@ -689,23 +675,23 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+                        * the node.  We know the rate is there because the
+                        * rate set is checked when the station associates. */
+                       /* NB: the rate set is assumed sorted */
+-                      for (; (srate >= 0) && (ni->ni_rates.rs_rates[srate] & IEEE80211_RATE_VAL) != vap->iv_fixed_rate; srate--);
+-
+-                      KASSERT(srate >= 0,
+-                              ("fixed rate %d not in rate set", vap->iv_fixed_rate));
++                      for (; (srate > 0) && (ni->ni_rates.rs_rates[srate] & IEEE80211_RATE_VAL) != vap->iv_fixed_rate; srate--);
+                       sn->static_rate_ndx = srate;
+                       ni->ni_txrate = srate;
+-                      DPRINTF(sc, "%s: %s " MAC_FMT " fixed rate %d%sMbps\n",
+-                              dev_info, __func__, MAC_ADDR(ni->ni_macaddr),
+-                              sn->rates[srate].rate / 2,
+-                              (sn->rates[srate].rate % 2) ? ".5 " : " ");
++                      if ((ni->ni_rates.rs_rates[srate] & IEEE80211_RATE_VAL) != vap->iv_fixed_rate)
++                              EPRINTF(sc, "Invalid static rate, falling back to basic rate\n");
++                      else
++                              DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s " MAC_FMT " fixed rate %d%sMbps\n",
++                                      dev_info, __func__, MAC_ADDR(ni->ni_macaddr),
++                                      sn->rates[srate].rate / 2,
++                                      (sn->rates[srate].rate % 2) ? ".5 " : " ");
+                       return;
+               }
+               for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+                       if (sn->rates[x].rix == 0xff) {
+-                              DPRINTF(sc, "%s: %s ignore bogus rix at %d\n",
++                              DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s ignore bogus rix at %d\n",
+                                       dev_info, __func__, x);
+                               continue;
+                       }
+@@ -735,9 +721,9 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+               }
+ #if 0
+-              DPRINTF(sc, "%s: Retry table for this node\n", __func__);
++              DPRINTF(sc, ATH_DEBUG_RATE, "%s: Retry table for this node\n", __func__);
+                 for (x = 0; x < ni->ni_rates.rs_nrates; x++)
+-                           DPRINTF(sc, "%2d  %2d %6d  \n", x, sn->retry_count[x], sn->perfect_tx_time[x]);
++                           DPRINTF(sc, ATH_DEBUG_RATE, "%2d  %2d %6d  \n", x, sn->retry_count[x], sn->perfect_tx_time[x]);
+ #endif
+               /* Set the initial rate */
+@@ -781,10 +767,10 @@ ath_timer_function(unsigned long data)
+               unsigned int interval = ath_timer_interval;
+               if (dev == NULL)
+-                      DPRINTF(sc, "%s: 'dev' is null in this timer \n", __func__);
++                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: 'dev' is null in this timer \n", __func__);
+               if (sc == NULL)
+-                      DPRINTF(sc, "%s: 'sc' is null in this timer\n", __func__);
++                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: 'sc' is null in this timer\n", __func__);
+               ic = &sc->sc_ic;
+@@ -808,7 +794,7 @@ ath_timer_function(unsigned long data)
+               timer  = &(ssc->timer);
+               if (timer == NULL)
+-                      DPRINTF(sc, "%s: timer is null - leave it\n", __func__);
++                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: timer is null - leave it\n", __func__);
+               timer->expires = jiffies + ((HZ * interval) / 1000);
+               add_timer(timer);
+@@ -904,7 +890,7 @@ static struct ath_ratectrl *
+ ath_rate_attach(struct ath_softc *sc)
+ {
+               struct minstrel_softc *osc;
+-              DPRINTF(sc, "%s: %s\n", dev_info, __func__);
++              DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s\n", dev_info, __func__);
+               _MOD_INC_USE(THIS_MODULE, return NULL);
+               osc = kmalloc(sizeof(struct minstrel_softc), GFP_ATOMIC);
+@@ -963,7 +949,7 @@ ath_proc_read_nodes(struct ieee80211vap
+                                       p += sprintf(p, "out of room for node " MAC_FMT "\n\n", MAC_ADDR(ni->ni_macaddr));
+                                       break;
+                               }
+-                              DPRINTF(sc, "%s: out of memeory to write tall of the nodes\n", __func__);
++                              DPRINTF(sc, ATH_DEBUG_RATE, "%s: out of memeory to write tall of the nodes\n", __func__);
+                                   break;
+                       }
+                       an = ATH_NODE(ni);
+--- a/ath_rate/amrr/amrr.c
++++ b/ath_rate/amrr/amrr.c
+@@ -64,24 +64,13 @@
+ #include <net80211/ieee80211_var.h>
+ #include <net80211/ieee80211_rate.h>
++#include "if_ath_debug.h"
+ #include "if_athvar.h"
+ #include "if_ath_hal.h"
+ #include "ah_desc.h"
+ #include "amrr.h"
+-#ifdef AR_DEBUG
+-#define       AMRR_DEBUG
+-#endif
+-#ifdef AMRR_DEBUG
+-#define       DPRINTF(sc, _fmt, ...) do {                                     \
+-      if (sc->sc_debug & 0x10)                                        \
+-              printk(_fmt, __VA_ARGS__);                              \
+-} while (0)
+-#else
+-#define       DPRINTF(sc, _fmt, ...)
+-#endif
+-
+ static int ath_rateinterval = 1000;           /* rate ctl interval (ms)  */
+ static int ath_rate_max_success_threshold = 10;
+ static int ath_rate_min_success_threshold = 1;
+@@ -197,7 +186,7 @@ ath_rate_update(struct ath_softc *sc, st
+       KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+-      DPRINTF(sc, "%s: set xmit rate for " MAC_FMT " to %dM\n",
++      DPRINTF(sc, ATH_DEBUG_RATE, "%s: set xmit rate for " MAC_FMT " to %dM\n",
+               __func__, MAC_ADDR(ni->ni_macaddr),
+               ni->ni_rates.rs_nrates > 0 ?
+                       (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0);
+@@ -297,9 +286,9 @@ ath_rate_ctl_start(struct ath_softc *sc,
+                * rate set is checked when the station associates.
+                */
+               srate = ni->ni_rates.rs_nrates - 1;
+-              for (; srate >= 0 && RATE(srate) != vap->iv_fixed_rate; srate--);
+-              KASSERT(srate >= 0,
+-                      ("fixed rate %d not in rate set", vap->iv_fixed_rate));
++              for (; srate > 0 && RATE(srate) != vap->iv_fixed_rate; srate--);
++              if (RATE(srate) != vap->iv_fixed_rate)
++                      EPRINTF(sc, "Invalid static rate, falling back to basic rate\n");
+       }
+       ath_rate_update(sc, ni, srate);
+ #undef RATE
+@@ -377,7 +366,7 @@ ath_rate_ctl(void *arg, struct ieee80211
+       old_rate = ni->ni_txrate;
+-      DPRINTF (sc, "cnt0: %d cnt1: %d cnt2: %d cnt3: %d -- threshold: %d\n",
++      DPRINTF(sc, ATH_DEBUG_RATE, "cnt0: %d cnt1: %d cnt2: %d cnt3: %d -- threshold: %d\n",
+                amn->amn_tx_try0_cnt,
+                amn->amn_tx_try1_cnt,
+                amn->amn_tx_try2_cnt,
+@@ -390,7 +379,7 @@ ath_rate_ctl(void *arg, struct ieee80211
+                       amn->amn_recovery = 1;
+                       amn->amn_success = 0;
+                       ni->ni_txrate++;
+-                      DPRINTF(sc, "increase rate to %d\n", ni->ni_txrate);
++                      DPRINTF(sc, ATH_DEBUG_RATE, "increase rate to %d\n", ni->ni_txrate);
+               } else
+                       amn->amn_recovery = 0;
+       } else if (is_failure(amn)) {
+@@ -401,12 +390,12 @@ ath_rate_ctl(void *arg, struct ieee80211
+                               amn->amn_success_threshold *= 2;
+                               amn->amn_success_threshold = min(amn->amn_success_threshold,
+                                                                 (u_int)ath_rate_max_success_threshold);
+-                              DPRINTF(sc, "decrease rate recovery thr: %d\n",
++                              DPRINTF(sc, ATH_DEBUG_RATE, "decrease rate recovery thr: %d\n",
+                                       amn->amn_success_threshold);
+                       } else {
+                               /* simple failure. */
+                               amn->amn_success_threshold = ath_rate_min_success_threshold;
+-                              DPRINTF(sc, "decrease rate normal thr: %d\n",
++                              DPRINTF(sc, ATH_DEBUG_RATE, "decrease rate normal thr: %d\n",
+                                       amn->amn_success_threshold);
+                       }
+                       amn->amn_recovery = 0;
+--- a/ath_rate/onoe/onoe.c
++++ b/ath_rate/onoe/onoe.c
+@@ -60,27 +60,13 @@
+ #include <net80211/ieee80211_var.h>
+ #include <net80211/ieee80211_rate.h>
++#include "if_ath_debug.h"
+ #include "if_athvar.h"
+ #include "if_ath_hal.h"
+ #include "ah_desc.h"
+ #include "onoe.h"
+-#ifdef AR_DEBUG
+-#define       ONOE_DEBUG
+-#endif
+-#ifdef ONOE_DEBUG
+-enum {
+-      ATH_DEBUG_RATE  = 0x00000010,   /* rate control */
+-};
+-#define       DPRINTF(sc, _fmt, ...) do {                             \
+-      if (sc->sc_debug & ATH_DEBUG_RATE)                      \
+-              printk(_fmt, __VA_ARGS__);                      \
+-} while (0)
+-#else
+-#define       DPRINTF(sc, _fmt, ...)
+-#endif
+-
+ /*
+  * Default parameters for the rate control algorithm.  These are
+  * all tunable with sysctls.  The rate controller runs periodically
+@@ -186,7 +172,7 @@ ath_rate_update(struct ath_softc *sc, st
+       KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+-      DPRINTF(sc, "%s: set xmit rate for " MAC_FMT " to %dM\n",
++      DPRINTF(sc, ATH_DEBUG_RATE, "%s: set xmit rate for " MAC_FMT " to %dM\n",
+               __func__, MAC_ADDR(ni->ni_macaddr),
+               ni->ni_rates.rs_nrates > 0 ?
+                       (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0);
+@@ -283,9 +269,9 @@ ath_rate_ctl_start(struct ath_softc *sc,
+                */
+               /* NB: the rate set is assumed sorted */
+               srate = ni->ni_rates.rs_nrates - 1;
+-              for (; srate >= 0 && RATE(srate) != vap->iv_fixed_rate; srate--);
+-              KASSERT(srate >= 0,
+-                      ("fixed rate %d not in rate set", vap->iv_fixed_rate));
++              for (; srate > 0 && RATE(srate) != vap->iv_fixed_rate; srate--);
++              if (RATE(srate) != vap->iv_fixed_rate)
++                      EPRINTF(sc, "Invalid static rate, falling back to basic rate\n");
+       }
+       ath_rate_update(sc, ni, srate);
+ #undef RATE
+@@ -364,7 +350,7 @@ ath_rate_ctl(void *arg, struct ieee80211
+           on->on_tx_retr < (on->on_tx_ok * ath_rate_raise) / 100)
+               dir = 1;
+-      DPRINTF(sc, MAC_FMT ": ok %d err %d retr %d upper %d dir %d\n",
++      DPRINTF(sc, ATH_DEBUG_RATE, MAC_FMT ": ok %d err %d retr %d upper %d dir %d\n",
+               MAC_ADDR(ni->ni_macaddr),
+               on->on_tx_ok, on->on_tx_err, on->on_tx_retr,
+               on->on_tx_upper, dir);
+@@ -395,7 +381,7 @@ ath_rate_ctl(void *arg, struct ieee80211
+       }
+       if (nrate != ni->ni_txrate) {
+-              DPRINTF(sc, "%s: %dM -> %dM (%d ok, %d err, %d retr)\n",
++              DPRINTF(sc, ATH_DEBUG_RATE, "%s: %dM -> %dM (%d ok, %d err, %d retr)\n",
+                   __func__,
+                   (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL) / 2,
+                   (rs->rs_rates[nrate] & IEEE80211_RATE_VAL) / 2,
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -62,30 +62,13 @@
+ #include <net80211/ieee80211_var.h>
+ #include <net80211/ieee80211_rate.h>
++#include "if_ath_debug.h"
+ #include "if_athvar.h"
+ #include "if_ath_hal.h"
+ #include "ah_desc.h"
+ #include "sample.h"
+-#ifdef AR_DEBUG
+-#define SAMPLE_DEBUG
+-#endif
+-#ifdef SAMPLE_DEBUG
+-enum {
+-      ATH_DEBUG_RATE          = 0x00000010,   /* rate control */
+-      ATH_DEBUG_ANY           = 0xffffffff
+-};
+-#define       DPRINTF(sc, m, fmt, ...) do {                           \
+-      if (sc->sc_debug & (m))                                 \
+-              printk(fmt, __VA_ARGS__);                       \
+-} while (0)
+-#else
+-#define       DPRINTF(sc, m, fmt, ...) do {                           \
+-      (void) sc;                                              \
+-} while (0)
+-#endif
+-
+ /*
+  * This file is an implementation of the SampleRate algorithm
+  * in "Bit-rate Selection in Wireless Networks"
+@@ -740,7 +723,7 @@ ath_rate_tx_complete(struct ath_softc *s
+               ndx[3] = rate_to_ndx(sn, rate[3]);
+ #if 0
+-              DPRINTF(sc, "%s: " MAC_FMT " size %u finaltsidx %u tries %u status %u rate/try %u/%u %u/%u %u/%u %u/%u\n",
++              DPRINTF(sc, ATH_DEBUG_RATE, "%s: " MAC_FMT " size %u finaltsidx %u tries %u status %u rate/try %u/%u %u/%u %u/%u %u/%u\n",
+                       dev_info, MAC_ADDR(an->an_node.ni_macaddr),
+                       bin_to_size(size_to_bin(frame_size)),
+                       finalTSIdx,
+@@ -886,15 +869,16 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+                       if ((ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL) == vap->iv_fixed_rate)
+                               srate = x;
+-              KASSERT(((ni->ni_rates.rs_rates[srate] & IEEE80211_RATE_VAL) == vap->iv_fixed_rate),
+-                      ("fixed rate %u not in rate set", vap->iv_fixed_rate));
+-
+               sn->static_rate_ndx = srate;
+               ni->ni_txrate = srate;
+-              DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s " MAC_FMT " fixed rate %u%sMbps\n",
+-                      dev_info, __func__, MAC_ADDR(ni->ni_macaddr),
+-                      sn->rates[srate].rate / 2,
+-                      (sn->rates[srate].rate % 0x1) ? ".5" : " ");
++
++              if ((ni->ni_rates.rs_rates[srate] & IEEE80211_RATE_VAL) != vap->iv_fixed_rate)
++                      EPRINTF(sc, "Invalid static rate, falling back to basic rate\n");
++              else
++                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s " MAC_FMT " fixed rate %u%sMbps\n",
++                              dev_info, __func__, MAC_ADDR(ni->ni_macaddr),
++                              sn->rates[srate].rate / 2,
++                              (sn->rates[srate].rate % 0x1) ? ".5" : " ");
+               return;
+       }
diff --git a/net/madwifi/patches/380-noderef_hack.patch b/net/madwifi/patches/380-noderef_hack.patch
new file mode 100644 (file)
index 0000000..7c082d4
--- /dev/null
@@ -0,0 +1,13 @@
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -427,8 +427,8 @@ ieee80211_reset_bss(struct ieee80211vap
+                         __func__, ni, MAC_ADDR(vap->iv_myaddr));
+       KASSERT(ni != NULL, ("unable to setup inital BSS node"));
+-      vap->iv_bss = PASS_NODE(ni);
+-      KASSERT((atomic_read(&vap->iv_bss->ni_refcnt) == 2), 
++      vap->iv_bss = ieee80211_ref_node(ni);
++      KASSERT((atomic_read(&vap->iv_bss->ni_refcnt) == 3), 
+               ("wrong refcount for new node."));
+       if (obss != NULL) {
diff --git a/net/madwifi/patches/381-ibss_modes.patch b/net/madwifi/patches/381-ibss_modes.patch
new file mode 100644 (file)
index 0000000..38969b0
--- /dev/null
@@ -0,0 +1,23 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1260,7 +1260,10 @@ ath_vap_create(struct ieee80211com *ic,
+       case IEEE80211_M_IBSS:
+               if ((sc->sc_nvaps != 0) && (ic->ic_opmode == IEEE80211_M_STA))
+                       return NULL;
+-              ic_opmode = opmode;
++              if (ic->ic_opmode == IEEE80211_M_HOSTAP)
++                      ic_opmode = ic->ic_opmode;
++              else
++                      ic_opmode = opmode;
+               break;
+       case IEEE80211_M_AHDEMO:
+       case IEEE80211_M_MONITOR:
+@@ -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)
+-              sc->sc_opmode = HAL_M_IBSS;
++              sc->sc_opmode = HAL_M_HOSTAP;
+       else
+               sc->sc_opmode = (HAL_OPMODE) ic->ic_opmode;     /* NB: compatible */
diff --git a/net/madwifi/patches/382-relax_bintval.patch b/net/madwifi/patches/382-relax_bintval.patch
new file mode 100644 (file)
index 0000000..0901949
--- /dev/null
@@ -0,0 +1,13 @@
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -61,8 +61,8 @@
+ #define       IEEE80211_DTIM_MIN              1       /* min DTIM period */
+ #define       IEEE80211_DTIM_DEFAULT          1       /* default DTIM period */
+-#define       IEEE80211_BINTVAL_MAX           1000    /* max beacon interval (TUs) */
+-#define       IEEE80211_BINTVAL_MIN           25      /* min beacon interval (TUs) */
++#define       IEEE80211_BINTVAL_MAX           5000    /* max beacon interval (TUs) */
++#define       IEEE80211_BINTVAL_MIN           10      /* min beacon interval (TUs) */
+ #define       IEEE80211_BINTVAL_DEFAULT       100     /* default beacon interval (TUs) */
+ #define IEEE80211_BINTVAL_VALID(_bi) \
+       ((IEEE80211_BINTVAL_MIN <= (_bi)) && \
diff --git a/net/madwifi/patches/383-ibss_hostap.patch b/net/madwifi/patches/383-ibss_hostap.patch
new file mode 100644 (file)
index 0000000..d449c30
--- /dev/null
@@ -0,0 +1,105 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1452,6 +1452,23 @@ ath_vap_create(struct ieee80211com *ic,
+               sc->sc_nstavaps++;
+       else if (opmode == IEEE80211_M_MONITOR)
+               sc->sc_nmonvaps++;
++
++
++      /* Driving the HAL in IBSS sometimes adapts the TSF and other timing registers
++       * from received beacons/probes. If that happens, expected TX interrupts may
++       * not occur until next reset. Which triggers the "lost beacon" tasklet.
++       * Resulting effectively in not sending packets for minutes. Because that only
++       * happens in large mesh networks, this mode needs to be activated by a kernel
++       * module parameter: hostap_for_ibss=1. Note that using this mode has side
++       * effects. Such as not supressing beacons/probe answers randomly when
++       * receiving other node beacons. It's recommended to lower the beacon interval
++       * then. When using an IBSS-VAP together with an HOSTAP-VAP, you may also need
++       * to re-trigger IBSS beacon generation after creating the HOSTAP-VAP by
++       * issueing "iwpriv athX bintval 1000".
++       */
++      if ((flags & IEEE80211_NO_STABEACONS) && (ic->ic_opmode == IEEE80211_M_IBSS))
++              sc->sc_opmode = HAL_M_HOSTAP;
++      else
+       /*
+        * Adhoc demo mode is a pseudo mode; to the HAL it's
+        * just IBSS mode and the driver doesn't use management
+@@ -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 ||
+-          sc->sc_opmode == HAL_M_IBSS ||      /* NB: AHDEMO too */
++          ic->ic_opmode == IEEE80211_M_IBSS ||
++          ic->ic_opmode == IEEE80211_M_AHDEMO ||
+           (sc->sc_nostabeacons) || sc->sc_scanning ||
+               (ic->ic_opmode == IEEE80211_M_HOSTAP))
+               rfilt |= HAL_RX_FILTER_BEACON;
+@@ -6435,6 +6453,33 @@ ath_capture(struct net_device *dev, cons
+ }
+ /*
++ * Advances (forwards/adds) a microsecond value to current chip's TSF registers
++ */
++
++/* from ath_info.c */
++#define AR5K_TSF_L32_5210             0x806c  /* TSF (lower 32 bits) */
++#define AR5K_TSF_L32_5211             0x804c
++#define AR5K_TSF_L32                  (ar_device(ah->ah_sc->devid) == 5210 ? \
++                                      AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211)
++
++#define AR5K_TSF_U32_5210             0x8070
++#define AR5K_TSF_U32_5211             0x8050
++#define AR5K_TSF_U32                  (ar_device(ah->ah_sc->devid) == 5210 ? \
++                                      AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
++
++static inline void ath_hal_settsf64(struct ath_hal *ah, u_int64_t tsf_adv)
++{
++      ATH_HAL_LOCK_IRQ(ah->ah_sc);
++      ath_hal_set_function(__func__);
++      tsf_adv += ah->ah_getTsf64(ah);
++      OS_REG_WRITE(ah, AR5K_TSF_L32, 0ll);
++      OS_REG_WRITE(ah, AR5K_TSF_U32, (tsf_adv >> 32) & 0xffffffffll);
++      OS_REG_WRITE(ah, AR5K_TSF_L32, (tsf_adv >> 00) & 0xffffffffll);
++      ath_hal_set_function(NULL);
++      ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
++}
++
++/*
+  * 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.
+@@ -6487,10 +6532,19 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+                       DPRINTF(sc, ATH_DEBUG_BEACON, 
+                               "Updated beacon timers\n");
+               }
+-              if ((sc->sc_opmode == HAL_M_IBSS) &&
+-                              IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid) &&
+-                              ath_hw_check_atim(sc, 1, vap->iv_bss->ni_intval)) {
+-                      DPRINTF(sc, ATH_DEBUG_ANY, "Fixed ATIM window after beacon recv\n");
++              if ((vap->iv_opmode == IEEE80211_M_IBSS) &&
++                              (sc->sc_opmode == HAL_M_HOSTAP) &&
++                              IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) {
++                      /* In this mode, we drive the HAL in HOSTAP mode. Hence
++                       * we do the IBSS merging in software. Also do not merge
++                       * if the difference it too small. Otherwise we are playing
++                       * tsf-pingpong with other vendors drivers */
++                      beacon_tsf = le64_to_cpu(ni->ni_tstamp.tsf);
++                      if (beacon_tsf > rtsf + 0xffff) {
++                              ath_hal_settsf64(sc->sc_ah, beacon_tsf - rtsf);
++                              ieee80211_ibss_merge(ni);
++                      }
++                      break;
+               }
+               /* NB: Fall Through */
+       case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
+@@ -6563,6 +6617,10 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+ #endif
+                       if (do_merge)
+                               ieee80211_ibss_merge(ni);
++
++                      if ((sc->sc_opmode == HAL_M_IBSS) &&
++                                      ath_hw_check_atim(sc, 1, vap->iv_bss->ni_intval))
++                              DPRINTF(sc, ATH_DEBUG_ANY, "Fixed ATIM window after beacon recv\n");
+               }
+               break;
+       }
diff --git a/net/madwifi/patches/384-hwdetect.patch b/net/madwifi/patches/384-hwdetect.patch
new file mode 100644 (file)
index 0000000..3b67615
--- /dev/null
@@ -0,0 +1,325 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -62,6 +62,7 @@
+ #include <linux/if_arp.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/time.h>
++#include <linux/pci.h>
+ #include <asm/uaccess.h>
+ #include "if_ethersubr.h"             /* for ETHER_IS_MULTICAST */
+@@ -401,6 +402,15 @@ static int outdoor = -1;
+ static int xchanmode = -1;
+ static int beacon_cal = 1;
++static const struct ath_hw_detect generic_hw_info = {
++      .vendor_name = "Unknown",
++      .card_name = "Generic",
++      .vendor = PCI_ANY_ID,
++      .id = PCI_ANY_ID,
++      .subvendor = PCI_ANY_ID,
++      .subid = PCI_ANY_ID
++};
++
+ static const char *hal_status_desc[] = {
+       "No error",
+       "No hardware present or device not yet supported",
+@@ -542,6 +552,8 @@ ath_attach(u_int16_t devid, struct net_d
+       DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid);
+ #endif
++      sc->sc_hwinfo = &generic_hw_info;
++
+       /* Allocate space for dynamically determined maximum VAP count */
+       sc->sc_bslot = 
+               kmalloc(ath_maxvaps * sizeof(struct ieee80211vap*), GFP_KERNEL);
+@@ -1508,6 +1520,29 @@ ath_vap_create(struct ieee80211com *ic,
+       return vap;
+ }
++void
++ath_hw_detect(struct ath_softc *sc, const struct ath_hw_detect *cards, int n_cards, u32 vendor, u32 id, u32 subvendor, u32 subid)
++{
++      int i;
++
++      for (i = 0; i < n_cards; i++) {
++              const struct ath_hw_detect *c = &cards[i];
++
++              if ((c->vendor != PCI_ANY_ID) && c->vendor != vendor)
++                      continue;
++              if ((c->id != PCI_ANY_ID) && c->id != id)
++                      continue;
++              if ((c->subvendor != PCI_ANY_ID) && c->subvendor != subvendor)
++                      continue;
++              if ((c->subid != PCI_ANY_ID) && c->subid != subid)
++                      continue;
++
++              sc->sc_hwinfo = c;
++              sc->sc_poweroffset = c->poweroffset;
++              break;
++      }
++}
++
+ static void
+ ath_vap_delete(struct ieee80211vap *vap)
+ {
+@@ -10225,6 +10260,7 @@ static u_int32_t
+ ath_set_clamped_maxtxpower(struct ath_softc *sc, 
+               u_int32_t new_clamped_maxtxpower)
+ {
++      new_clamped_maxtxpower -= sc->sc_poweroffset;
+       (void)ath_hal_settxpowlimit(sc->sc_ah, new_clamped_maxtxpower);
+       return ath_get_clamped_maxtxpower(sc);
+ }
+@@ -10238,6 +10274,7 @@ ath_get_clamped_maxtxpower(struct ath_so
+ {
+       u_int32_t clamped_maxtxpower;
+       (void)ath_hal_getmaxtxpow(sc->sc_ah, &clamped_maxtxpower);
++      clamped_maxtxpower += sc->sc_poweroffset;
+       return clamped_maxtxpower;
+ }
+@@ -10821,6 +10858,12 @@ ath_ioctl(struct net_device *dev, struct
+  * is to add module parameters.
+  */
++/* sysctls for hardware info */
++enum {
++      ATH_CARD_VENDOR,
++      ATH_CARD_NAME,
++};
++
+ /*
+  * Dynamic (i.e. per-device) sysctls.  These are automatically
+  * mirrored in /proc/sys.
+@@ -10900,6 +10943,38 @@ ath_sysctl_get_intmit(struct ath_softc *
+ }
+ static int
++ATH_SYSCTL_DECL(ath_sysctl_hwinfo, ctl, write, filp, buffer, lenp, ppos)
++{
++      struct ath_softc *sc = ctl->extra1;
++      struct ath_hal *ah = sc->sc_ah;
++      int ret = 0;
++
++      if (write)
++              return -EINVAL;
++
++      ATH_LOCK(sc);
++      switch((long)ctl->extra2) {
++      case ATH_CARD_VENDOR:
++              ctl->data = (char *)sc->sc_hwinfo->vendor_name;
++              break;
++      case ATH_CARD_NAME:
++              ctl->data = (char *)sc->sc_hwinfo->card_name;
++              break;
++      default:
++              ret = -EINVAL;
++              break;
++      }
++      if (ret == 0) {
++              ctl->maxlen = strlen(ctl->data);
++              ret = ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp,
++                              buffer, lenp, ppos);
++      }
++      ATH_UNLOCK(sc);
++
++      return ret;
++}
++
++static int
+ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
+ {
+       struct ath_softc *sc = ctl->extra1;
+@@ -11179,6 +11254,24 @@ static int maxint = 0x7fffffff;               /* 32-b
+ static const ctl_table ath_sysctl_template[] = {
+       { .ctl_name     = CTL_AUTO,
++        .procname     = "dev_vendor",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_hwinfo,
++        .strategy   = &sysctl_string,
++        .data         = "N/A",
++        .maxlen   = 1,
++        .extra2       = (void *)ATH_CARD_VENDOR,
++      },
++      { .ctl_name     = CTL_AUTO,
++        .procname     = "dev_name",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_hwinfo,
++        .strategy   = &sysctl_string,
++        .data         = "N/A",
++        .maxlen   = 1,
++        .extra2       = (void *)ATH_CARD_NAME,
++      },
++      { .ctl_name     = CTL_AUTO,
+         .procname     = "slottime",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -168,12 +168,16 @@ static inline struct net_device *_alloc_
+         void __user *buffer, size_t *lenp)
+ #define       ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
+       proc_dointvec(ctl, write, filp, buffer, lenp)
++#define       ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
++      proc_dostring(ctl, write, filp, buffer, lenp)
+ #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) */
+ #define       ATH_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \
+       f(ctl_table *ctl, int write, struct file *filp, \
+         void __user *buffer, size_t *lenp, loff_t *ppos)
+ #define       ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
+       proc_dointvec(ctl, write, filp, buffer, lenp, ppos)
++#define       ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
++      proc_dostring(ctl, write, filp, buffer, lenp, ppos)
+ #endif
+ #define       ATH_TIMEOUT     1000
+@@ -469,6 +473,7 @@ struct ath_hal;
+ struct ath_desc;
+ struct ath_ratectrl;
+ struct ath_tx99;
++struct ath_hw_detect;
+ struct proc_dir_entry;
+ /*
+@@ -629,6 +634,7 @@ struct ath_softc {
+       struct ath_ratectrl *sc_rc;             /* tx rate control support */
+       struct ath_tx99 *sc_tx99;               /* tx99 support */
+       void (*sc_setdefantenna)(struct ath_softc *, u_int);
++      const struct ath_hw_detect *sc_hwinfo;
+       unsigned int    sc_invalid:1;           /* being detached */
+       unsigned int    sc_mrretry:1;           /* multi-rate retry support */
+@@ -683,6 +689,7 @@ struct ath_softc {
+       const HAL_RATE_TABLE *sc_quarter_rates; /* quarter rate table */
+       HAL_OPMODE sc_opmode;                   /* current hal operating mode */
+       enum ieee80211_phymode sc_curmode;      /* current phy mode */
++      u_int sc_poweroffset;                   /* hardware power offset */
+       u_int16_t sc_curtxpow;                  /* current tx power limit */
+       u_int16_t sc_curaid;                    /* current association id */
+       HAL_CHANNEL sc_curchan;                 /* current h/w channel */
+@@ -929,4 +936,16 @@ int ar_device(int devid);
+ void ath_radar_detected(struct ath_softc *sc, const char* message);
++struct ath_hw_detect {
++      const char *vendor_name;
++      const char *card_name;
++      u32 vendor;
++      u32 id;
++      u32 subvendor;
++      u32 subid;
++      u32 poweroffset;
++};
++
++extern void ath_hw_detect(struct ath_softc *sc, const struct ath_hw_detect *cards, int n_cards, u32 vendor, u32 id, u32 subvendor, u32 subid);
++
+ #endif /* _DEV_ATH_ATHVAR_H */
+--- a/ath/if_ath_ahb.c
++++ b/ath/if_ath_ahb.c
+@@ -20,6 +20,7 @@
+ #include <linux/netdevice.h>
+ #include <linux/cache.h>
+ #include <linux/platform_device.h>
++#include <linux/pci.h>
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+@@ -181,12 +182,32 @@ exit_ath_wmac(u_int16_t wlanNum, struct
+       return 0;
+ }
++static const char ubnt[] = "Ubiquiti Networks";
++/* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */
++static const struct ath_hw_detect cards[] = {
++      { ubnt, "PowerStation2 (18V)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb102 },
++      { ubnt, "PowerStation2 (16D)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb202 },
++      { ubnt, "PowerStation2 (EXT)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb302 },
++      { ubnt, "PowerStation5 (22V)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb105 },
++      { ubnt, "PowerStation5 (EXT)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb305 },
++      { ubnt, "WispStation5",        PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa105 },
++      { ubnt, "LiteStation2",        PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa002 },
++      { ubnt, "LiteStation5",        PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa005 },
++      { ubnt, "NanoStation2",        PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc002 },
++      { ubnt, "NanoStation5",        PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc005 },
++      { ubnt, "NanoStation Loco2",   PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc102 },
++      { ubnt, "NanoStation Loco5",   PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc105 },
++      { ubnt, "Bullet2",             PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc202 },
++      { ubnt, "Bullet5",             PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc205 },
++};
++
+ static int
+ init_ath_wmac(u_int16_t devid, u_int16_t wlanNum, struct ar531x_config *config)
+ {
+       const char *athname;
+       struct net_device *dev;
+       struct ath_ahb_softc *sc;
++      u16 *radio_data;
+       if (((wlanNum != 0) && (wlanNum != 1)) ||
+               (sclist[wlanNum] != NULL))
+@@ -248,6 +269,16 @@ init_ath_wmac(u_int16_t devid, u_int16_t
+       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);
++      }
++
+       return 0;
+  bad4:
+--- a/ath/if_ath_pci.c
++++ b/ath/if_ath_pci.c
+@@ -123,6 +123,33 @@ static u16 ath_devidmap[][2] = {
+       { 0xff1a, 0x001a }
+ };
++static const char ubnt[] = "Ubiquiti Networks";
++/* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */
++static const struct ath_hw_detect cards[] = {
++      { ubnt, "XR2",     0x168c, 0x001b, 0x0777, 0x3002, 10 },
++      { ubnt, "XR2",     0x168c, 0x001b, 0x7777, 0x3002, 10 },
++      { ubnt, "XR2.3",   0x168c, 0x001b, 0x0777, 0x3b02, 10 },
++      { ubnt, "XR2.6",   0x168c, 0x001b, 0x0777, 0x3c02, 10 },
++      { ubnt, "XR3-2.8", 0x168c, 0x001b, 0x0777, 0x3b03, 10 },
++      { ubnt, "XR3-3.6", 0x168c, 0x001b, 0x0777, 0x3c03, 10 },
++      { ubnt, "XR3",     0x168c, 0x001b, 0x0777, 0x3003, 10 },
++      { ubnt, "XR4",     0x168c, 0x001b, 0x0777, 0x3004, 10 },
++      { ubnt, "XR5",     0x168c, 0x001b, 0x0777, 0x3005, 10 },
++      { ubnt, "XR5",     0x168c, 0x001b, 0x7777, 0x3005, 10 },
++      { ubnt, "XR7",     0x168c, 0x001b, 0x0777, 0x3007, 10 },
++      { ubnt, "XR9",     0x168c, 0x001b, 0x0777, 0x3009, 10 },
++      { ubnt, "SRC",     0x168c, 0x0013, 0x168c, 0x1042, 1 },
++      { ubnt, "SR2",     0x168c, 0x0013, 0x0777, 0x2041, 10 },
++      { ubnt, "SR4",     0x168c, 0x0013, 0x0777, 0x2004, 6 },
++      { ubnt, "SR4",     0x168c, 0x0013, 0x7777, 0x2004, 6 },
++      { ubnt, "SR4C",    0x168c, 0x0013, 0x0777, 0x1004, 6 },
++      { ubnt, "SR4C",    0x168c, 0x0013, 0x7777, 0x1004, 6 },
++      { ubnt, "SR5",     0x168c, 0x0013, 0x168c, 0x2042, 7 },
++      { ubnt, "SR9",     0x168c, 0x0013, 0x7777, 0x2009, 12 },
++      { ubnt, "SR71A",   0x168c, 0x0027, 0x168c, 0x2082, 10 },
++      { ubnt, "SR71",    0x168c, 0x0027, 0x0777, 0x4082, 10 },
++};
++
+ static int
+ ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
+@@ -257,6 +284,10 @@ ath_pci_probe(struct pci_dev *pdev, cons
+       printk(KERN_INFO "%s: %s: %s: mem=0x%lx, irq=%d\n",
+               dev_info, dev->name, athname ? athname : "Atheros ???", phymem, dev->irq);
++      ath_hw_detect(&sc->aps_sc, cards, ARRAY_SIZE(cards),
++              pdev->vendor, pdev->device,
++              pdev->subsystem_vendor, pdev->subsystem_device);
++
+       /* ready to process interrupts */
+       sc->aps_sc.sc_invalid = 0;
diff --git a/net/madwifi/patches/385-antenna_fix.patch b/net/madwifi/patches/385-antenna_fix.patch
new file mode 100644 (file)
index 0000000..16c7d95
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6669,6 +6669,7 @@ ath_setdefantenna(struct ath_softc *sc,
+       struct ath_hal *ah = sc->sc_ah;
+       /* XXX block beacon interrupts */
++      ath_hal_setdiversity(ah, (sc->sc_diversity != 0));
+       ath_hal_setdefantenna(ah, antenna);
+       if (sc->sc_defant != antenna)
+               sc->sc_stats.ast_ant_defswitch++;
diff --git a/net/madwifi/patches/386-acl_crashfix.patch b/net/madwifi/patches/386-acl_crashfix.patch
new file mode 100644 (file)
index 0000000..04a1ec9
--- /dev/null
@@ -0,0 +1,116 @@
+fixes ACL race condition caused by acl list modifications at run time
+
+Signed-off-by: Sebastian Gottschall <brainslayer@dd-wrt.com>
+
+--- a/net80211/ieee80211_acl.c
++++ b/net80211/ieee80211_acl.c
+@@ -112,9 +112,9 @@ acl_detach(struct ieee80211vap *vap)
+ {
+       struct aclstate *as = vap->iv_as;
+-      ACL_LOCK(as);
++      ACL_LOCK_IRQ(as);
+       acl_free_all_locked(as);
+-      ACL_UNLOCK(as);
++      ACL_UNLOCK_IRQ(as);
+       vap->iv_as = NULL;
+       ACL_LOCK_DESTROY(as);
+       FREE(as, M_DEVBUF);
+@@ -128,11 +128,18 @@ _find_acl(struct aclstate *as, const u_i
+       struct acl *acl;
+       int hash;
++      /* locking needed, as inserts are not atomic */
++      ACL_LOCK_IRQ(as);
+       hash = ACL_HASH(macaddr);
+       LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
+-              if (IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
+-                      return acl;
++              if (!IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
++                      continue;
++
++              ACL_UNLOCK_IRQ_EARLY(as);
++              return acl;
+       }
++      ACL_UNLOCK_IRQ(as);
++
+       return NULL;
+ }
+@@ -176,11 +183,11 @@ acl_add(struct ieee80211vap *vap, const
+               return -ENOMEM;
+       }
+-      ACL_LOCK(as);
++      ACL_LOCK_IRQ(as);
+       hash = ACL_HASH(mac);
+       LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
+               if (IEEE80211_ADDR_EQ(acl->acl_macaddr, mac)) {
+-                      ACL_UNLOCK_EARLY(as);
++                      ACL_UNLOCK_IRQ_EARLY(as);
+                       FREE(new, M_80211_ACL);
+                       IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
+                               "ACL: add " MAC_FMT " failed, already present\n",
+@@ -191,7 +198,7 @@ acl_add(struct ieee80211vap *vap, const
+       IEEE80211_ADDR_COPY(new->acl_macaddr, mac);
+       TAILQ_INSERT_TAIL(&as->as_list, new, acl_list);
+       LIST_INSERT_HEAD(&as->as_hash[hash], new, acl_hash);
+-      ACL_UNLOCK(as);
++      ACL_UNLOCK_IRQ(as);
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
+               "ACL: add " MAC_FMT "\n", MAC_ADDR(mac));
+@@ -204,11 +211,11 @@ acl_remove(struct ieee80211vap *vap, con
+       struct aclstate *as = vap->iv_as;
+       struct acl *acl;
+-      ACL_LOCK(as);
++      ACL_LOCK_IRQ(as);
+       acl = _find_acl(as, mac);
+       if (acl != NULL)
+               _acl_free(as, acl);
+-      ACL_UNLOCK(as);
++      ACL_UNLOCK_IRQ(as);
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
+               "ACL: remove " MAC_FMT "%s\n", MAC_ADDR(mac),
+@@ -235,9 +242,9 @@ acl_free_all(struct ieee80211vap *vap)
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL, "ACL: %s\n", "free all");
+-      ACL_LOCK(as);
++      ACL_LOCK_IRQ(as);
+       acl_free_all_locked(vap->iv_as);
+-      ACL_UNLOCK(as);
++      ACL_UNLOCK_IRQ(as);
+       return 0;
+ }
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -319,16 +319,15 @@ typedef spinlock_t ieee80211_scan_lock_t
+ typedef spinlock_t acl_lock_t;
+ #define       ACL_LOCK_INIT(_as, _name)       spin_lock_init(&(_as)->as_lock)
+ #define       ACL_LOCK_DESTROY(_as)
+-#define       ACL_LOCK(_as)                   do {    \
+-      ACL_LOCK_CHECK(_as);            \
+-      spin_lock(&(_as)->as_lock);
+-#define       ACL_UNLOCK(_as)                         \
+-      ACL_LOCK_ASSERT(_as);                   \
+-      spin_unlock(&(_as)->as_lock);           \
+-} while(0)
+-#define ACL_UNLOCK_EARLY(_as)                 \
+-      ACL_LOCK_ASSERT(_as);                   \
+-      spin_unlock(&(_as)->as_lock);
++#define       ACL_LOCK_IRQ(_as)       do {    \
++      unsigned long __acl_lockflags;          \
++      spin_lock_irqsave(&(_as)->as_lock, __acl_lockflags);
++#define       ACL_UNLOCK_IRQ(_as) \
++      spin_unlock_irqrestore(&(_as)->as_lock, __acl_lockflags); \
++} while (0)
++#define       ACL_UNLOCK_IRQ_EARLY(_as)       do { \
++      spin_unlock_irqrestore(&(_as)->as_lock, __acl_lockflags); \
++} while (0)
+ #if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked)
+ #define       ACL_LOCK_ASSERT(_as) \
diff --git a/net/madwifi/patches/387-maxassoc.patch b/net/madwifi/patches/387-maxassoc.patch
new file mode 100644 (file)
index 0000000..79e5b2f
--- /dev/null
@@ -0,0 +1,85 @@
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -198,6 +198,7 @@ struct ieee80211vap {
+       u_int32_t iv_debug;                             /* debug msg flags */
+       struct ieee80211_stats iv_stats;                /* statistics */
++      int iv_max_nodes;
+       int iv_monitor_nods_only;                       /* in monitor mode only nods traffic */
+       int iv_monitor_txf_len;                         /* in monitor mode, truncate tx packets */
+       int iv_monitor_phy_errors;                      /* in monitor mode, accept phy errors */
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -650,6 +650,7 @@ enum {
+       IEEE80211_PARAM_RSSI_DIS_THR    = 80,   /* rssi threshold for disconnection */
+       IEEE80211_PARAM_RSSI_DIS_COUNT  = 81,   /* counter for rssi threshold */
+       IEEE80211_PARAM_WDS_SEP                 = 82,   /* move wds stations into separate interfaces */
++      IEEE80211_PARAM_MAXASSOC                = 83,   /* maximum associated stations */
+ };
+ #define       SIOCG80211STATS                 (SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2875,6 +2875,12 @@ ieee80211_ioctl_setparam(struct net_devi
+               else
+                       vap->iv_flags_ext &= ~IEEE80211_FEXT_WDSSEP;
+               break;
++      case IEEE80211_PARAM_MAXASSOC:
++              if (vap->iv_opmode != IEEE80211_M_HOSTAP)
++                      retv = -EINVAL;
++              else
++                      vap->iv_max_nodes = value;
++              break;
+ #ifdef ATH_REVERSE_ENGINEERING
+       case IEEE80211_PARAM_DUMPREGS:
+               ieee80211_dump_registers(dev, info, w, extra);
+@@ -3234,6 +3240,9 @@ ieee80211_ioctl_getparam(struct net_devi
+       case IEEE80211_PARAM_WDS_SEP:
+               param[0] = !!(vap->iv_flags_ext & IEEE80211_FEXT_WDSSEP);
+               break;
++      case IEEE80211_PARAM_MAXASSOC:
++              param[0] = vap->iv_max_nodes;
++              break;
+       default:
+               return -EOPNOTSUPP;
+       }
+@@ -5789,6 +5798,10 @@ static const struct iw_priv_args ieee802
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wdssep"},
+       { IEEE80211_PARAM_WDS_SEP,
+        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_wdssep"},
++      { IEEE80211_PARAM_MAXASSOC,
++       IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maxassoc"},
++      { IEEE80211_PARAM_MAXASSOC,
++       0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_maxassoc"},
+ #ifdef ATH_REVERSE_ENGINEERING
+       /*
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -4020,7 +4020,26 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                       vap->iv_stats.is_rx_assoc_norate++;
+                       return;
+               }
++              if (vap->iv_max_nodes > 0) {
++                      unsigned int active_nodes = 0;
++                      struct ieee80211_node *tni;
++                      IEEE80211_NODE_TABLE_LOCK_IRQ(&ic->ic_sta);
++                      TAILQ_FOREACH(tni, &ic->ic_sta.nt_node, ni_list) {
++                              if (tni->ni_vap != vap)
++                                      continue;
++                              if (tni->ni_associd == 0)
++                                      continue;
++                              active_nodes++;
++                      }
++                      IEEE80211_NODE_TABLE_UNLOCK_IRQ(&ic->ic_sta);
++
++                      if (active_nodes >= vap->iv_max_nodes) {
++                              /* too many nodes connected */
++                              ieee80211_node_leave(ni);
++                              return;
++                      }
++              }
+               if (ni->ni_associd != 0 &&
+                   IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) {
+                       if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
diff --git a/net/madwifi/patches/388-apsta_fix.patch b/net/madwifi/patches/388-apsta_fix.patch
new file mode 100644 (file)
index 0000000..b0cb8e9
--- /dev/null
@@ -0,0 +1,60 @@
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -1415,7 +1415,8 @@ __ieee80211_newstate(struct ieee80211vap
+       vap->iv_state = nstate;                 /* state transition */
+       del_timer(&vap->iv_mgtsend);
+       if ((vap->iv_opmode != IEEE80211_M_HOSTAP) && 
+-                      (ostate != IEEE80211_S_SCAN))
++                      (ostate != IEEE80211_S_SCAN) &&
++                      !(vap->iv_flags_ext & IEEE80211_FEXT_SCAN_PENDING))
+               ieee80211_cancel_scan(vap);     /* background scan */
+       ni = vap->iv_bss;                       /* NB: no reference held */
+       switch (nstate) {
+@@ -1457,7 +1458,8 @@ __ieee80211_newstate(struct ieee80211vap
+                       }
+                       goto reset;
+               case IEEE80211_S_SCAN:
+-                      ieee80211_cancel_scan(vap);
++                      if (!(vap->iv_flags_ext & IEEE80211_FEXT_SCAN_PENDING))
++                              ieee80211_cancel_scan(vap);
+                       goto reset;
+               reset:
+                       ieee80211_reset_bss(vap);
+@@ -1995,7 +1997,9 @@ ieee80211_newstate(struct ieee80211vap *
+                                       }
+                               }
+                       }
+-              } else if (dstate == IEEE80211_S_SCAN) {
++              } else if ((dstate == IEEE80211_S_SCAN) ||
++                              (dstate == IEEE80211_S_AUTH) ||
++                              (dstate == IEEE80211_S_ASSOC)) {
+                       /* Force to scan pending... someone is scanning */
+                       vap->iv_flags_ext |= IEEE80211_FEXT_SCAN_PENDING;
+                       __ieee80211_newstate(vap, IEEE80211_S_INIT, arg);
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -238,7 +238,9 @@ ieee80211_hardstart(struct sk_buff *skb,
+       }
+       
+       /* Cancel any running BG scan */
+-      if (!(ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN_THR) && (vap->iv_state == IEEE80211_S_RUN))
++      if (!(ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN_THR) &&
++              (vap->iv_state == IEEE80211_S_RUN) &&
++              (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN))
+               ieee80211_cancel_scan(vap);
+       /* 
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2728,9 +2728,9 @@ ieee80211_ioctl_setparam(struct net_devi
+                               return -EINVAL;
+                       vap->iv_flags |= IEEE80211_F_BGSCAN;
+               } else {
+-                      /* XXX racey? */
++                      if (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN)
++                              ieee80211_cancel_scan(vap);     /* anything current */
+                       vap->iv_flags &= ~IEEE80211_F_BGSCAN;
+-                      ieee80211_cancel_scan(vap);     /* anything current */
+               }
+               break;
+       case IEEE80211_PARAM_BGSCAN_IDLE:
diff --git a/net/madwifi/patches/389-autochannel.patch b/net/madwifi/patches/389-autochannel.patch
new file mode 100644 (file)
index 0000000..548f09e
--- /dev/null
@@ -0,0 +1,249 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -384,6 +384,7 @@ static u_int32_t ath_get_real_maxtxpower
+ static void ath_poll_disable(struct net_device *dev);
+ static void ath_poll_enable(struct net_device *dev);
++static void ath_fetch_idle_time(struct ath_softc *sc);
+ /* calibrate every 30 secs in steady state but check every second at first. */
+ static int ath_calinterval = ATH_SHORT_CALINTERVAL;
+@@ -2581,6 +2582,7 @@ ath_init(struct net_device *dev)
+        * be followed by initialization of the appropriate bits
+        * and then setup of the interrupt mask.
+        */
++      ath_fetch_idle_time(sc);
+       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)) {
+@@ -2914,6 +2916,48 @@ ath_hw_check_atim(struct ath_softc *sc,
+       return 0;
+ }
++#define AR5K_MIBC       0x0040
++#define AR5K_MIBC_FREEZE   (1 << 1)
++#define AR5K_TXFC       0x80ec
++#define AR5K_RXFC       0x80f0
++#define AR5K_RXCLEAR  0x80f4
++#define AR5K_CYCLES           0x80f8
++static void
++ath_fetch_idle_time(struct ath_softc *sc)
++{
++      struct ieee80211com *ic = &sc->sc_ic;
++      struct ath_hal *ah = sc->sc_ah;
++      u_int32_t cc, rx;
++      u_int32_t time = 0;
++
++      if (sc->sc_ah->ah_macType < 5212)
++              return;
++
++      if (!ic->ic_curchan || (ic->ic_curchan == IEEE80211_CHAN_ANYC))
++              return;
++
++      OS_REG_WRITE(ah, AR5K_MIBC, AR5K_MIBC_FREEZE);
++      rx = OS_REG_READ(ah, AR5K_RXCLEAR);
++      cc = OS_REG_READ(ah, AR5K_CYCLES);
++
++      if (!cc)
++              return;
++
++      if (rx > cc)
++              return; /* should not happen */
++
++      if (sc->sc_last_chan)
++              sc->sc_last_chan->ic_idletime = 100 * (cc - rx) / cc;
++      sc->sc_last_chan = ic->ic_curchan;
++
++      OS_REG_WRITE(ah, AR5K_RXCLEAR, 0);
++      OS_REG_WRITE(ah, AR5K_CYCLES, 0);
++      OS_REG_WRITE(ah, AR5K_TXFC, 0);
++      OS_REG_WRITE(ah, AR5K_RXFC, 0);
++      OS_REG_WRITE(ah, AR5K_MIBC, 0);
++}
++#undef AR5K_RXCLEAR
++#undef AR5K_CYCLES
+ /*
+  * Reset the hardware w/o losing operational state.  This is
+@@ -2941,6 +2985,7 @@ ath_reset(struct net_device *dev)
+        * Convert to a HAL channel description with the flags
+        * constrained to reflect the current operating mode.
+        */
++      ath_fetch_idle_time(sc);
+       c = ic->ic_curchan;
+       sc->sc_curchan.channel = c->ic_freq;
+       sc->sc_curchan.channelFlags = ath_chan2flags(c);
+@@ -9023,6 +9068,7 @@ ath_chan_set(struct ath_softc *sc, struc
+       u_int8_t channel_change_required = 0;
+       struct timeval tv;
++
+       /*
+        * Convert to a HAL channel description with
+        * the flags constrained to reflect the current
+@@ -9031,6 +9077,14 @@ ath_chan_set(struct ath_softc *sc, struc
+       memset(&hchan, 0, sizeof(HAL_CHANNEL));
+       hchan.channel = chan->ic_freq;
+       hchan.channelFlags = ath_chan2flags(chan);
++
++      /* don't do duplicate channel changes, but do
++       * store the available idle time */
++      ath_fetch_idle_time(sc);
++      if ((sc->sc_curchan.channel == hchan.channel) &&
++              (sc->sc_curchan.channelFlags == hchan.channelFlags))
++              return 0;
++
+       KASSERT(hchan.channel != 0,
+               ("bogus channel %u/0x%x", hchan.channel, hchan.channelFlags));
+       do_gettimeofday(&tv);
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -774,6 +774,7 @@ struct ath_softc {
+       struct ieee80211vap **sc_bslot;         /* beacon xmit slots */
+       int sc_bnext;                           /* next slot for beacon xmit */
++      struct ieee80211_channel *sc_last_chan;
+       int sc_beacon_cal;                      /* use beacon timer for calibration */
+       u_int64_t sc_lastcal;                   /* last time the calibration was performed */
+       struct timer_list sc_cal_ch;            /* calibration timer */
+--- a/net80211/_ieee80211.h
++++ b/net80211/_ieee80211.h
+@@ -148,6 +148,7 @@ struct ieee80211_channel {
+       int8_t ic_maxpower;     /* maximum tx power in dBm */
+       int8_t ic_minpower;     /* minimum tx power in dBm */
+       u_int8_t ic_scanflags;
++      u_int8_t ic_idletime; /* phy idle time in % */
+ };
+ #define       IEEE80211_CHAN_MAX      255
+--- a/net80211/ieee80211_scan_ap.c
++++ b/net80211/ieee80211_scan_ap.c
+@@ -417,6 +417,19 @@ pc_cmp_rssi(struct ap_state *as, struct
+ /* This function must be invoked with locks acquired */
+ static int
++pc_cmp_idletime(struct ieee80211_channel *a,
++              struct ieee80211_channel *b)
++{
++      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;
++}
++
++
++/* This function must be invoked with locks acquired */
++static int
+ pc_cmp_samechan(struct ieee80211com *ic, struct ieee80211_channel *a,
+               struct ieee80211_channel *b)
+ {
+@@ -451,6 +464,7 @@ pc_cmp(const void *_a, const void *_b)
+       EVALUATE_CRITERION(radar, a, b);
+       EVALUATE_CRITERION(keepmode, params, a, b);
++      EVALUATE_CRITERION(idletime, a, b);
+       EVALUATE_CRITERION(sc, ic, a, b);
+       /* XXX: rssi useless? pick_channel evaluates it anyway */
+       EVALUATE_CRITERION(rssi, params->ss->ss_priv, a, b);
+@@ -519,16 +533,9 @@ pick_channel(struct ieee80211_scan_state
+ #endif
+       best = NULL;
+-      best_rssi = 0xff; /* If signal is bigger than 0xff, we'd be melting. */
+       for (i = 0; i < ss_last; i++) {
+               c = &chans[i];
+-              benefit = best_rssi - as->as_maxrssi[c->chan->ic_ieee];
+-              sta_assoc = ic->ic_sta_assoc;
+-
+-              /* Don't switch... */
+-              if (benefit <= 0)
+-                      continue;
+               /* Verify channel is not marked for non-occupancy */
+               if (IEEE80211_IS_CHAN_RADAR(c->chan))
+@@ -546,31 +553,8 @@ pick_channel(struct ieee80211_scan_state
+                               break;
+               }
+-              if (sta_assoc != 0) {
+-                      int sl = ic->ic_cn_total - 
+-                              ic->ic_chan_nodes[c->chan->ic_ieee]; /* count */
+-                      if (ic->ic_sc_algorithm == IEEE80211_SC_LOOSE) {
+-                              int sl_max = ic->ic_sc_sldg * benefit;
+-                              sl = 1000 * sl / sta_assoc; /* permil */
+-                              IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+-                                              "%s: chan %d, dB gained: %d, "
+-                                              "STAs lost: %d permil (max %d)\n",
+-                                              __func__, c->chan->ic_ieee, 
+-                                              benefit, sl, sl_max);
+-                              if (sl > sl_max)
+-                                      continue;
+-                      } else if (((ic->ic_sc_algorithm == 
+-                                               IEEE80211_SC_TIGHT) ||
+-                                      (ic->ic_sc_algorithm == 
+-                                               IEEE80211_SC_STRICT)) && 
+-                                      (sl > 0)) {
+-                              /* Break the loop as the subsequent chans 
+-                               * won't be better. */
+-                              break;
+-                      }
+-              }
+               best = c->chan;
+-              best_rssi = as->as_maxrssi[best->ic_ieee];
++              break;
+       }
+       if (best != NULL) {
+@@ -599,6 +583,9 @@ ap_end(struct ieee80211_scan_state *ss,
+               ("wrong opmode %u", vap->iv_opmode));
+       ic = vap->iv_ic;
++
++      /* record stats for the channel that was scanned last */
++      ic->ic_set_channel(ic);
+       bestchan = pick_channel(ss, vap, flags);
+       if (bestchan == NULL) {
+               if (ss->ss_last > 0) {
+--- a/net80211/ieee80211_scan.c
++++ b/net80211/ieee80211_scan.c
+@@ -1002,20 +1002,34 @@ ieee80211_scan_add_channels(struct ieee8
+ {
+       struct ieee80211_channel *c, *cg;
+       u_int modeflags;
++      int has_non_turbo = 0;
+       int i;
+       KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
+       modeflags = chanflags[mode];
+       for (i = 0; i < ic->ic_nchans; i++) {
+               c = &ic->ic_channels[i];
++              if (c->ic_flags & (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO))
++                      continue;
++
++              has_non_turbo = 1;
++              break;
++      }
++      for (i = 0; i < ic->ic_nchans; i++) {
++              c = &ic->ic_channels[i];
+               if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))
+                       continue;
+               if (c->ic_scanflags & IEEE80211_NOSCAN_SET)
+                       continue;
+-              if (modeflags &&
+-                      ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
+-                       (modeflags & IEEE80211_CHAN_ALLTURBO)))
+-                      continue;
++              if (modeflags) {
++                      if ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
++                               (modeflags & IEEE80211_CHAN_ALLTURBO))
++                              continue;
++              } else if (has_non_turbo) {
++                      if ((ss->ss_vap->iv_opmode == IEEE80211_M_HOSTAP) &&
++                              (c->ic_flags & (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)))
++                              continue;
++              }
+               if (mode == IEEE80211_MODE_AUTO) {
+                       /*
+                        * XXX special-case 11b/g channels so we select
diff --git a/net/madwifi/patches/390-frame_type.patch b/net/madwifi/patches/390-frame_type.patch
new file mode 100644 (file)
index 0000000..6de0110
--- /dev/null
@@ -0,0 +1,13 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -4443,7 +4443,9 @@ ath_eth_type_trans(struct sk_buff *skb,
+               if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
+                       skb->pkt_type = PACKET_OTHERHOST;
+-      return eth->h_proto;
++      if ((ntohs(eth->h_proto) >= 1536) || (ntohs(eth->h_proto) < 38))
++              return eth->h_proto;
++      return htons(ETH_P_802_2);
+ }
+ #endif
diff --git a/net/madwifi/patches/391-vap_auth.patch b/net/madwifi/patches/391-vap_auth.patch
new file mode 100644 (file)
index 0000000..832f9e1
--- /dev/null
@@ -0,0 +1,29 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1375,7 +1375,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;
+@@ -1763,6 +1763,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)) {   \
+@@ -1777,6 +1779,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/net/madwifi/patches/392-remove_wds_nodetracking.patch b/net/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/net/madwifi/patches/393-mbss_vap_auth.patch b/net/madwifi/patches/393-mbss_vap_auth.patch
new file mode 100644 (file)
index 0000000..a2637cc
--- /dev/null
@@ -0,0 +1,491 @@
+--- 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,12 @@ 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);
++              if (ni)
++                      ieee80211_unref_node(&ni);
+       }
++
++out:
+       if (skb != NULL)                /* no vaps, reclaim skb */
+               ieee80211_dev_kfree_skb(&skb);
+       return type;
+@@ -1147,11 +1158,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) {
+@@ -3520,6 +3529,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                                (vap->iv_opmode == IEEE80211_M_WDS)) &&
+                               (scan.capinfo & IEEE80211_CAPINFO_ESS))) {
+                       struct ieee80211vap *avp = NULL;
++                      int do_unref = 0;
+                       int found = 0;
+                       IEEE80211_LOCK_IRQ(vap->iv_ic);
+@@ -3553,10 +3563,12 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                                       ni->ni_associd |= 0xc000;
+                                       avp->iv_wdsnode = ieee80211_ref_node(ni);
+                                       IEEE80211_UNLOCK_IRQ(ic);
+-                              } else if (vap->iv_opmode == IEEE80211_M_IBSS) {
++                              } else if ((vap->iv_opmode == IEEE80211_M_IBSS) &&
++                                         IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid)) {
+                                       /* Create a new entry in the neighbor table. */
+                                       ni = ieee80211_add_neighbor(vap, wh, &scan);
+                               }
++                              do_unref = 1;
+                       } else {
+                               /*
+                                * Copy data from beacon to neighbor table.
+@@ -3595,6 +3607,8 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                               ni->ni_rssi = rssi;
+                               ni->ni_rtsf = rtsf;
+                               ni->ni_last_rx = jiffies;
++                              if (do_unref)
++                                      ieee80211_unref_node(&ni);
+                       }
+               }
+               break;
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6589,9 +6589,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");
+@@ -6746,7 +6745,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;
+@@ -6901,12 +6902,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);
+@@ -6968,11 +6972,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);
+@@ -6981,24 +6998,39 @@ 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:
++                      if (IEEE80211_IS_MULTICAST(wh->i_addr1))
++                              vap = NULL;
++                      else
++                              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 */
diff --git a/net/madwifi/patches/394-probereq.patch b/net/madwifi/patches/394-probereq.patch
new file mode 100644 (file)
index 0000000..706d5a5
--- /dev/null
@@ -0,0 +1,64 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3621,6 +3621,8 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                       vap->iv_stats.is_rx_mgtdiscard++;
+                       return;
+               }
++              if (vap->iv_no_probereq)
++                      return;
+               if (IEEE80211_IS_MULTICAST(wh->i_addr2)) {
+                       /* frame must be directed */
+                       vap->iv_stats.is_rx_mgtdiscard++;       /* XXX: stat */
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -651,6 +651,7 @@ enum {
+       IEEE80211_PARAM_RSSI_DIS_COUNT  = 81,   /* counter for rssi threshold */
+       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 */
+ };
+ #define       SIOCG80211STATS                 (SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -198,6 +198,7 @@ struct ieee80211vap {
+       u_int32_t iv_debug;                             /* debug msg flags */
+       struct ieee80211_stats iv_stats;                /* statistics */
++      int iv_no_probereq;
+       int iv_max_nodes;
+       int iv_monitor_nods_only;                       /* in monitor mode only nods traffic */
+       int iv_monitor_txf_len;                         /* in monitor mode, truncate tx packets */
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2881,6 +2881,9 @@ ieee80211_ioctl_setparam(struct net_devi
+               else
+                       vap->iv_max_nodes = value;
+               break;
++      case IEEE80211_PARAM_PROBEREQ:
++              vap->iv_no_probereq = !value;
++              break;
+ #ifdef ATH_REVERSE_ENGINEERING
+       case IEEE80211_PARAM_DUMPREGS:
+               ieee80211_dump_registers(dev, info, w, extra);
+@@ -3243,6 +3246,9 @@ ieee80211_ioctl_getparam(struct net_devi
+       case IEEE80211_PARAM_MAXASSOC:
+               param[0] = vap->iv_max_nodes;
+               break;
++      case IEEE80211_PARAM_PROBEREQ:
++              param[0] = !vap->iv_no_probereq;
++              break;
+       default:
+               return -EOPNOTSUPP;
+       }
+@@ -5802,6 +5808,10 @@ static const struct iw_priv_args ieee802
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maxassoc"},
+       { IEEE80211_PARAM_MAXASSOC,
+        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_maxassoc"},
++      { IEEE80211_PARAM_PROBEREQ,
++       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"},
+ #ifdef ATH_REVERSE_ENGINEERING
+       /*
diff --git a/net/madwifi/patches/395-ath_ff_unmap.patch b/net/madwifi/patches/395-ath_ff_unmap.patch
new file mode 100644 (file)
index 0000000..85ddc7b
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -13534,7 +13534,7 @@ cleanup_ath_buf(struct ath_softc *sc, st
+                               bus_unmap_single(
+                                       sc->sc_bdev,
+                                       bf->bf_skbaddrff[i], 
+-                                      (direction == BUS_DMA_TODEVICE ? 
++                                      (direction == BUS_DMA_FROMDEVICE ? 
+                                        sc->sc_rxbufsize : ffskb->len), 
+                                       direction);
+                               bf->bf_skbaddrff[i] = 0;
diff --git a/net/madwifi/patches/396-napi_ff_fix.patch b/net/madwifi/patches/396-napi_ff_fix.patch
new file mode 100644 (file)
index 0000000..ca35d4c
--- /dev/null
@@ -0,0 +1,65 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6734,10 +6734,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;
+@@ -6780,13 +6780,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) {
+@@ -7074,8 +7076,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
+@@ -1206,6 +1206,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/net/madwifi/patches/400-new_hal.patch b/net/madwifi/patches/400-new_hal.patch
new file mode 100644 (file)
index 0000000..12a5968
--- /dev/null
@@ -0,0 +1,153 @@
+--- 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 */
++#if defined(CONFIG_ATHEROS_AR71XX) || defined(CONFIG_ATH79)
++      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
+@@ -7568,7 +7576,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
+--- a/ath/if_ath_hal.h
++++ b/ath/if_ath_hal.h
+@@ -778,17 +778,6 @@ static inline HAL_STATUS ath_hal_getcapa
+       return ret;
+ }
+-static inline HAL_BOOL ath_hal_radar_wait(struct ath_hal *ah, HAL_CHANNEL *a1)
+-{
+-      HAL_BOOL ret;
+-      ATH_HAL_LOCK_IRQ(ah->ah_sc);
+-      ath_hal_set_function(__func__);
+-      ret = ah->ah_radarWait(ah, a1);
+-      ath_hal_set_function(NULL);
+-      ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
+-      return ret;
+-}
+-
+ static inline HAL_BOOL ath_hal_setmcastfilterindex(struct ath_hal *ah,
+                                                  u_int32_t index)
+ {
+@@ -1268,8 +1257,6 @@ static inline void ath_hal_dump_map(stru
+       /* HAL_STATUS ah_getCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE a1, u_int32_t capability, u_int32_t *result) */
+       __print_symbol("%s=ah_getCapability\n",
+                      (unsigned long)ah->ah_getCapability);
+-      /* HAL_BOOL ah_radarWait(struct ath_hal *ah, HAL_CHANNEL *a1) */
+-      __print_symbol("%s=ah_radarWait\n", (unsigned long)ah->ah_radarWait);
+       /* HAL_BOOL ah_setMulticastFilterIndex(struct ath_hal *ah, u_int32_t index) */
+       __print_symbol("%s=ah_setMulticastFilterIndex\n",
+                      (unsigned long)ah->ah_setMulticastFilterIndex);
diff --git a/net/madwifi/patches/401-changeset_r3602.patch b/net/madwifi/patches/401-changeset_r3602.patch
new file mode 100644 (file)
index 0000000..cf9c879
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -348,6 +348,8 @@ typedef spinlock_t acl_lock_t;
+ /* __skb_append got a third parameter in 2.6.14 */
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+ #define __skb_append(a,b,c)   __skb_append(a, b)
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
++#define __skb_append(a,b,c)   __skb_queue_after(c, a, b)
+ #endif
+ /*
diff --git a/net/madwifi/patches/402-changeset_r3603.patch b/net/madwifi/patches/402-changeset_r3603.patch
new file mode 100644 (file)
index 0000000..92f6e6e
--- /dev/null
@@ -0,0 +1,176 @@
+--- a/Makefile
++++ b/Makefile
+@@ -40,10 +40,7 @@
+ # Makefile for the HAL-based Atheros driver.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)
+ ifneq (svnversion.h,$(MAKECMDGOALS))
+--- a/ath/Makefile
++++ b/ath/Makefile
+@@ -40,10 +40,7 @@
+ # Makefile for the Atheros WLAN driver.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/..
+ ifeq ($(strip $(BUS)),AHB)
+--- a/ath_hal/Makefile
++++ b/ath_hal/Makefile
+@@ -40,10 +40,7 @@
+ # Makefile for the Atheros WLAN driver.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/..
+ include $(TOP)/Makefile.inc
+--- a/ath_rate/Makefile
++++ b/ath_rate/Makefile
+@@ -1,7 +1,4 @@
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/..
+ obj-y := amrr/ onoe/ sample/ minstrel/
+--- a/ath_rate/amrr/Makefile
++++ b/ath_rate/amrr/Makefile
+@@ -40,10 +40,7 @@
+ #
+ # Makefile for the Atheros Rate Control Support.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/../..
+ obj-m         += ath_rate_amrr.o
+--- a/ath_rate/minstrel/Makefile
++++ b/ath_rate/minstrel/Makefile
+@@ -38,10 +38,7 @@
+ #
+ # Makefile for the Atheros Rate Control Support.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/../..
+ obj-m         += ath_rate_minstrel.o
+--- a/ath_rate/onoe/Makefile
++++ b/ath_rate/onoe/Makefile
+@@ -40,10 +40,7 @@
+ #
+ # Makefile for the Atheros Rate Control Support.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/../..
+ obj-m         += ath_rate_onoe.o
+--- a/ath_rate/sample/Makefile
++++ b/ath_rate/sample/Makefile
+@@ -38,10 +38,7 @@
+ #
+ # Makefile for the Atheros Rate Control Support.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/../..
+ obj-m         += ath_rate_sample.o
+--- a/net80211/Makefile
++++ b/net80211/Makefile
+@@ -39,10 +39,7 @@
+ #
+ # Makefile for the 802.11 WLAN modules.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/..
+ #
+ # There is one authenticator mechanism: an in-kernel implementation
+--- a/regression/Makefile
++++ b/regression/Makefile
+@@ -1,7 +1,4 @@
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/..
+ obj-y := ccmp/ tkip/ wep/
+--- a/regression/ccmp/Makefile
++++ b/regression/ccmp/Makefile
+@@ -1,10 +1,7 @@
+ #
+ # Makefile for the CCMP regression test.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/../..
+ obj-m                 += ath_test_ccmp.o
+--- a/regression/tkip/Makefile
++++ b/regression/tkip/Makefile
+@@ -1,10 +1,7 @@
+ #
+ # Makefile for the TKIP regression test.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/../..
+ obj-m                 += ath_test_tkip.o
+--- a/regression/wep/Makefile
++++ b/regression/wep/Makefile
+@@ -1,10 +1,7 @@
+ #
+ # Makefile for the WEP regression test.
+ #
+-ifeq ($(obj),)
+-obj=  .
+-endif
+-
++obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/../..
+ obj-m                 += ath_test_wep.o
diff --git a/net/madwifi/patches/403-changeset_r3605.patch b/net/madwifi/patches/403-changeset_r3605.patch
new file mode 100644 (file)
index 0000000..57ce521
--- /dev/null
@@ -0,0 +1,70 @@
+--- a/include/compat.h
++++ b/include/compat.h
+@@ -182,6 +182,13 @@ static inline int timeval_compare(struct
+ #define DEV_ATH CTL_UNNUMBERED
+ #endif
++/* __skb_append got a third parameter in 2.6.14 */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
++#define __skb_queue_after(_list, _old, _new)  __skb_append(_old, _new)
++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
++#define __skb_queue_after(_list, _old, _new)  __skb_append(_old, _new, _list)
++#endif
++
+ #endif /* __KERNEL__ */
+ #endif /* _ATH_COMPAT_H_ */
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -345,13 +345,6 @@ typedef spinlock_t acl_lock_t;
+ #define       ACL_LOCK_CHECK(_as)
+ #endif
+-/* __skb_append got a third parameter in 2.6.14 */
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+-#define __skb_append(a,b,c)   __skb_append(a, b)
+-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+-#define __skb_append(a,b,c)   __skb_queue_after(c, a, b)
+-#endif
+-
+ /*
+  * Per-node power-save queue definitions.  Beware of control
+  * flow with IEEE80211_NODE_SAVEQ_LOCK/IEEE80211_NODE_SAVEQ_UNLOCK.
+@@ -395,16 +388,16 @@ typedef spinlock_t acl_lock_t;
+       _skb = __skb_dequeue(&(_ni)->ni_savedq);                \
+       (_qlen) = skb_queue_len(&(_ni)->ni_savedq);             \
+ } while (0)
+-#define       _IEEE80211_NODE_SAVEQ_ENQUEUE(_ni, _skb, _qlen, _age) do {\
+-      struct sk_buff *tail = skb_peek_tail(&(_ni)->ni_savedq);\
+-      if (tail != NULL) {                                     \
+-              _age -= M_AGE_GET(tail);                        \
+-              __skb_append(tail, _skb, &(_ni)->ni_savedq);    \
+-      } else {                                                \
+-              __skb_queue_head(&(_ni)->ni_savedq, _skb);      \
+-      }                                                       \
+-      M_AGE_SET(_skb, _age);                                  \
+-      (_qlen) = skb_queue_len(&(_ni)->ni_savedq);             \
++#define       _IEEE80211_NODE_SAVEQ_ENQUEUE(_ni, _skb, _qlen, _age) do {      \
++      struct sk_buff *tail = skb_peek_tail(&(_ni)->ni_savedq);        \
++      if (tail != NULL) {                                             \
++              _age -= M_AGE_GET(tail);                                \
++              __skb_queue_after(&(_ni)->ni_savedq, tail, _skb);       \
++      } else {                                                        \
++              __skb_queue_head(&(_ni)->ni_savedq, _skb);              \
++      }                                                               \
++      M_AGE_SET(_skb, _age);                                          \
++      (_qlen) = skb_queue_len(&(_ni)->ni_savedq);                     \
+ } while (0)
+ /*
+--- a/net80211/ieee80211_power.c
++++ b/net80211/ieee80211_power.c
+@@ -243,7 +243,7 @@ ieee80211_pwrsave(struct sk_buff *skb)
+       tail = skb_peek_tail(&ni->ni_savedq);
+       if (tail != NULL) {
+               age -= M_AGE_GET(tail);
+-              __skb_append(tail, skb, &ni->ni_savedq);
++              __skb_queue_after(&ni->ni_savedq, tail, skb);
+       } else
+               __skb_queue_head(&ni->ni_savedq, skb);
+       M_AGE_SET(skb, age);
diff --git a/net/madwifi/patches/404-linux24_fix.patch b/net/madwifi/patches/404-linux24_fix.patch
new file mode 100644 (file)
index 0000000..4ea20b3
--- /dev/null
@@ -0,0 +1,15 @@
+--- a/ath_hal/Makefile
++++ b/ath_hal/Makefile
+@@ -78,10 +78,11 @@ endif
+ quiet_cmd_uudecode = UUDECODE $@
+       cmd_uudecode = $(obj)/uudecode -o $@ $<
+-$(obj)/$(TARGET).hal.o: $(HAL)/public/$(TARGET).hal.o.uu $(obj)/uudecode
+ ifdef LINUX24
++$(TARGET).hal.o: $(HAL)/public/$(TARGET).hal.o.uu $(obj)/uudecode
+       $(Q)$(obj)/uudecode -o $@ $<
+ else
++$(obj)/$(TARGET).hal.o: $(HAL)/public/$(TARGET).hal.o.uu $(obj)/uudecode
+       $(call if_changed,uudecode)
+ endif
diff --git a/net/madwifi/patches/405-retransmit_check.patch b/net/madwifi/patches/405-retransmit_check.patch
new file mode 100644 (file)
index 0000000..11e78ab
--- /dev/null
@@ -0,0 +1,22 @@
+--- a/net80211/ieee80211.h
++++ b/net80211/ieee80211.h
+@@ -174,8 +174,6 @@ struct ieee80211_ctlframe_addr2 {
+ #define       IEEE80211_SEQ_SEQ_MASK                  0xfff0
+ #define       IEEE80211_SEQ_SEQ_SHIFT                 4
+-#define       IEEE80211_SEQ_LEQ(a,b)  ((int)((a)-(b)) <= 0)
+-
+ #define       IEEE80211_NWID_LEN                      32
+ #define       IEEE80211_QOS_TXOP                      0x00ff
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -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) &&
+-                          IEEE80211_SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
++                          (rxseq == ni->ni_rxseqs[tid])) {
+                               /* duplicate, discard */
+                               IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
+                                       bssid, "duplicate",
diff --git a/net/madwifi/patches/406-monitor_r3711.patch b/net/madwifi/patches/406-monitor_r3711.patch
new file mode 100644 (file)
index 0000000..4e2c6ae
--- /dev/null
@@ -0,0 +1,20 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6530,7 +6530,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. */
+-      tskb = ath_skb_removepad(skb, 0 /* Copy SKB */);
++      tskb = ath_skb_removepad(skb, !tx /* Copy SKB */);
+       if (tskb == NULL) {
+               DPRINTF(sc, ATH_DEBUG_ANY,
+                       "Dropping; ath_skb_removepad failed!\n");
+@@ -6538,6 +6538,8 @@ ath_capture(struct net_device *dev, cons
+       }
+       
+       ieee80211_input_monitor(ic, tskb, bf, tx, tsf, sc);
++      if (tskb != skb)
++              ieee80211_dev_kfree_skb(&tskb);
+ }
+ /*
diff --git a/net/madwifi/patches/407-new_athinfo.patch b/net/madwifi/patches/407-new_athinfo.patch
new file mode 100644 (file)
index 0000000..6c512ad
--- /dev/null
@@ -0,0 +1,2352 @@
+--- a/tools/ath_info.c
++++ b/tools/ath_info.c
+@@ -16,78 +16,8 @@
+  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+-/* So here is how it works:
+- *
+- * First compile...
+- *
+- * gcc ath_info.c -o ath_info
+- *
+- * then find card's physical address
+- *
+- * lspci -v
+- *
+- * 02:02.0 Ethernet controller: Atheros Communications, Inc. AR5212 802.11abg NIC (rev 01)
+- *         Subsystem: Fujitsu Limited. Unknown device 1234
+- *         Flags: bus master, medium devsel, latency 168, IRQ 23
+- *         Memory at c2000000 (32-bit, non-prefetchable) [size=64K]
+- *         Capabilities: [44] Power Management version 2
+- *
+- * address here is 0xc2000000
+- *
+- * load madwifi-ng or madwifi-old if not already loaded (be sure the
+- * interface is down!)
+- *
+- * modprobe ath_pci
+- *
+- * OR
+- *
+- * call:
+- * setpci -s 02:02.0 command=0x41f cache_line_size=0x10
+- *
+- * to enable access to the PCI device.
+- *
+- * and we run the thing...
+- *
+- * ./ath_info 0xc2000000
+- *
+- * In order to change the regdomain to 0, call:
+- *
+- * ./ath_info -w 0xc2000000 regdomain 0
+- *
+- * to change any PCI ID value, say:
+- *
+- * ./ath_info -w 0xc2000000 <name> X
+- *
+- * with <name> ::= pci_dev_id | pci_vendor_id | pci_class |
+- *                 pci_subsys_dev_id | pci_subsys_vendor_id
+- *
+- * With newer chipsets (>= AR5004x, i.e. MAC >= AR5213), Atheros introduced
+- * write protection on the EEPROM. On a GIGABYTE GN-WI01HT you can set GPIO 4
+- * to low to be able to write the EEPROM. This depends highly on the PCB layout,
+- * so there may be different GPIO used.
+- * This program currently sets GPIO 4 to low for a MAC >= AR5213, but you can
+- * override this with the -g option:
+- *
+- * ./ath_info -g 5:0 -w 0xc2000000 regdomain X
+- *
+- * would set GPIO 5 to low (and wouldn't touch GPIO 4). -g can be given several times.
+- *
+- * The write function is currently not tested with 5210 devices.
+- *
+- * Use at your own risk, entering a false device address will have really
+- * nasty results!
+- *
+- * Writing wrong values to the PCI id fields may prevent the driver from
+- * detecting the card!
+- *
+- * Transmitting on illegal frequencies may violate state laws. Stick to the local
+- * regulations!
+- *
+- * DISCLAIMER:
+- * The authors are in no case responsible for damaged hardware or violation of
+- * local laws by operating modified hardware.
+- *
+- */
++/* Try accepting 64-bit device address even with 32-bit userspace */
++#define _FILE_OFFSET_BITS 64
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -130,109 +60,103 @@ fprintf(stderr, "#ERR %s: " fmt "\n", __
+  */
+ #define AR5K_GPIODI   0x401c
+-/*
+- * Common silicon revision/version values
+- */
+-enum ath5k_srev_type {
+-      AR5K_VERSION_VER,
+-      AR5K_VERSION_REV,
+-      AR5K_VERSION_RAD,
+-};
+-
+ struct ath5k_srev_name {
+       const char *sr_name;
+-      enum ath5k_srev_type sr_type;
+-      u_int sr_val;
++      u_int8_t sr_val;
+ };
+-#define AR5K_SREV_UNKNOWN     0xffff
+-
+ /* Known MAC revision numbers */
+-#define AR5K_SREV_VER_AR5210  0x00
+-#define AR5K_SREV_VER_AR5311  0x10
+-#define AR5K_SREV_VER_AR5311A 0x20
+-#define AR5K_SREV_VER_AR5311B 0x30
+-#define AR5K_SREV_VER_AR5211  0x40
+-#define AR5K_SREV_VER_AR5212  0x50
+-#define AR5K_SREV_VER_AR5213  0x55
+-#define AR5K_SREV_VER_AR5213A 0x59
+-#define       AR5K_SREV_VER_AR2424    0xa0
+-#define       AR5K_SREV_VER_AR5424    0xa3
+-#define       AR5K_SREV_VER_AR5413    0xa4
+-#define AR5K_SREV_VER_AR5414  0xa5
+-#define       AR5K_SREV_VER_AR5416    0xc0
+-#define       AR5K_SREV_VER_AR5418    0xca
+-#define       AR5K_SREV_VER_AR2425    0xe0
+-
+-/* Known PHY revision nymbers */
+-#define AR5K_SREV_RAD_5110    0x00
+-#define AR5K_SREV_RAD_5111    0x10
+-#define AR5K_SREV_RAD_5111A   0x15
+-#define AR5K_SREV_RAD_2111    0x20
+-#define AR5K_SREV_RAD_5112    0x30
+-#define AR5K_SREV_RAD_5112A   0x35
+-#define AR5K_SREV_RAD_2112    0x40
+-#define AR5K_SREV_RAD_2112A   0x45
+-#define AR5K_SREV_RAD_SC1     0x63    /* Found on 5413/5414 */
+-#define       AR5K_SREV_RAD_SC2       0xa2    /* Found on 2424/5424 */
+-#define       AR5K_SREV_RAD_5133      0xc0    /* MIMO found on 5418 */
+-
+-static const struct ath5k_srev_name ath5k_srev_names[] = {
+-      {"5210", AR5K_VERSION_VER, AR5K_SREV_VER_AR5210},
+-      {"5311", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311},
+-      {"5311A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311A},
+-      {"5311B", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311B},
+-      {"5211", AR5K_VERSION_VER, AR5K_SREV_VER_AR5211},
+-      {"5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212},
+-      {"5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213},
+-      {"5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A},
+-      {"2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424},
+-      {"5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424},
+-      {"5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413},
+-      {"5414", AR5K_VERSION_VER, AR5K_SREV_VER_AR5414},
+-      {"5416", AR5K_VERSION_VER, AR5K_SREV_VER_AR5416},
+-      {"5418", AR5K_VERSION_VER, AR5K_SREV_VER_AR5418},
+-      {"2425", AR5K_VERSION_VER, AR5K_SREV_VER_AR2425},
+-      {"xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN},
+-      {"5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110},
+-      {"5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111},
+-      {"2111", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111},
+-      {"5112", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112},
+-      {"5112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A},
+-      {"2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112},
+-      {"2112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A},
+-      {"SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1},
+-      {"SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2},
+-      {"5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133},
+-      {"xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN},
++#define AR5K_SREV_MAC_AR5210  0x00
++#define AR5K_SREV_MAC_AR5311  0x10
++#define AR5K_SREV_MAC_AR5311A 0x20
++#define AR5K_SREV_MAC_AR5311B 0x30
++#define AR5K_SREV_MAC_AR5211  0x40
++#define AR5K_SREV_MAC_AR5212  0x50
++#define AR5K_SREV_MAC_AR5213  0x55
++#define AR5K_SREV_MAC_AR5213A 0x59
++#define AR5K_SREV_MAC_AR5513  0x61
++#define AR5K_SREV_MAC_AR2413  0x78
++#define AR5K_SREV_MAC_AR2414  0x79
++#define AR5K_SREV_MAC_AR2424  0xa0
++#define AR5K_SREV_MAC_AR5424  0xa3
++#define AR5K_SREV_MAC_AR5413  0xa4
++#define AR5K_SREV_MAC_AR5414  0xa5
++#define AR5K_SREV_MAC_AR5416  0xc0
++#define AR5K_SREV_MAC_AR5418  0xca
++#define AR5K_SREV_MAC_AR2425  0xe2
++
++/* Known PHY revision numbers */
++#define AR5K_SREV_PHY_5110    0x00
++#define AR5K_SREV_PHY_5111    0x10
++#define AR5K_SREV_PHY_5111A   0x15
++#define AR5K_SREV_PHY_2111    0x20
++#define AR5K_SREV_PHY_5112    0x30
++#define AR5K_SREV_PHY_5112A   0x35
++#define AR5K_SREV_PHY_2112    0x40
++#define AR5K_SREV_PHY_2112A   0x45
++#define AR5K_SREV_PHY_SC0     0x56    /* Found on 2413/2414 */
++#define AR5K_SREV_PHY_SC1     0x63    /* Found on 5413/5414 */
++#define AR5K_SREV_PHY_SC2     0xa2    /* Found on 2424/5424 */
++#define AR5K_SREV_PHY_5133    0xc0    /* MIMO found on 5418 */
++
++static const struct ath5k_srev_name ath5k_mac_names[] = {
++      {"5210", AR5K_SREV_MAC_AR5210},
++      {"5311", AR5K_SREV_MAC_AR5311},
++      {"5311A", AR5K_SREV_MAC_AR5311A},
++      {"5311B", AR5K_SREV_MAC_AR5311B},
++      {"5211", AR5K_SREV_MAC_AR5211},
++      {"5212", AR5K_SREV_MAC_AR5212},
++      {"5213", AR5K_SREV_MAC_AR5213},
++      {"5213A", AR5K_SREV_MAC_AR5213A},
++      {"2413", AR5K_SREV_MAC_AR2413},
++      {"2414", AR5K_SREV_MAC_AR2414},
++      {"2424", AR5K_SREV_MAC_AR2424},
++      {"5424", AR5K_SREV_MAC_AR5424},
++      {"5413", AR5K_SREV_MAC_AR5413},
++      {"5414", AR5K_SREV_MAC_AR5414},
++      {"5416", AR5K_SREV_MAC_AR5416},
++      {"5418", AR5K_SREV_MAC_AR5418},
++      {"2425", AR5K_SREV_MAC_AR2425},
++};
++
++static const struct ath5k_srev_name ath5k_phy_names[] = {
++      {"5110", AR5K_SREV_PHY_5110},
++      {"5111", AR5K_SREV_PHY_5111},
++      {"2111", AR5K_SREV_PHY_2111},
++      {"5112", AR5K_SREV_PHY_5112},
++      {"5112A", AR5K_SREV_PHY_5112A},
++      {"2112", AR5K_SREV_PHY_2112},
++      {"2112A", AR5K_SREV_PHY_2112A},
++      {"SChip", AR5K_SREV_PHY_SC0},
++      {"SChip", AR5K_SREV_PHY_SC1},
++      {"SChip", AR5K_SREV_PHY_SC2},
++      {"5133", AR5K_SREV_PHY_5133},
+ };
+ /*
+  * Silicon revision register
+  */
+ #define AR5K_SREV             0x4020  /* Register Address */
+-#define AR5K_SREV_REV         0x0000000f      /* Mask for revision */
+-#define AR5K_SREV_REV_S               0
+-#define AR5K_SREV_VER         0x000000ff      /* Mask for version */
+-#define AR5K_SREV_VER_S               4
++#define AR5K_SREV_VER         0x000000f0      /* Mask for version */
++#define AR5K_SREV_REV         0x000000ff      /* Mask for revision */
+ /*
+  * PHY chip revision register
+  */
+-#define       AR5K_PHY_CHIP_ID                0x9818
++#define AR5K_PHY_CHIP_ID              0x9818
+ /*
+  * PHY register
+  */
+-#define       AR5K_PHY_BASE                   0x9800
+-#define       AR5K_PHY(_n)                    (AR5K_PHY_BASE + ((_n) << 2))
++#define AR5K_PHY_BASE                 0x9800
++#define AR5K_PHY(_n)                  (AR5K_PHY_BASE + ((_n) << 2))
+ #define AR5K_PHY_SHIFT_2GHZ           0x00004007
+ #define AR5K_PHY_SHIFT_5GHZ           0x00000007
+ #define AR5K_RESET_CTL                0x4000  /* Register Address */
+ #define AR5K_RESET_CTL_PCU    0x00000001      /* Protocol Control Unit reset */
+ #define AR5K_RESET_CTL_DMA    0x00000002      /* DMA (Rx/Tx) reset -5210 only */
+-#define       AR5K_RESET_CTL_BASEBAND 0x00000002      /* Baseband reset (5211/5212) */
++#define AR5K_RESET_CTL_BASEBAND       0x00000002      /* Baseband reset (5211/5212) */
+ #define AR5K_RESET_CTL_MAC    0x00000004      /* MAC reset (PCU+Baseband?) -5210 only */
+ #define AR5K_RESET_CTL_PHY    0x00000008      /* PHY reset -5210 only */
+ #define AR5K_RESET_CTL_PCI    0x00000010      /* PCI Core reset (interrupts etc) */
+@@ -253,7 +177,7 @@ static const struct ath5k_srev_name ath5
+ #define AR5K_SLEEP_CTL_SLE_UNITS      0x00000008      /* not on 5210 */
+ #define AR5K_PCICFG                   0x4010  /* Register Address */
+-#define AR5K_PCICFG_EEAE              0x00000001      /* Eeprom access enable [5210] */
++#define AR5K_PCICFG_EEAE              0x00000001      /* EEPROM access enable [5210] */
+ #define AR5K_PCICFG_CLKRUNEN          0x00000004      /* CLKRUN enable [5211+] */
+ #define AR5K_PCICFG_EESIZE            0x00000018      /* Mask for EEPROM size [5211+] */
+ #define AR5K_PCICFG_EESIZE_S          3
+@@ -264,26 +188,118 @@ static const struct ath5k_srev_name ath5
+ #define AR5K_PCICFG_SPWR_DN           0x00010000      /* Mask for power status (5210) */
+-#define AR5K_EEPROM_BASE              0x6000
++#define AR5K_EEPROM_BASE      0x6000
+-#define AR5K_EEPROM_MAGIC             0x003d  /* Offset for EEPROM Magic number */
++/*
++ * Common AR5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
++ */
++#define AR5K_EEPROM_MAGIC             0x003d  /* EEPROM Magic number */
+ #define AR5K_EEPROM_MAGIC_VALUE               0x5aa5  /* Default - found on EEPROM */
+ #define AR5K_EEPROM_MAGIC_5212                0x0000145c      /* 5212 */
+ #define AR5K_EEPROM_MAGIC_5211                0x0000145b      /* 5211 */
+ #define AR5K_EEPROM_MAGIC_5210                0x0000145a      /* 5210 */
++#define AR5K_EEPROM_PROTECT           0x003f  /* EEPROM protect status */
++#define AR5K_EEPROM_PROTECT_RD_0_31   0x0001  /* Read protection bit for offsets 0x0 - 0x1f */
++#define AR5K_EEPROM_PROTECT_WR_0_31   0x0002  /* Write protection bit for offsets 0x0 - 0x1f */
++#define AR5K_EEPROM_PROTECT_RD_32_63  0x0004  /* 0x20 - 0x3f */
++#define AR5K_EEPROM_PROTECT_WR_32_63  0x0008
++#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010  /* 0x40 - 0x7f */
++#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020
++#define AR5K_EEPROM_PROTECT_RD_128_191        0x0040  /* 0x80 - 0xbf (regdom) */
++#define AR5K_EEPROM_PROTECT_WR_128_191        0x0080
++#define AR5K_EEPROM_PROTECT_RD_192_207        0x0100  /* 0xc0 - 0xcf */
++#define AR5K_EEPROM_PROTECT_WR_192_207        0x0200
++#define AR5K_EEPROM_PROTECT_RD_208_223        0x0400  /* 0xd0 - 0xdf */
++#define AR5K_EEPROM_PROTECT_WR_208_223        0x0800
++#define AR5K_EEPROM_PROTECT_RD_224_239        0x1000  /* 0xe0 - 0xef */
++#define AR5K_EEPROM_PROTECT_WR_224_239        0x2000
++#define AR5K_EEPROM_PROTECT_RD_240_255        0x4000  /* 0xf0 - 0xff */
++#define AR5K_EEPROM_PROTECT_WR_240_255        0x8000
++#define AR5K_EEPROM_REG_DOMAIN                0x00bf  /* EEPROM regdom */
++#define AR5K_EEPROM_INFO_BASE         0x00c0  /* EEPROM header */
++#define AR5K_EEPROM_INFO_MAX          (0x400 - AR5K_EEPROM_INFO_BASE)
++#define AR5K_EEPROM_INFO_CKSUM                0xffff
++#define AR5K_EEPROM_INFO(_n)          (AR5K_EEPROM_INFO_BASE + (_n))
++
++#define AR5K_EEPROM_VERSION           AR5K_EEPROM_INFO(1)     /* EEPROM Version */
++#define AR5K_EEPROM_VERSION_3_0               0x3000  /* No idea what's going on before this version */
++#define AR5K_EEPROM_VERSION_3_1               0x3001  /* ob/db values for 2GHz (AR5211_rfregs) */
++#define AR5K_EEPROM_VERSION_3_2               0x3002  /* different frequency representation (eeprom_bin2freq) */
++#define AR5K_EEPROM_VERSION_3_3               0x3003  /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
++#define AR5K_EEPROM_VERSION_3_4               0x3004  /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
++#define AR5K_EEPROM_VERSION_4_0               0x4000  /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_1               0x4001  /* has ee_margin_tx_rx (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_2               0x4002  /* has ee_cck_ofdm_gain_delta (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_3               0x4003
++#define AR5K_EEPROM_VERSION_4_4               0x4004
++#define AR5K_EEPROM_VERSION_4_5               0x4005
++#define AR5K_EEPROM_VERSION_4_6               0x4006  /* has ee_scaled_cck_delta */
++#define AR5K_EEPROM_VERSION_4_7               0x3007
++
++#define AR5K_EEPROM_MODE_11A          0
++#define AR5K_EEPROM_MODE_11B          1
++#define AR5K_EEPROM_MODE_11G          2
++
++#define AR5K_EEPROM_HDR                       AR5K_EEPROM_INFO(2)     /* Header that contains the device caps */
++#define AR5K_EEPROM_HDR_11A(_v)               (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
++#define AR5K_EEPROM_HDR_11B(_v)               (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
++#define AR5K_EEPROM_HDR_11G(_v)               (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
++#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)        (((_v) >> 3) & 0x1)     /* Disable turbo for 2GHz (?) */
++#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)        (((_v) >> 4) & 0x7f)    /* Max turbo power for a/XR mode (eeprom_init) */
++#define AR5K_EEPROM_HDR_DEVICE(_v)    (((_v) >> 11) & 0x7)
++#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)        (((_v) >> 15) & 0x1)    /* Disable turbo for 5GHz (?) */
++#define AR5K_EEPROM_HDR_RFKILL(_v)    (((_v) >> 14) & 0x1)    /* Device has RFKill support */
++
++/* Misc values available since EEPROM 4.0 */
++#define AR5K_EEPROM_MISC0             AR5K_EEPROM_INFO(4)
++#define AR5K_EEPROM_EARSTART(_v)      ((_v) & 0xfff)
++#define AR5K_EEPROM_HDR_XR2_DIS(_v)   (((_v) >> 12) & 0x1)
++#define AR5K_EEPROM_HDR_XR5_DIS(_v)   (((_v) >> 13) & 0x1)
++#define AR5K_EEPROM_EEMAP(_v)         (((_v) >> 14) & 0x3)
++#define AR5K_EEPROM_MISC1             AR5K_EEPROM_INFO(5)
++#define AR5K_EEPROM_TARGET_PWRSTART(_v)       ((_v) & 0xfff)
++#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)       (((_v) >> 14) & 0x1)
++
++#define AR5K_EEPROM_RFKILL_GPIO_SEL   0x0000001c
++#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2
++#define AR5K_EEPROM_RFKILL_POLARITY   0x00000002
++#define AR5K_EEPROM_RFKILL_POLARITY_S 1
++
++/* Newer EEPROMs are using a different offset */
++#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
++      (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
++
++#define AR5K_EEPROM_ANT_GAIN(_v)      AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
++#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff))
++#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff))
++
++/* calibration settings */
++#define AR5K_EEPROM_MODES_11A(_v)     AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
++#define AR5K_EEPROM_MODES_11B(_v)     AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
++#define AR5K_EEPROM_MODES_11G(_v)     AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
++#define AR5K_EEPROM_CTL(_v)           AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)     /* Conformance test limits */
++#define AR5K_EEPROM_CHANNELS_5GHZ(_v) AR5K_EEPROM_OFF(_v, 0x0100, 0x0150)     /* List of calibrated 5GHz chans */
++#define       AR5K_EEPROM_TARGET_PWR_OFF_11A(_v)      AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0055, 0x0000)
++#define       AR5K_EEPROM_TARGET_PWR_OFF_11B(_v)      AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0065, 0x0010)
++#define       AR5K_EEPROM_TARGET_PWR_OFF_11G(_v)      AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0069, 0x0014)
++
++/* [3.1 - 3.3] */
++#define AR5K_EEPROM_OBDB0_2GHZ                0x00ec
++#define AR5K_EEPROM_OBDB1_2GHZ                0x00ed
++
+ /*
+  * EEPROM data register
+  */
+ #define AR5K_EEPROM_DATA_5211 0x6004
+ #define AR5K_EEPROM_DATA_5210 0x6800
+-#define       AR5K_EEPROM_DATA        (mac_version == AR5K_SREV_VER_AR5210 ? \
++#define AR5K_EEPROM_DATA      (mac_version == AR5K_SREV_MAC_AR5210 ? \
+                               AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211)
+ /*
+  * EEPROM command register
+  */
+-#define AR5K_EEPROM_CMD               0x6008  /* Register Addres */
++#define AR5K_EEPROM_CMD               0x6008                  /* Register Address */
+ #define AR5K_EEPROM_CMD_READ  0x00000001      /* EEPROM read */
+ #define AR5K_EEPROM_CMD_WRITE 0x00000002      /* EEPROM write */
+ #define AR5K_EEPROM_CMD_RESET 0x00000004      /* EEPROM reset */
+@@ -291,43 +307,163 @@ static const struct ath5k_srev_name ath5
+ /*
+  * EEPROM status register
+  */
+-#define AR5K_EEPROM_STAT_5210 0x6c00  /* Register Address [5210] */
+-#define AR5K_EEPROM_STAT_5211 0x600c  /* Register Address [5211+] */
+-#define       AR5K_EEPROM_STATUS      (mac_version == AR5K_SREV_VER_AR5210 ? \
++#define AR5K_EEPROM_STAT_5210 0x6c00                  /* Register Address [5210] */
++#define AR5K_EEPROM_STAT_5211 0x600c                  /* Register Address [5211+] */
++#define AR5K_EEPROM_STATUS    (mac_version == AR5K_SREV_MAC_AR5210 ? \
+                               AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211)
+ #define AR5K_EEPROM_STAT_RDERR        0x00000001      /* EEPROM read failed */
+ #define AR5K_EEPROM_STAT_RDDONE       0x00000002      /* EEPROM read successful */
+ #define AR5K_EEPROM_STAT_WRERR        0x00000004      /* EEPROM write failed */
+ #define AR5K_EEPROM_STAT_WRDONE       0x00000008      /* EEPROM write successful */
+-#define AR5K_EEPROM_REG_DOMAIN                0x00bf  /* Offset for EEPROM regulatory domain */
+-#define AR5K_EEPROM_INFO_BASE         0x00c0  /* Offset for EEPROM header */
+-#define AR5K_EEPROM_INFO_MAX          (0x400 - AR5K_EEPROM_INFO_BASE)
+-#define AR5K_EEPROM_INFO_CKSUM                0xffff
+-#define AR5K_EEPROM_INFO(_n)          (AR5K_EEPROM_INFO_BASE + (_n))
+-#define AR5K_EEPROM_MODE_11A          0
+-#define AR5K_EEPROM_MODE_11B          1
+-#define AR5K_EEPROM_MODE_11G          2
++/*
++ * EEPROM config register (?)
++ */
++#define AR5K_EEPROM_CFG       0x6010
+-#define AR5K_EEPROM_VERSION           AR5K_EEPROM_INFO(1)
++/* Some EEPROM defines */
++#define AR5K_EEPROM_EEP_SCALE         100
++#define AR5K_EEPROM_EEP_DELTA         10
++#define AR5K_EEPROM_N_MODES           3
++#define AR5K_EEPROM_N_5GHZ_CHAN               10
++#define AR5K_EEPROM_N_2GHZ_CHAN               3
++#define AR5K_EEPROM_MAX_CHAN          10
++#define AR5K_EEPROM_N_PCDAC           11
++#define AR5K_EEPROM_N_TEST_FREQ               8
++#define AR5K_EEPROM_N_EDGES           8
++#define AR5K_EEPROM_N_INTERCEPTS      11
++#define AR5K_EEPROM_FREQ_M(_v)                AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
++#define AR5K_EEPROM_PCDAC_M           0x3f
++#define AR5K_EEPROM_PCDAC_START               1
++#define AR5K_EEPROM_PCDAC_STOP                63
++#define AR5K_EEPROM_PCDAC_STEP                1
++#define AR5K_EEPROM_NON_EDGE_M                0x40
++#define AR5K_EEPROM_CHANNEL_POWER     8
++#define AR5K_EEPROM_N_OBDB            4
++#define AR5K_EEPROM_OBDB_DIS          0xffff
++#define AR5K_EEPROM_CHANNEL_DIS               0xff
++#define AR5K_EEPROM_SCALE_OC_DELTA(_x)        (((_x) * 2) / 10)
++#define AR5K_EEPROM_N_CTLS(_v)                AR5K_EEPROM_OFF(_v, 16, 32)
++#define AR5K_EEPROM_MAX_CTLS          32
++#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4
++#define AR5K_EEPROM_N_XPD0_POINTS     4
++#define AR5K_EEPROM_N_XPD3_POINTS     3
++#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ       35
++#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ       55
++#define AR5K_EEPROM_POWER_M           0x3f
++#define AR5K_EEPROM_POWER_MIN         0
++#define AR5K_EEPROM_POWER_MAX         3150
++#define AR5K_EEPROM_POWER_STEP                50
++#define AR5K_EEPROM_POWER_TABLE_SIZE  64
++#define AR5K_EEPROM_N_POWER_LOC_11B   4
++#define AR5K_EEPROM_N_POWER_LOC_11G   6
++#define AR5K_EEPROM_I_GAIN            10
++#define AR5K_EEPROM_CCK_OFDM_DELTA    15
++#define AR5K_EEPROM_N_IQ_CAL          2
++
++enum ath5k_ant_setting {
++      AR5K_ANT_VARIABLE       = 0,    /* variable by programming */
++      AR5K_ANT_FIXED_A        = 1,    /* fixed to 11a frequencies */
++      AR5K_ANT_FIXED_B        = 2,    /* fixed to 11b frequencies */
++      AR5K_ANT_MAX            = 3,
++};
+-#define AR5K_EEPROM_HDR                       AR5K_EEPROM_INFO(2)     /* Header that contains the device caps */
+-#define AR5K_EEPROM_HDR_11A(_v)               (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)  /* Device has a support */
+-#define AR5K_EEPROM_HDR_11B(_v)               (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)  /* Device has b support */
+-#define AR5K_EEPROM_HDR_11G(_v)               (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)  /* Device has g support */
+-#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)        (((_v) >> 3) & 0x1)     /* Disable turbo for 2Ghz (?) */
+-#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)        (((_v) >> 4) & 0x7f)    /* Max turbo power for a/XR mode (eeprom_init) */
+-#define AR5K_EEPROM_HDR_DEVICE(_v)    (((_v) >> 11) & 0x7)
+-#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)        (((_v) >> 15) & 0x1)    /* Disable turbo for 5Ghz (?) */
+-#define AR5K_EEPROM_HDR_RFKILL(_v)    (((_v) >> 14) & 0x1)    /* Device has RFKill support */
++/* Per channel calibration data, used for power table setup */
++struct ath5k_chan_pcal_info {
++      u_int16_t       freq; /* Frequency */
++      /* Power levels in dBm * 4 units */
++      int16_t         pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
++      int16_t         pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
++      /* PCDAC tables in dBm * 2 units */
++      u_int16_t       pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS];
++      u_int16_t       pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS];
++      /* Max available power */
++      u_int16_t       max_pwr;
++};
+-/* Misc values available since EEPROM 4.0 */
+-#define AR5K_EEPROM_MISC0             0x00c4
+-#define AR5K_EEPROM_EARSTART(_v)      ((_v) & 0xfff)
+-#define AR5K_EEPROM_EEMAP(_v)         (((_v) >> 14) & 0x3)
+-#define AR5K_EEPROM_MISC1             0x00c5
+-#define AR5K_EEPROM_TARGET_PWRSTART(_v)       ((_v) & 0xfff)
+-#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)       (((_v) >> 14) & 0x1)
++/* Per rate calibration data for each mode, used for power table setup */
++struct ath5k_rate_pcal_info {
++      u_int16_t       freq; /* Frequency */
++      /* Power level for 6-24Mbit/s rates */
++      u_int16_t       target_power_6to24;
++      /* Power level for 36Mbit rate */
++      u_int16_t       target_power_36;
++      /* Power level for 48Mbit rate */
++      u_int16_t       target_power_48;
++      /* Power level for 54Mbit rate */
++      u_int16_t       target_power_54;
++};
++
++/* EEPROM calibration data */
++struct ath5k_eeprom_info {
++
++      /* Header information */
++      u_int16_t       ee_magic;
++      u_int16_t       ee_protect;
++      u_int16_t       ee_regdomain;
++      u_int16_t       ee_version;
++      u_int16_t       ee_header;
++      u_int16_t       ee_ant_gain;
++      u_int16_t       ee_misc0;
++      u_int16_t       ee_misc1;
++      u_int16_t       ee_cck_ofdm_gain_delta;
++      u_int16_t       ee_cck_ofdm_power_delta;
++      u_int16_t       ee_scaled_cck_delta;
++
++      /* Used for tx thermal adjustment (eeprom_init, rfregs) */
++      u_int16_t       ee_tx_clip;
++      u_int16_t       ee_pwd_84;
++      u_int16_t       ee_pwd_90;
++      u_int16_t       ee_gain_select;
++
++      /* RF Calibration settings (reset, rfregs) */
++      u_int16_t       ee_i_cal[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_q_cal[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_fixed_bias[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_turbo_max_power[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_xr_power[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_switch_settling[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
++      u_int16_t       ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
++      u_int16_t       ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
++      u_int16_t       ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_thr_62[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_xlna_gain[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_xpd[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_x_gain[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_i_gain[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
++
++      /* Power calibration data */
++      u_int16_t       ee_false_detect[AR5K_EEPROM_N_MODES];
++      u_int16_t       ee_cal_piers_a;
++      struct ath5k_chan_pcal_info     ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
++      u_int16_t       ee_cal_piers_b;
++      struct ath5k_chan_pcal_info     ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN];
++      u_int16_t       ee_cal_piers_g;
++      struct ath5k_chan_pcal_info     ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN];
++      /* Per rate target power levels */
++      u_int16_t       ee_rate_target_pwr_num_a;
++      struct ath5k_rate_pcal_info     ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
++      u_int16_t       ee_rate_target_pwr_num_b;
++      struct ath5k_rate_pcal_info     ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN];
++      u_int16_t       ee_rate_target_pwr_num_g;
++      struct ath5k_rate_pcal_info     ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN];
++
++      /* Conformance test limits (Unused) */
++      u_int16_t       ee_ctls;
++      u_int16_t       ee_ctl[AR5K_EEPROM_MAX_CTLS];
++
++      /* Noise Floor Calibration settings */
++      int16_t         ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
++      int8_t          ee_adc_desired_size[AR5K_EEPROM_N_MODES];
++      int8_t          ee_pga_desired_size[AR5K_EEPROM_N_MODES];
++
++      u_int32_t       ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
++};
+ /*
+  * Read data by masking
+@@ -350,7 +486,6 @@ static const struct ath5k_srev_name ath5
+       (*((volatile u_int32_t *)(mem + (_reg))) = (_val))
+ #endif
+-
+ #define AR5K_REG_ENABLE_BITS(_reg, _flags)    \
+       AR5K_REG_WRITE(_reg, AR5K_REG_READ(_reg) | (_flags))
+@@ -359,7 +494,12 @@ static const struct ath5k_srev_name ath5
+ #define AR5K_TUNE_REGISTER_TIMEOUT            20000
+-/* names for eeprom fields */
++#define AR5K_EEPROM_READ(_o, _v) do {                                 \
++      if ((ret = ath5k_hw_eeprom_read(mem, (_o), &(_v), mac_version)) != 0)   \
++              return (ret);                                           \
++} while (0)
++
++/* Names for EEPROM fields */
+ struct eeprom_entry {
+       const char *name;
+       int addr;
+@@ -375,8 +515,6 @@ static const struct eeprom_entry eeprom_
+       {"regdomain", AR5K_EEPROM_REG_DOMAIN},
+ };
+-static const int eeprom_addr_len = sizeof(eeprom_addr) / sizeof(eeprom_addr[0]);
+-
+ static int force_write = 0;
+ static int verbose = 0;
+@@ -398,8 +536,8 @@ static u_int32_t ath5k_hw_bitswap(u_int3
+ /*
+  * Get the PHY Chip revision
+  */
+-static u_int16_t
+-ath5k_hw_radio_revision(u_int16_t mac_version, void *mem, u_int8_t chip)
++static u_int16_t ath5k_hw_radio_revision(u_int16_t mac_version, void *mem,
++                                       u_int8_t chip)
+ {
+       int i;
+       u_int32_t srev;
+@@ -427,7 +565,7 @@ ath5k_hw_radio_revision(u_int16_t mac_ve
+       for (i = 0; i < 8; i++)
+               AR5K_REG_WRITE(AR5K_PHY(0x20), 0x00010000);
+-      if (mac_version == AR5K_SREV_VER_AR5210) {
++      if (mac_version == AR5K_SREV_MAC_AR5210) {
+               srev = AR5K_REG_READ(AR5K_PHY(256) >> 28) & 0xf;
+               ret = (u_int16_t)ath5k_hw_bitswap(srev, 4) + 1;
+@@ -447,9 +585,8 @@ ath5k_hw_radio_revision(u_int16_t mac_ve
+ /*
+  * Write to EEPROM
+  */
+-static int
+-ath5k_hw_eeprom_write(void *mem, u_int32_t offset, u_int16_t data,
+-                    u_int8_t mac_version)
++static int ath5k_hw_eeprom_write(void *mem, u_int32_t offset, u_int16_t data,
++                               u_int8_t mac_version)
+ {
+       u_int32_t status, timeout;
+@@ -457,7 +594,7 @@ ath5k_hw_eeprom_write(void *mem, u_int32
+        * Initialize EEPROM access
+        */
+-      if (mac_version == AR5K_SREV_VER_AR5210) {
++      if (mac_version == AR5K_SREV_MAC_AR5210) {
+               AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE);
+@@ -466,7 +603,7 @@ ath5k_hw_eeprom_write(void *mem, u_int32
+       } else {
+               /* not 5210 */
+-              /* reset eeprom access */
++              /* reset EEPROM access */
+               AR5K_REG_WRITE(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_RESET);
+               usleep(5);
+@@ -484,7 +621,7 @@ ath5k_hw_eeprom_write(void *mem, u_int32
+               status = AR5K_REG_READ(AR5K_EEPROM_STATUS);
+               if (status & AR5K_EEPROM_STAT_WRDONE) {
+                       if (status & AR5K_EEPROM_STAT_WRERR) {
+-                              err("eeprom write access to 0x%04x failed",
++                              err("EEPROM write access to 0x%04x failed",
+                                   offset);
+                               return 1;
+                       }
+@@ -499,16 +636,15 @@ ath5k_hw_eeprom_write(void *mem, u_int32
+ /*
+  * Read from EEPROM
+  */
+-static int
+-ath5k_hw_eeprom_read(void *mem, u_int32_t offset, u_int16_t *data,
+-                   u_int8_t mac_version)
++static int ath5k_hw_eeprom_read(void *mem, u_int32_t offset, u_int16_t *data,
++                              u_int8_t mac_version)
+ {
+       u_int32_t status, timeout;
+       /*
+        * Initialize EEPROM access
+        */
+-      if (mac_version == AR5K_SREV_VER_AR5210) {
++      if (mac_version == AR5K_SREV_MAC_AR5210) {
+               AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE);
+               (void)AR5K_REG_READ(AR5K_EEPROM_BASE + (4 * offset));
+       } else {
+@@ -531,50 +667,701 @@ ath5k_hw_eeprom_read(void *mem, u_int32_
+       return 1;
+ }
+-static const char *ath5k_hw_get_part_name(enum ath5k_srev_type type,
+-                                        u_int32_t val)
++/*
++ * Translate binary channel representation in EEPROM to frequency
++ */
++static u_int16_t ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee,
++                                     u_int16_t bin, unsigned int mode)
+ {
+-      const char *name = "xxxxx";
+-      int i;
++      u_int16_t val;
+-      for (i = 0; i < ARRAY_SIZE(ath5k_srev_names); i++) {
+-              if (ath5k_srev_names[i].sr_type != type ||
+-                  ath5k_srev_names[i].sr_val == AR5K_SREV_UNKNOWN)
+-                      continue;
+-              if ((val & 0xff) < ath5k_srev_names[i + 1].sr_val) {
+-                      name = ath5k_srev_names[i].sr_name;
++      if (bin == AR5K_EEPROM_CHANNEL_DIS)
++              return bin;
++
++      if (mode == AR5K_EEPROM_MODE_11A) {
++              if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
++                      val = (5 * bin) + 4800;
++              else
++                      val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
++                          (bin * 10) + 5100;
++      } else {
++              if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
++                      val = bin + 2300;
++              else
++                      val = bin + 2400;
++      }
++
++      return val;
++}
++
++/*
++ * Read antenna info from EEPROM
++ */
++static int ath5k_eeprom_read_ants(void *mem, u_int8_t mac_version,
++                                struct ath5k_eeprom_info *ee,
++                                u_int32_t *offset, unsigned int mode)
++{
++      u_int32_t o = *offset;
++      u_int16_t val;
++      int ret, i = 0;
++
++      AR5K_EEPROM_READ(o++, val);
++      ee->ee_switch_settling[mode]    = (val >> 8) & 0x7f;
++      ee->ee_ant_tx_rx[mode]          = (val >> 2) & 0x3f;
++      ee->ee_ant_control[mode][i]     = (val << 4) & 0x3f;
++
++      AR5K_EEPROM_READ(o++, val);
++      ee->ee_ant_control[mode][i++]   |= (val >> 12) & 0xf;
++      ee->ee_ant_control[mode][i++]   = (val >> 6) & 0x3f;
++      ee->ee_ant_control[mode][i++]   = val & 0x3f;
++
++      AR5K_EEPROM_READ(o++, val);
++      ee->ee_ant_control[mode][i++]   = (val >> 10) & 0x3f;
++      ee->ee_ant_control[mode][i++]   = (val >> 4) & 0x3f;
++      ee->ee_ant_control[mode][i]     = (val << 2) & 0x3f;
++
++      AR5K_EEPROM_READ(o++, val);
++      ee->ee_ant_control[mode][i++]   |= (val >> 14) & 0x3;
++      ee->ee_ant_control[mode][i++]   = (val >> 8) & 0x3f;
++      ee->ee_ant_control[mode][i++]   = (val >> 2) & 0x3f;
++      ee->ee_ant_control[mode][i]     = (val << 4) & 0x3f;
++
++      AR5K_EEPROM_READ(o++, val);
++      ee->ee_ant_control[mode][i++]   |= (val >> 12) & 0xf;
++      ee->ee_ant_control[mode][i++]   = (val >> 6) & 0x3f;
++      ee->ee_ant_control[mode][i++]   = val & 0x3f;
++
++      /* Get antenna modes */
++      ee->ee_antenna[mode][0] =
++          (ee->ee_ant_control[mode][0] << 4) | 0x1;
++      ee->ee_antenna[mode][AR5K_ANT_FIXED_A] =
++           ee->ee_ant_control[mode][1]        |
++          (ee->ee_ant_control[mode][2] << 6)  |
++          (ee->ee_ant_control[mode][3] << 12) |
++          (ee->ee_ant_control[mode][4] << 18) |
++          (ee->ee_ant_control[mode][5] << 24);
++      ee->ee_antenna[mode][AR5K_ANT_FIXED_B] =
++           ee->ee_ant_control[mode][6]        |
++          (ee->ee_ant_control[mode][7] << 6)  |
++          (ee->ee_ant_control[mode][8] << 12) |
++          (ee->ee_ant_control[mode][9] << 18) |
++          (ee->ee_ant_control[mode][10] << 24);
++
++      /* return new offset */
++      *offset = o;
++
++      return 0;
++}
++
++/*
++ * Read supported modes from EEPROM
++ */
++static int ath5k_eeprom_read_modes(void *mem, u_int8_t mac_version,
++                                 struct ath5k_eeprom_info *ee,
++                                 u_int32_t *offset, unsigned int mode)
++{
++      u_int32_t o = *offset;
++      u_int16_t val;
++      int ret;
++
++      AR5K_EEPROM_READ(o++, val);
++      ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff;
++      ee->ee_thr_62[mode]             = val & 0xff;
++
++      if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2)
++              ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
++
++      AR5K_EEPROM_READ(o++, val);
++      ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff;
++      ee->ee_tx_frm2xpa_enable[mode]  = val & 0xff;
++
++      AR5K_EEPROM_READ(o++, val);
++      ee->ee_pga_desired_size[mode]   = (val >> 8) & 0xff;
++
++      if ((val & 0xff) & 0x80)
++              ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
++      else
++              ee->ee_noise_floor_thr[mode] = val & 0xff;
++
++      if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2)
++              ee->ee_noise_floor_thr[mode] =
++                  mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
++
++      AR5K_EEPROM_READ(o++, val);
++      ee->ee_xlna_gain[mode]          = (val >> 5) & 0xff;
++      ee->ee_x_gain[mode]             = (val >> 1) & 0xf;
++      ee->ee_xpd[mode]                = val & 0x1;
++
++      if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
++              ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
++
++      if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
++              AR5K_EEPROM_READ(o++, val);
++              ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
++
++              if (mode == AR5K_EEPROM_MODE_11A)
++                      ee->ee_xr_power[mode] = val & 0x3f;
++              else {
++                      ee->ee_ob[mode][0] = val & 0x7;
++                      ee->ee_db[mode][0] = (val >> 3) & 0x7;
++              }
++      }
++
++      if (ee->ee_version < AR5K_EEPROM_VERSION_3_4) {
++              ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
++              ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
++      } else {
++              ee->ee_i_gain[mode] = (val >> 13) & 0x7;
++
++              AR5K_EEPROM_READ(o++, val);
++              ee->ee_i_gain[mode] |= (val << 3) & 0x38;
++
++              if (mode == AR5K_EEPROM_MODE_11G)
++                      ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
++      }
++
++      if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0 &&
++          mode == AR5K_EEPROM_MODE_11A) {
++              ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
++              ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
++      }
++
++      if (ee->ee_version >= AR5K_EEPROM_VERSION_4_6 &&
++          mode == AR5K_EEPROM_MODE_11G)
++              ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
++
++      /* return new offset */
++      *offset = o;
++
++      return 0;
++}
++
++/*
++ * Read per channel calibration info from EEPROM
++ * This doesn't work on 2112+ chips (EEPROM versions >= 4.6),
++ * I only tested it on 5213 + 5112. This is still work in progress...
++ *
++ * This info is used to calibrate the baseband power table. Imagine
++ * that for each channel there is a power curve that's hw specific
++ * (depends on amplifier) and we try to "correct" this curve using offests
++ * we pass on to phy chip (baseband -> before amplifier) so that it can
++ * use acurate power values when setting tx power (takes amplifier's performance
++ * on each channel into account).
++ *
++ * EEPROM provides us with the offsets for some pre-calibrated channels
++ * and we have to scale (to create the full table for these channels) and
++ * interpolate (in order to create the table for any channel).
++ */
++static int ath5k_eeprom_read_pcal_info(void *mem, u_int8_t mac_version,
++                                     struct ath5k_eeprom_info *ee,
++                                     u_int32_t *offset, unsigned int mode)
++{
++      u_int32_t o = *offset;
++      unsigned int i, c;
++      int ret;
++      u_int16_t val;
++      struct ath5k_chan_pcal_info *chan_pcal_info;
++      u_int16_t cal_piers;
++
++      switch (mode) {
++      case AR5K_EEPROM_MODE_11A:
++              chan_pcal_info = ee->ee_pwr_cal_a;
++              cal_piers = ee->ee_cal_piers_a;
++              break;
++      case AR5K_EEPROM_MODE_11B:
++              chan_pcal_info = ee->ee_pwr_cal_b;
++              cal_piers = ee->ee_cal_piers_b;
++              break;
++      case AR5K_EEPROM_MODE_11G:
++              chan_pcal_info = ee->ee_pwr_cal_g;
++              cal_piers = ee->ee_cal_piers_g;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      for (i = 0; i < cal_piers; i++) {
++              /* Power values in dBm * 4 */
++              for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
++                      AR5K_EEPROM_READ(o++, val);
++                      chan_pcal_info[i].pwr_x0[c] = (val & 0xff);
++                      chan_pcal_info[i].pwr_x0[++c] = ((val >> 8) & 0xff);
++              }
++
++              /* PCDAC steps (dBm * 2) */
++              AR5K_EEPROM_READ(o++, val);
++              chan_pcal_info[i].pcdac_x0[1] = (val & 0x1f);
++              chan_pcal_info[i].pcdac_x0[2] = ((val >> 5) & 0x1f);
++              chan_pcal_info[i].pcdac_x0[3] = ((val >> 10) & 0x1f);
++
++              /* No idea what these power levels are for (4 xpds ?)
++                 I got zeroes on my card and the EEPROM info
++                 dumps we found on the net also have weird values */
++              AR5K_EEPROM_READ(o++, val);
++              chan_pcal_info[i].pwr_x3[0] = (val & 0xff);
++              chan_pcal_info[i].pwr_x3[1] = ((val >> 8) & 0xff);
++
++              AR5K_EEPROM_READ(o++, val);
++              chan_pcal_info[i].pwr_x3[2] = (val & 0xff);
++              /* It's weird but they put it here, that's the
++                 PCDAC starting step */
++              chan_pcal_info[i].pcdac_x0[0] = ((val >> 8) & 0xff);
++
++              /* Static values seen on EEPROM info dumps */
++              chan_pcal_info[i].pcdac_x3[0] = 20;
++              chan_pcal_info[i].pcdac_x3[1] = 35;
++              chan_pcal_info[i].pcdac_x3[2] = 63;
++
++              /* Last xpd0 power level is also channel maximum */
++              chan_pcal_info[i].max_pwr = chan_pcal_info[i].pwr_x0[3];
++
++              /* Recreate pcdac_x0 table for this channel using pcdac steps */
++              chan_pcal_info[i].pcdac_x0[1] += chan_pcal_info[i].pcdac_x0[0];
++              chan_pcal_info[i].pcdac_x0[2] += chan_pcal_info[i].pcdac_x0[1];
++              chan_pcal_info[i].pcdac_x0[3] += chan_pcal_info[i].pcdac_x0[2];
++      }
++
++      /* return new offset */
++      (*offset) = o;
++
++      return 0;
++}
++
++/*
++ * Read per rate target power (this is the maximum tx power
++ * supported by the card). This info is used when setting
++ * tx power, no matter the channel.
++ *
++ * This also works for v5 EEPROMs.
++ */
++static int ath5k_eeprom_read_target_rate_pwr_info(void *mem,
++                                                u_int8_t mac_version,
++                                                struct ath5k_eeprom_info *ee,
++                                                u_int32_t *offset,
++                                                unsigned int mode)
++{
++      u_int32_t o = *offset;
++      u_int16_t val;
++      struct ath5k_rate_pcal_info *rate_pcal_info;
++      u_int16_t *rate_target_pwr_num;
++      int ret, i;
++
++      switch (mode) {
++      case AR5K_EEPROM_MODE_11A:
++              rate_pcal_info = ee->ee_rate_tpwr_a;
++              ee->ee_rate_target_pwr_num_a = AR5K_EEPROM_N_5GHZ_CHAN;
++              rate_target_pwr_num = &ee->ee_rate_target_pwr_num_a;
++              break;
++      case AR5K_EEPROM_MODE_11B:
++              rate_pcal_info = ee->ee_rate_tpwr_b;
++              ee->ee_rate_target_pwr_num_b = 2; /* 3rd is g mode'ss 1st */
++              rate_target_pwr_num = &ee->ee_rate_target_pwr_num_b;
++              break;
++      case AR5K_EEPROM_MODE_11G:
++              rate_pcal_info = ee->ee_rate_tpwr_g;
++              ee->ee_rate_target_pwr_num_g = AR5K_EEPROM_N_2GHZ_CHAN;
++              rate_target_pwr_num = &ee->ee_rate_target_pwr_num_g;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      /* Different freq mask for older eeproms (<= v3.2) */
++      if(ee->ee_version <= 0x3002){
++              for (i = 0; i < (*rate_target_pwr_num); i++) {
++                      AR5K_EEPROM_READ(o++, val);
++                      rate_pcal_info[i].freq =
++                          ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
++      
++                      rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
++                      rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
++      
++                      AR5K_EEPROM_READ(o++, val);
++      
++                      if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
++                          val == 0) {
++                              (*rate_target_pwr_num) = i;
++                              break;
++                      }
++
++                      rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
++                      rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
++                      rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
++              }
++      } else {
++              for (i = 0; i < (*rate_target_pwr_num); i++) {
++                      AR5K_EEPROM_READ(o++, val);
++                      rate_pcal_info[i].freq =
++                          ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
++      
++                      rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
++                      rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
++      
++                      AR5K_EEPROM_READ(o++, val);
++      
++                      if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
++                          val == 0) {
++                              (*rate_target_pwr_num) = i;
++                              break;
++                      }
++
++                      rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
++                      rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
++                      rate_pcal_info[i].target_power_54 = (val & 0x3f);
++              }
++      }
++      /* return new offset */
++      (*offset) = o;
++
++      return 0;
++}
++
++/*
++ * Initialize EEPROM & capabilities data
++ */
++static int ath5k_eeprom_init(void *mem, u_int8_t mac_version,
++                           struct ath5k_eeprom_info *ee)
++{
++      unsigned int mode, i;
++      int ret;
++      u_int32_t offset;
++      u_int16_t val;
++
++      /* Initial TX thermal adjustment values */
++      ee->ee_tx_clip = 4;
++      ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
++      ee->ee_gain_select = 1;
++
++      /*
++       * Read values from EEPROM and store them in the capability structure
++       */
++      AR5K_EEPROM_READ(AR5K_EEPROM_MAGIC, ee->ee_magic);
++      AR5K_EEPROM_READ(AR5K_EEPROM_PROTECT, ee->ee_protect);
++      AR5K_EEPROM_READ(AR5K_EEPROM_REG_DOMAIN, ee->ee_regdomain);
++      AR5K_EEPROM_READ(AR5K_EEPROM_VERSION, ee->ee_version);
++      AR5K_EEPROM_READ(AR5K_EEPROM_HDR, ee->ee_header);
++
++      /* Return if we have an old EEPROM */
++      if (ee->ee_version < AR5K_EEPROM_VERSION_3_0)
++              return 0;
++
++#ifdef notyet
++      /*
++       * Validate the checksum of the EEPROM date. There are some
++       * devices with invalid EEPROMs.
++       */
++      for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
++              AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
++              cksum ^= val;
++      }
++      if (cksum != AR5K_EEPROM_INFO_CKSUM) {
++              AR5K_PRINTF("Invalid EEPROM checksum 0x%04x\n", cksum);
++              return -EIO;
++      }
++#endif
++
++      AR5K_EEPROM_READ(AR5K_EEPROM_ANT_GAIN(ee->ee_version), ee->ee_ant_gain);
++
++      if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) {
++              AR5K_EEPROM_READ(AR5K_EEPROM_MISC0, ee->ee_misc0);
++              AR5K_EEPROM_READ(AR5K_EEPROM_MISC1, ee->ee_misc1);
++      }
++
++      if (ee->ee_version < AR5K_EEPROM_VERSION_3_3) {
++              AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
++              ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
++              ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
++
++              AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
++              ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
++              ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
++      }
++
++      /*
++       * Get conformance test limit values
++       */
++      offset = AR5K_EEPROM_CTL(ee->ee_version);
++      ee->ee_ctls = 0;
++
++      for (i = 0; i < AR5K_EEPROM_N_CTLS(ee->ee_version); i++) {
++              AR5K_EEPROM_READ(offset++, val);
++
++              if (((val >> 8) & 0xff) == 0)
++                      break;
++
++              ee->ee_ctl[i] = (val >> 8) & 0xff;
++              ee->ee_ctls++;
++
++              if ((val & 0xff) == 0)
+                       break;
++
++              ee->ee_ctl[i + 1] = val & 0xff;
++              ee->ee_ctls++;
++      }
++
++      /*
++       * Get values for 802.11a (5GHz)
++       */
++      mode = AR5K_EEPROM_MODE_11A;
++
++      ee->ee_turbo_max_power[mode] =
++          AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
++
++      offset = AR5K_EEPROM_MODES_11A(ee->ee_version);
++
++      ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      AR5K_EEPROM_READ(offset++, val);
++      ee->ee_adc_desired_size[mode]   = (int8_t)((val >> 8) & 0xff);
++      ee->ee_ob[mode][3]              = (val >> 5) & 0x7;
++      ee->ee_db[mode][3]              = (val >> 2) & 0x7;
++      ee->ee_ob[mode][2]              = (val << 1) & 0x7;
++
++      AR5K_EEPROM_READ(offset++, val);
++      ee->ee_ob[mode][2]              |= (val >> 15) & 0x1;
++      ee->ee_db[mode][2]              = (val >> 12) & 0x7;
++      ee->ee_ob[mode][1]              = (val >> 9) & 0x7;
++      ee->ee_db[mode][1]              = (val >> 6) & 0x7;
++      ee->ee_ob[mode][0]              = (val >> 3) & 0x7;
++      ee->ee_db[mode][0]              = val & 0x7;
++
++      ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1) {
++              AR5K_EEPROM_READ(offset++, val);
++              ee->ee_margin_tx_rx[mode] = val & 0x3f;
++      }
++
++      /*
++       * Get values for 802.11b (2.4GHz)
++       */
++      mode = AR5K_EEPROM_MODE_11B;
++      offset = AR5K_EEPROM_MODES_11B(ee->ee_version);
++
++      ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      AR5K_EEPROM_READ(offset++, val);
++      ee->ee_adc_desired_size[mode]   = (int8_t)((val >> 8) & 0xff);
++      ee->ee_ob[mode][1]              = (val >> 4) & 0x7;
++      ee->ee_db[mode][1]              = val & 0x7;
++
++      ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) {
++              AR5K_EEPROM_READ(offset++, val);
++
++              ee->ee_cal_piers_b = 0;
++
++              ee->ee_pwr_cal_b[0].freq =
++                      ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++              if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
++                      ee->ee_cal_piers_b++;
++
++              ee->ee_pwr_cal_b[1].freq =
++                      ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
++              if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
++                      ee->ee_cal_piers_b++;
++
++              AR5K_EEPROM_READ(offset++, val);
++              ee->ee_pwr_cal_b[2].freq =
++                      ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++              if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
++                      ee->ee_cal_piers_b++;
++      }
++
++      if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1)
++              ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
++
++      /*
++       * Get values for 802.11g (2.4GHz)
++       */
++      mode = AR5K_EEPROM_MODE_11G;
++      offset = AR5K_EEPROM_MODES_11G(ee->ee_version);
++
++      ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      AR5K_EEPROM_READ(offset++, val);
++      ee->ee_adc_desired_size[mode]   = (signed short int)((val >> 8) & 0xff);
++      ee->ee_ob[mode][1]              = (val >> 4) & 0x7;
++      ee->ee_db[mode][1]              = val & 0x7;
++
++      ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) {
++              AR5K_EEPROM_READ(offset++, val);
++
++              ee->ee_cal_piers_g = 0;
++
++              ee->ee_pwr_cal_g[0].freq =
++                      ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++              if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
++                      ee->ee_cal_piers_g++;
++
++              ee->ee_pwr_cal_g[1].freq =
++                      ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
++              if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
++                      ee->ee_cal_piers_g++;
++
++              AR5K_EEPROM_READ(offset++, val);
++              ee->ee_turbo_max_power[mode] = val & 0x7f;
++              ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
++
++              AR5K_EEPROM_READ(offset++, val);
++              ee->ee_pwr_cal_g[2].freq =
++                      ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++              if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
++                      ee->ee_cal_piers_g++;
++
++              if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1)
++                      ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
++
++              AR5K_EEPROM_READ(offset++, val);
++              ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
++              ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
++
++              if (ee->ee_version >= AR5K_EEPROM_VERSION_4_2) {
++                      AR5K_EEPROM_READ(offset++, val);
++                      ee->ee_cck_ofdm_gain_delta = val & 0xff;
+               }
+       }
+-      return (name);
++      /*
++       * Read 5GHz EEPROM channels
++       */
++      offset = AR5K_EEPROM_CHANNELS_5GHZ(ee->ee_version);
++      ee->ee_cal_piers_a = 0;
++      for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) {
++              AR5K_EEPROM_READ(offset++, val);
++
++              if ((val & 0xff) == 0)
++                      break;
++
++              ee->ee_pwr_cal_a[i].freq =
++                      ath5k_eeprom_bin2freq(ee, val & 0xff, AR5K_EEPROM_MODE_11A);
++              ee->ee_cal_piers_a++;
++
++              if (((val >> 8) & 0xff) == 0)
++                      break;
++
++              ee->ee_pwr_cal_a[++i].freq =
++                      ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, AR5K_EEPROM_MODE_11A);
++              ee->ee_cal_piers_a++;
++
++      }
++
++      /*
++       * Read power calibration info
++       */
++      mode = AR5K_EEPROM_MODE_11A;
++      ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      mode = AR5K_EEPROM_MODE_11B;
++      ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      mode = AR5K_EEPROM_MODE_11G;
++      ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++
++      /*
++       * Read per rate target power info
++       */
++      offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
++      mode = AR5K_EEPROM_MODE_11A;
++      ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
++      mode = AR5K_EEPROM_MODE_11B;
++      ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
++      mode = AR5K_EEPROM_MODE_11G;
++      ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode);
++      if (ret)
++              return ret;
++
++      return 0;
++}
++
++static const char *ath5k_hw_get_mac_name(u_int8_t val)
++{
++      static char name[16];
++      unsigned int i;
++
++      for (i = 0; i < ARRAY_SIZE(ath5k_mac_names); i++) {
++              if (val <= ath5k_mac_names[i].sr_val)
++                      break;
++      }
++
++      if (val == ath5k_mac_names[i].sr_val)
++              return ath5k_mac_names[i].sr_name;
++
++      snprintf(name, sizeof(name), "%s+", ath5k_mac_names[i - 1].sr_name);
++      return name;
++}
++
++static const char *ath5k_hw_get_phy_name(u_int8_t val)
++{
++      const char *name = "?????";
++      unsigned int i;
++
++      for (i = 0; i < ARRAY_SIZE(ath5k_phy_names); i++) {
++              if (val < ath5k_phy_names[i + 1].sr_val) {
++                      name = ath5k_phy_names[i].sr_name;
++                      break;
++              }
++      }
++
++      return name;
+ }
+ /* returns -1 on unknown name */
+ static int eeprom_name2addr(const char *name)
+ {
+-      int i;
++      unsigned int i;
++
+       if (!name || !name[0])
+               return -1;
+-      for (i = 0; i < eeprom_addr_len; i++)
++      for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++)
+               if (!strcmp(name, eeprom_addr[i].name))
+                       return eeprom_addr[i].addr;
+       return -1;
+-}                             /* eeprom_name2addr */
++}
+ /* returns "<unknown>" on unknown address */
+ static const char *eeprom_addr2name(int addr)
+ {
+-      int i;
+-      for (i = 0; i < eeprom_addr_len; i++)
++      unsigned int i;
++
++      for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++)
+               if (eeprom_addr[i].addr == addr)
+                       return eeprom_addr[i].name;
+       return "<unknown>";
+-}                             /* eeprom_addr2name */
++}
+-static int
+-do_write_pairs(int anr, int argc, char **argv, unsigned char *mem,
+-             int mac_version)
++static int do_write_pairs(int anr, int argc, char **argv, unsigned char *mem,
++                        int mac_version)
+ {
+ #define MAX_NR_WRITES 16
+       struct {
+@@ -635,7 +1422,7 @@ do_write_pairs(int anr, int argc, char *
+               }
+               anr++;
+               i++;
+-      }                       /* while (anr < (argc-1)) */
++      }
+       if (!(wr_ops_len = i)) {
+               err("no (addr,val) pairs given");
+@@ -702,20 +1489,22 @@ do_write_pairs(int anr, int argc, char *
+       }
+       return errors ? 11 : 0;
+-}                             /* do_write_pairs */
++}
+ static void usage(const char *n)
+ {
+-      int i;
++      unsigned int i;
+-      fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] [-d] <base_address> "
++      fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] [-d] [-R addr] [-W addr val] <base_address> "
+               "[<name1> <val1> [<name2> <val2> ...]]\n\n", n);
+       fprintf(stderr,
+               "-w      write values into EEPROM\n"
+               "-g N:M  set GPIO N to level M (only used with -w)\n"
+               "-v      verbose output\n"
+               "-f      force; suppress question before writing\n"
+-              "-d      dump eeprom (file 'ath-eeprom-dump.bin' and screen)\n"
++              "-d      dump EEPROM (file 'ath-eeprom-dump.bin' and screen)\n"
++              "-R <addr>       read register at <addr> (hex)\n"
++              "-W <addr> <val> write <val> (hex) into register at <addr> (hex)\n"
+               "<base_address>  device base address (see lspci output)\n\n");
+       fprintf(stderr,
+@@ -725,8 +1514,8 @@ static void usage(const char *n)
+               "  %s -w <base_address> regdomain N\n\n"
+               "- set a PCI id field to value N:\n"
+               "  %s -w <base_address> <field> N\n"
+-              "  where <field> is on of:\n    ", n, n, n);
+-      for (i = 0; i < eeprom_addr_len; i++)
++              "  where <field> is one of:\n    ", n, n, n);
++      for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++)
+               fprintf(stderr, " %s", eeprom_addr[i].name);
+       fprintf(stderr, "\n\n");
+       fprintf(stderr,
+@@ -739,19 +1528,457 @@ static void usage(const char *n)
+               "unlawful radio transmissions!\n\n");
+ }
++static void dump_capabilities(struct ath5k_eeprom_info *ee)
++{
++      u_int8_t has_a, has_b, has_g, has_rfkill, turbog_dis, turboa_dis;
++      u_int8_t xr2_dis, xr5_dis, has_crystal;
++
++      has_a = AR5K_EEPROM_HDR_11A(ee->ee_header);
++      has_b = AR5K_EEPROM_HDR_11B(ee->ee_header);
++      has_g = AR5K_EEPROM_HDR_11G(ee->ee_header);
++      has_rfkill = AR5K_EEPROM_HDR_RFKILL(ee->ee_header);
++      has_crystal = AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1);
++      turbog_dis = AR5K_EEPROM_HDR_T_2GHZ_DIS(ee->ee_header);
++      turboa_dis = AR5K_EEPROM_HDR_T_5GHZ_DIS(ee->ee_header);
++      xr2_dis = AR5K_EEPROM_HDR_XR2_DIS(ee->ee_misc0);
++      xr5_dis = AR5K_EEPROM_HDR_XR5_DIS(ee->ee_misc0);
++
++      printf("|================= Capabilities ================|\n");
++
++      printf("| 802.11a Support: ");
++      if (has_a)
++              printf(" yes |");
++      else
++              printf(" no  |");
++
++      printf(" Turbo-A disabled:");
++      if (turboa_dis)
++              printf(" yes |\n");
++      else
++              printf(" no  |\n");
++
++      printf("| 802.11b Support: ");
++      if (has_b)
++              printf(" yes |");
++      else
++              printf(" no  |");
++
++      printf(" Turbo-G disabled:");
++      if (turbog_dis)
++              printf(" yes |\n");
++      else
++              printf(" no  |\n");
++
++      printf("| 802.11g Support: ");
++      if (has_g)
++              printf(" yes |");
++      else
++              printf(" no  |");
++
++      printf(" 2GHz XR disabled:");
++      if (xr2_dis)
++              printf(" yes |\n");
++      else
++              printf(" no  |\n");
++
++      printf("| RFKill  Support: ");
++      if (has_rfkill)
++              printf(" yes |");
++      else
++              printf(" no  |");
++
++      printf(" 5GHz XR disabled:");
++      if (xr5_dis)
++              printf(" yes |\n");
++      else
++              printf(" no  |\n");
++
++      if (has_crystal != 2) {
++              printf("| 32kHz   Crystal: ");
++              if (has_crystal)
++                      printf(" yes |");
++              else
++                      printf(" no  |");
++
++              printf("                       |\n");
++      }
++
++      printf("\\===============================================/\n");
++}
++
++static void dump_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee)
++{
++      int i;
++
++      printf("|=========================================================|\n");
++      printf("| I power:              0x%02x |", ee->ee_i_cal[mode]);
++      printf(" Q power:              0x%02x |\n", ee->ee_q_cal[mode]);
++      printf("| Use fixed bias:       0x%02x |", ee->ee_fixed_bias[mode]);
++      printf(" Max turbo power:      0x%02x |\n", ee->ee_turbo_max_power[mode]);
++      printf("| Max XR power:         0x%02x |", ee->ee_xr_power[mode]);
++      printf(" Switch Settling Time: 0x%02x |\n", ee->ee_switch_settling[mode]);
++      printf("| Tx/Rx attenuation:    0x%02x |", ee->ee_ant_tx_rx[mode]);
++      printf(" TX end to XLNA On:    0x%02x |\n", ee->ee_tx_end2xlna_enable[mode]);
++      printf("| TX end to XPA Off:    0x%02x |", ee->ee_tx_end2xpa_disable[mode]);
++      printf(" TX end to XPA On:     0x%02x |\n", ee->ee_tx_frm2xpa_enable[mode]);
++      printf("| 62db Threshold:       0x%02x |", ee->ee_thr_62[mode]);
++      printf(" XLNA gain:            0x%02x |\n", ee->ee_xlna_gain[mode]);
++      printf("| XPD:                  0x%02x |", ee->ee_xpd[mode]);
++      printf(" XPD gain:             0x%02x |\n", ee->ee_x_gain[mode]);
++      printf("| I gain:               0x%02x |", ee->ee_i_gain[mode]);
++      printf(" Tx/Rx margin:         0x%02x |\n", ee->ee_margin_tx_rx[mode]);
++      printf("| False detect backoff: 0x%02x |", ee->ee_false_detect[mode]);
++      printf(" Noise Floor Threshold: %3d |\n", ee->ee_noise_floor_thr[mode]);
++      printf("| ADC desired size:      %3d |", ee->ee_adc_desired_size[mode]);
++      printf(" PGA desired size:      %3d |\n", ee->ee_pga_desired_size[mode]);
++      printf("|=========================================================|\n");
++      for (i = 0; i < AR5K_EEPROM_N_PCDAC; i++) {
++              printf("| Antenna control  %2i:  0x%02x |", i, ee->ee_ant_control[mode][i]);
++              i++;
++              printf(" Antenna control  %2i:  0x%02x |\n", i, ee->ee_ant_control[mode][i]);
++      }
++      printf("|=========================================================|\n");
++      for (i = 0; i < AR5K_EEPROM_N_OBDB; i++) {
++              printf("| Octave Band %i:          %2i |", i, ee->ee_ob[mode][i]);
++              printf(" db %i:                   %2i |\n", i, ee->ee_db[mode][i]);
++      }
++      printf("\\=========================================================/\n");
++}
++
++static void dump_power_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee)
++{
++      struct ath5k_chan_pcal_info *chan_pcal_info;
++      u_int16_t cal_piers;
++      int i, c;
++
++      switch (mode) {
++      case AR5K_EEPROM_MODE_11A:
++              chan_pcal_info = ee->ee_pwr_cal_a;
++              cal_piers = ee->ee_cal_piers_a;
++              break;
++      case AR5K_EEPROM_MODE_11B:
++              chan_pcal_info = ee->ee_pwr_cal_b;
++              cal_piers = ee->ee_cal_piers_b;
++              break;
++      case AR5K_EEPROM_MODE_11G:
++              chan_pcal_info = ee->ee_pwr_cal_g;
++              cal_piers = ee->ee_cal_piers_g;
++              break;
++      default:
++              return;
++      }
++
++      printf("/=================== Per channel power calibration ====================\\\n");
++      printf("| Freq | pwr_0 | pwr_1 | pwr_2 | pwr_3 |pwrx3_0|pwrx3_1|pwrx3_2|max_pwr|\n");
++      printf("|      | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac |       |\n");
++
++      for (i = 0; i < cal_piers; i++) {
++              char buf[16];
++
++              printf("|======|=======|=======|=======|=======|=======|=======|=======|=======|\n");
++              printf("| %4i |", chan_pcal_info[i].freq);
++              for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
++                      printf(" %2i.%02i |", chan_pcal_info[i].pwr_x0[c] / 4,
++                             chan_pcal_info[i].pwr_x0[c] % 4);
++              }
++              for (c = 0; c < AR5K_EEPROM_N_XPD3_POINTS; c++) {
++                      printf(" %2i.%02i |", chan_pcal_info[i].pwr_x3[c] / 4,
++                             chan_pcal_info[i].pwr_x3[c] % 4);
++              }
++              printf(" %2i.%02i |\n", chan_pcal_info[i].max_pwr / 4,
++                     chan_pcal_info[i].max_pwr % 4);
++
++              printf("|      |");
++              for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
++                      snprintf(buf, sizeof(buf), "[%i]",
++                               chan_pcal_info[i].pcdac_x0[c]);
++                      printf("%6s |", buf);
++              }
++              for (c = 0; c < AR5K_EEPROM_N_XPD3_POINTS; c++) {
++                      snprintf(buf, sizeof(buf), "[%i]",
++                               chan_pcal_info[i].pcdac_x3[c]);
++                      printf("%6s |", buf);
++              }
++              printf("       |\n");
++
++      }
++      printf("\\======================================================================/\n");
++}
++
++static void dump_rate_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee)
++{
++      int i;
++      struct ath5k_rate_pcal_info *rate_pcal_info;
++      u_int16_t rate_target_pwr_num;
++
++      switch (mode) {
++      case AR5K_EEPROM_MODE_11A:
++              rate_pcal_info = ee->ee_rate_tpwr_a;
++              rate_target_pwr_num = ee->ee_rate_target_pwr_num_a;
++              break;
++      case AR5K_EEPROM_MODE_11B:
++              rate_pcal_info = ee->ee_rate_tpwr_b;
++              rate_target_pwr_num = ee->ee_rate_target_pwr_num_b;
++              break;
++      case AR5K_EEPROM_MODE_11G:
++              rate_pcal_info = ee->ee_rate_tpwr_g;
++              rate_target_pwr_num = ee->ee_rate_target_pwr_num_g;
++              break;
++      default:
++              return;
++      }
++
++      printf("/============== Per rate power calibration ===========\\\n");
++      if (mode == AR5K_EEPROM_MODE_11B)
++              printf("| Freq |   1Mbit/s  | 2Mbit/s  | 5.5Mbit/s | 11Mbit/s |\n");
++      else
++              printf("| Freq | 6-24Mbit/s | 36Mbit/s |  48Mbit/s | 54Mbit/s |\n");
++
++      for (i = 0; i < rate_target_pwr_num; i++) {
++
++              printf("|======|============|==========|===========|==========|\n");
++              printf("| %4i |", rate_pcal_info[i].freq);
++              printf("    %2i.%02i   |",rate_pcal_info[i].target_power_6to24 /2,
++                                      rate_pcal_info[i].target_power_6to24 % 2);
++              printf("  %2i.%02i   |",rate_pcal_info[i].target_power_36 /2,
++                                      rate_pcal_info[i].target_power_36 % 2);
++              printf("   %2i.%02i   |",rate_pcal_info[i].target_power_48 /2,
++                                      rate_pcal_info[i].target_power_48 % 2);
++              printf("  %2i.%02i   |\n",rate_pcal_info[i].target_power_54 /2,
++                                      rate_pcal_info[i].target_power_54 % 2);
++      }
++      printf("\\=====================================================/\n");
++}
++
++static u_int32_t extend_tu(u_int32_t base_tu, u_int32_t val, u_int32_t mask)
++{
++      u_int32_t result;
++
++      result = (base_tu & ~mask) | (val & mask);
++      if ((base_tu & mask) > (val & mask))
++              result += mask + 1;
++      return result;
++}
++
++static void dump_timers_register(void *mem, u_int16_t mac_version)
++{
++#define AR5K_TIMER0_5210              0x802c  /* next TBTT */
++#define AR5K_TIMER0_5211              0x8028
++#define AR5K_TIMER0                   (mac_version == AR5K_SREV_MAC_AR5210 ? \
++                                      AR5K_TIMER0_5210 : AR5K_TIMER0_5211)
++
++#define AR5K_TIMER1_5210              0x8030  /* next DMA beacon */
++#define AR5K_TIMER1_5211              0x802c
++#define AR5K_TIMER1                   (mac_version == AR5K_SREV_MAC_AR5210 ? \
++                                      AR5K_TIMER1_5210 : AR5K_TIMER1_5211)
++
++#define AR5K_TIMER2_5210              0x8034  /* next SWBA interrupt */
++#define AR5K_TIMER2_5211              0x8030
++#define AR5K_TIMER2                   (mac_version == AR5K_SREV_MAC_AR5210 ? \
++                                      AR5K_TIMER2_5210 : AR5K_TIMER2_5211)
++
++#define AR5K_TIMER3_5210              0x8038  /* next ATIM window */
++#define AR5K_TIMER3_5211              0x8034
++#define AR5K_TIMER3                   (mac_version == AR5K_SREV_MAC_AR5210 ? \
++                                      AR5K_TIMER3_5210 : AR5K_TIMER3_5211)
++
++#define AR5K_TSF_L32_5210             0x806c  /* TSF (lower 32 bits) */
++#define AR5K_TSF_L32_5211             0x804c
++#define AR5K_TSF_L32                  (mac_version == AR5K_SREV_MAC_AR5210 ? \
++                                      AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211)
++
++#define AR5K_TSF_U32_5210             0x8070
++#define AR5K_TSF_U32_5211             0x8050
++#define AR5K_TSF_U32                  (mac_version == AR5K_SREV_MAC_AR5210 ? \
++                                      AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
++
++#define AR5K_BEACON_5210              0x8024
++#define AR5K_BEACON_5211              0x8020
++#define AR5K_BEACON                   (mac_version == AR5K_SREV_MAC_AR5210 ? \
++                                      AR5K_BEACON_5210 : AR5K_BEACON_5211)
++
++#define AR5K_LAST_TSTP                        0x8080
++
++      const int timer_mask = 0xffff;
++
++      u_int32_t timer0, timer1, timer2, timer3, now_tu;
++      u_int32_t timer0_tu, timer1_tu, timer2_tu, timer3_tu;
++      u_int64_t now_tsf;
++
++      timer0 = AR5K_REG_READ(AR5K_TIMER0);            /* 0x0000ffff */
++      timer1 = AR5K_REG_READ(AR5K_TIMER1_5211);       /* 0x0007ffff */
++      timer2 = AR5K_REG_READ(AR5K_TIMER2_5211);       /* 0x?1ffffff */
++      timer3 = AR5K_REG_READ(AR5K_TIMER3_5211);       /* 0x0000ffff */
++
++      now_tsf = ((u_int64_t)AR5K_REG_READ(AR5K_TSF_U32_5211) << 32)
++              | (u_int64_t)AR5K_REG_READ(AR5K_TSF_L32_5211);
++
++      now_tu = now_tsf >> 10;
++
++      timer0_tu = extend_tu(now_tu, timer0, 0xffff);
++      printf("TIMER0: 0x%08x, TBTT: %5u, TU: 0x%08x\n", timer0,
++             timer0 & timer_mask, timer0_tu);
++      timer1_tu = extend_tu(now_tu, timer1 >> 3, 0x7ffff >> 3);
++      printf("TIMER1: 0x%08x, DMAb: %5u, TU: 0x%08x (%+d)\n", timer1,
++             (timer1 >> 3) & timer_mask, timer1_tu, timer1_tu - timer0_tu);
++      timer2_tu = extend_tu(now_tu, timer2 >> 3, 0x1ffffff >> 3);
++      printf("TIMER2: 0x%08x, SWBA: %5u, TU: 0x%08x (%+d)\n", timer2,
++             (timer2 >> 3) & timer_mask, timer2_tu, timer2_tu - timer0_tu);
++      timer3_tu = extend_tu(now_tu, timer3, 0xffff);
++      printf("TIMER3: 0x%08x, ATIM: %5u, TU: 0x%08x (%+d)\n", timer3,
++             timer3 & timer_mask, timer3_tu, timer3_tu - timer0_tu);
++      printf("TSF: 0x%016llx, TSFTU: %5u, TU: 0x%08x\n",
++             (unsigned long long)now_tsf, now_tu & timer_mask, now_tu);
++
++      printf("BEACON: 0x%08x\n", AR5K_REG_READ(AR5K_BEACON));
++      printf("LAST_TSTP: 0x%08x\n", AR5K_REG_READ(AR5K_LAST_TSTP));
++}
++
++#define AR5K_KEYTABLE_0_5210          0x9000
++#define AR5K_KEYTABLE_0_5211          0x8800
++#define AR5K_KEYTABLE_0                       (mac_version == AR5K_SREV_MAC_AR5210 ? \
++                                      AR5K_KEYTABLE_0_5210 : \
++                                      AR5K_KEYTABLE_0_5211)
++
++#define AR5K_KEYTABLE(_n)             (AR5K_KEYTABLE_0_5211 + ((_n) << 5))
++#define AR5K_KEYTABLE_OFF(_n, x)      (AR5K_KEYTABLE(_n) + ((x) << 2))
++#define AR5K_KEYTABLE_VALID           0x00008000
++
++#define AR5K_KEYTABLE_SIZE_5210               64
++#define AR5K_KEYTABLE_SIZE_5211               128
++#define AR5K_KEYTABLE_SIZE            (mac_version == AR5K_SREV_MAC_AR5210 ? \
++                                      AR5K_KEYTABLE_SIZE_5210 : \
++                                      AR5K_KEYTABLE_SIZE_5211)
++
++static void keycache_dump(void *mem, u_int16_t mac_version)
++{
++      int i, keylen;
++      u_int32_t val0, val1, val2, val3, val4, keytype, ant, mac0, mac1;
++
++      /* dump all 128 entries */
++      printf("Dumping keycache entries...\n");
++      for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) {
++              mac1 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 7));
++              if (mac1 & AR5K_KEYTABLE_VALID) {
++                      val0    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 0));
++                      val1    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 1));
++                      val2    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 2));
++                      val3    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 3));
++                      val4    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 4));
++                      keytype = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 5));
++                      ant = keytype & 8;
++                      keytype &= ~8;
++                      switch (keytype) {
++                      case 0: /* WEP40  */ keylen =  40 / 8; break;
++                      case 1: /* WEP104 */ keylen = 104 / 8; break;
++                      case 3: /* WEP128 */ keylen = 128 / 8; break;
++                      case 4: /* TKIP   */ keylen = 128 / 8; break;
++                      case 5: /* AES    */ keylen = 128 / 8; break;
++                      case 6: /* CCM    */ keylen = 128 / 8; break;
++                      default:             keylen = 0;       break;
++                      }
++                      mac0 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 6));
++
++                      printf("[%3u] keytype %d [%s%s%s%s%s%s%s%s] mac %02x:%02x:%02x:%02x:%02x:%02x key:%08x-%08x-%08x-%08x-%08x\n",
++                             i,
++                             keytype,
++                             keytype == 0 ? "WEP40 " : "",
++                             keytype == 1 ? "WEP104" : "",
++                             keytype == 3 ? "WEP128" : "",
++                             keytype == 4 ? "TKIP  " : "",
++                             keytype == 5 ? "AES   " : "",
++                             keytype == 6 ? "CCM   " : "",
++                             keytype == 7 ? "NULL  " : "",
++                             ant     == 8 ? "+ANT"   : "",
++                             ((mac0 <<  1) & 0xff),
++                             ((mac0 >>  7) & 0xff),
++                             ((mac0 >> 15) & 0xff),
++                             ((mac0 >> 23) & 0xff),
++                             ((mac1 <<  1) & 0xff) | (mac0 >> 31),
++                             ((mac1 >>  7) & 0xff),
++                             val0, val1, val2, val3, val4);
++              }
++      }
++}
++
++/* copy key index (0) to key index (idx) */
++
++static void keycache_copy(void *mem, u_int16_t mac_version, int idx)
++{
++      u_int32_t val0, val1, val2, val3, val4, keytype, mac0, mac1;
++
++      printf("Copying keycache entry 0 to %d\n", idx);
++      if (idx < 0 || idx >= AR5K_KEYTABLE_SIZE) {
++              printf("invalid keycache index\n");
++              return;
++      }
++
++      val0    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 0));
++      val1    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 1));
++      val2    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 2));
++      val3    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 3));
++      val4    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 4));
++      keytype = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 5));
++      mac0    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 6));
++      mac1    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 7));
++
++      AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 0), val0);
++      AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 1), val1);
++      AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 2), val2);
++      AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 3), val3);
++      AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 4), val4);
++      AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 5), keytype);
++      AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 6), mac0);
++      AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 7), mac1);
++}
++
++static void sta_id0_id1_dump(void *mem)
++{
++#define AR5K_STA_ID0                  0x8000
++#define AR5K_STA_ID1                  0x8004
++#define AR5K_STA_ID1_AP                 0x00010000
++#define AR5K_STA_ID1_ADHOC              0x00020000
++#define AR5K_STA_ID1_NO_KEYSRCH               0x00080000
++
++      u_int32_t sta_id0, sta_id1;
++
++      sta_id0 = AR5K_REG_READ(AR5K_STA_ID0);
++      sta_id1 = AR5K_REG_READ(AR5K_STA_ID1);
++      printf("STA_ID0: %02x:%02x:%02x:%02x:%02x:%02x\n",
++             (sta_id0 >>  0) & 0xff,
++             (sta_id0 >>  8) & 0xff,
++             (sta_id0 >> 16) & 0xff,
++             (sta_id0 >> 24) & 0xff,
++             (sta_id1 >>  0) & 0xff,
++             (sta_id1 >>  8) & 0xff);
++      printf("STA_ID1: 0x%08x, AP: %d, IBSS: %d, KeyCache Disable: %d\n",
++             sta_id1,
++             sta_id1 & AR5K_STA_ID1_AP ? 1 : 0,
++             sta_id1 & AR5K_STA_ID1_ADHOC ? 1 : 0,
++             sta_id1 & AR5K_STA_ID1_NO_KEYSRCH ? 1 : 0);
++}
++
+ int
+ CMD(athinfo)(int argc, char *argv[])
+ {
+-      u_int32_t dev_addr;
+-      u_int16_t eeprom_header, srev, phy_rev_5ghz, phy_rev_2ghz;
+-      u_int16_t eeprom_version, mac_version, regdomain, has_crystal, ee_magic;
+-      u_int8_t error, has_a, has_b, has_g, has_rfkill, eeprom_size;
+-      int byte_size = 0;
++      unsigned long long dev_addr;
++      u_int16_t srev, phy_rev_5ghz, phy_rev_2ghz, ee_magic;
++      u_int8_t mac_version, mac_revision;
++      u_int8_t error, eeprom_size, dev_type, eemap;
++      struct ath5k_eeprom_info *ee;
++      unsigned int byte_size = 0;
+       void *mem;
+       int fd;
+-      int i, anr = 1;
++      unsigned int i;
++      int anr = 1;
+       int do_write = 0;       /* default: read only */
+       int do_dump = 0;
++      int reg_read = 0;
++      int reg_write = 0;
++      unsigned int reg_write_val = 0;
++      unsigned int timer_count = 1;
++      int do_keycache_dump = 0;
++      int keycache_copy_idx = 0;
+       struct {
+               int valid;
+@@ -759,7 +1986,7 @@ CMD(athinfo)(int argc, char *argv[])
+       } gpio_set[AR5K_NUM_GPIO];
+       int nr_gpio_set = 0;
+-      for (i = 0; i < sizeof(gpio_set) / sizeof(gpio_set[0]); i++)
++      for (i = 0; i < ARRAY_SIZE(gpio_set); i++)
+               gpio_set[i].valid = 0;
+       if (argc < 2) {
+@@ -769,6 +1996,15 @@ CMD(athinfo)(int argc, char *argv[])
+       while (anr < argc && argv[anr][0] == '-') {
+               switch (argv[anr][1]) {
++              case 't':
++                      if (++anr < argc) {
++                              timer_count = atoi(argv[anr]);
++                              printf("timer_count:%d\n", timer_count);
++                      } else {
++                              usage(argv[0]);
++                              return 0;
++                      }
++                      break;
+               case 'w':
+                       do_write = 1;
+                       break;
+@@ -777,7 +2013,7 @@ CMD(athinfo)(int argc, char *argv[])
+                       if (strlen(argv[anr]) != 3 || argv[anr][1] != ':' ||
+                           argv[anr][0] < '0' || argv[anr][0] > '5' ||
+                           (argv[anr][2] != '0' && argv[anr][2] != '1')) {
+-                              err("invalid gpio spec. %s", argv[anr]);
++                              err("invalid GPIO spec. %s", argv[anr]);
+                               return 2;
+                       }
+                       gpio_set[argv[anr][0] - '0'].valid = 1;
+@@ -797,6 +2033,25 @@ CMD(athinfo)(int argc, char *argv[])
+                       do_dump = 1;
+                       break;
++              case 'R':
++                      anr++;
++                      reg_read = strtoul(argv[anr], NULL, 16);
++                      break;
++
++              case 'W':
++                      anr++;
++                      reg_write = strtoul(argv[anr++], NULL, 16);
++                      reg_write_val = strtoul(argv[anr], NULL, 16);
++                      break;
++
++              case 'k':
++                      do_keycache_dump = 1;
++                      break;
++
++              case 'K':
++                      keycache_copy_idx = atoi(argv[++anr]);
++                      break;
++
+               case 'h':
+                       usage(argv[0]);
+                       return 0;
+@@ -805,10 +2060,10 @@ CMD(athinfo)(int argc, char *argv[])
+               default:
+                       err("unknown option %s", argv[anr]);
+                       return 2;
+-              }               /* switch (argv[anr][1]) */
++              }
+               anr++;
+-      }                       /* while (anr < argc && ...) */
++      }
+       if (anr >= argc) {
+               err("missing device address");
+@@ -816,7 +2071,7 @@ CMD(athinfo)(int argc, char *argv[])
+               return 3;
+       }
+-      dev_addr = strtoul(argv[anr], NULL, 16);
++      dev_addr = strtoull(argv[anr], NULL, 16);
+       fd = open("/dev/mem", O_RDWR);
+       if (fd < 0) {
+@@ -828,7 +2083,7 @@ CMD(athinfo)(int argc, char *argv[])
+                  MAP_SHARED | MAP_FILE, fd, dev_addr);
+       if (mem == MAP_FAILED) {
+-              printf("Mmap of device at 0x%08X for 0x%X bytes failed - "
++              printf("mmap of device at 0x%08llX for 0x%X bytes failed - "
+                      "%s\n", dev_addr, AR5K_PCI_MEM_SIZE, strerror(errno));
+               return -3;
+       }
+@@ -856,10 +2111,31 @@ CMD(athinfo)(int argc, char *argv[])
+       AR5K_REG_DISABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_SPWR_DN);
+       usleep(500);
++      if (reg_read) {
++              printf("READ %04x = %08x\n", reg_read, AR5K_REG_READ(reg_read));
++              return 0;
++      }
++
++      if (reg_write) {
++              printf("WRITE %04x = %08x\n", reg_write, reg_write_val);
++              AR5K_REG_WRITE(reg_write, reg_write_val);
++              return 0;
++      }
++
+       srev = AR5K_REG_READ(AR5K_SREV);
+-      mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER) << 4;
++      if (srev >= 0x0100) {
++              printf("MAC revision 0x%04x is not supported!\n", srev);
++              return -1;
++      }
++      mac_version = srev & AR5K_SREV_VER;
++      mac_revision = srev & AR5K_SREV_REV;
+-      /* Verify eeprom magic value first */
++      printf(" -==Device Information==-\n");
++
++      printf("MAC Revision: %-5s (0x%02x)\n",
++             ath5k_hw_get_mac_name(mac_revision), mac_revision);
++
++      /* Verify EEPROM magic value first */
+       error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_MAGIC, &ee_magic,
+                                    mac_version);
+@@ -872,157 +2148,114 @@ CMD(athinfo)(int argc, char *argv[])
+               printf("Warning: Invalid EEPROM Magic number!\n");
+       }
+-      error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_HDR, &eeprom_header,
+-                                   mac_version);
+-
+-      if (error) {
+-              printf("Unable to read EEPROM Header!\n");
+-              return -1;
+-      }
+-
+-      error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_VERSION, &eeprom_version,
+-                                   mac_version);
+-
+-      if (error) {
+-              printf("Unable to read EEPROM version!\n");
++      ee = calloc(sizeof(struct ath5k_eeprom_info), 1);
++      if (!ee) {
++              printf("Cannot allocate memory for EEPROM information\n");
+               return -1;
+       }
+-      error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_REG_DOMAIN, &regdomain,
+-                                   mac_version);
+-
+-      if (error) {
+-              printf("Unable to read Regdomain!\n");
++      if (ath5k_eeprom_init(mem, mac_version, ee)) {
++              printf("EEPROM init failed\n");
+               return -1;
+       }
+-      if (eeprom_version >= 0x4000) {
+-              error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_MISC0,
+-                                           &has_crystal, mac_version);
+-
+-              if (error) {
+-                      printf("Unable to read EEPROM Misc data!\n");
+-                      return -1;
+-              }
+-
+-              has_crystal = AR5K_EEPROM_HAS32KHZCRYSTAL(has_crystal);
+-      } else {
+-              has_crystal = 2;
+-      }
+-
+       eeprom_size = AR5K_REG_MS(AR5K_REG_READ(AR5K_PCICFG),
+                                 AR5K_PCICFG_EESIZE);
+-      has_a = AR5K_EEPROM_HDR_11A(eeprom_header);
+-      has_b = AR5K_EEPROM_HDR_11B(eeprom_header);
+-      has_g = AR5K_EEPROM_HDR_11G(eeprom_header);
+-      has_rfkill = AR5K_EEPROM_HDR_RFKILL(eeprom_header);
++      dev_type = AR5K_EEPROM_HDR_DEVICE(ee->ee_header);
++      eemap = AR5K_EEPROM_EEMAP(ee->ee_misc0);
+-      if (has_a)
++      /* 1 = ?? 2 = ?? 3 = card 4 = wmac */
++      printf("Device type:  %1i\n", dev_type);
++
++      if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+               phy_rev_5ghz = ath5k_hw_radio_revision(mac_version, mem, 1);
+       else
+               phy_rev_5ghz = 0;
+-      if (has_b)
++      if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+               phy_rev_2ghz = ath5k_hw_radio_revision(mac_version, mem, 0);
+       else
+               phy_rev_2ghz = 0;
+-      printf(" -==Device Information==-\n");
+-
+-      printf("MAC Version:  %-5s (0x%02x)\n",
+-             ath5k_hw_get_part_name(AR5K_VERSION_VER, mac_version),
+-             mac_version);
+-
+-      printf("MAC Revision: %-5s (0x%02x)\n",
+-             ath5k_hw_get_part_name(AR5K_VERSION_VER, srev), srev);
+-
+-      /* Single-chip PHY with a/b/g support */
+-      if (has_b && !phy_rev_2ghz) {
+-              printf("PHY Revision: %-5s (0x%02x)\n",
+-                     ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_5ghz),
+-                     phy_rev_5ghz);
+-              phy_rev_5ghz = 0;
+-      }
+-
+-      /* Single-chip PHY with b/g support */
+-      if (!has_a) {
+-              printf("PHY Revision: %-5s (0x%02x)\n",
+-                     ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_2ghz),
+-                     phy_rev_2ghz);
+-              phy_rev_2ghz = 0;
+-      }
+-
+-      /* Different chip for 5Ghz and 2Ghz */
+       if (phy_rev_5ghz) {
+-              printf("5Ghz PHY Revision: %-5s (0x%2x)\n",
+-                     ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_5ghz),
+-                     phy_rev_5ghz);
++              printf("5GHz PHY Revision: %-5s (0x%02x)\n",
++                     ath5k_hw_get_phy_name(phy_rev_5ghz), phy_rev_5ghz);
+       }
+       if (phy_rev_2ghz) {
+-              printf("2Ghz PHY Revision: %-5s (0x%2x)\n",
+-                     ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_2ghz),
+-                     phy_rev_2ghz);
++              printf("2GHz PHY Revision: %-5s (0x%02x)\n",
++                     ath5k_hw_get_phy_name(phy_rev_2ghz), phy_rev_2ghz);
+       }
+-      printf(" -==EEPROM Information==-\n");
+-
+-      printf("EEPROM Version:     %x.%x\n",
+-             (eeprom_version & 0xF000) >> 12, eeprom_version & 0xFFF);
++      printf("\n");
++      printf("/============== EEPROM Information =============\\\n");
++      printf("| EEPROM Version:   %1x.%1x |",
++             (ee->ee_version & 0xF000) >> 12, ee->ee_version & 0xFFF);
+-      printf("EEPROM Size: ");
++      printf(" EEPROM Size: ");
+       if (eeprom_size == 0) {
+-              printf("       4K\n");
+-              byte_size = 4096;
++              printf("  4 kbit |\n");
++              byte_size = 4096 / 8;
+       } else if (eeprom_size == 1) {
+-              printf("       8K\n");
+-              byte_size = 8192;
++              printf("  8 kbit |\n");
++              byte_size = 8192 / 8;
+       } else if (eeprom_size == 2) {
+-              printf("       16K\n");
+-              byte_size = 16384;
++              printf(" 16 kbit |\n");
++              byte_size = 16384 / 8;
+       } else
+-              printf("       ??\n");
++              printf(" unknown |\n");
+-      printf("Regulatory Domain:  0x%X\n", regdomain);
+-
+-      printf(" -==== Capabilities ====-\n");
+-
+-      printf("|  802.11a Support: ");
+-      if (has_a)
+-              printf("yes  |\n");
+-      else
+-              printf("no   |\n");
+-
+-      printf("|  802.11b Support: ");
+-      if (has_b)
+-              printf("yes  |\n");
+-      else
+-              printf("no   |\n");
++      printf("| EEMAP:              %i |", eemap);
+-      printf("|  802.11g Support: ");
+-      if (has_g)
+-              printf("yes  |\n");
+-      else
+-              printf("no   |\n");
++      printf(" Reg. Domain:     0x%02X |\n", ee->ee_regdomain);
+-      printf("|  RFKill  Support: ");
+-      if (has_rfkill)
+-              printf("yes  |\n");
+-      else
+-              printf("no   |\n");
++      dump_capabilities(ee);
++      printf("\n");
+-      if (has_crystal != 2) {
+-              printf("|  32KHz   Crystal: ");
+-              if (has_crystal)
+-                      printf("yes  |\n");
+-              else
+-                      printf("no   |\n");
++      printf("/=========================================================\\\n");
++      printf("|          Calibration data common for all modes          |\n");
++      printf("|=========================================================|\n");
++      printf("|          CCK/OFDM gain delta:            %2i             |\n", ee->ee_cck_ofdm_gain_delta);
++      printf("|          CCK/OFDM power delta:           %2i             |\n", ee->ee_cck_ofdm_power_delta);
++      printf("|          Scaled CCK delta:               %2i             |\n", ee->ee_scaled_cck_delta);
++      printf("|          2GHz Antenna gain:              %2i             |\n", AR5K_EEPROM_ANT_GAIN_2GHZ(ee->ee_ant_gain));
++      printf("|          5GHz Antenna gain:              %2i             |\n", AR5K_EEPROM_ANT_GAIN_5GHZ(ee->ee_ant_gain));
++      printf("|          Turbo 2W maximum dBm:           %2i             |\n", AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header));
++      printf("|          Target power start:          0x%03x             |\n", AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1));
++      printf("|          EAR Start:                   0x%03x             |\n", AR5K_EEPROM_EARSTART(ee->ee_misc0));
++      printf("\\=========================================================/\n");
++
++      printf("\n");
++      if (AR5K_EEPROM_HDR_11A(ee->ee_header)) {
++              printf("/=========================================================\\\n");
++              printf("|          Calibration data for 802.11a operation         |\n");
++              dump_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee);
++              dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee);
++              dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee);
++              printf("\n");
++      }
++
++      if (AR5K_EEPROM_HDR_11B(ee->ee_header)) {
++              printf("/=========================================================\\\n");
++              printf("|          Calibration data for 802.11b operation         |\n");
++              dump_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee);
++              dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee);
++              dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee);
++              printf("\n");
++      }
++
++      if (AR5K_EEPROM_HDR_11G(ee->ee_header)) {
++              printf("/=========================================================\\\n");
++              printf("|          Calibration data for 802.11g operation         |\n");
++              dump_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee);
++              dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee);
++              dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee);
++              printf("\n");
+       }
+-      printf(" ========================\n");
+       /* print current GPIO settings */
+-      printf("GPIO registers: CR %08x DO %08x DI %08x\n",
++      printf("GPIO registers: CR 0x%08x, DO 0x%08x, DI 0x%08x\n",
+              AR5K_REG_READ(AR5K_GPIOCR), AR5K_REG_READ(AR5K_GPIODO),
+              AR5K_REG_READ(AR5K_GPIODI));
+@@ -1030,18 +2263,18 @@ CMD(athinfo)(int argc, char *argv[])
+               u_int16_t data;
+               FILE *dumpfile = fopen("ath-eeprom-dump.bin", "w");
+-              printf("\nEEPROM dump (%d byte)\n", byte_size);
++              printf("\nEEPROM dump (%d bytes)\n", byte_size);
+               printf("==============================================");
+-              for (i = 1; i <= (byte_size / 2); i++) {
++              for (i = 0; i < byte_size / 2; i++) {
+                       error =
+                           ath5k_hw_eeprom_read(mem, i, &data, mac_version);
+                       if (error) {
+                               printf("\nUnable to read at %04x\n", i);
+                               continue;
+                       }
+-                      if (!((i - 1) % 8))
+-                              printf("\n%04x:  ", i);
+-                      printf("%04x ", data);
++                      if (!(i % 8))
++                              printf("\n%04x: ", i);
++                      printf(" %04x", data);
+                       fwrite(&data, 2, 1, dumpfile);
+               }
+               printf("\n==============================================\n");
+@@ -1054,18 +2287,18 @@ CMD(athinfo)(int argc, char *argv[])
+               u_int32_t old_cr = rcr, old_do = rdo;
+               int rc;
+-              if (mac_version >= AR5K_SREV_VER_AR5213 && !nr_gpio_set) {
+-                      dbg("new MAC %x (>= AR5213) set gpio4 to low",
++              if (mac_version >= AR5K_SREV_MAC_AR5213 && !nr_gpio_set) {
++                      dbg("new MAC %x (>= AR5213) set GPIO4 to low",
+                           mac_version);
+                       gpio_set[4].valid = 1;
+                       gpio_set[4].value = 0;
+               }
+-              /* set gpios */
++              /* set GPIOs */
+               dbg("old GPIO CR %08x DO %08x DI %08x",
+                   rcr, rdo, AR5K_REG_READ(AR5K_GPIODI));
+-              for (i = 0; i < sizeof(gpio_set) / sizeof(gpio_set[0]); i++) {
++              for (i = 0; i < ARRAY_SIZE(gpio_set); i++) {
+                       if (gpio_set[i].valid) {
+                               rcr |= AR5K_GPIOCR_OUT(i);      /* we use mode 3 */
+                               rcr &= ~AR5K_GPIOCR_INT_SEL(i);
+@@ -1111,5 +2344,17 @@ CMD(athinfo)(int argc, char *argv[])
+               return rc;
+       }
++
++      sta_id0_id1_dump(mem);
++
++      for (i = 0; i < timer_count; i++)
++              dump_timers_register(mem, mac_version);
++
++      if (do_keycache_dump)
++              keycache_dump(mem, mac_version);
++
++      if (keycache_copy_idx > 0)
++              keycache_copy(mem, mac_version, keycache_copy_idx);
++
+       return 0;
+ }
diff --git a/net/madwifi/patches/408-changeset_r3337.patch b/net/madwifi/patches/408-changeset_r3337.patch
new file mode 100644 (file)
index 0000000..53e76a9
--- /dev/null
@@ -0,0 +1,34 @@
+--- a/THANKS
++++ b/THANKS
+@@ -129,6 +129,7 @@ Derek J Smithies
+ jhansen
+ Benoit Papillault
+ Russell Harmon
++Alessandro Erta
+ Apologies to anyone whose name was unintentionally left off.
+ Please let us know if you think your name should be mentioned here!
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -3147,7 +3147,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 *)
+-              (SKB_CB(skb) + sizeof(struct ieee80211_cb));
++              (SKB_CB(skb) + 1); /* NB: SKB_CB casts to CB struct*. */
+       const HAL_RATE_TABLE *rt;
+       unsigned int pktlen, hdrlen, try0, power;
+       HAL_PKT_TYPE atype;
+--- a/net80211/ieee80211_monitor.c
++++ b/net80211/ieee80211_monitor.c
+@@ -128,8 +128,8 @@ struct ar5212_openbsd_desc {
+ void
+ ieee80211_monitor_encap(struct ieee80211vap *vap, struct sk_buff *skb)
+ {
+-      struct ieee80211_phy_params *ph =
+-              (struct ieee80211_phy_params *) (SKB_CB(skb) + sizeof(struct ieee80211_cb));
++      struct ieee80211_phy_params *ph = (struct ieee80211_phy_params *)
++              (SKB_CB(skb) + 1); /* NB: SKB_CB casts to CB struct*. */
+       SKB_CB(skb)->flags = M_RAW;
+       SKB_CB(skb)->ni = NULL;
+       SKB_CB(skb)->next = NULL;
diff --git a/net/madwifi/patches/409-wext_compat.patch b/net/madwifi/patches/409-wext_compat.patch
new file mode 100644 (file)
index 0000000..4497092
--- /dev/null
@@ -0,0 +1,133 @@
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -73,6 +73,13 @@
+        (_vap)->iv_ic->ic_roaming == IEEE80211_ROAMING_AUTO)
+ #define       RESCAN  1
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
++#define IWE(func, ...) func(&iweinfo, __VA_ARGS__)
++static struct iw_request_info iweinfo = { 0, 0 };
++#else
++#define IWE(func, ...) func(__VA_ARGS__)
++#endif
++
+ static void
+ pre_announced_chanswitch(struct net_device *dev, u_int32_t channel, u_int32_t tbtt);
+@@ -1800,7 +1807,7 @@ giwscan_cb(void *arg, const struct ieee8
+               IEEE80211_ADDR_COPY(iwe.u.ap_addr.sa_data, se->se_macaddr);
+       else
+               IEEE80211_ADDR_COPY(iwe.u.ap_addr.sa_data, se->se_bssid);
+-      current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
++      current_ev = IWE(iwe_stream_add_event, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+       /* We ran out of space in the buffer. */
+       if (last_ev == current_ev)
+@@ -1811,7 +1818,7 @@ giwscan_cb(void *arg, const struct ieee8
+       iwe.cmd = SIOCGIWESSID;
+       iwe.u.data.flags = 1;
+       iwe.u.data.length = se->se_ssid[1];
+-      current_ev = iwe_stream_add_point(current_ev,
++      current_ev = IWE(iwe_stream_add_point, current_ev,
+               end_buf, &iwe, (char *) se->se_ssid+2);
+       /* We ran out of space in the buffer. */
+@@ -1824,7 +1831,7 @@ giwscan_cb(void *arg, const struct ieee8
+               iwe.cmd = SIOCGIWMODE;
+               iwe.u.mode = se->se_capinfo & IEEE80211_CAPINFO_ESS ?
+                       IW_MODE_MASTER : IW_MODE_ADHOC;
+-              current_ev = iwe_stream_add_event(current_ev,
++              current_ev = IWE(iwe_stream_add_event, current_ev,
+                       end_buf, &iwe, IW_EV_UINT_LEN);
+               /* We ran out of space in the buffer. */
+@@ -1837,7 +1844,7 @@ giwscan_cb(void *arg, const struct ieee8
+       iwe.cmd = SIOCGIWFREQ;
+       iwe.u.freq.m = se->se_chan->ic_freq * 100000;
+       iwe.u.freq.e = 1;
+-      current_ev = iwe_stream_add_event(current_ev,
++      current_ev = IWE(iwe_stream_add_event, current_ev,
+               end_buf, &iwe, IW_EV_FREQ_LEN);
+       /* We ran out of space in the buffer. */
+@@ -1848,7 +1855,7 @@ giwscan_cb(void *arg, const struct ieee8
+       last_ev = current_ev;
+       iwe.cmd = IWEVQUAL;
+       set_quality(&iwe.u.qual, se->se_rssi, ATH_DEFAULT_NOISE);
+-      current_ev = iwe_stream_add_event(current_ev,
++      current_ev = IWE(iwe_stream_add_event, current_ev,
+               end_buf, &iwe, IW_EV_QUAL_LEN);
+       /* We ran out of space in the buffer */
+@@ -1863,7 +1870,7 @@ giwscan_cb(void *arg, const struct ieee8
+       else
+               iwe.u.data.flags = IW_ENCODE_DISABLED;
+       iwe.u.data.length = 0;
+-      current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
++      current_ev = IWE(iwe_stream_add_point, current_ev, end_buf, &iwe, "");
+       /* We ran out of space in the buffer. */
+       if (last_ev == current_ev)
+@@ -1878,7 +1885,7 @@ giwscan_cb(void *arg, const struct ieee8
+               int r = se->se_rates[2 + j] & IEEE80211_RATE_VAL;
+               if (r != 0) {
+                       iwe.u.bitrate.value = r * (1000000 / 2);
+-                      current_val = iwe_stream_add_value(current_ev,
++                      current_val = IWE(iwe_stream_add_value, current_ev,
+                               current_val, end_buf, &iwe,
+                               IW_EV_PARAM_LEN);
+               }
+@@ -1887,7 +1894,7 @@ giwscan_cb(void *arg, const struct ieee8
+               int r = se->se_xrates[2+j] & IEEE80211_RATE_VAL;
+               if (r != 0) {
+                       iwe.u.bitrate.value = r * (1000000 / 2);
+-                      current_val = iwe_stream_add_value(current_ev,
++                      current_val = IWE(iwe_stream_add_value, current_ev,
+                               current_val, end_buf, &iwe,
+                               IW_EV_PARAM_LEN);
+               }
+@@ -1906,7 +1913,7 @@ giwscan_cb(void *arg, const struct ieee8
+       iwe.cmd = IWEVCUSTOM;
+       snprintf(buf, sizeof(buf), "bcn_int=%d", se->se_intval);
+       iwe.u.data.length = strlen(buf);
+-      current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
++      current_ev = IWE(iwe_stream_add_point, current_ev, end_buf, &iwe, buf);
+       /* We ran out of space in the buffer. */
+       if (last_ev == current_ev)
+@@ -1930,7 +1937,7 @@ giwscan_cb(void *arg, const struct ieee8
+                               rsn_leader, sizeof(rsn_leader) - 1);
+ #endif
+               if (iwe.u.data.length != 0) {
+-                      current_ev = iwe_stream_add_point(current_ev, end_buf,
++                      current_ev = IWE(iwe_stream_add_point, current_ev, end_buf,
+                               &iwe, buf);
+                       /* We ran out of space in the buffer */
+@@ -1956,7 +1963,7 @@ giwscan_cb(void *arg, const struct ieee8
+                       wpa_leader, sizeof(wpa_leader) - 1);
+ #endif
+               if (iwe.u.data.length != 0) {
+-                      current_ev = iwe_stream_add_point(current_ev, end_buf,
++                      current_ev = IWE(iwe_stream_add_point, current_ev, end_buf,
+                               &iwe, buf);
+                       /* We ran out of space in the buffer. */
+@@ -1975,7 +1982,7 @@ giwscan_cb(void *arg, const struct ieee8
+                       se->se_wme_ie, se->se_wme_ie[1] + 2,
+                       wme_leader, sizeof(wme_leader) - 1);
+               if (iwe.u.data.length != 0) {
+-                      current_ev = iwe_stream_add_point(current_ev, end_buf,
++                      current_ev = IWE(iwe_stream_add_point, current_ev, end_buf,
+                               &iwe, buf);
+                       /* We ran out of space in the buffer. */
+@@ -1993,7 +2000,7 @@ giwscan_cb(void *arg, const struct ieee8
+                       se->se_ath_ie, se->se_ath_ie[1] + 2,
+                       ath_leader, sizeof(ath_leader) - 1);
+               if (iwe.u.data.length != 0) {
+-                      current_ev = iwe_stream_add_point(current_ev, end_buf,
++                      current_ev = IWE(iwe_stream_add_point, current_ev, end_buf,
+                               &iwe, buf);
+                       /* We ran out of space in the buffer. */
diff --git a/net/madwifi/patches/410-ar231x_2.6.28.patch b/net/madwifi/patches/410-ar231x_2.6.28.patch
new file mode 100644 (file)
index 0000000..30d1c56
--- /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";
+ /* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */
+ static const struct ath_hw_detect cards[] = {
+@@ -201,6 +173,114 @@ static const struct ath_hw_detect cards[
+       { ubnt, "Bullet5",             PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc205 },
+ };
++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)
+ {
+@@ -253,7 +333,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;
+       }
+@@ -263,21 +343,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;
+@@ -292,6 +363,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;
+@@ -312,11 +406,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/net/madwifi/patches/411-autochannel_multi.patch b/net/madwifi/patches/411-autochannel_multi.patch
new file mode 100644 (file)
index 0000000..d05c447
--- /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 bias;
++}
++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)
+ {
+@@ -1169,7 +1286,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__,
+@@ -1180,6 +1297,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
+@@ -2775,6 +2775,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",
+@@ -2797,6 +2798,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
+@@ -1231,6 +1231,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 */
+@@ -1249,6 +1250,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
+@@ -208,9 +208,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 */
+       ss->ss_last = 0;
+       ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode);
+@@ -423,8 +429,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));
+ }
+@@ -575,6 +583,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);
+@@ -586,8 +595,11 @@ ap_end(struct ieee80211_scan_state *ss,
+       /* record stats for the channel that was scanned last */
+       ic->ic_set_channel(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! "
+@@ -606,6 +618,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;
+                       }
+@@ -618,6 +631,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/net/madwifi/patches/412-fragmentation_fix.patch b/net/madwifi/patches/412-fragmentation_fix.patch
new file mode 100644 (file)
index 0000000..92c411b
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -3684,6 +3684,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/net/madwifi/patches/413-rxorn.patch b/net/madwifi/patches/413-rxorn.patch
new file mode 100644 (file)
index 0000000..0e8d885
--- /dev/null
@@ -0,0 +1,31 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -2308,6 +2308,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
+@@ -2320,10 +2331,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/net/madwifi/patches/414-txpower.patch b/net/madwifi/patches/414-txpower.patch
new file mode 100644 (file)
index 0000000..3c18bd6
--- /dev/null
@@ -0,0 +1,262 @@
+--- 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,8 @@ 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_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
+@@ -908,6 +908,21 @@ ieee80211_ioctl_giwessid(struct net_devi
+       return 0;
+ }
++static u16
++ieee80211_get_maxtxpow(struct ieee80211com *ic)
++{
++      u_int16_t txp = IEEE80211_TXPOWER_MAX;
++
++      if (ic->ic_bsschan && (ic->ic_bsschan != IEEE80211_CHAN_ANYC))
++              txp = min(txp, (u16) ic->ic_bsschan->ic_maxpower);
++
++      if (ic->ic_max_txpower > 0)
++              txp = min(txp, ic->ic_max_txpower);
++
++      return txp;
++}
++
++
+ static int
+ ieee80211_ioctl_giwrange(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *data, char *extra)
+@@ -920,17 +935,21 @@ 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 = ieee80211_get_maxtxpow(ic);
++
+       /* 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 +1398,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 +1413,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 +1587,18 @@ 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;
++
++      txp = ieee80211_get_maxtxpow(ic);
++      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);
+@@ -3168,7 +3167,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;
+@@ -8394,7 +8393,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 */
+@@ -10387,59 +10386,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_max_txpower = ath_get_clamped_maxtxpower(sc);
+ }
+ #ifdef ATH_SUPERG_XR
diff --git a/net/madwifi/patches/415-chan_switch.patch b/net/madwifi/patches/415-chan_switch.patch
new file mode 100644 (file)
index 0000000..6dc5da8
--- /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)
+@@ -4634,7 +4606,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/net/madwifi/patches/416-wprobe.patch b/net/madwifi/patches/416-wprobe.patch
new file mode 100644 (file)
index 0000000..0b378d7
--- /dev/null
@@ -0,0 +1,549 @@
+--- /dev/null
++++ b/ath/ath_wprobe.c
+@@ -0,0 +1,433 @@
++#include <net80211/ieee80211_node.h>
++#include <linux/wprobe.h>
++
++atomic_t cleanup_tasks = ATOMIC_INIT(0);
++
++enum wp_node_val {
++      WP_NODE_RSSI,
++      WP_NODE_SIGNAL,
++      WP_NODE_RX_RATE,
++      WP_NODE_TX_RATE,
++      WP_NODE_RETRANSMIT_200,
++      WP_NODE_RETRANSMIT_400,
++      WP_NODE_RETRANSMIT_800,
++      WP_NODE_RETRANSMIT_1600,
++};
++
++enum wp_global_val {
++      WP_GLOBAL_NOISE,
++      WP_GLOBAL_PHY_BUSY,
++      WP_GLOBAL_PHY_RX,
++      WP_GLOBAL_PHY_TX,
++      WP_GLOBAL_FRAMES,
++      WP_GLOBAL_PROBEREQ,
++};
++
++static struct wprobe_item ath_wprobe_globals[] = {
++      [WP_GLOBAL_NOISE] = {
++              .name = "noise",
++              .type = WPROBE_VAL_S16,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_GLOBAL_PHY_BUSY] = {
++              .name = "phy_busy",
++              .type = WPROBE_VAL_U8,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_GLOBAL_PHY_RX] = {
++              .name = "phy_rx",
++              .type = WPROBE_VAL_U8,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_GLOBAL_PHY_TX] = {
++              .name = "phy_tx",
++              .type = WPROBE_VAL_U8,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_GLOBAL_FRAMES] = {
++              .name = "frames",
++              .type = WPROBE_VAL_U32,
++      },
++      [WP_GLOBAL_PROBEREQ] = {
++              .name = "probereq",
++              .type = WPROBE_VAL_U32,
++      },
++};
++
++static struct wprobe_item ath_wprobe_link[] = {
++      [WP_NODE_RSSI] = {
++              .name = "rssi",
++              .type = WPROBE_VAL_U8,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_NODE_SIGNAL] = {
++              .name = "signal",
++              .type = WPROBE_VAL_S16,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_NODE_RX_RATE] = {
++              .name = "rx_rate",
++              .type = WPROBE_VAL_U16,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_NODE_TX_RATE] = {
++              .name = "tx_rate",
++              .type = WPROBE_VAL_U16,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_NODE_RETRANSMIT_200] = {
++              .name = "retransmit_200",
++              .type = WPROBE_VAL_U8,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_NODE_RETRANSMIT_400] = {
++              .name = "retransmit_400",
++              .type = WPROBE_VAL_U8,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_NODE_RETRANSMIT_800] = {
++              .name = "retransmit_800",
++              .type = WPROBE_VAL_U8,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++      [WP_NODE_RETRANSMIT_1600] = {
++              .name = "retransmit_1600",
++              .type = WPROBE_VAL_U8,
++              .flags = WPROBE_F_KEEPSTAT
++      },
++};
++
++#define AR5K_MIBC       0x0040
++#define AR5K_MIBC_FREEZE      (1 << 1)
++#define AR5K_TXFC       0x80ec
++#define AR5K_RXFC       0x80f0
++#define AR5K_RXCLEAR    0x80f4
++#define AR5K_CYCLES     0x80f8
++
++#define READ_CLR(_ah, _reg) \
++      ({ u32 __val = OS_REG_READ(_ah, _reg); OS_REG_WRITE(_ah, _reg, 0); __val; })
++
++static bool
++wprobe_disabled(void)
++{
++      return (!wprobe_add_iface || IS_ERR(wprobe_add_iface));
++}
++
++static int
++ath_wprobe_sync(struct wprobe_iface *dev, struct wprobe_link *l, struct wprobe_value *val, bool measure)
++{
++      struct ath_vap *avp = container_of(dev, struct ath_vap, av_wpif);
++      struct ieee80211vap *vap = &avp->av_vap;
++      struct ieee80211com *ic = vap->iv_ic;
++      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_hal *ah = sc->sc_ah;
++      u32 cc, busy, rx, tx;
++      s16 noise;
++
++      if (l)
++              goto out;
++
++      OS_REG_WRITE(ah, AR5K_MIBC, AR5K_MIBC_FREEZE);
++      cc = READ_CLR(ah, AR5K_CYCLES);
++      busy = READ_CLR(ah, AR5K_RXCLEAR);
++      rx = READ_CLR(ah, AR5K_RXFC);
++      tx = READ_CLR(ah, AR5K_TXFC);
++      OS_REG_WRITE(ah, AR5K_MIBC, 0);
++      noise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan));
++      ic->ic_channoise = noise;
++
++      WPROBE_FILL_BEGIN(val, ath_wprobe_globals);
++      if (cc & 0xf0000000) {
++              /* scale down if the counters are near max */
++              cc >>= 8;
++              busy >>= 8;
++              rx >>= 8;
++              tx >>= 8;
++      }
++      if (ah->ah_macType < 5212)
++              goto phy_skip;
++      if (!cc)
++              goto phy_skip;
++      if (busy > cc)
++              goto phy_skip;
++      if (rx > cc)
++              goto phy_skip;
++      if (tx > cc)
++              goto phy_skip;
++      busy = (busy * 100) / cc;
++      rx = (rx * 100) / cc;
++      tx = (tx * 100) / cc;
++      WPROBE_SET(WP_GLOBAL_PHY_BUSY, U8, busy);
++      WPROBE_SET(WP_GLOBAL_PHY_RX, U8, rx);
++      WPROBE_SET(WP_GLOBAL_PHY_TX, U8, tx);
++      WPROBE_SET(WP_GLOBAL_FRAMES, U32, avp->av_rxframes);
++      WPROBE_SET(WP_GLOBAL_PROBEREQ, U32, avp->av_rxprobereq);
++
++phy_skip:
++      WPROBE_SET(WP_GLOBAL_NOISE, S16, noise);
++      WPROBE_FILL_END();
++
++out:
++      return 0;
++}
++
++#undef AR5K_TXFC
++#undef AR5K_RXFC
++#undef AR5K_RXCLEAR
++#undef AR5K_CYCLES
++#undef AR5K_MIBC
++#undef AR5K_MIBC_FREEZE
++#undef READ_CLR
++
++static const struct wprobe_iface ath_wprobe_dev = {
++      .link_items = ath_wprobe_link,
++      .n_link_items = ARRAY_SIZE(ath_wprobe_link),
++      .global_items = ath_wprobe_globals,
++      .n_global_items = ARRAY_SIZE(ath_wprobe_globals),
++      .sync_data = ath_wprobe_sync,
++};
++
++static int
++ath_lookup_rateval(struct ieee80211_node *ni, int rate)
++{
++      struct ieee80211vap *vap = ni->ni_vap;
++      struct ieee80211com *ic = vap->iv_ic;
++      struct ath_softc *sc = ic->ic_dev->priv;
++      const HAL_RATE_TABLE *rt = sc->sc_currates;
++
++      if ((!rt) || (rate < 0) || (rate >= ARRAY_SIZE(sc->sc_hwmap)))
++              return -1;
++
++      rate = sc->sc_hwmap[rate].ieeerate;
++      rate = sc->sc_rixmap[rate & IEEE80211_RATE_VAL];
++      if ((rate < 0) || (rate >= rt->rateCount))
++              return -1;
++
++      return rt->info[rate].rateKbps;
++}
++
++static void
++ath_wprobe_report_rx(struct ieee80211vap *vap, struct ath_rx_status *rs, struct sk_buff *skb)
++{
++      const struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data;
++      struct wprobe_wlan_hdr hdr;
++      struct ath_vap *avp;
++      int hdrsize;
++
++      if (wprobe_disabled())
++              return;
++
++      avp = ATH_VAP(vap);
++      avp->av_rxframes++;
++      if (wh->i_fc[0] == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ))
++              avp->av_rxprobereq++;
++
++      memset(&hdr, 0, sizeof(hdr));
++      hdr.len = skb->len;
++      hdr.snr = rs->rs_rssi;
++      hdr.type = WPROBE_PKT_RX;
++      if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
++              hdrsize = sizeof(struct ieee80211_ctlframe_addr2);
++      else
++              hdrsize = ieee80211_hdrsize(skb->data);
++      wprobe_add_frame(&avp->av_wpif, &hdr, skb->data, hdrsize + 0x42);
++}
++
++
++static void
++ath_node_sample_rx(struct ieee80211_node *ni, struct ath_rx_status *rs)
++{
++      struct ath_node *an = ATH_NODE(ni);
++      struct ieee80211vap *vap = ni->ni_vap;
++      struct ieee80211com *ic = vap->iv_ic;
++      struct wprobe_link *l = &an->an_wplink;
++      struct wprobe_value *v = l->val;
++      unsigned long flags;
++      int rate;
++
++      if (wprobe_disabled() || !an->an_wplink_active || !l->val)
++              return;
++
++      rate = ath_lookup_rateval(ni, rs->rs_rate);
++
++      spin_lock_irqsave(&l->iface->lock, flags);
++      WPROBE_FILL_BEGIN(v, ath_wprobe_link);
++      WPROBE_SET(WP_NODE_RSSI, U8, rs->rs_rssi);
++      WPROBE_SET(WP_NODE_SIGNAL, S16, ic->ic_channoise + rs->rs_rssi);
++      if ((rate > 0) && (rate <= 600000))
++              WPROBE_SET(WP_NODE_RX_RATE, U16, rate);
++      WPROBE_FILL_END();
++      wprobe_update_stats(l->iface, l);
++      spin_unlock_irqrestore(&l->iface->lock, flags);
++}
++
++static void
++ath_wprobe_report_tx(struct ieee80211vap *vap, struct ath_tx_status *ts, struct sk_buff *skb)
++{
++      const struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data;
++      struct wprobe_wlan_hdr hdr;
++      struct ath_vap *avp;
++      int hdrsize;
++
++      if (wprobe_disabled())
++              return;
++
++      avp = ATH_VAP(vap);
++
++      memset(&hdr, 0, sizeof(hdr));
++      hdr.len = skb->len;
++      hdr.snr = ts->ts_rssi;
++      hdr.type = WPROBE_PKT_TX;
++      if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
++              hdrsize = sizeof(struct ieee80211_ctlframe_addr2);
++      else
++              hdrsize = ieee80211_hdrsize(skb->data);
++      wprobe_add_frame(&avp->av_wpif, &hdr, skb->data, hdrsize + 0x42);
++}
++
++
++
++static void
++ath_node_sample_tx(struct ieee80211_node *ni, struct ath_tx_status *ts, struct sk_buff *skb)
++{
++      struct ath_node *an = ATH_NODE(ni);
++      struct ieee80211vap *vap = ni->ni_vap;
++      struct ieee80211com *ic = vap->iv_ic;
++      struct wprobe_link *l = &an->an_wplink;
++      struct wprobe_value *v = l->val;
++      unsigned long flags;
++      int rate, rexmit_counter;
++      int len = skb->len;
++
++      if (wprobe_disabled() || !an->an_wplink_active || !l->val)
++              return;
++
++      ath_wprobe_report_tx(vap, ts, skb);
++      rate = ath_lookup_rateval(ni, ts->ts_rate);
++
++      spin_lock_irqsave(&l->iface->lock, flags);
++      WPROBE_FILL_BEGIN(v, ath_wprobe_link);
++      WPROBE_SET(WP_NODE_RSSI, U8, ts->ts_rssi);
++      WPROBE_SET(WP_NODE_SIGNAL, S16, ic->ic_channoise + ts->ts_rssi);
++
++      if (len <= 200)
++              rexmit_counter = WP_NODE_RETRANSMIT_200;
++      else if (len <= 400)
++              rexmit_counter = WP_NODE_RETRANSMIT_400;
++      else if (len <= 800)
++              rexmit_counter = WP_NODE_RETRANSMIT_800;
++      else
++              rexmit_counter = WP_NODE_RETRANSMIT_1600;
++      WPROBE_SET(rexmit_counter, U8, ts->ts_longretry);
++
++      if ((rate > 0) && (rate <= 600000))
++              WPROBE_SET(WP_NODE_TX_RATE, U16, rate);
++      WPROBE_FILL_END();
++      wprobe_update_stats(l->iface, l);
++      spin_unlock_irqrestore(&l->iface->lock, flags);
++}
++
++static void
++ath_wprobe_node_join(struct ieee80211vap *vap, struct ieee80211_node *ni)
++{
++      struct wprobe_iface *dev;
++      struct wprobe_link *l;
++      struct ath_vap *avp;
++      struct ath_node *an = ATH_NODE(ni);
++
++      if (wprobe_disabled() || an->an_wplink_active)
++              return;
++
++      avp = ATH_VAP(vap);
++      dev = &avp->av_wpif;
++      l = &an->an_wplink;
++
++      ieee80211_ref_node(ni);
++      wprobe_add_link(dev, l, ni->ni_macaddr);
++      an->an_wplink_active = 1;
++}
++
++static void
++ath_wprobe_do_node_leave(struct work_struct *work)
++{
++      struct ath_node *an = container_of(work, struct ath_node, an_destroy);
++      struct ieee80211_node *ni = &an->an_node;
++      struct ieee80211vap *vap = ni->ni_vap;
++      struct wprobe_iface *dev;
++      struct wprobe_link *l;
++      struct ath_vap *avp;
++
++      avp = ATH_VAP(vap);
++      dev = &avp->av_wpif;
++      l = &an->an_wplink;
++
++      wprobe_remove_link(dev, l);
++      ieee80211_unref_node(&ni);
++      atomic_dec(&cleanup_tasks);
++}
++
++static void
++ath_wprobe_node_leave(struct ieee80211vap *vap, struct ieee80211_node *ni)
++{
++      struct ath_node *an = ATH_NODE(ni);
++
++      if (wprobe_disabled() || !an->an_wplink_active)
++              return;
++
++      atomic_inc(&cleanup_tasks);
++      an->an_wplink_active = 0;
++      IEEE80211_INIT_WORK(&an->an_destroy, ath_wprobe_do_node_leave);
++      schedule_work(&an->an_destroy);
++}
++
++static void
++ath_init_wprobe_dev(struct ath_vap *avp)
++{
++      struct ieee80211vap *vap = &avp->av_vap;
++      struct wprobe_iface *dev = &avp->av_wpif;
++
++      if (wprobe_disabled() || (vap->iv_opmode == IEEE80211_M_WDS))
++              return;
++
++      memcpy(dev, &ath_wprobe_dev, sizeof(struct wprobe_iface));
++      dev->addr = vap->iv_myaddr;
++      dev->name = vap->iv_dev->name;
++      wprobe_add_iface(dev);
++}
++
++static void
++ath_remove_wprobe_dev(struct ath_vap *avp)
++{
++      struct ieee80211vap *vap = &avp->av_vap;
++      struct ieee80211com *ic = vap->iv_ic;
++      struct ieee80211_node *ni;
++      struct wprobe_iface *dev = &avp->av_wpif;
++      struct wprobe_link *l;
++      struct ath_node *an;
++      unsigned long flags;
++
++      if (wprobe_disabled() || (vap->iv_opmode == IEEE80211_M_WDS))
++              return;
++
++restart:
++      rcu_read_lock();
++      list_for_each_entry_rcu(l, &dev->links, list) {
++              an = container_of(l, struct ath_node, an_wplink);
++
++              if (!an->an_wplink_active)
++                      continue;
++
++              ni = &an->an_node;
++              ath_wprobe_node_leave(vap, ni);
++              rcu_read_unlock();
++              goto restart;
++      }
++      rcu_read_unlock();
++
++      /* wait for the cleanup tasks to finish */
++      while (atomic_read(&cleanup_tasks) != 0) {
++              schedule();
++      }
++
++      wprobe_remove_iface(dev);
++}
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -400,6 +400,7 @@ static int countrycode = -1;
+ static int maxvaps = -1;
+ static int outdoor = -1;
+ static int xchanmode = -1;
++#include "ath_wprobe.c"
+ static int beacon_cal = 1;
+ static const struct ath_hw_detect generic_hw_info = {
+@@ -1525,6 +1526,7 @@ ath_vap_create(struct ieee80211com *ic,
+               ath_hal_intrset(ah, sc->sc_imask);
+       }
++      ath_init_wprobe_dev(avp);
+       return vap;
+ }
+@@ -1606,6 +1608,7 @@ ath_vap_delete(struct ieee80211vap *vap)
+               decrease = 0;
+       ieee80211_vap_detach(vap);
++      ath_remove_wprobe_dev(ATH_VAP(vap));
+       /* NB: memory is reclaimed through dev->destructor callback */
+       if (decrease)
+               sc->sc_nvaps--;
+@@ -5940,6 +5943,7 @@ ath_node_cleanup(struct ieee80211_node *
+       /* Clean up node-specific rate things - this currently appears to 
+        * always be a no-op */
+       sc->sc_rc->ops->node_cleanup(sc, ATH_NODE(ni));
++      ath_wprobe_node_leave(ni->ni_vap, ni);
+       ATH_NODE_UAPSD_LOCK_IRQ(an);
+ #ifdef IEEE80211_DEBUG_REFCNT
+@@ -7010,6 +7014,8 @@ drop_micfail:
+                               goto lookup_slowpath;
+                       }
+                       ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
++                      ath_node_sample_rx(ni, rs);
++                      ath_wprobe_report_rx(ni->ni_vap, rs, skb);
+                       type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
+                       ieee80211_unref_node(&ni);
+               } else {
+@@ -7024,15 +7030,21 @@ lookup_slowpath:
+                       else
+                               vap = ieee80211_find_rxvap(ic, wh->i_addr1);
+-                      if (vap)
++                      if (vap) {
++                              ath_wprobe_report_rx(vap, rs, skb);
+                               ni = ieee80211_find_rxnode(ic, vap, wh);
+-                      else
++                      } else {
++                              TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++                                      ath_wprobe_report_rx(vap, rs, skb);
++                              }
+                               ni = NULL;
++                      }
+                       if (ni != NULL) {
+                               ieee80211_keyix_t keyix;
+                               ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
++                              ath_node_sample_rx(ni, rs);
+                               type = ieee80211_input(vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
+                               /*
+                                * If the station has a key cache slot assigned
+@@ -8612,6 +8624,7 @@ ath_tx_processq(struct ath_softc *sc, st
+                               sc->sc_stats.ast_tx_rssi = ts->ts_rssi;
+                               ATH_RSSI_LPF(an->an_halstats.ns_avgtxrssi,
+                                       ts->ts_rssi);
++                                      ath_node_sample_tx(&an->an_node, ts, bf->bf_skb);
+                               if (bf->bf_skb->priority == WME_AC_VO ||
+                                   bf->bf_skb->priority == WME_AC_VI)
+                                       ni->ni_ic->ic_wme.wme_hipri_traffic++;
+@@ -10111,6 +10124,7 @@ ath_newassoc(struct ieee80211_node *ni,
+       struct ath_softc *sc = ic->ic_dev->priv;
+       sc->sc_rc->ops->newassoc(sc, ATH_NODE(ni), isnew);
++      ath_wprobe_node_join(ni->ni_vap, ni);
+       /* are we supporting compression? */
+       if (!(vap->iv_ath_cap & ni->ni_ath_flags & IEEE80211_NODE_COMP))
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -46,6 +46,7 @@
+ #include "ah_desc.h"
+ #include "ah_os.h"
+ #include "if_athioctl.h"
++#include <linux/wprobe.h>
+ #include "net80211/ieee80211.h"               /* XXX for WME_NUM_AC */
+ #include <asm/io.h>
+ #include <linux/list.h>
+@@ -352,6 +353,9 @@ typedef STAILQ_HEAD(, ath_buf) ath_bufhe
+ /* driver-specific node state */
+ struct ath_node {
+       struct ieee80211_node an_node;          /* base class */
++      struct wprobe_link an_wplink;
++      uint8_t an_wplink_active;
++      struct work_struct an_destroy;
+       u_int16_t an_decomp_index;              /* decompression mask index */
+       u_int32_t an_avgrssi;                   /* average rssi over all rx frames */
+       u_int8_t  an_prevdatarix;               /* rate ix of last data frame */
+@@ -521,6 +525,9 @@ struct ath_vap {
+ #else
+       unsigned int av_beacon_alloc;
+ #endif
++      struct wprobe_iface av_wpif;
++      u32 av_rxframes;
++      u32 av_rxprobereq;
+ };
+ #define       ATH_VAP(_v)     ((struct ath_vap *)(_v))
diff --git a/net/madwifi/patches/417-beacon_txpower.patch b/net/madwifi/patches/417-beacon_txpower.patch
new file mode 100644 (file)
index 0000000..8a59c12
--- /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;
+@@ -4932,6 +4932,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;
+@@ -4999,7 +5000,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
+@@ -2871,6 +2871,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);
+@@ -3236,6 +3239,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;
+       }
+@@ -5810,6 +5816,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/net/madwifi/patches/419-skb_unmap_crash.patch b/net/madwifi/patches/419-skb_unmap_crash.patch
new file mode 100644 (file)
index 0000000..37602e4
--- /dev/null
@@ -0,0 +1,20 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -13499,7 +13499,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, 
+@@ -13507,8 +13507,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/net/madwifi/patches/420-diversity_fix.patch b/net/madwifi/patches/420-diversity_fix.patch
new file mode 100644 (file)
index 0000000..90bcd0e
--- /dev/null
@@ -0,0 +1,86 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -797,7 +797,6 @@ ath_attach(u_int16_t devid, struct net_d
+               break;
+       }
+-      sc->sc_setdefantenna = ath_setdefantenna;
+       sc->sc_rc = ieee80211_rate_attach(sc, ratectl);
+       if (sc->sc_rc == NULL) {
+               error = EIO;
+@@ -2624,9 +2623,6 @@ ath_init(struct net_device *dev)
+       ath_radar_update(sc);
+       ath_rp_flush(sc);
+-      /* Set the default RX antenna; it may get lost on reset. */
+-      ath_setdefantenna(sc, sc->sc_defant);
+-
+       /*
+        * Setup the hardware after reset: the key cache
+        * is filled as needed and the receive engine is
+@@ -3019,7 +3015,6 @@ ath_reset(struct net_device *dev)
+       ath_setintmit(sc);
+       ath_update_txpow(sc);           /* update tx power state */
+       ath_radar_update(sc);
+-      ath_setdefantenna(sc, sc->sc_defant);
+       if (ath_startrecv(sc) != 0)     /* restart recv */
+               EPRINTF(sc, "Unable to start receive logic.\n");
+       if (sc->sc_softled)
+@@ -5353,27 +5348,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.
+@@ -6734,9 +6708,8 @@ ath_setdefantenna(struct ath_softc *sc,
+ {
+       struct ath_hal *ah = sc->sc_ah;
+-      /* XXX block beacon interrupts */
+-      ath_hal_setdiversity(ah, (sc->sc_diversity != 0));
+       ath_hal_setdefantenna(ah, antenna);
++      ath_hal_setantennaswitch(ah, sc->sc_diversity ? 0 : antenna);
+       if (sc->sc_defant != antenna)
+               sc->sc_stats.ast_ant_defswitch++;
+       sc->sc_defant = antenna;
+@@ -11160,7 +11133,7 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+                                       break;
+                               }
+                               sc->sc_diversity = val;
+-                              ath_hal_setdiversity(ah, val);
++                              ath_setdefantenna(sc, sc->sc_defant);
+                               break;
+                       case ATH_TXINTRPERIOD:
+                               /* XXX: validate? */
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -640,7 +640,6 @@ struct ath_softc {
+       spinlock_t sc_hal_lock;                 /* hardware access lock */
+       struct ath_ratectrl *sc_rc;             /* tx rate control support */
+       struct ath_tx99 *sc_tx99;               /* tx99 support */
+-      void (*sc_setdefantenna)(struct ath_softc *, u_int);
+       const struct ath_hw_detect *sc_hwinfo;
+       unsigned int    sc_invalid:1;           /* being detached */
diff --git a/net/madwifi/patches/421-channel_handling.patch b/net/madwifi/patches/421-channel_handling.patch
new file mode 100644 (file)
index 0000000..2a8ec27
--- /dev/null
@@ -0,0 +1,1351 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -148,7 +148,6 @@ static int ath_key_set(struct ieee80211v
+ static void ath_key_update_begin(struct ieee80211vap *);
+ static void ath_key_update_end(struct ieee80211vap *);
+ static void ath_mode_init(struct net_device *);
+-static void ath_setslottime(struct ath_softc *);
+ static void ath_updateslot(struct net_device *);
+ static int ath_beaconq_setup(struct ath_softc *);
+ static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *);
+@@ -240,7 +239,7 @@ static void ath_setup_stationkey(struct
+ static void ath_setup_stationwepkey(struct ieee80211_node *);
+ static void ath_setup_keycacheslot(struct ath_softc *, struct ieee80211_node *);
+ static void ath_newassoc(struct ieee80211_node *, int);
+-static int ath_getchannels(struct net_device *, u_int, HAL_BOOL, HAL_BOOL);
++static int ath_getchannels(struct net_device *);
+ static void ath_led_event(struct ath_softc *, int);
+ static void ath_update_txpow(struct ath_softc *);
+@@ -265,7 +264,6 @@ static int ath_change_mtu(struct net_dev
+ static int ath_ioctl(struct net_device *, struct ifreq *, int);
+ static int ath_rate_setup(struct net_device *, u_int);
+-static void ath_setup_subrates(struct net_device *);
+ #ifdef ATH_SUPERG_XR
+ static int ath_xr_rate_setup(struct net_device *);
+ static void ath_grppoll_txq_setup(struct ath_softc *, int, int);
+@@ -387,8 +385,6 @@ static void ath_fetch_idle_time(struct a
+ /* calibrate every 30 secs in steady state but check every second at first. */
+ static int ath_calinterval = ATH_SHORT_CALINTERVAL;
+-static int ath_countrycode = CTRY_DEFAULT;    /* country code */
+-static int ath_outdoor = AH_FALSE;            /* enable outdoor use */
+ static int ath_xchanmode = AH_TRUE;           /* enable extended channels */
+ static int ath_maxvaps = ATH_MAXVAPS_DEFAULT;   /* set default maximum vaps */
+ static int bstuck_thresh = BSTUCK_THRESH;       /* Stuck beacon count required for reset */
+@@ -396,9 +392,7 @@ static char *autocreate = NULL;
+ static char *ratectl = DEF_RATE_CTL;
+ static int rfkill = 0;
+ static int tpc = 1;
+-static int countrycode = -1;
+ static int maxvaps = -1;
+-static int outdoor = -1;
+ static int xchanmode = -1;
+ #include "ath_wprobe.c"
+ static int beacon_cal = 1;
+@@ -437,9 +431,7 @@ static struct notifier_block ath_event_b
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+ MODULE_PARM(beacon_cal, "i");
+-MODULE_PARM(countrycode, "i");
+ MODULE_PARM(maxvaps, "i");
+-MODULE_PARM(outdoor, "i");
+ MODULE_PARM(xchanmode, "i");
+ MODULE_PARM(rfkill, "i");
+ #ifdef ATH_CAP_TPC
+@@ -451,9 +443,7 @@ MODULE_PARM(ratectl, "s");
+ #else
+ #include <linux/moduleparam.h>
+ module_param(beacon_cal, int, 0600);
+-module_param(countrycode, int, 0600);
+ module_param(maxvaps, int, 0600);
+-module_param(outdoor, int, 0600);
+ module_param(xchanmode, int, 0600);
+ module_param(rfkill, int, 0600);
+ #ifdef ATH_CAP_TPC
+@@ -463,9 +453,7 @@ module_param(bstuck_thresh, int, 0600);
+ module_param(autocreate, charp, 0600);
+ module_param(ratectl, charp, 0600);
+ #endif
+-MODULE_PARM_DESC(countrycode, "Override default country code");
+ MODULE_PARM_DESC(maxvaps, "Maximum VAPs");
+-MODULE_PARM_DESC(outdoor, "Enable/disable outdoor use");
+ MODULE_PARM_DESC(xchanmode, "Enable/disable extended channel mode");
+ MODULE_PARM_DESC(rfkill, "Enable/disable RFKILL capability");
+ #ifdef ATH_CAP_TPC
+@@ -531,6 +519,50 @@ MODULE_PARM_DESC(ieee80211_debug, "Load-
+                               (bssid)[0] |= (((id) << 2) | 0x02);     \
+               } while (0)
++static inline int ath_chan2mode(struct ieee80211_channel *c)
++{
++      if (IEEE80211_IS_CHAN_HALF(c))
++              return ATH_MODE_HALF;
++      else if (IEEE80211_IS_CHAN_QUARTER(c))
++              return ATH_MODE_QUARTER;
++      else
++              return ieee80211_chan2mode(c);
++}
++
++static inline int rate_hal2ieee(int dot11Rate, int f)
++{
++      int flag = dot11Rate & ~(IEEE80211_RATE_VAL);
++      dot11Rate &= IEEE80211_RATE_VAL;
++
++      if (f == 4) { /* Quarter */
++              if (dot11Rate == 4)
++                      return 18 | flag;
++      }
++      return (dot11Rate * f) | flag;
++}
++
++static inline int rate_factor(int mode)
++{
++      int f;
++
++      /*
++       * NB: Fix up rates. HAL returns half or quarter dot11Rates,
++       * while the stack deals with full rates only
++       */
++      switch(mode) {
++              case ATH_MODE_HALF:
++                      f = 2;
++                      break;
++              case ATH_MODE_QUARTER:
++                      f = 4;
++                      break;
++              default:
++                      f = 1;
++                      break;
++      }
++      return f;
++}
++
+ /* Initialize ath_softc structure */
+ int
+@@ -647,14 +679,6 @@ ath_attach(u_int16_t devid, struct net_d
+       for (i = 0; i < sc->sc_keymax; i++)
+               ath_hal_keyreset(ah, i);
+-      /*
+-       * Collect the channel list using the default country
+-       * code and including outdoor channels.  The 802.11 layer
+-       * is responsible for filtering this list based on settings
+-       * like the phy mode.
+-       */
+-      if (countrycode != -1)
+-              ath_countrycode = countrycode;
+       if (maxvaps != -1) {
+               ath_maxvaps = maxvaps;
+               if (ath_maxvaps < ATH_MAXVAPS_MIN)
+@@ -662,17 +686,14 @@ ath_attach(u_int16_t devid, struct net_d
+               else if (ath_maxvaps > ATH_MAXVAPS_MAX)
+                       ath_maxvaps = ATH_MAXVAPS_MAX;
+       }
+-      if (outdoor != -1)
+-              ath_outdoor = outdoor;
+       if (xchanmode != -1)
+               ath_xchanmode = xchanmode;
+-      error = ath_getchannels(dev, ath_countrycode,
+-                      ath_outdoor, ath_xchanmode);
++      error = ath_getchannels(dev);
+       if (error != 0)
+               goto bad;
+-      ic->ic_country_code = ath_countrycode;
+-      ic->ic_country_outdoor = ath_outdoor;
++      ic->ic_country_code = CTRY_DEFAULT;
++      ic->ic_country_outdoor = 0;
+       IPRINTF(sc, "Switching rfkill capability %s\n",
+               rfkill ? "on" : "off");
+@@ -686,9 +707,8 @@ ath_attach(u_int16_t devid, struct net_d
+       ath_rate_setup(dev, IEEE80211_MODE_11G);
+       ath_rate_setup(dev, IEEE80211_MODE_TURBO_A);
+       ath_rate_setup(dev, IEEE80211_MODE_TURBO_G);
+-
+-      /* Setup for half/quarter rates */
+-      ath_setup_subrates(dev);
++      ath_rate_setup(dev, ATH_MODE_HALF);
++      ath_rate_setup(dev, ATH_MODE_QUARTER);
+       /* NB: setup here so ath_rate_update is happy */
+       ath_setcurmode(sc, IEEE80211_MODE_11A);
+@@ -908,10 +928,6 @@ ath_attach(u_int16_t devid, struct net_d
+                       IEEE80211_ATHC_COMP : 0);
+ #endif
+-#ifdef ATH_SUPERG_DYNTURBO
+-      ic->ic_ath_cap |= (ath_hal_turboagsupported(ah, ath_countrycode) ? 
+-                      (IEEE80211_ATHC_TURBOP | IEEE80211_ATHC_AR) : 0);
+-#endif
+ #ifdef ATH_SUPERG_XR
+       ic->ic_ath_cap |= (ath_hal_xrsupported(ah) ? IEEE80211_ATHC_XR : 0);
+ #endif
+@@ -4470,17 +4486,17 @@ ath_mode_init(struct net_device *dev)
+  * Set the slot time based on the current setting.
+  */
+ static void
+-ath_setslottime(struct ath_softc *sc)
++ath_settiming(struct ath_softc *sc)
+ {
+-      struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
++      u_int offset = getTimingOffset(sc);
+-      if (sc->sc_slottimeconf > 0) /* manual override */
+-              ath_hal_setslottime(ah, sc->sc_slottimeconf);
+-      else if (ic->ic_flags & IEEE80211_F_SHSLOT)
+-              ath_hal_setslottime(ah, HAL_SLOT_TIME_9);
+-      else
+-              ath_hal_setslottime(ah, HAL_SLOT_TIME_20);
++      if (sc->sc_slottimeconf > 0)
++              ath_hal_setslottime(ah, offset + sc->sc_slottimeconf);
++      if (sc->sc_acktimeconf > 0)
++              ath_hal_setacktimeout(ah, 2 * offset + sc->sc_acktimeconf);
++      if (sc->sc_ctstimeconf > 0)
++              ath_hal_setctstimeout(ah, 2 * offset + sc->sc_ctstimeconf);
+       sc->sc_updateslot = OK;
+ }
+@@ -4502,7 +4518,7 @@ ath_updateslot(struct net_device *dev)
+       if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+               sc->sc_updateslot = UPDATE;
+       else if (dev->flags & IFF_RUNNING)
+-              ath_setslottime(sc);
++              ath_settiming(sc);
+ }
+ #ifdef ATH_SUPERG_DYNTURBO
+@@ -5346,7 +5362,7 @@ ath_beacon_send(struct ath_softc *sc, in
+               sc->sc_updateslot = COMMIT;     /* commit next beacon */
+               sc->sc_slotupdate = slot;
+       } else if ((sc->sc_updateslot == COMMIT) && (sc->sc_slotupdate == slot))
+-              ath_setslottime(sc);            /* commit change to hardware */
++              ath_settiming(sc);              /* commit change to hardware */
+       if (bfaddr != 0) {
+               /*
+@@ -7802,12 +7818,14 @@ ath_get_ivlen(struct ieee80211_key *k)
+  * Get transmit rate index using rate in Kbps
+  */
+ static __inline int
+-ath_tx_findindex(const HAL_RATE_TABLE *rt, int rate)
++ath_tx_findindex(struct ath_softc *sc, const HAL_RATE_TABLE *rt, int rate)
+ {
+       unsigned int i, ndx = 0;
++      int f;
++      f = rate_factor(sc->sc_curmode);
+       for (i = 0; i < rt->rateCount; i++) {
+-              if (rt->info[i].rateKbps == rate) {
++              if ((rt->info[i].rateKbps * f) == rate) {
+                       ndx = i;
+                       break;
+               }
+@@ -8100,7 +8118,7 @@ ath_tx_start(struct net_device *dev, str
+               atype = HAL_PKT_TYPE_NORMAL;            /* default */
+               if (ismcast) {
+-                      rix = ath_tx_findindex(rt, vap->iv_mcast_rate);
++                      rix = ath_tx_findindex(sc, rt, vap->iv_mcast_rate);
+                       txrate = rt->info[rix].rateCode;
+                       if (shortPreamble)
+                               txrate |= rt->info[rix].shortPreamble;
+@@ -9067,7 +9085,7 @@ ath_chan_change(struct ath_softc *sc, st
+       struct net_device *dev = sc->sc_dev;
+       enum ieee80211_phymode mode;
+-      mode = ieee80211_chan2mode(chan);
++      mode = ath_chan2mode(chan);
+       ath_rate_setup(dev, mode);
+       ath_setcurmode(sc, mode);
+@@ -10124,8 +10142,7 @@ ath_newassoc(struct ieee80211_node *ni,
+ }
+ static int
+-ath_getchannels(struct net_device *dev, u_int cc,
+-      HAL_BOOL outdoor, HAL_BOOL xchanmode)
++ath_getchannels(struct net_device *dev)
+ {
+       struct ath_softc *sc = dev->priv;
+       struct ieee80211com *ic = &sc->sc_ic;
+@@ -10139,17 +10156,31 @@ ath_getchannels(struct net_device *dev,
+               EPRINTF(sc, "Insufficient memory for channel table!\n");
+               return -ENOMEM;
+       }
++
++restart:
+       if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan,
+           ic->ic_regclassids, IEEE80211_REGCLASSIDS_MAX, &ic->ic_nregclass,
+-          cc, HAL_MODE_ALL, outdoor, xchanmode)) {
++          ic->ic_country_code, HAL_MODE_ALL, ic->ic_country_outdoor, ath_xchanmode)) {
+               u_int32_t rd;
+               ath_hal_getregdomain(ah, &rd);
+               EPRINTF(sc, "Unable to collect channel list from HAL; "
+-                      "regdomain likely %u country code %u\n", rd, cc);
++                      "regdomain likely %u country code %u\n", rd, ic->ic_country_code);
++              if ((ic->ic_country_code != CTRY_DEFAULT) ||
++                      (ic->ic_country_outdoor != 0)) {
++                      EPRINTF(sc, "Reverting to defaults\n");
++                      ic->ic_country_code = CTRY_DEFAULT;
++                      ic->ic_country_outdoor = 0;
++                      goto restart;
++              }
+               kfree(chans);
+               return -EINVAL;
+       }
++#ifdef ATH_SUPERG_DYNTURBO
++      ic->ic_ath_cap &= ~(IEEE80211_ATHC_TURBOP | IEEE80211_ATHC_AR);
++      ic->ic_ath_cap |= (ath_hal_turboagsupported(ah, ic->ic_country_code) ?
++                      (IEEE80211_ATHC_TURBOP | IEEE80211_ATHC_AR) : 0);
++#endif
+       /*
+        * Convert HAL channels to ieee80211 ones.
+        */
+@@ -10395,7 +10426,7 @@ ath_xr_rate_setup(struct net_device *dev
+       struct ieee80211com *ic = &sc->sc_ic;
+       const HAL_RATE_TABLE *rt;
+       struct ieee80211_rateset *rs;
+-      unsigned int i, maxrates;
++      unsigned int i, j, maxrates;
+       sc->sc_xr_rates = ath_hal_getratetable(ah, HAL_MODE_XR);
+       rt = sc->sc_xr_rates;
+       if (rt == NULL)
+@@ -10408,57 +10439,16 @@ ath_xr_rate_setup(struct net_device *dev
+       } else
+               maxrates = rt->rateCount;
+       rs = &ic->ic_sup_xr_rates;
+-      for (i = 0; i < maxrates; i++)
+-              rs->rs_rates[i] = rt->info[i].dot11Rate;
+-      rs->rs_nrates = maxrates;
++      for (j = 0, i = 0; i < maxrates; i++) {
++              if (!rt->info[i].valid)
++                      continue;
++              rs->rs_rates[j++] = rt->info[i].dot11Rate;
++      }
++      rs->rs_nrates = j;
+       return 1;
+ }
+ #endif
+-/* Setup half/quarter rate table support */
+-static void
+-ath_setup_subrates(struct net_device *dev)
+-{
+-      struct ath_softc *sc = dev->priv;
+-      struct ath_hal *ah = sc->sc_ah;
+-      struct ieee80211com *ic = &sc->sc_ic;
+-      const HAL_RATE_TABLE *rt;
+-      struct ieee80211_rateset *rs;
+-      unsigned int i, maxrates;
+-
+-      sc->sc_half_rates = ath_hal_getratetable(ah, HAL_MODE_11A_HALF_RATE);
+-      rt = sc->sc_half_rates;
+-      if (rt != NULL) {
+-              if (rt->rateCount > IEEE80211_RATE_MAXSIZE) {
+-                      DPRINTF(sc, ATH_DEBUG_ANY,
+-                              "The rate table is too small (%u > %u)\n",
+-                             rt->rateCount, IEEE80211_RATE_MAXSIZE);
+-                      maxrates = IEEE80211_RATE_MAXSIZE;
+-              } else
+-                      maxrates = rt->rateCount;
+-              rs = &ic->ic_sup_half_rates;
+-              for (i = 0; i < maxrates; i++)
+-                      rs->rs_rates[i] = rt->info[i].dot11Rate;
+-              rs->rs_nrates = maxrates;
+-      }
+-
+-      sc->sc_quarter_rates = ath_hal_getratetable(ah, HAL_MODE_11A_QUARTER_RATE);
+-      rt = sc->sc_quarter_rates;
+-      if (rt != NULL) {
+-              if (rt->rateCount > IEEE80211_RATE_MAXSIZE) {
+-                      DPRINTF(sc, ATH_DEBUG_ANY,
+-                              "The rate table is too small (%u > %u)\n",
+-                             rt->rateCount, IEEE80211_RATE_MAXSIZE);
+-                      maxrates = IEEE80211_RATE_MAXSIZE;
+-              } else
+-                      maxrates = rt->rateCount;
+-              rs = &ic->ic_sup_quarter_rates;
+-              for (i = 0; i < maxrates; i++)
+-                      rs->rs_rates[i] = rt->info[i].dot11Rate;
+-              rs->rs_nrates = maxrates;
+-      }
+-}
+-
+ static int
+ ath_rate_setup(struct net_device *dev, u_int mode)
+ {
+@@ -10467,7 +10457,7 @@ ath_rate_setup(struct net_device *dev, u
+       struct ieee80211com *ic = &sc->sc_ic;
+       const HAL_RATE_TABLE *rt;
+       struct ieee80211_rateset *rs;
+-      unsigned int i, maxrates;
++      unsigned int i, j, maxrates, f;
+       switch (mode) {
+       case IEEE80211_MODE_11A:
+@@ -10485,6 +10475,12 @@ ath_rate_setup(struct net_device *dev, u
+       case IEEE80211_MODE_TURBO_G:
+               sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_108G);
+               break;
++      case ATH_MODE_HALF:
++              sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11A_HALF_RATE);
++              break;
++      case ATH_MODE_QUARTER:
++              sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11A_QUARTER_RATE);
++              break;
+       default:
+               DPRINTF(sc, ATH_DEBUG_ANY, "Invalid mode %u\n", mode);
+               return 0;
+@@ -10499,10 +10495,16 @@ ath_rate_setup(struct net_device *dev, u
+               maxrates = IEEE80211_RATE_MAXSIZE;
+       } else
+               maxrates = rt->rateCount;
++
++      /* NB: quarter/half rate channels hijack the 11A rateset */
++      if (mode >= IEEE80211_MODE_MAX)
++              return 1;
++
+       rs = &ic->ic_sup_rates[mode];
+       for (i = 0; i < maxrates; i++)
+               rs->rs_rates[i] = rt->info[i].dot11Rate;
+       rs->rs_nrates = maxrates;
++
+       return 1;
+ }
+@@ -10531,13 +10533,18 @@ ath_setcurmode(struct ath_softc *sc, enu
+               {   0, 500, 130 },
+       };
+       const HAL_RATE_TABLE *rt;
+-      unsigned int i, j;
++      unsigned int i, j, f;
++      /*
++       * NB: Fix up rixmap. HAL returns half or quarter dot11Rates,
++       * while the stack deals with full rates only
++       */
++      f = rate_factor(mode);
+       memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap));
+       rt = sc->sc_rates[mode];
+       KASSERT(rt != NULL, ("no h/w rate set for phy mode %u", mode));
+       for (i = 0; i < rt->rateCount; i++)
+-              sc->sc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i;
++              sc->sc_rixmap[rate_hal2ieee(rt->info[i].dot11Rate, f) & IEEE80211_RATE_VAL] = i;
+       memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap));
+       for (i = 0; i < 32; i++) {
+               u_int8_t ix = rt->rateCodeToIndex[i];
+@@ -10547,7 +10554,7 @@ ath_setcurmode(struct ath_softc *sc, enu
+                       continue;
+               }
+               sc->sc_hwmap[i].ieeerate =
+-                      rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
++                      rate_hal2ieee(rt->info[ix].dot11Rate, f) & IEEE80211_RATE_VAL;
+               if (rt->info[ix].shortPreamble ||
+                   rt->info[ix].phy == IEEE80211_T_OFDM)
+                       sc->sc_hwmap[i].flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+@@ -10948,9 +10955,106 @@ enum {
+       ATH_MAXVAPS             = 26,
+       ATH_INTMIT                      = 27,
+       ATH_NOISE_IMMUNITY      = 28,
+-      ATH_OFDM_WEAK_DET       = 29
++      ATH_OFDM_WEAK_DET       = 29,
++      ATH_CHANBW              = 30,
++      ATH_OUTDOOR             = 31,
+ };
++/*
++ * perform the channel related sysctl, reload the channel list
++ * and try to stay on the current frequency
++ */
++static int ath_sysctl_setchanparam(struct ath_softc *sc, unsigned long ctl, u_int val)
++{
++      struct ieee80211com *ic = &sc->sc_ic;
++      struct ath_hal *ah = sc->sc_ah;
++      struct ieee80211_channel *c = NULL;
++      struct ieee80211vap *vap;
++      u_int16_t freq = 0;
++      struct ifreq ifr;
++
++      if (ic->ic_curchan != IEEE80211_CHAN_ANYC)
++              freq = ic->ic_curchan->ic_freq;
++
++      switch(ctl) {
++      case ATH_COUNTRYCODE:
++              ic->ic_country_code = val;
++              break;
++      case ATH_OUTDOOR:
++              ic->ic_country_outdoor = val;
++              break;
++      case ATH_CHANBW:
++              switch(val) {
++              case 0:
++              case 5:
++              case 10:
++              case 20:
++              case 40:
++                      if (ath_hal_setcapability(ah, HAL_CAP_CHANBW, 1, val, NULL) == AH_TRUE) {
++                              sc->sc_chanbw = val;
++                              break;
++                      }
++              default:
++                      return -EINVAL;
++              }
++              break;
++      }
++
++      if (ic->ic_curchan != IEEE80211_CHAN_ANYC)
++              freq = ic->ic_curchan->ic_freq;
++
++      /* clear out any old state */
++      TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++              vap->iv_des_mode = IEEE80211_MODE_AUTO;
++              vap->iv_des_chan = IEEE80211_CHAN_ANYC;
++      }
++      ieee80211_scan_flush(ic);
++
++      IEEE80211_LOCK_IRQ(ic);
++      ath_getchannels(sc->sc_dev);
++      ieee80211_update_channels(ic, 0);
++      if (freq)
++              c = ieee80211_find_channel(ic, freq, IEEE80211_MODE_AUTO);
++      if (!c)
++              c = &ic->ic_channels[0];
++      ic->ic_curchan = c;
++      ic->ic_bsschan = c;
++      ic->ic_curmode = IEEE80211_MODE_AUTO;
++      IEEE80211_UNLOCK_IRQ(ic);
++
++      if (!(sc->sc_dev->flags & IFF_RUNNING)) {
++              ic->ic_bsschan = IEEE80211_CHAN_ANYC;
++              return 0;
++      }
++
++#ifndef ifr_media
++#define    ifr_media       ifr_ifru.ifru_ivalue
++#endif
++      memset(&ifr, 0, sizeof(ifr));
++      ifr.ifr_media = ic->ic_media.ifm_cur->ifm_media & ~IFM_MMASK;
++      ifr.ifr_media |= IFM_MAKEMODE(IEEE80211_MODE_AUTO);
++      ifmedia_ioctl(ic->ic_dev, &ifr, &ic->ic_media, SIOCSIFMEDIA);
++
++      /* apply the channel to the hw */
++      ath_set_channel(ic);
++
++      TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++              struct net_device *dev = vap->iv_dev;
++
++              /* reactivate all active vaps */
++              vap->iv_state = IEEE80211_S_SCAN;
++              if ((vap->iv_opmode == IEEE80211_M_HOSTAP) ||
++                      (vap->iv_opmode == IEEE80211_M_MONITOR) ||
++                      (vap->iv_opmode == IEEE80211_M_WDS))
++                      ieee80211_new_state(vap, IEEE80211_S_RUN, 0);
++              else
++                      ieee80211_new_state(vap, IEEE80211_S_INIT, -1);
++      }
++
++      return 0;
++}
++
++
+ static int
+ ath_sysctl_set_intmit(struct ath_softc *sc, long ctl, u_int val)
+ {
+@@ -11029,6 +11133,7 @@ static int
+ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
+ {
+       struct ath_softc *sc = ctl->extra1;
++      struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
+       u_int val;
+       u_int tab_3_val[3];
+@@ -11052,25 +11157,34 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+                               lenp, ppos);
+               if (ret == 0) {
+                       switch ((long)ctl->extra2) {
++                      case ATH_REGDOMAIN:
++                              ath_hal_setregdomain(ah, val);
++                              break;
++                      case ATH_OUTDOOR:
++                      case ATH_COUNTRYCODE:
++                      case ATH_CHANBW:
++                              ret = ath_sysctl_setchanparam(sc, (long) ctl->extra2, val);
++                              break;
+                       case ATH_SLOTTIME:
+-                              if (val > 0) {
+-                                      if (!ath_hal_setslottime(ah, val))
+-                                              ret = -EINVAL;
+-                                      else
+-                                              sc->sc_slottimeconf = val;
+-                              } else {
+-                                      /* disable manual override */
++                              if (val > 0)
++                                      sc->sc_slottimeconf = val;
++                              else
+                                       sc->sc_slottimeconf = 0;
+-                                      ath_setslottime(sc);
+-                              }
++                              ath_settiming(sc);
+                               break;
+                       case ATH_ACKTIMEOUT:
+-                              if (!ath_hal_setacktimeout(ah, val))
+-                                      ret = -EINVAL;
++                              if (val > 0)
++                                      sc->sc_acktimeconf = val;
++                              else
++                                      sc->sc_acktimeconf = 0;
++                              ath_settiming(sc);
+                               break;
+                       case ATH_CTSTIMEOUT:
+-                              if (!ath_hal_setctstimeout(ah, val))
+-                                      ret = -EINVAL;
++                              if (val > 0)
++                                      sc->sc_ctstimeconf = val;
++                              else
++                                      sc->sc_ctstimeconf = 0;
++                              ath_settiming(sc);
+                               break;
+                       case ATH_SOFTLED:
+                               if (val != sc->sc_softled) {
+@@ -11223,6 +11337,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+               }
+       } else {
+               switch ((long)ctl->extra2) {
++              case ATH_CHANBW:
++                      val = sc->sc_chanbw ?: 20;
++                      break;
+               case ATH_SLOTTIME:
+                       val = ath_hal_getslottime(ah);
+                       break;
+@@ -11241,6 +11358,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+               case ATH_COUNTRYCODE:
+                       ath_hal_getcountrycode(ah, &val);
+                       break;
++              case ATH_OUTDOOR:
++                      val = ic->ic_country_outdoor;
++                      break;
+               case ATH_MAXVAPS:
+                       val = ath_maxvaps;
+                       break;
+@@ -11354,11 +11474,17 @@ static const ctl_table ath_sysctl_templa
+       },
+       { .ctl_name     = CTL_AUTO,
+         .procname     = "countrycode",
+-        .mode         = 0444,
++        .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_COUNTRYCODE,
+       },
+       { .ctl_name     = CTL_AUTO,
++        .procname     = "outdoor",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_halparam,
++        .extra2       = (void *)ATH_OUTDOOR,
++      },
++      { .ctl_name     = CTL_AUTO,
+         .procname     = "maxvaps",
+         .mode         = 0444,
+         .proc_handler = ath_sysctl_halparam,
+@@ -11366,7 +11492,7 @@ static const ctl_table ath_sysctl_templa
+       },
+       { .ctl_name     = CTL_AUTO,
+         .procname     = "regdomain",
+-        .mode         = 0444,
++        .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_REGDOMAIN,
+       },
+@@ -11429,6 +11555,12 @@ static const ctl_table ath_sysctl_templa
+         .extra2       = (void *)ATH_ACKRATE,
+       },
+       { .ctl_name     = CTL_AUTO,
++        .procname     = "channelbw",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_halparam,
++        .extra2       = (void *)ATH_CHANBW,
++      },
++      { .ctl_name     = CTL_AUTO,
+         .procname     = "rp",
+         .mode         = 0200,
+         .proc_handler = ath_sysctl_halparam,
+@@ -11669,13 +11801,6 @@ static ctl_table ath_static_sysctls[] =
+       },
+ #endif
+       { .ctl_name     = CTL_AUTO,
+-        .procname     = "countrycode",
+-        .mode         = 0444,
+-        .data         = &ath_countrycode,
+-        .maxlen       = sizeof(ath_countrycode),
+-        .proc_handler = proc_dointvec
+-      },
+-      { .ctl_name     = CTL_AUTO,
+         .procname     = "maxvaps",
+         .mode         = 0444,
+         .data         = &ath_maxvaps,
+@@ -11683,13 +11808,6 @@ static ctl_table ath_static_sysctls[] =
+         .proc_handler = proc_dointvec
+       },
+       { .ctl_name     = CTL_AUTO,
+-        .procname     = "outdoor",
+-        .mode         = 0444,
+-        .data         = &ath_outdoor,
+-        .maxlen       = sizeof(ath_outdoor),
+-        .proc_handler = proc_dointvec
+-      },
+-      { .ctl_name     = CTL_AUTO,
+         .procname     = "xchanmode",
+         .mode         = 0444,
+         .data         = &ath_xchanmode,
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -688,17 +688,18 @@ struct ath_softc {
+       int8_t sc_ofdm_weak_det; /* OFDM weak frames detection, -1 == auto */
+       /* rate tables */
+-      const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX];
++#define ATH_MODE_HALF         (IEEE80211_MODE_MAX)
++#define ATH_MODE_QUARTER      (IEEE80211_MODE_MAX + 1)
++      const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX + 2];
+       const HAL_RATE_TABLE *sc_currates;      /* current rate table */
+       const HAL_RATE_TABLE *sc_xr_rates;      /* XR rate table */
+-      const HAL_RATE_TABLE *sc_half_rates;    /* half rate table */
+-      const HAL_RATE_TABLE *sc_quarter_rates; /* quarter rate table */
+       HAL_OPMODE sc_opmode;                   /* current hal operating mode */
+       enum ieee80211_phymode sc_curmode;      /* current phy mode */
+       u_int sc_poweroffset;                   /* hardware power offset */
+       u_int16_t sc_curtxpow;                  /* current tx power limit */
+       u_int16_t sc_curaid;                    /* current association id */
+       HAL_CHANNEL sc_curchan;                 /* current h/w channel */
++      u_int8_t sc_chanbw;                             /* channel bandwidth */
+       u_int8_t sc_curbssid[IEEE80211_ADDR_LEN];
+       u_int8_t        sc_rixmap[256];                 /* IEEE to h/w rate table ix */
+       struct {
+@@ -809,6 +810,8 @@ struct ath_softc {
+       u_int32_t sc_dturbo_bw_turbo;           /* bandwidth threshold */
+ #endif
+       u_int sc_slottimeconf;                  /* manual override for slottime */
++      u_int sc_acktimeconf;                   /* manual override for acktime */
++      u_int sc_ctstimeconf;                   /* manual override for ctstime */
+       struct timer_list sc_dfs_excl_timer;    /* mark expiration timer task */
+       struct timer_list sc_dfs_cac_timer;     /* dfs wait timer */
+@@ -827,6 +830,7 @@ struct ath_softc {
+       int sc_rp_num;
+       int sc_rp_min;
+       HAL_BOOL (*sc_rp_analyse)(struct ath_softc *sc);
++      struct ATH_TQ_STRUCT sc_refresh_tq;
+       struct ATH_TQ_STRUCT sc_rp_tq;
+       
+       int sc_rp_ignored;                      /* if set, we ignored all 
+@@ -942,6 +946,48 @@ int ar_device(int devid);
+         DEV_NAME(_v->iv_ic->ic_dev))
+ void ath_radar_detected(struct ath_softc *sc, const char* message);
++static inline u_int getTimingOffset(struct ath_softc *sc)
++{
++      struct ieee80211com *ic = &sc->sc_ic;
++      u_int usec = 9;
++      if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
++              usec = 20;
++              if (ic->ic_flags & IEEE80211_F_SHSLOT)
++                      usec = 9;
++      } else if (IEEE80211_IS_CHAN_A(ic->ic_curchan))
++              usec = 9;
++
++      if (IEEE80211_IS_CHAN_TURBO(ic->ic_curchan))
++              usec = 6;
++
++      if (IEEE80211_IS_CHAN_HALF(ic->ic_curchan))
++              usec = 13;
++      else if (IEEE80211_IS_CHAN_QUARTER(ic->ic_curchan))
++              usec = 21;
++      return usec;
++}
++
++static inline void ath_get_timings(struct ath_softc *sc, u_int *t_slot, u_int *t_sifs, u_int *t_difs)
++{
++      struct ieee80211_channel *c = sc->sc_ic.ic_curchan;
++
++      *t_slot = getTimingOffset(sc) + sc->sc_slottimeconf;
++
++      if (IEEE80211_IS_CHAN_HALF(c)) {
++              *t_sifs = 32;
++              *t_difs = 56;
++      } else if (IEEE80211_IS_CHAN_QUARTER(c)) {
++              *t_sifs = 64;
++              *t_difs = 112;
++      } else if (IEEE80211_IS_CHAN_TURBO(c)) {
++              *t_sifs = 8;
++              *t_difs = 28;
++      } else {
++              *t_sifs = 16;
++              *t_difs = 28;
++      }
++}
++
+ struct ath_hw_detect {
+       const char *vendor_name;
+--- a/tools/athctrl.c
++++ b/tools/athctrl.c
+@@ -118,7 +118,7 @@ CMD(athctrl)(int argc, char *argv[])
+       }
+       if (distance >= 0) {
+-              int slottime = 9 + (distance / 300) + ((distance % 300) ? 1 : 0);
++              int slottime = (distance / 300) + ((distance % 300) ? 1 : 0);
+               int acktimeout = slottime * 2 + 3;
+               int ctstimeout = slottime * 2 + 3;
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -243,34 +243,17 @@ static const  struct country_code_to_str
+       {CTRY_ZIMBABWE,             "ZW"}
+ };
+-int
+-ieee80211_ifattach(struct ieee80211com *ic)
++void ieee80211_update_channels(struct ieee80211com *ic, int init)
+ {
+-      struct net_device *dev = ic->ic_dev;
+       struct ieee80211_channel *c;
++      struct ieee80211vap *vap;
+       struct ifmediareq imr;
++      int ext = 0;
+       int i;
+-      _MOD_INC_USE(THIS_MODULE, return -ENODEV);
+-
+-      /*
+-       * Pick an initial operating mode until we have a vap
+-       * created to lock it down correctly.  This is only
+-       * drivers have something defined for configuring the
+-       * hardware at startup.
+-       */
+-      ic->ic_opmode = IEEE80211_M_STA;        /* everyone supports this */
+-
+-      /*
+-       * Fill in 802.11 available channel set, mark
+-       * all available channels as active, and pick
+-       * a default channel if not already specified.
+-       */
+-      KASSERT(0 < ic->ic_nchans && ic->ic_nchans < IEEE80211_CHAN_MAX,
+-              ("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;
++      ic->ic_modecaps = 1 << IEEE80211_MODE_AUTO;
+       for (i = 0; i < ic->ic_nchans; i++) {
+               c = &ic->ic_channels[i];
+@@ -298,6 +281,8 @@ ieee80211_ifattach(struct ieee80211com *
+                       ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_A;
+               if (IEEE80211_IS_CHAN_108G(c))
+                       ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_G;
++              if (IEEE80211_IS_CHAN_HALF(c) || IEEE80211_IS_CHAN_QUARTER(c))
++                      ext = 1;
+       }
+       /* Initialize candidate channels to all available */
+       memcpy(ic->ic_chan_active, ic->ic_chan_avail,
+@@ -311,11 +296,59 @@ ieee80211_ifattach(struct ieee80211com *
+        * When 11g is supported, force the rate set to
+        * include basic rates suitable for a mixed b/g bss.
+        */
+-      if (ic->ic_modecaps & (1 << IEEE80211_MODE_11G))
++      if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11G)) && !ext)
+               ieee80211_set11gbasicrates(
+                       &ic->ic_sup_rates[IEEE80211_MODE_11G],
+                       IEEE80211_MODE_11G);
++      if (init)
++              return;
++
++      ifmedia_removeall(&ic->ic_media);
++      ieee80211_media_setup(ic, &ic->ic_media, ic->ic_caps, NULL, NULL);
++      ieee80211com_media_status(ic->ic_dev, &imr);
++      ifmedia_set(&ic->ic_media, imr.ifm_active);
++
++      TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++              struct ieee80211vap *avp;
++              TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
++                      (void) ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps, NULL, NULL);
++                      ieee80211_media_status(vap->iv_dev, &imr);
++                      ifmedia_set(&vap->iv_media, imr.ifm_active);
++              }
++              (void) ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps, NULL, NULL);
++              ieee80211_media_status(vap->iv_dev, &imr);
++              ifmedia_set(&vap->iv_media, imr.ifm_active);
++      }
++}
++EXPORT_SYMBOL(ieee80211_update_channels);
++
++int
++ieee80211_ifattach(struct ieee80211com *ic)
++{
++      struct net_device *dev = ic->ic_dev;
++      struct ieee80211_channel *c;
++      struct ifmediareq imr;
++
++      _MOD_INC_USE(THIS_MODULE, return -ENODEV);
++
++      /*
++       * Pick an initial operating mode until we have a vap
++       * created to lock it down correctly.  This is only
++       * drivers have something defined for configuring the
++       * hardware at startup.
++       */
++      ic->ic_opmode = IEEE80211_M_STA;        /* everyone supports this */
++
++      /*
++       * Fill in 802.11 available channel set, mark
++       * all available channels as active, and pick
++       * a default channel if not already specified.
++       */
++      KASSERT(0 < ic->ic_nchans && ic->ic_nchans < IEEE80211_CHAN_MAX,
++              ("invalid number of channels specified: %u", ic->ic_nchans));
++      ieee80211_update_channels(ic, 1);
++
+       /* Setup initial channel settings */
+       ic->ic_bsschan = IEEE80211_CHAN_ANYC;
+       /* Arbitrarily pick the first channel */
+@@ -327,6 +360,7 @@ ieee80211_ifattach(struct ieee80211com *
+       /* Enable WME by default, if we're capable. */
+       if (ic->ic_caps & IEEE80211_C_WME)
+               ic->ic_flags |= IEEE80211_F_WME;
++
+       (void) ieee80211_setmode(ic, ic->ic_curmode);
+       /* Store default beacon interval, as nec. */
+@@ -763,7 +797,8 @@ ieee80211_media_setup(struct ieee80211co
+       struct ieee80211_rateset allrates;
+       /* Fill in media characteristics. */
+-      ifmedia_init(media, 0, media_change, media_stat);
++      if (media_change || media_stat)
++              ifmedia_init(media, 0, media_change, media_stat);
+       maxrate = 0;
+       memset(&allrates, 0, sizeof(allrates));
+@@ -793,7 +828,7 @@ ieee80211_media_setup(struct ieee80211co
+                       ADD(media, IFM_AUTO, mopt | IFM_IEEE80211_WDS);
+               if (mode == IEEE80211_MODE_AUTO)
+                       continue;
+-              rs = &ic->ic_sup_rates[mode];
++              rs = &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, mode)];
+               for (i = 0; i < rs->rs_nrates; i++) {
+                       rate = rs->rs_rates[i];
+@@ -1207,7 +1242,7 @@ ieee80211_announce(struct ieee80211com *
+               if ((ic->ic_modecaps & (1 << mode)) == 0)
+                       continue;
+               if_printf(dev, "%s rates: ", ieee80211_phymode_name[mode]);
+-              rs = &ic->ic_sup_rates[mode];
++              rs = &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, mode)];
+               for (i = 0; i < rs->rs_nrates; i++) {
+                       rate = rs->rs_rates[i];
+                       mword = ieee80211_rate2media(ic, rate, mode);
+@@ -1417,7 +1452,7 @@ ieee80211com_media_change(struct net_dev
+                        * now so drivers have a consistent state.
+                        */
+                       KASSERT(vap->iv_bss != NULL, ("no bss node"));
+-                      vap->iv_bss->ni_rates = ic->ic_sup_rates[newphymode];
++                      vap->iv_bss->ni_rates = ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, newphymode)];
+               }
+               error = -ENETRESET;
+       }
+@@ -1435,7 +1470,7 @@ findrate(struct ieee80211com *ic, enum i
+ {
+ #define       IEEERATE(_ic,_m,_i) \
+       ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
+-      int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
++      int i, nrates = ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, mode)].rs_nrates;
+       for (i = 0; i < nrates; i++)
+               if (IEEERATE(ic, mode, i) == rate)
+                       return i;
+@@ -1877,11 +1912,6 @@ ieee80211_build_countryie(struct ieee802
+                       if (ieee80211_chan2mode(c) != curmode_noturbo)
+                               continue;
+-                      /* Skip half/quarter rate channels */
+-                      if (IEEE80211_IS_CHAN_HALF(c) ||
+-                          IEEE80211_IS_CHAN_QUARTER(c))
+-                              continue;
+-
+                       if (*cur_runlen == 0) {
+                               (*cur_runlen)++;
+                               *cur_pow = c->ic_maxregpower;
+@@ -1915,7 +1945,7 @@ void
+ ieee80211_build_sc_ie(struct ieee80211com *ic)
+ {
+       struct ieee80211_ie_sc *ie = &ic->ic_sc_ie;
+-      int i, j;
++      int i, j, k;
+       struct ieee80211_channel *c;
+       u_int8_t prevchan;
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -336,8 +336,6 @@ struct ieee80211com {
+       u_int8_t ic_nopened;                    /* VAPs been opened */
+       struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
+       struct ieee80211_rateset ic_sup_xr_rates;
+-      struct ieee80211_rateset ic_sup_half_rates;
+-      struct ieee80211_rateset ic_sup_quarter_rates;
+       u_int16_t ic_modecaps;                  /* set of mode capabilities */
+       u_int16_t ic_curmode;                   /* current mode */
+       u_int16_t ic_lintval;                   /* beacon interval */
+@@ -714,6 +712,7 @@ MALLOC_DECLARE(M_80211_VAP);
+ int ieee80211_ifattach(struct ieee80211com *);
+ void ieee80211_ifdetach(struct ieee80211com *);
++void ieee80211_update_channels(struct ieee80211com *ic, int);
+ int ieee80211_vap_setup(struct ieee80211com *, struct net_device *,
+       const char *, int, int, struct ieee80211vap *);
+ int ieee80211_vap_attach(struct ieee80211vap *, ifm_change_cb_t, ifm_stat_cb_t);
+@@ -793,6 +792,23 @@ ieee80211_anyhdrspace(struct ieee80211co
+       return size;
+ }
++static __inline int
++ieee80211_chan2ratemode(struct ieee80211_channel *c, int mode)
++{
++      if (mode == -1)
++              mode = ieee80211_chan2mode(c);
++
++      /*
++       * Use 11a rateset for half/quarter to restrict things
++       * to pure OFDM
++       */
++      if (IEEE80211_IS_CHAN_HALF(c) ||
++              IEEE80211_IS_CHAN_QUARTER(c))
++              return IEEE80211_MODE_11A;
++
++      return mode;
++}
++
+ /* Macros to print MAC address used in 802.11 headers */
+ #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -287,7 +287,7 @@ ieee80211_node_set_chan(struct ieee80211
+               ni->ni_rates = ic->ic_sup_xr_rates;
+       else
+ #endif
+-      ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(chan)];
++      ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2ratemode(chan, -1)];
+ }
+ static __inline void
+@@ -387,6 +387,8 @@ ieee80211_create_ibss(struct ieee80211va
+       ic->ic_bsschan = chan;
+       ieee80211_node_set_chan(ic, ni);
+       ic->ic_curmode = ieee80211_chan2mode(chan);
++      ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2ratemode(chan, -1)];
++
+       spin_lock_irqsave(&channel_lock, flags);
+       ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
+       spin_unlock_irqrestore(&channel_lock, flags);
+@@ -394,14 +396,8 @@ ieee80211_create_ibss(struct ieee80211va
+       /* Update country ie information */
+       ieee80211_build_countryie(ic);
+-      if (IEEE80211_IS_CHAN_HALF(chan)) {
+-              ni->ni_rates = ic->ic_sup_half_rates;
+-      } else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
+-              ni->ni_rates = ic->ic_sup_quarter_rates;
+-      }
+-
+-      if ((vap->iv_flags & IEEE80211_F_PUREG) &&
+-              IEEE80211_IS_CHAN_ANYG(chan)) {
++      if ((ieee80211_chan2ratemode(chan, -1) != IEEE80211_MODE_11A) &&
++              IEEE80211_IS_CHAN_ANYG(chan) && (vap->iv_flags & IEEE80211_F_PUREG)) {
+               ieee80211_setpuregbasicrates(&ni->ni_rates);
+       }
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -490,12 +490,7 @@ check_rate(struct ieee80211vap *vap, con
+       okrate = badrate = fixedrate = 0;
+-      if (IEEE80211_IS_CHAN_HALF(se->se_chan))
+-              srs = &ic->ic_sup_half_rates;
+-      else if (IEEE80211_IS_CHAN_QUARTER(se->se_chan))
+-              srs = &ic->ic_sup_quarter_rates;
+-      else
+-              srs = &ic->ic_sup_rates[ieee80211_chan2mode(se->se_chan)];
++      srs = &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, -1)];
+       nrs = se->se_rates[1];
+       rs = se->se_rates + 2;
+       fixedrate = IEEE80211_FIXED_RATE_NONE;
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -1676,8 +1676,8 @@ ieee80211_send_probereq(struct ieee80211
+       frm = ieee80211_add_ssid(frm, ssid, ssidlen);
+       mode = ieee80211_chan2mode(ic->ic_curchan);
+-      frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]);
+-      frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]);
++      frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, mode)]);
++      frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, mode)]);
+       if (optie != NULL) {
+               memcpy(frm, optie, optielen);
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -404,7 +404,7 @@ ieee80211_fix_rate(struct ieee80211_node
+       error = 0;
+       okrate = badrate = fixedrate = 0;
+-      srs = &ic->ic_sup_rates[ieee80211_chan2mode(ni->ni_chan)];
++      srs = &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, -1)];
+       nrs = &ni->ni_rates;
+       fixedrate = IEEE80211_FIXED_RATE_NONE;
+       for (i = 0; i < nrs->rs_nrates;) {
+@@ -1407,6 +1407,7 @@ ieee80211_new_state(struct ieee80211vap
+       IEEE80211_VAPS_UNLOCK_IRQ(ic);
+       return rc;
+ }
++EXPORT_SYMBOL(ieee80211_new_state);
+ static int
+ __ieee80211_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -195,31 +195,7 @@ calc_usecs_unicast_packet(struct ath_sof
+                       return 0;
+               }
+-              /* XXX: Getting MAC/PHY level timings should be fixed for turbo
+-               * rates, and there is probably a way to get this from the
+-               * HAL... */
+-              switch (rt->info[rix].phy) {
+-              case IEEE80211_T_OFDM:
+-#if 0
+-                      t_slot = 9;
+-                      t_sifs = 16;
+-                      t_difs = 28;
+-                      /* fall through */
+-#endif
+-              case IEEE80211_T_TURBO:
+-                      t_slot = 9;
+-                      t_sifs = 8;
+-                      t_difs = 28;
+-                      break;
+-              case IEEE80211_T_DS:
+-                      /* Fall through to default */
+-              default:
+-                      /* pg. 205 ieee.802.11.pdf */
+-                      t_slot = 20;
+-                      t_difs = 50;
+-                      t_sifs = 10;
+-              }
+-
++              ath_get_timings(sc, &t_slot, &t_sifs, &t_difs);
+               if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+               (rt->info[rix].phy == IEEE80211_T_OFDM)) {
+                       if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -172,26 +172,7 @@ calc_usecs_unicast_packet(struct ath_sof
+        * rates, and there is probably a way to get this from the
+        * hal...
+        */
+-      switch (rt->info[rix].phy) {
+-      case IEEE80211_T_OFDM:
+-              t_slot = 9;
+-              t_sifs = 16;
+-              t_difs = 28;
+-              /* fall through */
+-      case IEEE80211_T_TURBO:
+-              t_slot = 9;
+-              t_sifs = 8;
+-              t_difs = 28;
+-              break;
+-      case IEEE80211_T_DS:
+-              /* fall through to default */
+-      default:
+-              /* pg 205 ieee.802.11.pdf */
+-              t_slot = 20;
+-              t_difs = 50;
+-              t_sifs = 10;
+-      }
+-
++      ath_get_timings(sc, &t_slot, &t_sifs, &t_difs);
+       rts = cts = 0;
+       if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2142,7 +2142,7 @@ ieee80211_ioctl_setmode(struct net_devic
+               vap->iv_des_mode = mode;
+               if (IS_UP_AUTO(vap))
+-                      ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
++                      ieee80211_init(vap->iv_dev, 0);
+               retv = 0;
+       }
+@@ -4090,46 +4090,60 @@ ieee80211_ioctl_getchanlist(struct net_d
+       return 0;
+ }
++static int alreadyListed(struct ieee80211req_chaninfo *chans, u_int16_t mhz)
++{
++      int i;
++      for (i = 0; i < chans->ic_nchans; i++) {
++              if (chans->ic_chans[i].ic_freq == mhz)
++                      return 1;
++      }
++      return 0;
++}
++
+ static int
+ ieee80211_ioctl_getchaninfo(struct net_device *dev,
+-      struct iw_request_info *info, void *w, char *extra)
++                          struct iw_request_info *info, void *w, char *extra)
+ {
+       struct ieee80211vap *vap = dev->priv;
+       struct ieee80211com *ic = vap->iv_ic;
+-      struct ieee80211req_chaninfo chans;
++      struct ieee80211req_chaninfo *chans =
++          (struct ieee80211req_chaninfo *)extra;
++
+       u_int8_t reported[IEEE80211_CHAN_BYTES];        /* XXX stack usage? */
+       int i;
+-      memset(&chans, 0, sizeof(chans));
+-      memset(&reported, 0, sizeof(reported));
++      memset(chans, 0, sizeof(*chans));
++      memset(reported, 0, sizeof(reported));
+       for (i = 0; i < ic->ic_nchans; i++) {
+               const struct ieee80211_channel *c = &ic->ic_channels[i];
+               const struct ieee80211_channel *c1 = c;
+-              if (isclr(reported, c->ic_ieee)) {
++              if (!alreadyListed(chans, c->ic_freq)) {
+                       setbit(reported, c->ic_ieee);
+-                      /* pick turbo channel over non-turbo channel, and
+-                       * 11g channel over 11b channel */
+                       if (IEEE80211_IS_CHAN_A(c))
+-                              c1 = findchannel(ic, c->ic_ieee, IEEE80211_MODE_TURBO_A);
++                              c1 = findchannel(ic, c->ic_freq,
++                                               IEEE80211_MODE_TURBO_A);
+                       if (IEEE80211_IS_CHAN_ANYG(c))
+-                              c1 = findchannel(ic, c->ic_ieee, IEEE80211_MODE_TURBO_G);
++                              c1 = findchannel(ic, c->ic_freq,
++                                               IEEE80211_MODE_TURBO_G);
+                       else if (IEEE80211_IS_CHAN_B(c)) {
+-                              c1 = findchannel(ic, c->ic_ieee, IEEE80211_MODE_TURBO_G);
++                              c1 = findchannel(ic, c->ic_freq,
++                                               IEEE80211_MODE_TURBO_G);
+                               if (!c1)
+-                                      c1 = findchannel(ic, c->ic_ieee, IEEE80211_MODE_11G);
++                                      c1 = findchannel(ic, c->ic_freq,
++                                                       IEEE80211_MODE_11G);
+                       }
+                       if (c1)
+                               c = c1;
+-                      /* Copy the entire structure, whereas it used to just copy a few fields */
+-                      memcpy(&chans.ic_chans[chans.ic_nchans], c, sizeof(struct ieee80211_channel));
+-                      if (++chans.ic_nchans >= IEEE80211_CHAN_MAX)
++                      chans->ic_chans[chans->ic_nchans].ic_ieee = c->ic_ieee;
++                      chans->ic_chans[chans->ic_nchans].ic_freq = c->ic_freq;
++                      chans->ic_chans[chans->ic_nchans].ic_flags = c->ic_flags;
++                      if (++chans->ic_nchans >= IEEE80211_CHAN_MAX)
+                               break;
+               }
+       }
+-      memcpy(extra, &chans, sizeof(struct ieee80211req_chaninfo));
+       return 0;
+ }
+--- a/net80211/ieee80211_scan_ap.c
++++ b/net80211/ieee80211_scan_ap.c
+@@ -512,12 +512,13 @@ pick_channel(struct ieee80211_scan_state
+       int ss_last = ss->ss_last;
+       struct ieee80211_channel *best;
+       struct ap_state *as = ss->ss_priv;
+-      struct channel chans[ss_last]; /* actually ss_last-1 is required */
++      struct channel *chans; /* actually ss_last-1 is required */
+       struct channel *c = NULL;
+       struct pc_params params = { vap, ss, flags };
+       int benefit = 0;
+       int sta_assoc = 0;
++      chans = (struct channel *)kmalloc(ss_last*sizeof(struct channel),GFP_ATOMIC);
+       for (i = 0; i < ss_last; i++) {
+               chans[i].chan = ss->ss_chans[i];
+               chans[i].orig = i;
+@@ -571,6 +572,7 @@ pick_channel(struct ieee80211_scan_state
+                               "%s: best: channel %u rssi %d\n",
+                               __func__, i, as->as_maxrssi[i]);
+       }
++      kfree(chans);
+       return best;
+ }
+@@ -609,6 +611,7 @@ ap_end(struct ieee80211_scan_state *ss,
+               res = 1; /* Do NOT restart scan */
+       } else {
+               struct ieee80211_scan_entry se;
++              int i;
+               /* XXX: notify all VAPs? */
+               /* if this is a dynamic turbo frequency , start with normal 
+                * mode first */
+@@ -623,6 +626,11 @@ ap_end(struct ieee80211_scan_state *ss,
+                               return 0;
+                       }
+               }
++              for (i = (bestchan - &ic->ic_channels[0])/sizeof(*bestchan) + 1; i < ic->ic_nchans; i++) {
++                      if ((ic->ic_channels[i].ic_freq == bestchan->ic_freq) &&
++                              IEEE80211_IS_CHAN_ANYG(&ic->ic_channels[i]))
++                              bestchan = &ic->ic_channels[i];
++              }
+               memset(&se, 0, sizeof(se));
+               se.se_chan = bestchan;
+--- a/tools/wlanconfig.c
++++ b/tools/wlanconfig.c
+@@ -737,7 +737,7 @@ list_channels(const char *ifname, int al
+       if (get80211priv(ifname, IEEE80211_IOCTL_GETCHANINFO, &chans, sizeof(chans)) < 0)
+               errx(1, "unable to get channel information");
+       if (!allchans) {
+-              uint8_t active[32];
++              uint8_t active[IEEE80211_CHAN_BYTES];
+               if (get80211priv(ifname, IEEE80211_IOCTL_GETCHANLIST, &active, sizeof(active)) < 0)
+                       errx(1, "unable to get active channel list");
+--- a/net80211/ieee80211_scan.c
++++ b/net80211/ieee80211_scan.c
+@@ -1044,6 +1044,7 @@ ieee80211_scan_assoc_fail(struct ieee802
+               ss->ss_ops->scan_assoc_fail(ss, mac, reason);
+       }
+ }
++EXPORT_SYMBOL(ieee80211_scan_flush);
+ /*
+  * Iterate over the contents of the scan cache.
+--- a/ath/if_ath_hal_wrappers.h
++++ b/ath/if_ath_hal_wrappers.h
+@@ -111,6 +111,11 @@ static inline HAL_BOOL ath_hal_getregdom
+       return (ath_hal_getcapability(ah, HAL_CAP_REG_DMN, 0, destination) == HAL_OK);
+ }
++static inline HAL_BOOL ath_hal_setregdomain(struct ath_hal *ah, u_int32_t v)
++{
++      return (ath_hal_setcapability(ah, HAL_CAP_REG_DMN, 0, v, NULL));
++}
++
+ static inline HAL_BOOL ath_hal_gettkipmic(struct ath_hal *ah)
+ {
+       return (ath_hal_getcapability(ah, HAL_CAP_TKIP_MIC, 1, NULL) == HAL_OK);
diff --git a/net/madwifi/patches/422-confchange_reset.patch b/net/madwifi/patches/422-confchange_reset.patch
new file mode 100644 (file)
index 0000000..33040ae
--- /dev/null
@@ -0,0 +1,31 @@
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -70,7 +70,8 @@
+       (((_dev)->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP))
+ #define       IS_UP_AUTO(_vap) \
+       (IS_UP((_vap)->iv_dev) && \
+-       (_vap)->iv_ic->ic_roaming == IEEE80211_ROAMING_AUTO)
++       (((_vap)->iv_opmode == IEEE80211_M_HOSTAP) || \
++       (_vap)->iv_ic->ic_roaming == IEEE80211_ROAMING_AUTO))
+ #define       RESCAN  1
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+@@ -283,7 +284,7 @@ ieee80211_ioctl_siwencode(struct net_dev
+                               vap->iv_flags &= ~IEEE80211_F_DROPUNENC;
+               }
+       }
+-      if ((error == 0) && IS_UP(vap->iv_dev)) {
++      if ((error == 0) && IS_UP_AUTO(vap) && wepchange) {
+               /*
+                * Device is up and running; we must kick it to
+                * effect the change.  If we're enabling/disabling
+@@ -291,8 +292,7 @@ ieee80211_ioctl_siwencode(struct net_dev
+                * so the 802.11 state machine is reset.  Otherwise
+                * the key state should have been updated above.
+                */
+-              if (wepchange && IS_UP_AUTO(vap))
+-                      ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
++              ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
+       }
+ #ifdef ATH_SUPERG_XR
+       /* set the same params on the xr vap device if exists */
diff --git a/net/madwifi/patches/423-phyerr_handling.patch b/net/madwifi/patches/423-phyerr_handling.patch
new file mode 100644 (file)
index 0000000..7f3cbaf
--- /dev/null
@@ -0,0 +1,28 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -4391,13 +4391,12 @@ ath_key_update_end(struct ieee80211vap *
+ static u_int32_t
+ ath_calcrxfilter(struct ath_softc *sc)
+ {
+-#define       RX_FILTER_PRESERVE      (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR)
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct net_device *dev = ic->ic_dev;
+       struct ath_hal *ah = sc->sc_ah;
+       u_int32_t rfilt;
+-      rfilt = (ath_hal_getrxfilter(ah) & RX_FILTER_PRESERVE) |
++      rfilt = ath_hal_getrxfilter(ah) |
+                HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST |
+                HAL_RX_FILTER_MCAST;
+       if (ic->ic_opmode != IEEE80211_M_STA)
+@@ -4416,9 +4415,8 @@ ath_calcrxfilter(struct ath_softc *sc)
+       if (sc->sc_hasintmit && !sc->sc_needmib && ath_hal_getintmit(ah, NULL))
+               rfilt |= HAL_RX_FILTER_PHYERR;
+       if (sc->sc_curchan.privFlags & CHANNEL_DFS)
+-              rfilt |= (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR);
++              rfilt |= HAL_RX_FILTER_PHYRADAR;
+       return rfilt;
+-#undef RX_FILTER_PRESERVE
+ }
+ /*
diff --git a/net/madwifi/patches/424-timing.patch b/net/madwifi/patches/424-timing.patch
new file mode 100644 (file)
index 0000000..8369db6
--- /dev/null
@@ -0,0 +1,764 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -382,6 +382,7 @@ static u_int32_t ath_set_clamped_maxtxpo
+ static void ath_poll_disable(struct net_device *dev);
+ static void ath_poll_enable(struct net_device *dev);
+ static void ath_fetch_idle_time(struct ath_softc *sc);
++static void ath_set_timing(struct ath_softc *sc);
+ /* calibrate every 30 secs in steady state but check every second at first. */
+ static int ath_calinterval = ATH_SHORT_CALINTERVAL;
+@@ -1185,6 +1186,7 @@ ath_attach(u_int16_t devid, struct net_d
+       sc->sc_intmit = -1;
+       sc->sc_noise_immunity = -1;
+       sc->sc_ofdm_weak_det = -1;
++      sc->sc_coverage = 7; /* 2100 meters */
+       return 0;
+ bad3:
+@@ -2673,6 +2675,7 @@ ath_init(struct net_device *dev)
+        */
+       ath_chan_change(sc, ic->ic_curchan);
+       ath_set_ack_bitrate(sc, sc->sc_ackrate);
++      ath_set_timing(sc);
+       dev->flags |= IFF_RUNNING;              /* we are ready to go */
+       ieee80211_start_running(ic);            /* start all VAPs */
+ #ifdef ATH_TX99_DIAG
+@@ -4484,17 +4487,52 @@ ath_mode_init(struct net_device *dev)
+  * Set the slot time based on the current setting.
+  */
+ static void
+-ath_settiming(struct ath_softc *sc)
++ath_set_timing(struct ath_softc *sc)
+ {
++      struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
+-      u_int offset = getTimingOffset(sc);
++      struct ath_timings *t = &sc->sc_timings;
++      u_int offset = 9;
++
++      t->sifs = 16;
++      if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
++              offset = 20;
++              if (ic->ic_flags & IEEE80211_F_SHSLOT)
++                      offset = 9;
++      } else if (IEEE80211_IS_CHAN_A(ic->ic_curchan)) {
++              offset = 9;
++      }
++
++      if (IEEE80211_IS_CHAN_TURBO(ic->ic_curchan)) {
++              offset = 6;
++              t->sifs = 8;
++      } else if (IEEE80211_IS_CHAN_HALF(ic->ic_curchan)) {
++              offset = 13;
++              t->sifs = 32;
++      } else if (IEEE80211_IS_CHAN_QUARTER(ic->ic_curchan)) {
++              offset = 21;
++              t->sifs = 64;
++      }
++
++      t->slot = offset + sc->sc_coverage;
++      t->ack = t->slot * 2 + 3;
++      t->cts = t->slot * 2 + 3;
+       if (sc->sc_slottimeconf > 0)
+-              ath_hal_setslottime(ah, offset + sc->sc_slottimeconf);
++              t->slot = sc->sc_slottimeconf;
+       if (sc->sc_acktimeconf > 0)
+-              ath_hal_setacktimeout(ah, 2 * offset + sc->sc_acktimeconf);
++              t->ack = sc->sc_acktimeconf;
+       if (sc->sc_ctstimeconf > 0)
+-              ath_hal_setctstimeout(ah, 2 * offset + sc->sc_ctstimeconf);
++              t->cts = sc->sc_ctstimeconf;
++
++      t->difs = 2 * t->sifs + t->slot;
++      t->eifs = t->sifs + t->difs + 3;
++
++      ath_hal_setslottime(ah, t->slot);
++      ath_hal_setacktimeout(ah, t->ack);
++      ath_hal_setctstimeout(ah, t->cts);
++      ath_hal_seteifstime(ah, t->eifs);
++
+       sc->sc_updateslot = OK;
+ }
+@@ -4516,7 +4554,7 @@ ath_updateslot(struct net_device *dev)
+       if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+               sc->sc_updateslot = UPDATE;
+       else if (dev->flags & IFF_RUNNING)
+-              ath_settiming(sc);
++              ath_set_timing(sc);
+ }
+ #ifdef ATH_SUPERG_DYNTURBO
+@@ -5360,7 +5398,7 @@ ath_beacon_send(struct ath_softc *sc, in
+               sc->sc_updateslot = COMMIT;     /* commit next beacon */
+               sc->sc_slotupdate = slot;
+       } else if ((sc->sc_updateslot == COMMIT) && (sc->sc_slotupdate == slot))
+-              ath_settiming(sc);              /* commit change to hardware */
++              ath_set_timing(sc);             /* commit change to hardware */
+       if (bfaddr != 0) {
+               /*
+@@ -9433,7 +9471,8 @@ ath_set_coverageclass(struct ieee80211co
+ {
+       struct ath_softc *sc = ic->ic_dev->priv;
+-      ath_hal_setcoverageclass(sc->sc_ah, ic->ic_coverageclass, 0);
++      sc->sc_coverage = ic->ic_coverageclass * 3;
++      ath_set_timing(sc);
+       return;
+ }
+@@ -10956,6 +10995,7 @@ enum {
+       ATH_OFDM_WEAK_DET       = 29,
+       ATH_CHANBW              = 30,
+       ATH_OUTDOOR             = 31,
++      ATH_DISTANCE    = 32,
+ };
+ /*
+@@ -11168,21 +11208,31 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+                                       sc->sc_slottimeconf = val;
+                               else
+                                       sc->sc_slottimeconf = 0;
+-                              ath_settiming(sc);
++                              ath_set_timing(sc);
+                               break;
+                       case ATH_ACKTIMEOUT:
+                               if (val > 0)
+                                       sc->sc_acktimeconf = val;
+                               else
+                                       sc->sc_acktimeconf = 0;
+-                              ath_settiming(sc);
++                              ath_set_timing(sc);
+                               break;
+                       case ATH_CTSTIMEOUT:
+                               if (val > 0)
+                                       sc->sc_ctstimeconf = val;
+                               else
+                                       sc->sc_ctstimeconf = 0;
+-                              ath_settiming(sc);
++                              ath_set_timing(sc);
++                              break;
++                      case ATH_DISTANCE:
++                              if (val > 0) {
++                                      sc->sc_coverage = ((val - 1) / 300) + 1;
++                                      ic->ic_coverageclass = ((sc->sc_coverage - 1) / 3) + 1;
++                              } else {
++                                      sc->sc_coverage = 0;
++                                      ic->ic_coverageclass = 0;
++                              }
++                              ath_set_timing(sc);
+                               break;
+                       case ATH_SOFTLED:
+                               if (val != sc->sc_softled) {
+@@ -11338,6 +11388,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+               case ATH_CHANBW:
+                       val = sc->sc_chanbw ?: 20;
+                       break;
++              case ATH_DISTANCE:
++                      val = sc->sc_coverage * 300;
++                      break;
+               case ATH_SLOTTIME:
+                       val = ath_hal_getslottime(ah);
+                       break;
+@@ -11459,6 +11512,12 @@ static const ctl_table ath_sysctl_templa
+         .extra2       = (void *)ATH_CTSTIMEOUT,
+       },
+       { .ctl_name     = CTL_AUTO,
++        .procname     = "distance",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_halparam,
++        .extra2       = (void *)ATH_DISTANCE,
++      },
++      { .ctl_name     = CTL_AUTO,
+         .procname     = "softled",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+--- a/ath/if_ath_hal.h
++++ b/ath/if_ath_hal.h
+@@ -284,6 +284,17 @@ static inline u_int ath_hal_getslottime(
+       return ret;
+ }
++static inline u_int ath_hal_geteifstime(struct ath_hal *ah)
++{
++      u_int ret;
++      ATH_HAL_LOCK_IRQ(ah->ah_sc);
++      ath_hal_set_function(__func__);
++      ret = ah->ah_getEifsTime(ah);
++      ath_hal_set_function(NULL);
++      ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
++      return ret;
++}
++
+ static inline void ath_hal_beaconinit(struct ath_hal *ah, u_int32_t nexttbtt,
+                                     u_int32_t intval)
+ {
+@@ -839,6 +850,17 @@ static inline HAL_BOOL ath_hal_setslotti
+       ath_hal_set_function(NULL);
+       ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
+       return ret;
++}
++
++static inline HAL_BOOL ath_hal_seteifstime(struct ath_hal *ah, u_int a1)
++{
++      HAL_BOOL ret;
++      ATH_HAL_LOCK_IRQ(ah->ah_sc);
++      ath_hal_set_function(__func__);
++      ret = ah->ah_setEifsTime(ah, a1);
++      ath_hal_set_function(NULL);
++      ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
++      return ret;
+ }
+ static inline void ath_hal_setledstate(struct ath_hal *ah, HAL_LED_STATE a1)
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -613,6 +613,15 @@ struct ath_rp {
+       int       rp_analyzed;
+ };
++struct ath_timings {
++      u_int   slot;
++      u_int   ack;
++      u_int   cts;
++      u_int   sifs;
++      u_int   difs;
++      u_int   eifs;
++};
++
+ struct ath_softc {
+       struct ieee80211com sc_ic;              /* NB: must be first */
+       struct net_device *sc_dev;
+@@ -839,6 +848,8 @@ struct ath_softc {
+                                                * detected radars */
+       u_int32_t sc_nexttbtt;
+       u_int64_t sc_last_tsf;
++      u_int sc_coverage;
++      struct ath_timings sc_timings;
+ };
+ typedef void (*ath_callback) (struct ath_softc *);
+@@ -946,49 +957,76 @@ int ar_device(int devid);
+         DEV_NAME(_v->iv_ic->ic_dev))
+ void ath_radar_detected(struct ath_softc *sc, const char* message);
+-static inline u_int getTimingOffset(struct ath_softc *sc)
+-{
+-      struct ieee80211com *ic = &sc->sc_ic;
+-      u_int usec = 9;
+-      if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
+-              usec = 20;
+-              if (ic->ic_flags & IEEE80211_F_SHSLOT)
+-                      usec = 9;
+-      } else if (IEEE80211_IS_CHAN_A(ic->ic_curchan))
+-              usec = 9;
+-
+-      if (IEEE80211_IS_CHAN_TURBO(ic->ic_curchan))
+-              usec = 6;
+-
+-      if (IEEE80211_IS_CHAN_HALF(ic->ic_curchan))
+-              usec = 13;
+-      else if (IEEE80211_IS_CHAN_QUARTER(ic->ic_curchan))
+-              usec = 21;
+-      return usec;
+-}
+-static inline void ath_get_timings(struct ath_softc *sc, u_int *t_slot, u_int *t_sifs, u_int *t_difs)
+-{
+-      struct ieee80211_channel *c = sc->sc_ic.ic_curchan;
++#ifndef MIN
++#define MIN(a,b)        ((a) < (b) ? (a) : (b))
++#endif
++#ifndef MAX
++#define MAX(a,b)        ((a) > (b) ? (a) : (b))
++#endif
+-      *t_slot = getTimingOffset(sc) + sc->sc_slottimeconf;
+-      if (IEEE80211_IS_CHAN_HALF(c)) {
+-              *t_sifs = 32;
+-              *t_difs = 56;
+-      } else if (IEEE80211_IS_CHAN_QUARTER(c)) {
+-              *t_sifs = 64;
+-              *t_difs = 112;
+-      } else if (IEEE80211_IS_CHAN_TURBO(c)) {
+-              *t_sifs = 8;
+-              *t_difs = 28;
+-      } else {
+-              *t_sifs = 16;
+-              *t_difs = 28;
+-      }
++/* Calculate the transmit duration of a frame. */
++static inline unsigned
++calc_usecs_unicast_packet(struct ath_softc *sc, int length,
++              int rix, int short_retries, int long_retries)
++{
++              const HAL_RATE_TABLE *rt = sc->sc_currates;
++              struct ieee80211com *ic = &sc->sc_ic;
++              struct ath_timings *t = &sc->sc_timings;
++              unsigned int x = 0, tt = 0;
++              unsigned int cix = rt->info[rix].controlRate;
++              int rts = 0, cts = 0;
++              int cw = ATH_DEFAULT_CWMIN;
++
++              KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
++
++              if (!rt->info[rix].rateKbps) {
++                      printk(KERN_WARNING "rix %d (%d) bad ratekbps %d mode %u\n",
++                             rix, rt->info[rix].dot11Rate,
++                             rt->info[rix].rateKbps,
++                             sc->sc_curmode);
++                      return 0;
++              }
++
++              if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
++                      (rt->info[rix].phy == IEEE80211_T_OFDM)) {
++
++                      if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
++                              rts = 1;
++                      else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
++                              cts = 1;
++
++                      cix = rt->info[sc->sc_protrix].controlRate;
++              }
++
++              if ((rts || cts) && rt->info[cix].rateKbps) {
++                      int ctsrate = rt->info[cix].rateCode;
++                      int ctsduration = 0;
++
++                      ctsrate |= rt->info[cix].shortPreamble;
++                      if (rts)        /* SIFS + CTS */
++                              ctsduration += rt->info[cix].spAckDuration;
++
++                      ctsduration += ath_hal_computetxtime(sc->sc_ah,
++                                                           rt, length, rix, AH_TRUE);
++
++                      if (cts)        /* SIFS + ACK */
++                              ctsduration += rt->info[cix].spAckDuration;
++
++                      tt += (short_retries + 1) * ctsduration;
++              }
++              tt += t->difs;
++              tt += (long_retries + 1) * (t->sifs + rt->info[rix].spAckDuration);
++              tt += (long_retries + 1) * ath_hal_computetxtime(sc->sc_ah, rt, length,
++                                                      rix, AH_TRUE);
++              for (x = 0; x <= short_retries + long_retries; x++) {
++                      cw = MIN(ATH_DEFAULT_CWMAX, (cw + 1) * 2);
++                      tt += (t->slot * cw / 2);
++              }
++              return tt;
+ }
+-
+ struct ath_hw_detect {
+       const char *vendor_name;
+       const char *card_name;
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -170,85 +170,6 @@ rate_to_ndx(struct minstrel_node *sn, in
+               return -1;
+ }
+-/* Calculate the transmit duration of a frame. */
+-static unsigned
+-calc_usecs_unicast_packet(struct ath_softc *sc, int length,
+-              int rix, int short_retries, int long_retries)
+-{
+-              const HAL_RATE_TABLE *rt = sc->sc_currates;
+-              struct ieee80211com *ic = &sc->sc_ic;
+-              unsigned t_slot = 20;
+-              unsigned t_difs = 50;
+-              unsigned t_sifs = 10;
+-              unsigned int x = 0, tt = 0;
+-              unsigned int cix = rt->info[rix].controlRate;
+-              int rts = 0, cts = 0;
+-              int cw = ATH_DEFAULT_CWMIN;
+-
+-              KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+-
+-              if (!rt->info[rix].rateKbps) {
+-                      printk(KERN_WARNING "rix %d (%d) bad ratekbps %d mode %u\n",
+-                             rix, rt->info[rix].dot11Rate,
+-                             rt->info[rix].rateKbps,
+-                             sc->sc_curmode);
+-                      return 0;
+-              }
+-
+-              ath_get_timings(sc, &t_slot, &t_sifs, &t_difs);
+-              if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+-              (rt->info[rix].phy == IEEE80211_T_OFDM)) {
+-                      if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
+-                              rts = 1;
+-                      else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
+-                              cts = 1;
+-
+-                      cix = rt->info[sc->sc_protrix].controlRate;
+-              }
+-
+-#if 0
+-              if (length > ic->ic_rtsthreshold)
+-                      rts = 1;
+-#endif
+-
+-              if (rts || cts) {
+-                      int ctsrate = rt->info[cix].rateCode;
+-                      int ctsduration = 0;
+-
+-                      if (!rt->info[cix].rateKbps) {
+-#if 0
+-                              printk(KERN_WARNING "cix %d (%d) bad ratekbps %d mode %u\n",
+-                                     cix, rt->info[cix].dot11Rate,
+-                                     rt->info[cix].rateKbps,
+-                                     sc->sc_curmode);
+-#endif
+-                              return 0;
+-                      }
+-
+-
+-                      ctsrate |= rt->info[cix].shortPreamble;
+-                      if (rts)        /* SIFS + CTS */
+-                              ctsduration += rt->info[cix].spAckDuration;
+-
+-                      ctsduration += ath_hal_computetxtime(sc->sc_ah,
+-                                                           rt, length, rix, AH_TRUE);
+-
+-                      if (cts)        /* SIFS + ACK */
+-                              ctsduration += rt->info[cix].spAckDuration;
+-
+-                      tt += (short_retries + 1) * ctsduration;
+-              }
+-              tt += t_difs;
+-              tt += (long_retries + 1) * (t_sifs + rt->info[rix].spAckDuration);
+-              tt += (long_retries + 1) * ath_hal_computetxtime(sc->sc_ah, rt, length,
+-                                                      rix, AH_TRUE);
+-              for (x = 0; x <= short_retries + long_retries; x++) {
+-                      cw = MIN(ATH_DEFAULT_CWMAX, (cw + 1) * 2);
+-                      tt += (t_slot * cw / 2);
+-              }
+-              return tt;
+-}
+-
+ static void
+ ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
+ {
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -137,92 +137,6 @@ rate_to_ndx(struct sample_node *sn, int
+       return -1;
+ }
+-/*
+- * Calculate the transmit duration of a frame.
+- */
+-static unsigned
+-calc_usecs_unicast_packet(struct ath_softc *sc, int length,
+-      int rix, int short_retries, int long_retries)
+-{
+-      const HAL_RATE_TABLE *rt = sc->sc_currates;
+-      int rts, cts;
+-
+-      unsigned t_slot;
+-      unsigned t_difs;
+-      unsigned t_sifs;
+-      struct ieee80211com *ic = &sc->sc_ic;
+-      unsigned int tt = 0;
+-      unsigned int x;
+-      unsigned int cw = ATH_DEFAULT_CWMIN;
+-      unsigned int cix = rt->info[rix].controlRate;
+-      KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+-
+-      if (!rt->info[rix].rateKbps) {
+-              printk(KERN_WARNING "rix %u (%u) bad ratekbps %u mode %u\n",
+-                     rix, rt->info[rix].dot11Rate,
+-                     rt->info[rix].rateKbps,
+-                     sc->sc_curmode);
+-
+-              return 0;
+-      }
+-
+-      cix = rt->info[rix].controlRate;
+-      /* 
+-       * XXX getting mac/phy level timings should be fixed for turbo
+-       * rates, and there is probably a way to get this from the
+-       * hal...
+-       */
+-      ath_get_timings(sc, &t_slot, &t_sifs, &t_difs);
+-      rts = cts = 0;
+-
+-      if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+-          rt->info[rix].phy == IEEE80211_T_OFDM) {
+-              if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
+-                      rts = 1;
+-              else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
+-                      cts = 1;
+-
+-              cix = rt->info[sc->sc_protrix].controlRate;
+-      }
+-
+-      if (0 /*length > ic->ic_rtsthreshold */)
+-              rts = 1;
+-
+-      if (rts || cts) {
+-              int ctsrate;
+-              int ctsduration = 0;
+-
+-              if (!rt->info[cix].rateKbps) {
+-                      printk(KERN_WARNING "cix %u (%u) bad ratekbps %u mode %u\n",
+-                             cix, rt->info[cix].dot11Rate,
+-                             rt->info[cix].rateKbps,
+-                             sc->sc_curmode);
+-                      return 0;
+-              }
+-
+-
+-              ctsrate = rt->info[cix].rateCode | rt->info[cix].shortPreamble;
+-              if (rts)                /* SIFS + CTS */
+-                      ctsduration += rt->info[cix].spAckDuration;
+-
+-              ctsduration += ath_hal_computetxtime(sc->sc_ah,
+-                                                   rt, length, rix, AH_TRUE);
+-
+-              if (cts)        /* SIFS + ACK */
+-                      ctsduration += rt->info[cix].spAckDuration;
+-
+-              tt += (short_retries + 1) * ctsduration;
+-      }
+-      tt += t_difs;
+-      tt += (long_retries+1)*(t_sifs + rt->info[rix].spAckDuration);
+-      tt += (long_retries+1)*ath_hal_computetxtime(sc->sc_ah, rt, length,
+-                                              rix, AH_TRUE);
+-      for (x = 0; x <= short_retries + long_retries; x++) {
+-              cw = MIN(ATH_DEFAULT_CWMAX, (cw + 1) * 2);
+-              tt += (t_slot * cw / 2);
+-      }
+-      return tt;
+-}
+ static void
+ ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2745,6 +2745,7 @@ ieee80211_ioctl_setparam(struct net_devi
+       case IEEE80211_PARAM_COVERAGE_CLASS:
+               if (value <= IEEE80211_COVERAGE_CLASS_MAX) {
+                       ic->ic_coverageclass = value;
++                      ic->ic_set_coverageclass(ic);
+                       if (IS_UP_AUTO(vap))
+                               ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
+                       retv = 0;
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -94,7 +94,7 @@
+ #define IEEE80211_BGSCAN_TRIGGER_INTVL 20 /* min trigger interval for thresh based bgscan (secs) */
+-#define IEEE80211_COVERAGE_CLASS_MAX  31      /* max coverage class */
++#define IEEE80211_COVERAGE_CLASS_MAX  255     /* max coverage class */
+ #define IEEE80211_REGCLASSIDS_MAX     10      /* max regclass id list */
+ #define       IEEE80211_PS_SLEEP      0x1             /* STA is in power saving mode */
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -50,7 +50,7 @@ all: compile
+ DEBUG = -DAR_DEBUG
+-ALLPROGS=     athstats 80211stats athkey athchans athctrl \
++ALLPROGS=     athstats 80211stats athkey athchans \
+       $(if $(DEBUG),athdebug 80211debug) wlanconfig ath_info
+ OBJS= $(patsubst %,%.o,$(ALLPROGS))
+--- a/tools/athctrl.c
++++ /dev/null
+@@ -1,133 +0,0 @@
+-/*-
+- * Copyright (c) 2002-2004 Gunter Burchardt, Local-Web AG
+- * All rights reserved.
+- *
+- * Redistribution and use in source and binary forms, with or without
+- * modification, are permitted provided that the following conditions
+- * are met:
+- * 1. Redistributions of source code must retain the above copyright
+- *    notice, this list of conditions and the following disclaimer,
+- *    without modification.
+- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+- *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+- *    redistribution must be conditioned upon including a substantially
+- *    similar Disclaimer requirement for further binary redistribution.
+- * 3. Neither the names of the above-listed copyright holders nor the names
+- *    of any contributors may be used to endorse or promote products derived
+- *    from this software without specific prior written permission.
+- *
+- * Alternatively, this software may be distributed under the terms of the
+- * GNU General Public License ("GPL") version 2 as published by the Free
+- * Software Foundation.
+- *
+- * NO WARRANTY
+- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+- * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+- * THE POSSIBILITY OF SUCH DAMAGES.
+- *
+- * $Id: athctrl.c 2394 2007-05-30 01:41:18Z mtaylor $
+- */
+-
+-/*
+- * Simple Atheros-specific tool to inspect and set atheros specific values
+- * athctrl [-i interface] [-d distance]
+- * (default interface is wifi0).  
+- */
+-#include <sys/types.h>
+-#include <sys/file.h>
+-
+-#include <getopt.h>
+-
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
+-#include <err.h>
+-
+-#include <net/if.h>
+-#include "do_multi.h"
+-
+-static int
+-setsysctrl(const char *dev, const char *control , u_long value)
+-{
+-      char buffer[256];
+-      FILE * fd;
+-
+-      snprintf(buffer, sizeof(buffer), "/proc/sys/dev/%s/%s", dev, control);
+-      fd = fopen(buffer, "w");
+-      if (fd != NULL) {
+-              fprintf(fd, "%li", value);
+-              fclose(fd);
+-      } else
+-              fprintf(stderr, "Could not open %s for writing!\n", buffer);
+-
+-      return 0;
+-}
+-
+-static void usage(void)
+-{
+-      fprintf(stderr,
+-          "Atheros driver control\n"
+-          "Copyright (c) 2002-2004 Gunter Burchardt, Local-Web AG\n"
+-          "\n"
+-          "usage: athctrl [-i interface] [-d distance]\n"
+-          "\n"
+-          "options:\n"
+-          "   -h   show this usage\n"
+-      "   -i   interface (default interface is wifi0)\n"
+-          "   -d   specify the maximum distance of a sta or the distance\n"
+-      "        of the master\n");
+-
+-      exit(1);
+-}
+-
+-int
+-CMD(athctrl)(int argc, char *argv[])
+-{
+-      char device[IFNAMSIZ + 1];
+-      int distance = -1;
+-      int c;
+-
+-      strncpy(device, "wifi0", sizeof (device));
+-
+-      for (;;) {
+-              c = getopt(argc, argv, "d:i:h");
+-              if (c < 0)
+-                      break;
+-              switch (c) {
+-              case 'h':
+-                      usage();
+-                      break;
+-              case 'd':
+-                      distance = atoi(optarg);
+-                      break;
+-              case 'i':
+-                      strncpy(device, optarg, sizeof (device));
+-                      break;
+-              default:
+-                      usage();
+-                      break;
+-              }
+-      }
+-
+-      if (distance >= 0) {
+-              int slottime = (distance / 300) + ((distance % 300) ? 1 : 0);
+-              int acktimeout = slottime * 2 + 3;
+-              int ctstimeout = slottime * 2 + 3;
+-
+-              printf("Setting distance on interface %s to %i meters\n",
+-                      device, distance);
+-              setsysctrl(device, "slottime", slottime);
+-              setsysctrl(device, "acktimeout", acktimeout);
+-              setsysctrl(device, "ctstimeout", ctstimeout);
+-      } else
+-              usage();
+-      return 0;
+-}
+--- a/tools/do_multi.c
++++ b/tools/do_multi.c
+@@ -18,8 +18,6 @@ main(int argc, char *argv[])
+       ret = a80211stats_init(argc, argv);
+     if(strcmp(progname, "athchans") == 0)
+       ret = athchans_init(argc, argv);
+-    if(strcmp(progname, "athctrl") == 0)
+-      ret =  athctrl_init(argc, argv);
+ #ifdef AR_DEBUG
+     if(strcmp(progname, "athdebug") == 0)
+       ret =  athdebug_init(argc, argv);
+--- a/tools/do_multi.h
++++ b/tools/do_multi.h
+@@ -2,7 +2,6 @@
+ int a80211debug_init(int argc, char *argv[]);
+ int a80211stats_init(int argc, char *argv[]);
+ int athchans_init(int argc, char *argv[]);
+-int athctrl_init(int argc, char *argv[]);
+ int athdebug_init(int argc, char *argv[]);
+ int athkey_init(int argc, char *argv[]);
+ int athstats_init(int argc, char *argv[]);
+--- a/ath_rate/minstrel/minstrel.h
++++ b/ath_rate/minstrel/minstrel.h
+@@ -172,14 +172,6 @@ struct minstrel_node {
+ #define       ATH_NODE_MINSTREL(an)   ((struct minstrel_node *)&an[1])
+-
+-#ifndef MIN
+-#define MIN(a,b)        ((a) < (b) ? (a) : (b))
+-#endif
+-#ifndef MAX
+-#define MAX(a,b)        ((a) > (b) ? (a) : (b))
+-#endif
+-
+ /*
+  * Definitions for pulling the rate and trie counts from
+  * a 5212 h/w descriptor. These Don't belong here; the
+--- a/ath_rate/sample/sample.h
++++ b/ath_rate/sample/sample.h
+@@ -98,14 +98,6 @@ struct sample_node {
+ };
+ #define       ATH_NODE_SAMPLE(an)     ((struct sample_node *)&an[1])
+-
+-#ifndef MIN
+-#define MIN(a,b)        ((a) < (b) ? (a) : (b))
+-#endif
+-#ifndef MAX
+-#define MAX(a,b)        ((a) > (b) ? (a) : (b))
+-#endif
+-
+ /*
+  * Definitions for pulling the rate and trie counts from
+  * a 5212 h/w descriptor. These Don't belong here; the
diff --git a/net/madwifi/patches/425-rc_rexmit.patch b/net/madwifi/patches/425-rc_rexmit.patch
new file mode 100644 (file)
index 0000000..252767a
--- /dev/null
@@ -0,0 +1,506 @@
+--- a/net80211/ieee80211_rate.h
++++ b/net80211/ieee80211_rate.h
+@@ -81,6 +81,8 @@ struct ieee80211vap;
+ /* Multi-rare retry: 3 additional rate/retry pairs */
+ struct ieee80211_mrr {
++      int rate0;
++      int retries0;
+       int rate1;
+       int retries1;
+       int rate2;
+@@ -142,7 +144,7 @@ struct ieee80211_rate_ops {
+        * for packets that were successfully sent and for those that
+        * failed (consult the descriptor for details). */
+       void (*tx_complete)(struct ath_softc *sc, struct ath_node *an,
+-                          const struct ath_buf *bf);
++                          const struct ath_buf *bf, const struct ieee80211_mrr *mrr);
+ };
+ struct ath_ratectrl {
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -8638,6 +8638,8 @@ ath_tx_processq(struct ath_softc *sc, st
+               ni = bf->bf_node;
+               if (ni != NULL) {
++                      struct ieee80211_mrr mrr;
++
+                       an = ATH_NODE(ni);
+                       if (ts->ts_status == 0) {
+                               u_int8_t txant = ts->ts_antenna;
+@@ -8690,15 +8692,43 @@ ath_tx_processq(struct ath_softc *sc, st
+                       lr = ts->ts_longretry;
+                       sc->sc_stats.ast_tx_shortretry += sr;
+                       sc->sc_stats.ast_tx_longretry += lr;
++                      memset(&mrr, 0, sizeof(mrr));
++
++                      switch(ah->ah_macType) {
++                      case 5210:
++                      case 5211:
++                              goto skip_mrr;
++
++                      case 5212:
++                              mrr.rate0 = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate0)].ieeerate;
++                              mrr.rate1 = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate1)].ieeerate;
++                              mrr.rate2 = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate2)].ieeerate;
++                              mrr.rate3 = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate3)].ieeerate;
++                              break;
++
++                      case 5416:
++                              mrr.rate0 = sc->sc_hwmap[MS(ds->ds_ctl3, AR5416_XmitRate0)].ieeerate;
++                              mrr.rate1 = sc->sc_hwmap[MS(ds->ds_ctl3, AR5416_XmitRate1)].ieeerate;
++                              mrr.rate2 = sc->sc_hwmap[MS(ds->ds_ctl3, AR5416_XmitRate2)].ieeerate;
++                              mrr.rate3 = sc->sc_hwmap[MS(ds->ds_ctl3, AR5416_XmitRate3)].ieeerate;
++                              break;
++                      }
++
++                      mrr.retries0 = MS(ds->ds_ctl2, AR_XmitDataTries0);
++                      mrr.retries1 = MS(ds->ds_ctl2, AR_XmitDataTries1);
++                      mrr.retries2 = MS(ds->ds_ctl2, AR_XmitDataTries2);
++                      mrr.retries3 = MS(ds->ds_ctl2, AR_XmitDataTries3);
++
+                       /*
+                        * Hand the descriptor to the rate control algorithm
+                        * if the frame wasn't dropped for filtering or sent
+                        * w/o waiting for an ack.  In those cases the rssi
+                        * and retry counts will be meaningless.
+                        */
++skip_mrr:
+                       if ((ts->ts_status & HAL_TXERR_FILT) == 0 &&
+                           (bf->bf_flags & HAL_TXDESC_NOACK) == 0)
+-                              sc->sc_rc->ops->tx_complete(sc, an, bf);
++                              sc->sc_rc->ops->tx_complete(sc, an, bf, &mrr);
+               }
+               bus_unmap_single(sc->sc_bdev, bf->bf_skbaddr,
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -595,6 +595,46 @@ struct ath_vap {
+       (_tqs)->axq_link = NULL; \
+ } while (0)
++/*
++ * Definitions for pulling the rate and trie counts from
++ * a 5212 h/w descriptor. These Don't belong here; the
++ * driver should record this information so the rate control
++ * code doesn't go groveling around in the descriptor bits.
++ */
++#define       ds_ctl2 ds_hw[0]
++#define       ds_ctl3 ds_hw[1]
++
++/* TX ds_ctl3 */
++#define       AR_XmitDataTries0       0x000f0000      /* series 0 max attempts */
++#define       AR_XmitDataTries0_S     16
++#define       AR_XmitDataTries1       0x00f00000      /* series 1 max attempts */
++#define       AR_XmitDataTries1_S     20
++#define       AR_XmitDataTries2       0x0f000000      /* series 2 max attempts */
++#define       AR_XmitDataTries2_S     24
++#define       AR_XmitDataTries3       0xf0000000      /* series 3 max attempts */
++#define       AR_XmitDataTries3_S     28
++
++/* TX ds_ctl3 */
++#define       AR_XmitRate0            0x0000001f      /* series 0 tx rate */
++#define       AR_XmitRate0_S          0
++#define       AR_XmitRate1            0x000003e0      /* series 1 tx rate */
++#define       AR_XmitRate1_S          5
++#define       AR_XmitRate2            0x00007c00      /* series 2 tx rate */
++#define       AR_XmitRate2_S          10
++#define       AR_XmitRate3            0x000f8000      /* series 3 tx rate */
++#define       AR_XmitRate3_S          15
++
++#define AR5416_XmitRate0        0x000000ff
++#define AR5416_XmitRate0_S      0
++#define AR5416_XmitRate1        0x0000ff00
++#define AR5416_XmitRate1_S      8
++#define AR5416_XmitRate2        0x00ff0000
++#define AR5416_XmitRate2_S      16
++#define AR5416_XmitRate3        0xff000000
++#define AR5416_XmitRate3_S      24
++
++#define MS(_v, _f)    (((_v) & (_f)) >> _f##_S)
++
+ /* 
+  * concat buffers from one queue to other
+  */
+--- a/ath_rate/amrr/amrr.c
++++ b/ath_rate/amrr/amrr.c
+@@ -123,7 +123,8 @@ ath_rate_get_mrr(struct ath_softc *sc, s
+ static void
+ ath_rate_tx_complete(struct ath_softc *sc,
+-      struct ath_node *an, const struct ath_buf *bf)
++      struct ath_node *an, const struct ath_buf *bf,
++      const struct ieee80211_mrr *mrr)
+ {
+       struct amrr_node *amn = ATH_NODE_AMRR(an);
+       const struct ath_tx_status *ts = &bf->bf_dsstatus.ds_txstat;
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -333,7 +333,8 @@ ath_rate_get_mrr(struct ath_softc *sc, s
+ static void
+ ath_rate_tx_complete(struct ath_softc *sc,
+-              struct ath_node *an, const struct ath_buf *bf)
++              struct ath_node *an, const struct ath_buf *bf,
++              const struct ieee80211_mrr *mrr)
+ {
+               struct minstrel_node *sn = ATH_NODE_MINSTREL(an);
+               struct ieee80211com *ic = &sc->sc_ic;
+@@ -341,12 +342,9 @@ ath_rate_tx_complete(struct ath_softc *s
+               const struct ath_desc *ds = &bf->bf_desc[0];
+               int final_rate = 0;
+               int tries = 0;
+-              int mrr;
++              int use_mrr;
+               int final_ndx;
+-              int rate0, tries0, ndx0;
+-              int rate1, tries1, ndx1;
+-              int rate2, tries2, ndx2;
+-              int rate3, tries3, ndx3;
++              int ndx0, ndx1, ndx2, ndx3;
+               /* This is the index in the retry chain we finish at.
+                * With no retransmits, it is always 0.
+@@ -376,9 +374,9 @@ ath_rate_tx_complete(struct ath_softc *s
+               if (!ts->ts_status)  /* Success when sending a packet*/
+                       sn->rs_ratesuccess[final_ndx]++;
+-              mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT) && ENABLE_MRR;
++              use_mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT) && ENABLE_MRR;
+-              if (!mrr) {
++              if (!use_mrr) {
+                       if ((0 <= final_ndx) && (final_ndx < sn->num_rates)) {
+                               sn->rs_rateattempts[final_ndx] += tries; /* only one rate was used */
+                       }
+@@ -388,47 +386,36 @@ ath_rate_tx_complete(struct ath_softc *s
+               /* Now, query the hal/hardware to find out the contents of the multirate retry chain.
+                * If we have it set to 6,3,2,2, this call will always return 6,3,2,2. For some packets, we can
+                * get a mrr of 0, -1, -1, -1, which indicates there is no chain installed for that packet */
+-              rate0 = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate0)].ieeerate;
+-              tries0 = MS(ds->ds_ctl2, AR_XmitDataTries0);
+-              ndx0 = rate_to_ndx(sn, rate0);
++              ndx0 = rate_to_ndx(sn, mrr->rate0);
++              ndx1 = rate_to_ndx(sn, mrr->rate1);
++              ndx2 = rate_to_ndx(sn, mrr->rate2);
++              ndx3 = rate_to_ndx(sn, mrr->rate3);
+-              rate1 = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate1)].ieeerate;
+-              tries1 = MS(ds->ds_ctl2, AR_XmitDataTries1);
+-              ndx1 = rate_to_ndx(sn, rate1);
+-
+-              rate2 = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate2)].ieeerate;
+-              tries2 = MS(ds->ds_ctl2, AR_XmitDataTries2);
+-              ndx2 = rate_to_ndx(sn, rate2);
+-
+-              rate3 = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate3)].ieeerate;
+-              tries3 = MS(ds->ds_ctl2, AR_XmitDataTries3);
+-              ndx3 = rate_to_ndx(sn, rate3);
+-
+-              sn->rs_rateattempts[ndx0] += MIN(tries, tries0);
+-              if (tries <= tries0)
++              sn->rs_rateattempts[ndx0] += MIN(tries, mrr->retries0);
++              if (tries <= mrr->retries0)
+                       return;
+-              if (tries1 < 0)
++              if (mrr->retries1 < 0)
+                       return;
+-              tries = tries - tries0;
+-              sn->rs_rateattempts[ndx1] += MIN(tries, tries1);
+-              if (tries <= tries1)
++              tries = tries - mrr->retries0;
++              sn->rs_rateattempts[ndx1] += MIN(tries, mrr->retries1);
++              if (tries <= mrr->retries1)
+                       return;
+               if (bf->rcflags)
+                       sn->sample_count++;
+-              if  (tries2 < 0)
++              if (mrr->retries2 < 0)
+                       return;
+-              tries = tries - tries1;
+-              sn->rs_rateattempts[ndx2] += MIN(tries, tries2);
+-              if (tries <= tries2)
++              tries = tries - mrr->retries1;
++              sn->rs_rateattempts[ndx2] += MIN(tries, mrr->retries2);
++              if (tries <= mrr->retries2)
+                       return;
+-              if  (tries3 < 0)
++              if (mrr->retries3 < 0)
+                       return;
+-              tries = tries - tries2;
+-              sn->rs_rateattempts[ndx3] += MIN(tries, tries3);
++              tries = tries - mrr->retries2;
++              sn->rs_rateattempts[ndx3] += MIN(tries, mrr->retries3);
+ }
+ static void
+--- a/ath_rate/minstrel/minstrel.h
++++ b/ath_rate/minstrel/minstrel.h
+@@ -172,36 +172,6 @@ struct minstrel_node {
+ #define       ATH_NODE_MINSTREL(an)   ((struct minstrel_node *)&an[1])
+-/*
+- * Definitions for pulling the rate and trie counts from
+- * a 5212 h/w descriptor. These Don't belong here; the
+- * driver should record this information so the rate control
+- * code doesn't go groveling around in the descriptor bits.
+- */
+-#define       ds_ctl2 ds_hw[0]
+-#define       ds_ctl3 ds_hw[1]
+-
+-/* TX ds_ctl3 */
+-#define       AR_XmitDataTries0       0x000f0000      /* series 0 max attempts */
+-#define       AR_XmitDataTries0_S     16
+-#define       AR_XmitDataTries1       0x00f00000      /* series 1 max attempts */
+-#define       AR_XmitDataTries1_S     20
+-#define       AR_XmitDataTries2       0x0f000000      /* series 2 max attempts */
+-#define       AR_XmitDataTries2_S     24
+-#define       AR_XmitDataTries3       0xf0000000      /* series 3 max attempts */
+-#define       AR_XmitDataTries3_S     28
+-
+-/* TX ds_ctl3 */
+-#define       AR_XmitRate0            0x0000001f      /* series 0 tx rate */
+-#define       AR_XmitRate0_S          0
+-#define       AR_XmitRate1            0x000003e0      /* series 1 tx rate */
+-#define       AR_XmitRate1_S          5
+-#define       AR_XmitRate2            0x00007c00      /* series 2 tx rate */
+-#define       AR_XmitRate2_S          10
+-#define       AR_XmitRate3            0x000f8000      /* series 3 tx rate */
+-#define       AR_XmitRate3_S          15
+-
+-#define MS(_v, _f)    (((_v) & (_f)) >> _f##_S)
+ #endif /* _DEV_ATH_RATE_MINSTEL_H */
+ /* The comment below is magic for those who use emacs to edit this file. */
+--- a/ath_rate/onoe/onoe.c
++++ b/ath_rate/onoe/onoe.c
+@@ -137,7 +137,8 @@ ath_rate_get_mrr(struct ath_softc *sc, s
+ static void
+ ath_rate_tx_complete(struct ath_softc *sc,
+-      struct ath_node *an, const struct ath_buf *bf)
++      struct ath_node *an, const struct ath_buf *bf,
++      const struct ieee80211_mrr *mrr)
+ {
+       struct onoe_node *on = ATH_NODE_ONOE(an);
+       const struct ath_tx_status *ts = &bf->bf_dsstatus.ds_txstat;
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -178,10 +178,6 @@ static __inline int best_rate_ndx(struct
+                   !sn->stats[size_bin][x].packets_acked))
+                       continue;
+-              /* 9 megabits never works better than 12 */
+-              if (sn->rates[x].rate == 18)
+-                      continue;
+-
+               /* don't use a bit-rate that has been failing */
+               if (sn->stats[size_bin][x].successive_failures > 3)
+                       continue;
+@@ -234,10 +230,6 @@ pick_sample_ndx(struct sample_node *sn,
+               if (sn->rates[ndx].rate > 22 && ndx > current_ndx + 2)
+                       continue;
+-              /* 9 megabits never works better than 12 */
+-              if (sn->rates[ndx].rate == 18)
+-                      continue;
+-
+               /* if we're using 11 megabits, only sample up to 12 megabits
+                */
+               if (sn->rates[current_ndx].rate == 22 && ndx > current_ndx + 1)
+@@ -531,7 +523,8 @@ update_stats(struct ath_softc *sc, struc
+ static void
+ ath_rate_tx_complete(struct ath_softc *sc,
+-      struct ath_node *an, const struct ath_buf *bf)
++      struct ath_node *an, const struct ath_buf *bf,
++      const struct ieee80211_mrr *mrr)
+ {
+       struct sample_node *sn = ATH_NODE_SAMPLE(an);
+       struct ieee80211com *ic = &sc->sc_ic;
+@@ -541,7 +534,7 @@ ath_rate_tx_complete(struct ath_softc *s
+       unsigned int short_tries;
+       unsigned int long_tries;
+       unsigned int frame_size;
+-      unsigned int mrr;
++      unsigned int use_mrr;
+       final_rate = sc->sc_hwmap[ts->ts_rate &~ HAL_TXSTAT_ALTRATE].ieeerate;
+       short_tries = ts->ts_shortretry + 1;
+@@ -557,7 +550,7 @@ ath_rate_tx_complete(struct ath_softc *s
+               return;
+       }
+-      mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT) && ENABLE_MRR;
++      use_mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT) && ENABLE_MRR;
+       if (sc->sc_mrretry && ts->ts_status) {
+@@ -566,22 +559,15 @@ ath_rate_tx_complete(struct ath_softc *s
+                       dev_info,
+                       MAC_ADDR(an->an_node.ni_macaddr),
+                       bin_to_size(size_to_bin(frame_size)),
+-                      sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate0)].ieeerate,
+-                              MS(ds->ds_ctl2, AR_XmitDataTries0),
+-                      sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate1)].ieeerate,
+-                              MS(ds->ds_ctl2, AR_XmitDataTries1),
+-                      sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate2)].ieeerate,
+-                              MS(ds->ds_ctl2, AR_XmitDataTries2),
+-                      sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate3)].ieeerate,
+-                              MS(ds->ds_ctl2, AR_XmitDataTries3),
++                      mrr->rate0,
++                      mrr->rate1,
++                      mrr->rate2,
++                      mrr->rate3,
+                       ts->ts_status ? "FAIL" : "OK",
+                       short_tries, long_tries);
+       }
+-      mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT) && ENABLE_MRR;
+-
+-
+-      if (!mrr || !(ts->ts_rate & HAL_TXSTAT_ALTRATE)) {
++      if (!use_mrr || !(ts->ts_rate & HAL_TXSTAT_ALTRATE)) {
+               /* only one rate was used */
+               int ndx = rate_to_ndx(sn, final_rate);
+               if ((ndx >= 0) && (ndx < sn->num_rates)) {
+@@ -593,7 +579,6 @@ ath_rate_tx_complete(struct ath_softc *s
+                               short_tries, long_tries, ts->ts_status);
+               }
+       } else {
+-              unsigned int rate[4], tries[4];
+               int ndx[4];
+               int finalTSIdx = ts->ts_finaltsi;
+@@ -601,21 +586,10 @@ ath_rate_tx_complete(struct ath_softc *s
+                * Process intermediate rates that failed.
+                */
+-              rate[0] = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate0)].ieeerate;
+-              tries[0] = MS(ds->ds_ctl2, AR_XmitDataTries0);
+-              ndx[0] = rate_to_ndx(sn, rate[0]);
+-
+-              rate[1] = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate1)].ieeerate;
+-              tries[1] = MS(ds->ds_ctl2, AR_XmitDataTries1);
+-              ndx[1] = rate_to_ndx(sn, rate[1]);
+-
+-              rate[2] = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate2)].ieeerate;
+-              tries[2] = MS(ds->ds_ctl2, AR_XmitDataTries2);
+-              ndx[2] = rate_to_ndx(sn, rate[2]);
+-
+-              rate[3] = sc->sc_hwmap[MS(ds->ds_ctl3, AR_XmitRate3)].ieeerate;
+-              tries[3] = MS(ds->ds_ctl2, AR_XmitDataTries3);
+-              ndx[3] = rate_to_ndx(sn, rate[3]);
++              ndx[0] = rate_to_ndx(sn, mrr->rate0);
++              ndx[1] = rate_to_ndx(sn, mrr->rate1);
++              ndx[2] = rate_to_ndx(sn, mrr->rate2);
++              ndx[3] = rate_to_ndx(sn, mrr->rate3);
+ #if 0
+               DPRINTF(sc, ATH_DEBUG_RATE, "%s: " MAC_FMT " size %u finaltsidx %u tries %u status %u rate/try %u/%u %u/%u %u/%u %u/%u\n",
+@@ -636,43 +610,43 @@ ath_rate_tx_complete(struct ath_softc *s
+                * sample higher rates 1 try at a time doing so
+                * may unfairly penalize them.
+                */
+-              if (tries[0] && ndx[0] >= 0) {
++              if (mrr->retries0 && ndx[0] >= 0) {
+                       update_stats(sc, an, frame_size,
+-                              ndx[0], tries[0],
+-                              ndx[1], tries[1],
+-                              ndx[2], tries[2],
+-                              ndx[3], tries[3],
++                              ndx[0], mrr->retries0,
++                              ndx[1], mrr->retries1,
++                              ndx[2], mrr->retries2,
++                              ndx[3], mrr->retries3,
+                               short_tries, long_tries,
+-                              long_tries > tries[0]);
+-                      long_tries -= tries[0];
++                              long_tries > mrr->retries0);
++                      long_tries -= mrr->retries0;
+               }
+-              if (tries[1] && ndx[1] >= 0 && finalTSIdx > 0) {
++              if (mrr->retries1 && ndx[1] >= 0 && finalTSIdx > 0) {
+                       update_stats(sc, an, frame_size,
+-                              ndx[1], tries[1],
+-                              ndx[2], tries[2],
+-                              ndx[3], tries[3],
++                              ndx[1], mrr->retries1,
++                              ndx[2], mrr->retries2,
++                              ndx[3], mrr->retries3,
+                               0, 0,
+                               short_tries, long_tries,
+                               ts->ts_status);
+-                      long_tries -= tries[1];
++                      long_tries -= mrr->retries1;
+               }
+-              if (tries[2] && ndx[2] >= 0 && finalTSIdx > 1) {
++              if (mrr->retries2 && ndx[2] >= 0 && finalTSIdx > 1) {
+                       update_stats(sc, an, frame_size,
+-                              ndx[2], tries[2],
+-                              ndx[3], tries[3],
++                              ndx[2], mrr->retries2,
++                              ndx[3], mrr->retries3,
+                               0, 0,
+                               0, 0,
+                               short_tries, long_tries,
+                               ts->ts_status);
+-                      long_tries -= tries[2];
++                      long_tries -= mrr->retries2;
+               }
+-              if (tries[3] && ndx[3] >= 0 && finalTSIdx > 2) {
++              if (mrr->retries3 && ndx[3] >= 0 && finalTSIdx > 2) {
+                       update_stats(sc, an, frame_size,
+-                              ndx[3], tries[3],
++                              ndx[3], mrr->retries3,
+                               0, 0,
+                               0, 0,
+                               0, 0,
+--- a/ath_rate/sample/sample.h
++++ b/ath_rate/sample/sample.h
+@@ -98,35 +98,4 @@ struct sample_node {
+ };
+ #define       ATH_NODE_SAMPLE(an)     ((struct sample_node *)&an[1])
+-/*
+- * Definitions for pulling the rate and trie counts from
+- * a 5212 h/w descriptor. These Don't belong here; the
+- * driver should record this information so the rate control
+- * code doesn't go groveling around in the descriptor bits.
+- */
+-#define       ds_ctl2 ds_hw[0]
+-#define       ds_ctl3 ds_hw[1]
+-
+-/* TX ds_ctl3 */
+-#define       AR_XmitDataTries0       0x000f0000      /* series 0 max attempts */
+-#define       AR_XmitDataTries0_S     16
+-#define       AR_XmitDataTries1       0x00f00000      /* series 1 max attempts */
+-#define       AR_XmitDataTries1_S     20
+-#define       AR_XmitDataTries2       0x0f000000      /* series 2 max attempts */
+-#define       AR_XmitDataTries2_S     24
+-#define       AR_XmitDataTries3       0xf0000000      /* series 3 max attempts */
+-#define       AR_XmitDataTries3_S     28
+-
+-/* TX ds_ctl3 */
+-#define       AR_XmitRate0            0x0000001f      /* series 0 tx rate */
+-#define       AR_XmitRate0_S          0
+-#define       AR_XmitRate1            0x000003e0      /* series 1 tx rate */
+-#define       AR_XmitRate1_S          5
+-#define       AR_XmitRate2            0x00007c00      /* series 2 tx rate */
+-#define       AR_XmitRate2_S          10
+-#define       AR_XmitRate3            0x000f8000      /* series 3 tx rate */
+-#define       AR_XmitRate3_S          15
+-
+-#define MS(_v, _f)    (((_v) & (_f)) >> _f##_S)
+-
+ #endif /* _DEV_ATH_RATE_SAMPLE_H */
diff --git a/net/madwifi/patches/426-header_len.patch b/net/madwifi/patches/426-header_len.patch
new file mode 100644 (file)
index 0000000..acfbc18
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -888,9 +888,6 @@ ath_attach(u_int16_t devid, struct net_d
+                               IEEE80211_ADDR_LEN +
+                               IEEE80211_WEP_IVLEN +
+                               IEEE80211_WEP_KIDLEN;
+-#ifdef ATH_SUPERG_FF
+-      dev->hard_header_len += ATH_FF_MAX_HDR;
+-#endif
+ #endif
+       dev->type = ARPHRD_IEEE80211;
diff --git a/net/madwifi/patches/427-ignore_eeprom_ff.patch b/net/madwifi/patches/427-ignore_eeprom_ff.patch
new file mode 100644 (file)
index 0000000..eead70c
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -915,7 +915,7 @@ ath_attach(u_int16_t devid, struct net_d
+       ic->ic_ath_cap = 0;
+       sc->sc_fftxqmin = ATH_FF_TXQMIN;
+ #ifdef ATH_SUPERG_FF
+-      ic->ic_ath_cap |= (ath_hal_fastframesupported(ah) ? 
++      ic->ic_ath_cap |= (ah->ah_macType >= 5212 ?
+                       IEEE80211_ATHC_FF : 0);
+ #endif
+       ic->ic_ath_cap |= (ath_hal_burstsupported(ah) ? 
diff --git a/net/madwifi/patches/430-use_netdev_priv.patch b/net/madwifi/patches/430-use_netdev_priv.patch
new file mode 100644 (file)
index 0000000..3f65424
--- /dev/null
@@ -0,0 +1,1936 @@
+--- a/ath/ath_wprobe.c
++++ b/ath/ath_wprobe.c
+@@ -119,7 +119,7 @@ ath_wprobe_sync(struct wprobe_iface *dev
+       struct ath_vap *avp = container_of(dev, struct ath_vap, av_wpif);
+       struct ieee80211vap *vap = &avp->av_vap;
+       struct ieee80211com *ic = vap->iv_ic;
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       struct ath_hal *ah = sc->sc_ah;
+       u32 cc, busy, rx, tx;
+       s16 noise;
+@@ -192,7 +192,7 @@ ath_lookup_rateval(struct ieee80211_node
+ {
+       struct ieee80211vap *vap = ni->ni_vap;
+       struct ieee80211com *ic = vap->iv_ic;
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       const HAL_RATE_TABLE *rt = sc->sc_currates;
+       if ((!rt) || (rate < 0) || (rate >= ARRAY_SIZE(sc->sc_hwmap)))
+--- a/ath/if_ath_ahb.c
++++ b/ath/if_ath_ahb.c
+@@ -203,7 +203,7 @@ static int ahb_wmac_probe(struct platfor
+       if (!dev)
+               return -ENOMEM;
+-      sc = dev->priv;
++      sc = netdev_priv(dev);
+       sc->aps_sc.sc_dev = dev;
+       dev->irq = platform_get_irq(pdev, 0);
+@@ -300,7 +300,7 @@ init_ath_wmac(u_int16_t devid, u_int16_t
+               printk(KERN_ERR "%s: no memory for device state\n", dev_info);
+               goto bad2;
+       }
+-      sc = dev->priv;
++      sc = netdev_priv(dev);
+       sc->aps_sc.sc_dev = dev;
+       /*
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -569,7 +569,7 @@ static inline int rate_factor(int mode)
+ int
+ ath_attach(u_int16_t devid, struct net_device *dev, HAL_BUS_TAG tag)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ieee80211vap *vap;
+       struct ath_hal *ah;
+@@ -1206,7 +1206,7 @@ bad:
+ int
+ ath_detach(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       HAL_INT tmp;
+@@ -1266,7 +1266,7 @@ static struct ieee80211vap *
+ ath_vap_create(struct ieee80211com *ic, const char *name,
+       int opmode, int flags, struct net_device *mdev, struct ieee80211vap *master)
+ {
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       struct ath_hal *ah = sc->sc_ah;
+       struct net_device *dev;
+       struct ath_vap *avp;
+@@ -1344,7 +1344,7 @@ ath_vap_create(struct ieee80211com *ic,
+               return NULL;
+       }
+-      avp = dev->priv;
++      avp = netdev_priv(dev);
+       ieee80211_vap_setup(ic, dev, name, opmode, flags, master);
+       /* override with driver methods */
+       vap = &avp->av_vap;
+@@ -1571,7 +1571,7 @@ static void
+ ath_vap_delete(struct ieee80211vap *vap)
+ {
+       struct net_device *dev = vap->iv_ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       struct ath_vap *avp = ATH_VAP(vap);
+       int decrease = 1;
+@@ -1673,7 +1673,7 @@ void
+ ath_suspend(struct net_device *dev)
+ {
+ #ifdef AR_DEBUG
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+ #endif
+       DPRINTF(sc, ATH_DEBUG_ANY, "flags=%x\n", dev->flags);
+@@ -1684,7 +1684,7 @@ void
+ ath_resume(struct net_device *dev)
+ {
+ #ifdef AR_DEBUG
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+ #endif
+       DPRINTF(sc, ATH_DEBUG_ANY, "flags=%x\n", dev->flags);
+@@ -2248,7 +2248,7 @@ ath_intr(int irq, void *dev_id, struct p
+ #endif
+ {
+       struct net_device *dev = dev_id;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       u_int64_t hw_tsf = 0;
+       HAL_INT status;
+@@ -2469,7 +2469,7 @@ static void
+ ath_fatal_tasklet(TQUEUE_ARG data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       EPRINTF(sc, "Hardware error; resetting.\n");
+       ath_reset(dev);
+@@ -2479,7 +2479,7 @@ static void
+ ath_rxorn_tasklet(TQUEUE_ARG data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       EPRINTF(sc, "Receive FIFO overrun; resetting.\n");
+       ath_reset(dev);
+@@ -2489,7 +2489,7 @@ static void
+ ath_bmiss_tasklet(TQUEUE_ARG data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       if (time_before(jiffies, sc->sc_ic.ic_bmiss_guard)) {
+               /* Beacon miss interrupt occured too short after last beacon
+@@ -2568,7 +2568,7 @@ done:
+ static int
+ ath_init(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
+       HAL_STATUS status;
+@@ -2693,7 +2693,7 @@ done:
+ static int
+ ath_stop_locked(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
+@@ -2778,7 +2778,7 @@ static void ath_set_beacon_cal(struct at
+ static int
+ ath_stop(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       int error;
+       ATH_LOCK(sc);
+@@ -2998,7 +2998,7 @@ ath_fetch_idle_time(struct ath_softc *sc
+ static int
+ ath_reset(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
+       struct ieee80211_channel *c;
+@@ -3164,7 +3164,7 @@ dot11_to_ratecode(struct ath_softc *sc,
+ static int
+ ath_tx_startraw(struct net_device *dev, struct ath_buf *bf, struct sk_buff *skb)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       struct ieee80211_phy_params *ph = (struct ieee80211_phy_params *)
+               (SKB_CB(skb) + 1); /* NB: SKB_CB casts to CB struct*. */
+@@ -3477,7 +3477,7 @@ _take_txbuf(struct ath_softc *sc, int fo
+ static int
+ ath_hardstart(struct sk_buff *skb, struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211_node *ni = NULL;
+       struct ath_buf *bf = NULL;
+       ath_bufhead bf_head;
+@@ -3792,7 +3792,7 @@ static int
+ ath_mgtstart(struct ieee80211com *ic, struct sk_buff *skb)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_buf *bf = NULL;
+       int error;
+@@ -4151,7 +4151,7 @@ static ieee80211_keyix_t
+ ath_key_alloc(struct ieee80211vap *vap, const struct ieee80211_key *k)
+ {
+       struct net_device *dev = vap->iv_ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       /*
+        * Group key allocation must be handled specially for
+@@ -4216,7 +4216,7 @@ ath_key_delete(struct ieee80211vap *vap,
+                               struct ieee80211_node *ninfo)
+ {
+       struct net_device *dev = vap->iv_ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       struct ieee80211_node *ni = NULL;
+       const struct ieee80211_cipher *cip = k->wk_cipher;
+@@ -4292,14 +4292,14 @@ ath_key_set(struct ieee80211vap *vap, co
+       const u_int8_t mac[IEEE80211_ADDR_LEN])
+ {
+       struct net_device *dev = vap->iv_ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       return ath_keyset(sc, k, mac, vap->iv_bss);
+ }
+ static void ath_poll_disable(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       /*
+        * XXX Using in_softirq is not right since we might
+@@ -4317,7 +4317,7 @@ static void ath_poll_disable(struct net_
+ static void ath_poll_enable(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       /* NB: see above */
+       if (!in_softirq()) {
+@@ -4343,7 +4343,7 @@ ath_key_update_begin(struct ieee80211vap
+ {
+       struct net_device *dev = vap->iv_ic->ic_dev;
+ #ifdef AR_DEBUG
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+ #endif
+       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "Begin\n");
+@@ -4361,7 +4361,7 @@ ath_key_update_end(struct ieee80211vap *
+ {
+       struct net_device *dev = vap->iv_ic->ic_dev;
+ #ifdef AR_DEBUG
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+ #endif
+       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "End\n");
+@@ -4454,7 +4454,7 @@ ath_merge_mcast(struct ath_softc *sc, u_
+ static void
+ ath_mode_init(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       u_int32_t rfilt, mfilt[2];
+@@ -4540,7 +4540,7 @@ ath_set_timing(struct ath_softc *sc)
+ static void
+ ath_updateslot(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       /*
+@@ -4570,7 +4570,7 @@ ath_beacon_dturbo_config(struct ieee8021
+       (vap->iv_bss && (vap->iv_bss->ni_ath_flags & (IEEE80211_ATHC_TURBOP)) == \
+               (IEEE80211_ATHC_TURBOP))
+       struct ieee80211com *ic = vap->iv_ic;
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       if (ic->ic_opmode == IEEE80211_M_HOSTAP && IS_CAPABLE(vap)) {
+@@ -4618,7 +4618,7 @@ static void
+ ath_beacon_dturbo_update(struct ieee80211vap *vap, int *needmark, u_int8_t dtim)
+ {
+       struct ieee80211com *ic = vap->iv_ic;
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       u_int32_t bss_traffic;
+       if (sc->sc_ignore_ar) {
+@@ -4759,7 +4759,7 @@ static void
+ ath_turbo_switch_mode(unsigned long data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       unsigned int newflags;
+@@ -5438,7 +5438,7 @@ static void
+ ath_bstuck_tasklet(TQUEUE_ARG data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       /*
+        * XXX:if the bmisscount is cleared while the
+        *     tasklet execution is pending, the following
+@@ -5891,7 +5891,7 @@ ath_node_alloc_debug(struct ieee80211vap
+ ath_node_alloc(struct ieee80211vap *vap)
+ #endif 
+ {
+-      struct ath_softc *sc = vap->iv_ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(vap->iv_ic->ic_dev);
+       const size_t space = sizeof(struct ath_node) + sc->sc_rc->arc_space;
+       struct ath_node *an = kmalloc(space, GFP_ATOMIC);
+       if (an != NULL) {
+@@ -5927,7 +5927,7 @@ ath_node_cleanup(struct ieee80211_node *
+ #endif
+ {
+       struct ieee80211com *ic = ni->ni_ic;
+-      struct ath_softc *sc = ni->ni_ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ni->ni_ic->ic_dev);
+       struct ath_node *an = ATH_NODE(ni);
+       struct ath_buf *bf;
+@@ -5985,7 +5985,7 @@ ath_node_free_debug(struct ieee80211_nod
+ ath_node_free(struct ieee80211_node *ni)
+ #endif
+ {
+-      struct ath_softc *sc = ni->ni_ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ni->ni_ic->ic_dev);
+ #ifdef IEEE80211_DEBUG_REFCNT
+       sc->sc_node_free_debug(ni, func, line);
+@@ -6033,7 +6033,7 @@ ath_node_move_data(const struct ieee8021
+ #ifdef NOT_YET
+       struct ath_txq *txq = NULL;
+       struct ieee80211com *ic = ni->ni_ic;
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       struct ath_buf *bf, *prev, *bf_tmp, *bf_tmp1;
+       struct ath_hal *ah = sc->sc_ah;
+       struct sk_buff *skb = NULL;
+@@ -6553,7 +6553,7 @@ static void
+ ath_capture(struct net_device *dev, const struct ath_buf *bf,
+               struct sk_buff *skb, u_int64_t tsf, unsigned int tx)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct sk_buff *tskb = NULL;
+   
+@@ -6613,7 +6613,7 @@ static void
+ ath_recv_mgmt(struct ieee80211vap * vap, struct ieee80211_node *ni_or_null,
+       struct sk_buff *skb, int subtype, int rssi, u_int64_t rtsf)
+ {
+-      struct ath_softc *sc = vap->iv_ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(vap->iv_ic->ic_dev);
+ #ifdef AR_DEBUG
+         struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data;
+ #endif
+@@ -6780,7 +6780,7 @@ ath_rx_poll(struct net_device *dev, int
+       struct net_device *dev = sc->sc_dev;
+       int rx_limit = budget;
+ #else
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       int rx_limit = min(dev->quota, *budget);
+ #endif
+       struct ath_buf *bf;
+@@ -7305,7 +7305,7 @@ static void ath_grppoll_start(struct iee
+       struct sk_buff *skb = NULL;
+       struct ath_buf *bf, *head = NULL;
+       struct ieee80211com *ic = vap->iv_ic;
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       struct ath_hal *ah = sc->sc_ah;
+       u_int8_t rate;
+       unsigned int ctsrate = 0, ctsduration = 0;
+@@ -7523,7 +7523,7 @@ static void ath_grppoll_start(struct iee
+ static void ath_grppoll_stop(struct ieee80211vap *vap)
+ {
+       struct ieee80211com *ic = vap->iv_ic;
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       struct ath_hal *ah = sc->sc_ah;
+       struct ath_txq *txq = &sc->sc_grpplq;
+       struct ath_buf *bf;
+@@ -7735,7 +7735,7 @@ ath_txq_update(struct ath_softc *sc, str
+ static int
+ ath_wme_update(struct ieee80211com *ic)
+ {
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       if (sc->sc_uapsdq)
+               ath_txq_update(sc, sc->sc_uapsdq, WME_AC_VO);
+@@ -7754,7 +7754,7 @@ ath_uapsd_flush(struct ieee80211_node *n
+ {
+       struct ath_node *an = ATH_NODE(ni);
+       struct ath_buf *bf;
+-      struct ath_softc *sc = ni->ni_ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ni->ni_ic->ic_dev);
+       struct ath_txq *txq;
+       ATH_NODE_UAPSD_LOCK_IRQ(an);
+@@ -7945,7 +7945,7 @@ ath_tx_start(struct net_device *dev, str
+               struct ath_buf *bf, struct sk_buff *skb, int nextfraglen)
+ {
+ #define       MIN(a,b)        ((a) < (b) ? (a) : (b))
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = ni->ni_ic;
+       struct ieee80211vap *vap = ni->ni_vap;
+       struct ath_hal *ah = sc->sc_ah;
+@@ -8854,7 +8854,7 @@ static void
+ ath_tx_tasklet_q0(TQUEUE_ARG data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       unsigned long flags;
+ process_tx_again:
+@@ -8885,7 +8885,7 @@ static void
+ ath_tx_tasklet_q0123(TQUEUE_ARG data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       unsigned long flags;
+ process_tx_again:
+@@ -8930,7 +8930,7 @@ static void
+ ath_tx_tasklet(TQUEUE_ARG data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       unsigned int i;
+       unsigned long flags;
+@@ -8958,7 +8958,7 @@ process_tx_again:
+ static void
+ ath_tx_timeout(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       if (ath_chan_unavail(sc))
+               return;
+@@ -9366,7 +9366,7 @@ static void
+ ath_calibrate(unsigned long arg)
+ {
+       struct net_device *dev = (struct net_device *)arg;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       struct ieee80211com *ic = &sc->sc_ic;
+       /* u_int32_t nchans; */
+@@ -9441,7 +9441,7 @@ static void
+ ath_scan_start(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       u_int32_t rfilt;
+@@ -9461,7 +9461,7 @@ static void
+ ath_scan_end(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       u_int32_t rfilt;
+@@ -9479,7 +9479,7 @@ static void
+ ath_set_channel(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       (void) ath_chan_set(sc, ic->ic_curchan);
+       ic->ic_channoise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan));
+@@ -9496,7 +9496,7 @@ ath_set_channel(struct ieee80211com *ic)
+ static void
+ ath_set_coverageclass(struct ieee80211com *ic)
+ {
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       sc->sc_coverage = ic->ic_coverageclass * 3;
+       ath_set_timing(sc);
+@@ -9507,7 +9507,7 @@ ath_set_coverageclass(struct ieee80211co
+ static u_int
+ ath_mhz2ieee(struct ieee80211com *ic, u_int freq, u_int flags)
+ {
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       return (ath_hal_mhz2ieee(sc->sc_ah, freq, flags));
+ }
+@@ -9522,7 +9522,7 @@ ath_newstate(struct ieee80211vap *vap, e
+       struct ath_vap *avp = ATH_VAP(vap);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       struct ieee80211_node *ni, *wds_ni;
+       unsigned int i;
+@@ -9962,7 +9962,7 @@ ath_setup_comp(struct ieee80211_node *ni
+ {
+ #define       IEEE80211_KEY_XR        (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)
+       struct ieee80211vap *vap = ni->ni_vap;
+-      struct ath_softc *sc = vap->iv_ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(vap->iv_ic->ic_dev);
+       struct ath_node *an = ATH_NODE(ni);
+       ieee80211_keyix_t keyix;
+@@ -10016,7 +10016,7 @@ static void
+ ath_setup_stationkey(struct ieee80211_node *ni)
+ {
+       struct ieee80211vap *vap = ni->ni_vap;
+-      struct ath_softc *sc = vap->iv_ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(vap->iv_ic->ic_dev);
+       ieee80211_keyix_t keyix;
+       keyix = ath_key_alloc(vap, &ni->ni_ucastkey);
+@@ -10177,7 +10177,7 @@ ath_newassoc(struct ieee80211_node *ni,
+ {
+       struct ieee80211com *ic = ni->ni_ic;
+       struct ieee80211vap *vap = ni->ni_vap;
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       sc->sc_rc->ops->newassoc(sc, ATH_NODE(ni), isnew);
+       ath_wprobe_node_join(ni->ni_vap, ni);
+@@ -10208,7 +10208,7 @@ ath_newassoc(struct ieee80211_node *ni,
+ static int
+ ath_getchannels(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
+       HAL_CHANNEL *chans;
+@@ -10485,7 +10485,7 @@ ath_update_txpow(struct ath_softc *sc)
+ static int
+ ath_xr_rate_setup(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       struct ieee80211com *ic = &sc->sc_ic;
+       const HAL_RATE_TABLE *rt;
+@@ -10516,7 +10516,7 @@ ath_xr_rate_setup(struct net_device *dev
+ static int
+ ath_rate_setup(struct net_device *dev, u_int mode)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       struct ieee80211com *ic = &sc->sc_ic;
+       const HAL_RATE_TABLE *rt;
+@@ -10763,7 +10763,7 @@ ath_printtxbuf(const struct ath_buf *bf,
+ {
+       const struct ath_tx_status *ts = &bf->bf_dsstatus.ds_txstat;
+       const struct ath_desc *ds = bf->bf_desc;
+-      struct ath_softc *sc = bf->bf_node->ni_ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(bf->bf_node->ni_ic->ic_dev);
+       u_int8_t status = done ? ts->ts_status : 0;
+       DPRINTF(sc, ATH_DEBUG_ANY, 
+@@ -10790,7 +10790,7 @@ ath_printtxbuf(const struct ath_buf *bf,
+ static struct net_device_stats *
+ ath_getstats(struct net_device *dev)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct net_device_stats *stats = &sc->sc_devstats;
+       /* update according to private statistics */
+@@ -10813,7 +10813,7 @@ ath_getstats(struct net_device *dev)
+ static int
+ ath_set_mac_address(struct net_device *dev, void *addr)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
+       struct sockaddr *mac = addr;
+@@ -10842,7 +10842,7 @@ ath_set_mac_address(struct net_device *d
+ static int
+ ath_change_mtu(struct net_device *dev, int mtu)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       int error = 0;
+       if (!(ATH_MIN_MTU < mtu && mtu <= ATH_MAX_MTU)) {
+@@ -10929,7 +10929,7 @@ bad:
+ static int
+ ath_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       int error;
+@@ -11810,7 +11810,7 @@ static void
+ ath_announce(struct net_device *dev)
+ {
+ #define       HAL_MODE_DUALBAND       (HAL_MODE_11A|HAL_MODE_11B)
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct ath_hal *ah = sc->sc_ah;
+       u_int modes, cc;
+       static const int MLEN = 1024;
+@@ -11997,7 +11997,7 @@ static void
+ txcont_configure_radio(struct ieee80211com *ic)
+ {
+       struct net_device           *dev = ic->ic_dev;
+-      struct ath_softc            *sc = dev->priv;
++      struct ath_softc            *sc = netdev_priv(dev);
+       struct ath_hal              *ah = sc->sc_ah;
+       struct ieee80211_wme_state  *wme = &ic->ic_wme;
+       struct ieee80211vap         *vap = TAILQ_FIRST(&ic->ic_vaps);
+@@ -12271,7 +12271,7 @@ static void
+ txcont_queue_packet(struct ieee80211com *ic, struct ath_txq* txq)
+ {
+       struct net_device *dev             = ic->ic_dev;
+-      struct ath_softc *sc               = dev->priv;
++      struct ath_softc *sc               = netdev_priv(dev);
+       struct ath_hal *ah                 = sc->sc_ah;
+       struct ath_buf *bf                 = NULL;
+       struct sk_buff *skb                = NULL;
+@@ -12404,7 +12404,7 @@ static void
+ txcont_on(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       if (IFF_RUNNING != (ic->ic_dev->flags & IFF_RUNNING)) {
+               EPRINTF(sc, "Cannot enable txcont when"
+@@ -12425,7 +12425,7 @@ static void
+ txcont_off(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       if (TAILQ_FIRST(&ic->ic_vaps)->iv_opmode != IEEE80211_M_WDS)
+               sc->sc_beacons = 1;
+@@ -12439,7 +12439,7 @@ static int
+ ath_get_dfs_testmode(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       return sc->sc_dfs_testmode;
+ }
+@@ -12466,7 +12466,7 @@ static void
+ ath_set_dfs_testmode(struct ieee80211com *ic, int value)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       sc->sc_dfs_testmode = !!value;
+ }
+@@ -12476,7 +12476,7 @@ static int
+ ath_get_txcont(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       return sc->sc_txcont;
+ }
+@@ -12494,7 +12494,7 @@ static void
+ ath_set_txcont_power(struct ieee80211com *ic, unsigned int txpower)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       int new_txcont_power = txpower > IEEE80211_TXPOWER_MAX ? 
+               IEEE80211_TXPOWER_MAX : txpower;
+       if (sc->sc_txcont_power != new_txcont_power) {
+@@ -12512,7 +12512,7 @@ static int
+ ath_get_txcont_power(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       /* VERY conservative default */
+       return sc->sc_txcont_power ? sc->sc_txcont_power : 0;
+ }
+@@ -12522,7 +12522,7 @@ ath_get_txcont_power(struct ieee80211com
+ ath_set_txcont_rate(struct ieee80211com *ic, unsigned int new_rate)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       if (sc->sc_txcont_rate != new_rate) {
+               /*  NOTE: This value is sanity checked and dropped down to 
+                *  closest rate in txcont_on. */
+@@ -12539,7 +12539,7 @@ ath_set_txcont_rate(struct ieee80211com
+ ath_get_txcont_rate(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       return sc->sc_txcont_rate ? sc->sc_txcont_rate : 0;
+ }
+@@ -12549,7 +12549,7 @@ static void
+ ath_set_dfs_cac_time(struct ieee80211com *ic, unsigned int time_s)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       sc->sc_dfs_cac_period = time_s;
+ }
+@@ -12559,7 +12559,7 @@ static unsigned int
+ ath_get_dfs_cac_time(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       return sc->sc_dfs_cac_period;
+ }
+@@ -12579,7 +12579,7 @@ static void
+ ath_set_dfs_excl_period(struct ieee80211com *ic, unsigned int time_s)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       sc->sc_dfs_excl_period = time_s;
+ }
+@@ -12588,7 +12588,7 @@ static unsigned int
+ ath_get_dfs_excl_period(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       return sc->sc_dfs_excl_period;
+ }
+@@ -12600,7 +12600,7 @@ static unsigned int
+ ath_test_radar(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc   = dev->priv;
++      struct ath_softc *sc   = netdev_priv(dev);
+       if ((ic->ic_flags & IEEE80211_F_DOTH) && (sc->sc_curchan.privFlags & CHANNEL_DFS))
+               ath_radar_detected(sc, "ath_test_radar from user space");
+       else
+@@ -12616,7 +12616,7 @@ static unsigned int
+ ath_dump_hal_map(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc   = dev->priv;
++      struct ath_softc *sc   = netdev_priv(dev);
+       ath_hal_dump_map(sc->sc_ah);
+       return 0;
+ }
+@@ -12724,7 +12724,7 @@ ath_rcv_dev_event(struct notifier_block
+       void *ptr)
+ {
+       struct net_device *dev = (struct net_device *)ptr;
+-      struct ath_softc *sc = (struct ath_softc *)dev->priv;
++      struct ath_softc *sc = (struct ath_softc *)netdev_priv(dev);
+       if (!dev || !sc || dev->open != &ath_init)
+               return 0;
+@@ -13459,7 +13459,7 @@ static unsigned int
+ ath_read_register(struct ieee80211com *ic, unsigned int address, 
+               unsigned int* value)
+ {
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       if (address >= MAX_REGISTER_ADDRESS) {
+               IPRINTF(sc, "Illegal Atheros register access "
+                               "attempted: 0x%04x >= 0x%04x\n",
+@@ -13489,7 +13489,7 @@ static unsigned int
+ ath_write_register(struct ieee80211com *ic, unsigned int address, 
+               unsigned int value)
+ {
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       if (address >= MAX_REGISTER_ADDRESS) {
+               IPRINTF(sc, "Illegal Atheros register access "
+                               "attempted: 0x%04x >= 0x%04x\n",
+@@ -13517,7 +13517,7 @@ static void
+ ath_registers_dump(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       ath_ar5212_registers_dump(sc);
+ }
+ #endif /* #ifdef ATH_REVERSE_ENGINEERING */
+@@ -13529,7 +13529,7 @@ static void
+ ath_registers_mark(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       ath_ar5212_registers_mark(sc);
+ }
+ #endif /* #ifdef ATH_REVERSE_ENGINEERING */
+@@ -13541,7 +13541,7 @@ static void
+ ath_registers_dump_delta(struct ieee80211com *ic)
+ {
+       struct net_device *dev = ic->ic_dev;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       ath_ar5212_registers_dump_delta(sc);
+ }
+ #endif /* #ifdef ATH_REVERSE_ENGINEERING */
+--- a/ath/if_ath_pci.c
++++ b/ath/if_ath_pci.c
+@@ -226,7 +226,7 @@ ath_pci_probe(struct pci_dev *pdev, cons
+               printk(KERN_ERR "%s: no memory for device state\n", dev_info);
+               goto bad2;
+       }
+-      sc = dev->priv;
++      sc = netdev_priv(dev);
+       sc->aps_sc.sc_dev = dev;
+       sc->aps_sc.sc_iobase = mem;
+@@ -309,7 +309,7 @@ static void
+ ath_pci_remove(struct pci_dev *pdev)
+ {
+       struct net_device *dev = pci_get_drvdata(pdev);
+-      struct ath_pci_softc *sc = dev->priv;
++      struct ath_pci_softc *sc = netdev_priv(dev);
+       ath_detach(dev);
+       if (dev->irq)
+@@ -327,7 +327,7 @@ ath_pci_suspend(struct pci_dev *pdev, pm
+       struct net_device *dev = pci_get_drvdata(pdev);
+       ath_suspend(dev);
+-      PCI_SAVE_STATE(pdev, ((struct ath_pci_softc *)dev->priv)->aps_pmstate);
++      PCI_SAVE_STATE(pdev, ((struct ath_pci_softc *)netdev_priv(dev))->aps_pmstate);
+       pci_disable_device(pdev);
+       return pci_set_power_state(pdev, PCI_D3hot);
+ }
+@@ -344,7 +344,7 @@ ath_pci_resume(struct pci_dev *pdev)
+               return err;
+       /* XXX - Should this return nonzero on fail? */
+-      PCI_RESTORE_STATE(pdev, ((struct ath_pci_softc *)dev->priv)->aps_pmstate);
++      PCI_RESTORE_STATE(pdev, ((struct ath_pci_softc *)netdev_priv(dev))->aps_pmstate);
+       err = pci_enable_device(pdev);
+       if (err)
+--- a/ath/if_ath_radar.c
++++ b/ath/if_ath_radar.c
+@@ -1533,7 +1533,7 @@ static void ath_rp_clear(struct ath_soft
+ static void ath_rp_tasklet(TQUEUE_ARG data)
+ {
+       struct net_device *dev = (struct net_device *) data;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       if (sc->sc_rp_analyse != NULL)
+               sc->sc_rp_analyse(sc);
+--- a/ath_rate/amrr/amrr.c
++++ b/ath_rate/amrr/amrr.c
+@@ -298,7 +298,7 @@ ath_rate_ctl_start(struct ath_softc *sc,
+ static void
+ ath_rate_cb(void *arg, struct ieee80211_node *ni)
+ {
+-      ath_rate_update(ni->ni_ic->ic_dev->priv, ni, (long) arg);
++      ath_rate_update(netdev_priv(ni->ni_ic->ic_dev), ni, (long) arg);
+ }
+ /*
+@@ -308,7 +308,7 @@ static void
+ ath_rate_newstate(struct ieee80211vap *vap, enum ieee80211_state state)
+ {
+       struct ieee80211com *ic = vap->iv_ic;
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       struct amrr_softc *asc = (struct amrr_softc *) sc->sc_rc;
+       struct ieee80211_node *ni;
+@@ -420,7 +420,7 @@ static void
+ ath_ratectl(unsigned long data)
+ {
+       struct net_device *dev = (struct net_device *)data;
+-      struct ath_softc *sc = dev->priv;
++      struct ath_softc *sc = netdev_priv(dev);
+       struct amrr_softc *asc = (struct amrr_softc *)sc->sc_rc;
+       struct ieee80211com *ic = &sc->sc_ic;
+       int interval;
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -622,7 +622,7 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+ static void
+ ath_rate_cb(void *arg, struct ieee80211_node *ni)
+ {
+-              ath_rate_ctl_reset(ni->ni_ic->ic_dev->priv, ni);
++              ath_rate_ctl_reset(netdev_priv(ni->ni_ic->ic_dev), ni);
+ }
+ /* Reset the rate control state for each 802.11 state transition. */
+@@ -636,7 +636,7 @@ ath_rate_newstate(struct ieee80211vap *v
+                               /* Sync rates for associated stations and neighbors. */
+                               ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, NULL);
+                       }
+-                      ath_rate_newassoc(ic->ic_dev->priv, ATH_NODE(vap->iv_bss), 1);
++                      ath_rate_newassoc(netdev_priv(ic->ic_dev), ATH_NODE(vap->iv_bss), 1);
+               }
+ }
+@@ -822,7 +822,7 @@ ath_proc_read_nodes(struct ieee80211vap
+               unsigned int x = 0;
+               unsigned int this_tp, this_prob, this_eprob;
+ #ifdef AR_DEBUG
+-                      struct ath_softc *sc = vap->iv_ic->ic_dev->priv;;
++                      struct ath_softc *sc = netdev_priv(vap->iv_ic->ic_dev);
+ #endif
+               IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+--- a/ath_rate/onoe/onoe.c
++++ b/ath_rate/onoe/onoe.c
+@@ -281,7 +281,7 @@ ath_rate_ctl_start(struct ath_softc *sc,
+ static void
+ ath_rate_cb(void *arg, struct ieee80211_node *ni)
+ {
+-      ath_rate_update(ni->ni_ic->ic_dev->priv, ni, (long) arg);
++      ath_rate_update(netdev_priv(ni->ni_ic->ic_dev), ni, (long) arg);
+ }
+ /*
+@@ -291,7 +291,7 @@ static void
+ ath_rate_newstate(struct ieee80211vap *vap, enum ieee80211_state state)
+ {
+       struct ieee80211com *ic = vap->iv_ic;
+-      struct ath_softc *sc = ic->ic_dev->priv;
++      struct ath_softc *sc = netdev_priv(ic->ic_dev);
+       struct ieee80211_node *ni;
+       if (state == IEEE80211_S_INIT)
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -803,7 +803,7 @@ ath_rate_ctl_reset(struct ath_softc *sc,
+ static void
+ ath_rate_cb(void *arg, struct ieee80211_node *ni)
+ {
+-      ath_rate_ctl_reset(ni->ni_ic->ic_dev->priv, ni);
++      ath_rate_ctl_reset(netdev_priv(ni->ni_ic->ic_dev), ni);
+ }
+ /*
+@@ -821,7 +821,7 @@ ath_rate_newstate(struct ieee80211vap *v
+                        */
+                       ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, NULL);
+               }
+-              ath_rate_newassoc(ic->ic_dev->priv, ATH_NODE(vap->iv_bss), 1);
++              ath_rate_newassoc(netdev_priv(ic->ic_dev), ATH_NODE(vap->iv_bss), 1);
+       }
+ }
+--- a/include/compat.h
++++ b/include/compat.h
+@@ -162,6 +162,10 @@ static inline int timeval_compare(struct
+ #define IRQF_SHARED SA_SHIRQ
+ #endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)
++#define netdev_priv(_netdev) ((_netdev)->priv)
++#endif
++
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ #define skb_end_pointer(_skb) ((_skb)->end)
+ #define skb_tail_pointer(_skb) ((_skb)->tail)
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -458,7 +458,7 @@ ieee80211_vap_setup(struct ieee80211com
+ #define       IEEE80211_C_OPMODE \
+       (IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | IEEE80211_C_AHDEMO | \
+        IEEE80211_C_MONITOR)
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct net_device *parent = ic->ic_dev;
+       int err;
+@@ -1355,7 +1355,7 @@ media_status(enum ieee80211_opmode opmod
+ static void
+ ieee80211com_media_status(struct net_device *dev, struct ifmediareq *imr)
+ {
+-      struct ieee80211com *ic = dev->priv;    /* XXX */
++      struct ieee80211com *ic = netdev_priv(dev);     /* XXX */
+       imr->ifm_status = IFM_AVALID;
+       if (!TAILQ_EMPTY(&ic->ic_vaps))
+@@ -1407,7 +1407,7 @@ media2mode(const struct ifmedia_entry *i
+ static int
+ ieee80211com_media_change(struct net_device *dev)
+ {
+-      struct ieee80211com *ic = dev->priv;    /* XXX */
++      struct ieee80211com *ic = netdev_priv(dev);     /* XXX */
+       struct ieee80211vap *vap;
+       struct ifmedia_entry *ime = ic->ic_media.ifm_cur;
+       enum ieee80211_phymode newphymode;
+@@ -1511,7 +1511,7 @@ checkrate(struct ieee80211com *ic, enum
+ int
+ ieee80211_media_change(struct net_device *dev)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ifmedia_entry *ime = vap->iv_media.ifm_cur;
+       enum ieee80211_phymode newmode;
+@@ -1545,7 +1545,7 @@ EXPORT_SYMBOL(ieee80211_media_change);
+ void
+ ieee80211_media_status(struct net_device *dev, struct ifmediareq *imr)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       enum ieee80211_phymode mode;
+       struct ieee80211_rateset *rs;
+@@ -1751,7 +1751,7 @@ EXPORT_SYMBOL(ieee80211_media2rate);
+ static struct net_device_stats *
+ ieee80211_getstats(struct net_device *dev)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct net_device_stats *stats = &vap->iv_devstats;
+       /* XXX: Total guess as to what to count where */
+@@ -1790,7 +1790,7 @@ ieee80211_change_mtu(struct net_device *
+ static void
+ ieee80211_set_multicast_list(struct net_device *dev)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct net_device *parent = ic->ic_dev;
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -183,7 +183,7 @@ EXPORT_SYMBOL(ieee80211_getmgtframe);
+ static void
+ ieee80211_vlan_register(struct net_device *dev, struct vlan_group *grp)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       vap->iv_vlgrp = grp;
+ }
+@@ -194,7 +194,7 @@ ieee80211_vlan_register(struct net_devic
+ static void
+ ieee80211_vlan_add_vid(struct net_device *dev, unsigned short vid)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       if (vap->iv_vlgrp != NULL)
+               vap->iv_bss->ni_vlan = vid;
+@@ -206,7 +206,7 @@ ieee80211_vlan_add_vid(struct net_device
+ static void
+ ieee80211_vlan_kill_vid(struct net_device *dev, unsigned short vid)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       if (vap->iv_vlgrp != NULL)
+               vlan_group_set_device(vap->iv_vlgrp, vid, NULL);
+@@ -989,8 +989,8 @@ ieee80211_rcv_dev_event(struct notifier_
+       switch (event) {
+       case NETDEV_CHANGENAME:
+-              ieee80211_virtfs_vdetach(dev->priv);
+-              ieee80211_virtfs_latevattach(dev->priv);
++              ieee80211_virtfs_vdetach(netdev_priv(dev));
++              ieee80211_virtfs_latevattach(netdev_priv(dev));
+               return NOTIFY_DONE;
+       default:
+               break;
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -201,7 +201,7 @@ ieee80211_classify(struct ieee80211_node
+ int
+ ieee80211_hardstart(struct sk_buff *skb, struct net_device *dev)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct net_device *parent = ic->ic_dev;
+       struct ieee80211_node *ni = NULL;
+@@ -317,7 +317,7 @@ bad:
+  */
+ void ieee80211_parent_queue_xmit(struct sk_buff *skb) {
+-      struct ieee80211vap *vap = skb->dev->priv;
++      struct ieee80211vap *vap = netdev_priv(skb->dev);
+       vap->iv_devstats.tx_packets++;
+       vap->iv_devstats.tx_bytes += skb->len;
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -970,7 +970,7 @@ ieee80211_init(struct net_device *dev, i
+ {
+ #define       IS_RUNNING(_dev) \
+       ((_dev->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP))
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct net_device *parent = ic->ic_dev;
+@@ -1087,7 +1087,7 @@ ieee80211_init(struct net_device *dev, i
+ int
+ ieee80211_open(struct net_device *dev)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       return ieee80211_init(dev, 0);
+ }
+@@ -1131,7 +1131,7 @@ EXPORT_SYMBOL(ieee80211_start_running);
+ int
+ ieee80211_stop(struct net_device *dev)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct net_device *parent = ic->ic_dev;
+       struct ieee80211_node *tni, *ni;
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -87,7 +87,7 @@ pre_announced_chanswitch(struct net_devi
+ static int
+ preempt_scan(struct net_device *dev, int max_grace, int max_wait)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       int total_delay = 0;
+       int canceled = 0, ready = 0;
+@@ -122,7 +122,7 @@ preempt_scan(struct net_device *dev, int
+ static struct iw_statistics *
+ ieee80211_iw_getstats(struct net_device *dev)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct iw_statistics *is = &vap->iv_iwstats;
+       struct ieee80211com *ic = vap->iv_ic;
+@@ -146,7 +146,7 @@ static int
+ ieee80211_ioctl_giwname(struct net_device *dev, struct iw_request_info *info,
+       char *name, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211_channel *c = vap->iv_ic->ic_curchan;
+       if (IEEE80211_IS_CHAN_108G(c))
+@@ -198,7 +198,7 @@ static int
+ ieee80211_ioctl_siwencode(struct net_device *dev,
+       struct iw_request_info *info, struct iw_point *erq, char *keybuf)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       int error;
+       int wepchange = 0;
+       ieee80211_keyix_t kix;
+@@ -306,7 +306,7 @@ static int
+ ieee80211_ioctl_giwencode(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *erq, char *key)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211_key *k;
+       int error;
+       ieee80211_keyix_t kix;
+@@ -351,7 +351,7 @@ ieee80211_ioctl_siwrate(struct net_devic
+               IFM_IEEE80211_11A | IFM_IEEE80211_TURBO,
+               IFM_IEEE80211_11G | IFM_IEEE80211_TURBO,
+       };
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ifreq ifr;
+       int rate, retv;
+@@ -386,7 +386,7 @@ static int
+ ieee80211_ioctl_giwrate(struct net_device *dev,       struct iw_request_info *info,
+       struct iw_param *rrq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ifmediareq imr;
+       int rate;
+@@ -424,7 +424,7 @@ static int
+ ieee80211_ioctl_siwrts(struct net_device *dev, struct iw_request_info *info,
+       struct iw_param *rts, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       u16 val;
+@@ -447,7 +447,7 @@ static int
+ ieee80211_ioctl_giwrts(struct net_device *dev, struct iw_request_info *info,
+       struct iw_param *rts, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       rts->value = vap->iv_rtsthreshold;
+       rts->disabled = (rts->value == IEEE80211_RTS_MAX);
+@@ -460,7 +460,7 @@ static int
+ ieee80211_ioctl_siwfrag(struct net_device *dev,       struct iw_request_info *info,
+       struct iw_param *rts, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       u16 val;
+@@ -483,7 +483,7 @@ static int
+ ieee80211_ioctl_giwfrag(struct net_device *dev,       struct iw_request_info *info,
+       struct iw_param *rts, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       rts->value = vap->iv_fragthreshold;
+       rts->disabled = (rts->value == 2346);
+@@ -496,7 +496,7 @@ static int
+ ieee80211_ioctl_siwap(struct net_device *dev, struct iw_request_info *info,
+       struct sockaddr *ap_addr, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       /* NB: should not be set when in AP mode */
+       if (vap->iv_opmode == IEEE80211_M_HOSTAP)
+@@ -532,7 +532,7 @@ static int
+ ieee80211_ioctl_giwap(struct net_device *dev, struct iw_request_info *info,
+       struct sockaddr *ap_addr, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       if (vap->iv_flags & IEEE80211_F_DESBSSID)
+               IEEE80211_ADDR_COPY(&ap_addr->sa_data, vap->iv_des_bssid);
+@@ -553,7 +553,7 @@ static int
+ ieee80211_ioctl_siwnickn(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *data, char *nickname)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       if (data->length > IEEE80211_NWID_LEN)
+               return -E2BIG;
+@@ -569,7 +569,7 @@ static int
+ ieee80211_ioctl_giwnickn(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *data, char *nickname)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       if (data->length > vap->iv_nicknamelen + 1)
+               data->length = vap->iv_nicknamelen + 1;
+@@ -678,7 +678,7 @@ static int
+ ieee80211_ioctl_siwfreq(struct net_device *dev, struct iw_request_info *info,
+       struct iw_freq *freq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_channel *c, *c2;
+       int i;
+@@ -767,7 +767,7 @@ static int
+ ieee80211_ioctl_giwfreq(struct net_device *dev, struct iw_request_info *info,
+       struct iw_freq *freq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       if (vap->iv_state == IEEE80211_S_RUN &&
+@@ -808,7 +808,7 @@ static int
+ ieee80211_ioctl_siwessid(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *data, char *ssid)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       if (vap->iv_opmode == IEEE80211_M_WDS)
+               return -EOPNOTSUPP;
+@@ -853,7 +853,7 @@ static int
+ ieee80211_ioctl_giwessid(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *data, char *essid)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       if (vap->iv_opmode == IEEE80211_M_WDS)
+               return -EOPNOTSUPP;
+@@ -899,7 +899,7 @@ static int
+ ieee80211_ioctl_giwrange(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *data, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_node *ni = vap->iv_bss;
+       struct iw_range *range = (struct iw_range *) extra;
+@@ -1047,7 +1047,7 @@ ieee80211_ioctl_setspy(struct net_device
+       struct iw_point *data, char *extra)
+ {
+       /* save the list of node addresses */
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct sockaddr address[IW_MAX_SPY];
+       unsigned int number = data->length;
+       int i;
+@@ -1085,7 +1085,7 @@ ieee80211_ioctl_getspy(struct net_device
+        * locate nodes by mac (ieee80211_find_node()),
+        * copy out rssi, set updated flag appropriately
+        */
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211_node_table *nt = &vap->iv_ic->ic_sta;
+       struct ieee80211_node *ni;
+       struct ieee80211com *ic = vap->iv_ic;
+@@ -1133,7 +1133,7 @@ static int
+ ieee80211_ioctl_setthrspy(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *data, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct iw_thrspy threshold;
+       if (data->length != 1)
+@@ -1170,7 +1170,7 @@ static int
+ ieee80211_ioctl_getthrspy(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *data, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct iw_thrspy *threshold;
+@@ -1191,7 +1191,7 @@ static int
+ ieee80211_ioctl_siwmode(struct net_device *dev, struct iw_request_info *info,
+       __u32 *mode, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ifmediareq imr;
+       int valid = 0;
+@@ -1216,7 +1216,7 @@ static int
+ ieee80211_ioctl_giwmode(struct net_device *dev,       struct iw_request_info *info,
+       __u32 *mode, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ifmediareq imr;
+       memset(&imr, 0, sizeof(imr));
+@@ -1239,7 +1239,7 @@ static int
+ ieee80211_ioctl_siwpower(struct net_device *dev, struct iw_request_info *info,
+       struct iw_param *wrq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       /* XXX: These values, flags, and caps do not seem to be used elsewhere 
+@@ -1278,7 +1278,7 @@ static int
+ ieee80211_ioctl_giwpower(struct net_device *dev, struct iw_request_info *info,
+       struct iw_param *rrq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       rrq->disabled = (ic->ic_flags & IEEE80211_F_PMGTON) == 0;
+@@ -1302,7 +1302,7 @@ static int
+ ieee80211_ioctl_siwretry(struct net_device *dev, struct iw_request_info *info,
+       struct iw_param *rrq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       if (rrq->disabled) {
+@@ -1334,7 +1334,7 @@ static int
+ ieee80211_ioctl_giwretry(struct net_device *dev, struct iw_request_info *info,
+       struct iw_param *rrq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       rrq->disabled = (vap->iv_flags & IEEE80211_F_SWRETRY) == 0;
+       if (!rrq->disabled) {
+@@ -1365,7 +1365,7 @@ static int
+ ieee80211_ioctl_siwtxpow(struct net_device *dev, struct iw_request_info *info,
+       struct iw_param *rrq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       int fixed, disabled;
+@@ -1402,7 +1402,7 @@ ieee80211_get_txcont(struct net_device *
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       params[0] = ic->ic_get_txcont(ic);
+       return 0;
+@@ -1413,7 +1413,7 @@ ieee80211_get_dfs_cac_time(struct net_de
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       params[0] = ic->ic_get_dfs_cac_time(ic);
+       return 0;
+@@ -1424,7 +1424,7 @@ ieee80211_get_dfs_excl_period(struct net
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       params[0] = ic->ic_get_dfs_excl_period(ic);
+       return 0;
+@@ -1434,7 +1434,7 @@ ieee80211_set_dfs_cac_time(struct net_de
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       ic->ic_set_dfs_cac_time(ic, params[1]);
+       return 0;
+@@ -1444,7 +1444,7 @@ ieee80211_set_dfs_excl_period  (struct n
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       ic->ic_set_dfs_excl_period(ic, params[1]);
+       return 0;
+@@ -1455,7 +1455,7 @@ ieee80211_get_dfs_testmode(struct net_de
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       params[0] = ic->ic_get_dfs_testmode(ic);
+       return 0;
+@@ -1466,7 +1466,7 @@ ieee80211_get_txcont_rate(struct net_dev
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       params[0] = ic->ic_get_txcont_rate(ic);
+       return 0;
+@@ -1477,7 +1477,7 @@ ieee80211_set_txcont(struct net_device *
+               void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       ic->ic_set_txcont(ic, params[1]);
+       return 0;
+@@ -1488,7 +1488,7 @@ ieee80211_set_dfs_testmode(struct net_de
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       ic->ic_set_dfs_testmode(ic, params[1]);
+       return 0;
+@@ -1499,7 +1499,7 @@ ieee80211_set_txcont_rate(struct net_dev
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       ic->ic_set_txcont_rate(ic, params[1]);
+       return 0;
+@@ -1510,7 +1510,7 @@ ieee80211_set_txcont_power(struct net_de
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       ic->ic_set_txcont_power(ic, params[1]);
+       return 0;
+@@ -1521,7 +1521,7 @@ ieee80211_get_txcont_power(struct net_de
+               struct iw_request_info *info, void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       params[0] = ic->ic_get_txcont_power(ic);
+       return 0;
+@@ -1533,7 +1533,7 @@ ieee80211_ioctl_hal_map(struct net_devic
+        void *w, char *extra)
+ {
+        int *params = (int*) extra;
+-       struct ieee80211vap *vap = dev->priv;
++       struct ieee80211vap *vap = netdev_priv(dev);
+        struct ieee80211com *ic = vap->iv_ic;
+        params[0] = ic->ic_dump_hal_map(ic);
+        return 0;
+@@ -1545,7 +1545,7 @@ ieee80211_ioctl_radar(struct net_device
+       void *w, char *extra)
+ {
+       int *params = (int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       if (!(ic->ic_flags & IEEE80211_F_DOTH))
+               return 0;
+@@ -1557,7 +1557,7 @@ static int
+ ieee80211_ioctl_giwtxpow(struct net_device *dev, struct iw_request_info *info,
+       struct iw_param *rrq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       unsigned int power = ic->ic_txpowlimit;
+       struct ieee80211_channel *c;
+@@ -1581,7 +1581,7 @@ static int
+ ieee80211_dump_registers(struct net_device *dev, struct iw_request_info *info, void *w, char *extra)
+ {
+       unsigned int *params = (unsigned int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       switch (params[1]) {
+       case 2:
+@@ -1604,7 +1604,7 @@ static int
+ ieee80211_ioctl_writereg(struct net_device *dev, struct iw_request_info *info, void *w, char *extra)
+ {
+       unsigned int *params = (unsigned int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       return ic->ic_write_register(ic, params[0], params[1]);
+ }
+@@ -1615,7 +1615,7 @@ static int
+ ieee80211_ioctl_readreg(struct net_device *dev, struct iw_request_info *info, void *w, char *extra)
+ {
+       unsigned int *params = (unsigned int*) extra;
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       return ic->ic_read_register(ic, params[0], &params[0]);
+ }
+@@ -1651,7 +1651,7 @@ static int
+ ieee80211_ioctl_iwaplist(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *data, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct waplistreq req;          /* XXX off stack */
+@@ -1673,7 +1673,7 @@ static int
+ ieee80211_ioctl_siwscan(struct net_device *dev,       struct iw_request_info *info,
+       struct iw_point *data, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       /*
+        * XXX don't permit a scan to be started unless we
+@@ -1997,7 +1997,7 @@ static int
+ ieee80211_ioctl_giwscan(struct net_device *dev,       struct iw_request_info *info,
+       struct iw_point *data, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct iwscanreq req;
+       int res = 0;
+@@ -2098,7 +2098,7 @@ static int
+ ieee80211_ioctl_setmode(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *wri, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ifreq ifr;
+       char s[6];              /* big enough for ``11adt'' */
+@@ -2222,10 +2222,10 @@ ieee80211_setathcap(struct ieee80211vap
+ static int
+ ieee80211_set_turbo(struct net_device *dev, int flag)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ifreq ifr;
+-      struct ieee80211vap *tmpvap = dev->priv;
++      struct ieee80211vap *tmpvap = netdev_priv(dev);
+       int nvap = 0;
+       TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next)
+@@ -2246,7 +2246,7 @@ static int
+ ieee80211_ioctl_setparam(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_rsnparms *rsn = &vap->iv_bss->ni_rsn;
+       unsigned int *i = (unsigned int *) extra;
+@@ -2926,7 +2926,7 @@ static int
+ ieee80211_ioctl_getmode(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *wri, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ifmediareq imr;
+@@ -2964,7 +2964,7 @@ static int
+ ieee80211_ioctl_getparam(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_rsnparms *rsn = &vap->iv_bss->ni_rsn;
+       unsigned int *param = (unsigned int *) extra;
+@@ -3309,7 +3309,7 @@ static int
+ ieee80211_ioctl_setoptie(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *wri, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       void *ie;
+       /*
+@@ -3343,7 +3343,7 @@ static int
+ ieee80211_ioctl_getoptie(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *wri, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       if (vap->iv_opt_ie == NULL) {
+               wri->length = 0;
+@@ -3407,7 +3407,7 @@ ieee80211_ioctl_setappiebuf(struct net_d
+       struct iw_request_info *info,
+       struct iw_point *data, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211req_getset_appiebuf *iebuf =
+               (struct ieee80211req_getset_appiebuf *)extra;
+       enum ieee80211_opmode chk_opmode;
+@@ -3449,7 +3449,7 @@ static int
+ ieee80211_ioctl_getappiebuf(struct net_device *dev, struct iw_request_info *info,
+       struct iw_point *data, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211req_getset_appiebuf *iebuf =
+               (struct ieee80211req_getset_appiebuf *)extra;
+       int max_iebuf_len;
+@@ -3490,7 +3490,7 @@ static int
+ ieee80211_ioctl_setfilter(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211req_set_filter *app_filter = (struct ieee80211req_set_filter *)extra;
+       if ((extra == NULL) || (app_filter->app_filterype & ~IEEE80211_FILTER_TYPE_ALL))
+@@ -3505,7 +3505,7 @@ static int
+ ieee80211_ioctl_setkey(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211req_key *ik = (struct ieee80211req_key *)extra;
+       struct ieee80211_node *ni;
+@@ -3588,7 +3588,7 @@ ieee80211_ioctl_setkey(struct net_device
+ static int
+ ieee80211_ioctl_getkey(struct net_device *dev, struct iwreq *iwr)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_node *ni;
+       struct ieee80211req_key ik;
+@@ -3649,7 +3649,7 @@ static int
+ ieee80211_ioctl_delkey(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211req_del_key *dk = (struct ieee80211req_del_key *)extra;
+       ieee80211_keyix_t kix;
+@@ -3723,7 +3723,7 @@ static int
+ ieee80211_ioctl_setmlme(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211req_mlme *mlme = (struct ieee80211req_mlme *)extra;
+       struct ieee80211_node *ni;
+@@ -3826,7 +3826,7 @@ static int
+ ieee80211_ioctl_wdsaddmac(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct sockaddr *sa = (struct sockaddr *)extra;
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211vap *avp;
+@@ -3855,7 +3855,7 @@ static int
+ ieee80211_ioctl_wdssetmac(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct sockaddr *sa = (struct sockaddr *)extra;
+       if (vap->iv_opmode != IEEE80211_M_WDS)
+@@ -3922,7 +3922,7 @@ ieee80211_ioctl_setscanlist(struct net_d
+       struct iw_request_info *info,
+       struct iw_point *data, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       char *s, *next;
+       int val = 1;
+@@ -3997,7 +3997,7 @@ static int
+ ieee80211_ioctl_addmac(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct sockaddr *sa = (struct sockaddr *)extra;
+       const struct ieee80211_aclator *acl = vap->iv_acl;
+@@ -4015,7 +4015,7 @@ static int
+ ieee80211_ioctl_delmac(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct sockaddr *sa = (struct sockaddr *)extra;
+       const struct ieee80211_aclator *acl = vap->iv_acl;
+@@ -4033,7 +4033,7 @@ static int
+ ieee80211_ioctl_setchanlist(struct net_device *dev,
+       struct iw_request_info *info, void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211req_chanlist *list =
+               (struct ieee80211req_chanlist *)extra;
+@@ -4084,7 +4084,7 @@ static int
+ ieee80211_ioctl_getchanlist(struct net_device *dev,
+       struct iw_request_info *info, void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       memcpy(extra, ic->ic_chan_active, sizeof(ic->ic_chan_active));
+@@ -4105,7 +4105,7 @@ static int
+ ieee80211_ioctl_getchaninfo(struct net_device *dev,
+                           struct iw_request_info *info, void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211req_chaninfo *chans =
+           (struct ieee80211req_chaninfo *)extra;
+@@ -4152,7 +4152,7 @@ static int
+ ieee80211_ioctl_setwmmparams(struct net_device *dev,
+       struct iw_request_info *info, void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       unsigned int *param = (unsigned int *) extra;
+       unsigned int ac = (param[1] < WME_NUM_AC) ? param[1] : WME_AC_BE;
+       unsigned int bss = param[2];
+@@ -4240,7 +4240,7 @@ static int
+ ieee80211_ioctl_getwmmparams(struct net_device *dev,
+       struct iw_request_info *info, void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       unsigned int *param = (unsigned int *) extra;
+       unsigned int ac = (param[1] < WME_NUM_AC) ? param[1] : WME_AC_BE;
+       struct ieee80211_wme_state *wme = &vap->iv_ic->ic_wme;
+@@ -4275,7 +4275,7 @@ ieee80211_ioctl_getwmmparams(struct net_
+ static int
+ ieee80211_ioctl_getwpaie(struct net_device *dev, struct iwreq *iwr)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_node *ni;
+       struct ieee80211req_wpaie wpaie;
+@@ -4309,7 +4309,7 @@ ieee80211_ioctl_getwpaie(struct net_devi
+ static int
+ ieee80211_ioctl_getstastats(struct net_device *dev, struct iwreq *iwr)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_node *ni;
+       u_int8_t macaddr[IEEE80211_ADDR_LEN];
+@@ -4428,7 +4428,7 @@ get_scan_result(void *arg, const struct
+ static int
+ ieee80211_ioctl_getscanresults(struct net_device *dev, struct iwreq *iwr)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct scanreq req;
+       int error;
+@@ -4591,7 +4591,7 @@ get_sta_info(void *arg, struct ieee80211
+ static int
+ ieee80211_ioctl_getstainfo(struct net_device *dev, struct iwreq *iwr)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct stainforeq req;
+       int error;
+@@ -4625,7 +4625,7 @@ ieee80211_ioctl_getstainfo(struct net_de
+ static void
+ pre_announced_chanswitch(struct net_device *dev, u_int32_t channel, u_int32_t tbtt) {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211vap *avp;
+@@ -4643,7 +4643,7 @@ static int
+ ieee80211_ioctl_chanswitch(struct net_device *dev, struct iw_request_info *info,
+       void *w, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       unsigned int *param = (unsigned int *) extra;
+@@ -4688,7 +4688,7 @@ static int
+ ieee80211_ioctl_giwgenie(struct net_device *dev,
+       struct iw_request_info *info, struct iw_point *out, char *buf)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       if (out->length < vap->iv_opt_ie_len)
+               return -E2BIG;
+@@ -5221,7 +5221,7 @@ static int
+ ieee80211_ioctl_giwencodeext(struct net_device *dev,
+       struct iw_request_info *info, struct iw_point *erq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct iw_encode_ext *ext;
+       struct ieee80211_key *wk;
+       ieee80211_keyix_t kix;
+@@ -5281,7 +5281,7 @@ static int
+ ieee80211_ioctl_siwencodeext(struct net_device *dev,
+       struct iw_request_info *info, struct iw_point *erq, char *extra)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       struct ieee80211req_key kr;
+       ieee80211_keyix_t kix;
+@@ -5957,7 +5957,7 @@ static struct iw_handler_def ieee80211_i
+ static int
+ ieee80211_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+-      struct ieee80211vap *vap = dev->priv;
++      struct ieee80211vap *vap = netdev_priv(dev);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_node *ni;
diff --git a/net/madwifi/patches/431-compile_fixes.patch b/net/madwifi/patches/431-compile_fixes.patch
new file mode 100644 (file)
index 0000000..b11d406
--- /dev/null
@@ -0,0 +1,35 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -2388,7 +2388,9 @@ ath_intr(int irq, void *dev_id, struct p
+               if (status & (HAL_INT_RX | HAL_INT_RXPHY)) {
+                       ath_uapsd_processtriggers(sc, hw_tsf);
+                       sc->sc_isr &= ~HAL_INT_RX;
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
++                      if (napi_schedule_prep(&sc->sc_napi))
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+                       if (netif_rx_schedule_prep(dev, &sc->sc_napi))
+ #else
+                       if (netif_rx_schedule_prep(dev))
+@@ -2396,7 +2398,9 @@ ath_intr(int irq, void *dev_id, struct p
+                       {
+                               sc->sc_imask &= ~HAL_INT_RX;
+                               ath_hal_intrset(ah, sc->sc_imask);
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
++                              __napi_schedule(&sc->sc_napi);
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+                               __netif_rx_schedule(dev, &sc->sc_napi);
+ #else
+                               __netif_rx_schedule(dev);
+@@ -7135,7 +7139,9 @@ rx_next:
+               local_irq_restore(flags);
+       }
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
++      napi_complete(napi);
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+       netif_rx_complete(dev, napi);
+ #else
+       netif_rx_complete(dev);
diff --git a/net/madwifi/patches/432-netdev_ops.patch b/net/madwifi/patches/432-netdev_ops.patch
new file mode 100644 (file)
index 0000000..af829b1
--- /dev/null
@@ -0,0 +1,184 @@
+Convert to net_device_ops for Linux 2.6.29+
+http://madwifi-project.org/changeset/4005
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -566,6 +566,20 @@ static inline int rate_factor(int mode)
+ /* Initialize ath_softc structure */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
++static const struct net_device_ops ath_netdev_ops = {
++      .ndo_open               = ath_init,
++      .ndo_stop               = ath_stop,
++      .ndo_start_xmit         = ath_hardstart,
++      .ndo_tx_timeout         = ath_tx_timeout,
++      .ndo_set_multicast_list = ath_mode_init,
++      .ndo_do_ioctl           = ath_ioctl,
++      .ndo_get_stats          = ath_getstats,
++      .ndo_set_mac_address    = ath_set_mac_address,
++      .ndo_change_mtu         = ath_change_mtu,
++};
++#endif
++
+ int
+ ath_attach(u_int16_t devid, struct net_device *dev, HAL_BUS_TAG tag)
+ {
+@@ -865,16 +879,20 @@ ath_attach(u_int16_t devid, struct net_d
+       }
+       /* NB: ether_setup is done by bus-specific code */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+       dev->open = ath_init;
+       dev->stop = ath_stop;
+       dev->hard_start_xmit = ath_hardstart;
+       dev->tx_timeout = ath_tx_timeout;
+-      dev->watchdog_timeo = 5 * HZ;
+       dev->set_multicast_list = ath_mode_init;
+       dev->do_ioctl = ath_ioctl;
+       dev->get_stats = ath_getstats;
+       dev->set_mac_address = ath_set_mac_address;
+       dev->change_mtu = ath_change_mtu;
++#else
++      dev->netdev_ops = &ath_netdev_ops;
++#endif
++      dev->watchdog_timeo = 5 * HZ;
+       dev->tx_queue_len = ATH_TXBUF - ATH_TXBUF_MGT_RESERVED;
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+       netif_napi_add(dev, &sc->sc_napi, ath_rx_poll, 64);
+@@ -1257,7 +1275,6 @@ ath_detach(struct net_device *dev)
+       ath_dynamic_sysctl_unregister(sc);
+       ATH_LOCK_DESTROY(sc);
+       ATH_HAL_LOCK_DESTROY(sc);
+-      dev->stop = NULL; /* prevent calling ath_stop again */
+       unregister_netdev(dev);
+       return 0;
+ }
+@@ -12732,8 +12749,13 @@ ath_rcv_dev_event(struct notifier_block
+       struct net_device *dev = (struct net_device *)ptr;
+       struct ath_softc *sc = (struct ath_softc *)netdev_priv(dev);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+       if (!dev || !sc || dev->open != &ath_init)
+               return 0;
++#else
++      if (!dev || !sc || dev->netdev_ops->ndo_open != &ath_init)
++              return 0;
++#endif
+       switch (event) {
+       case NETDEV_CHANGENAME:
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -451,6 +451,18 @@ ieee80211_ifdetach(struct ieee80211com *
+ }
+ EXPORT_SYMBOL(ieee80211_ifdetach);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
++static const struct net_device_ops ieee80211_netdev_ops = {
++      .ndo_get_stats          = ieee80211_getstats,
++      .ndo_open               = ieee80211_open,
++      .ndo_stop               = ieee80211_stop,
++      .ndo_start_xmit         = ieee80211_hardstart,
++      .ndo_set_multicast_list = ieee80211_set_multicast_list,
++      .ndo_change_mtu         = ieee80211_change_mtu,
++      .ndo_do_ioctl           = ieee80211_ioctl,
++};
++#endif
++
+ int
+ ieee80211_vap_setup(struct ieee80211com *ic, struct net_device *dev,
+       const char *name, int opmode, int flags, struct ieee80211vap *master)
+@@ -471,16 +483,21 @@ ieee80211_vap_setup(struct ieee80211com
+               } else
+                       strncpy(dev->name, name, sizeof(dev->name));
+       }
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+       dev->get_stats = ieee80211_getstats;
+       dev->open = ieee80211_open;
+       dev->stop = ieee80211_stop;
+       dev->hard_start_xmit = ieee80211_hardstart;
+       dev->set_multicast_list = ieee80211_set_multicast_list;
++      dev->do_ioctl = ieee80211_ioctl;
+ #if 0
+       dev->set_mac_address = ieee80211_set_mac_address;
+ #endif
+       dev->change_mtu = ieee80211_change_mtu;
++#else
++      dev->netdev_ops = &ieee80211_netdev_ops;
++#endif
+       dev->tx_queue_len = 0;                  /* NB: bypass queuing */
+       dev->hard_header_len = parent->hard_header_len;
+       /*
+@@ -1824,7 +1841,11 @@ ieee80211_set_multicast_list(struct net_
+       IEEE80211_UNLOCK_IRQ(ic);
+       /* XXX: Merge multicast list into parent device */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+       parent->set_multicast_list(ic->ic_dev);
++#else
++      parent->netdev_ops->ndo_set_multicast_list(ic->ic_dev);
++#endif
+ }
+ void
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -984,8 +984,14 @@ ieee80211_rcv_dev_event(struct notifier_
+       void *ptr)
+ {
+       struct net_device *dev = (struct net_device *) ptr;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+       if (!dev || dev->open != &ieee80211_open)
+               return 0;
++#else
++      if (!dev || dev->netdev_ops->ndo_open != &ieee80211_open)
++              return 0;
++#endif
+       switch (event) {
+       case NETDEV_CHANGENAME:
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -739,6 +739,7 @@ void ieee80211_build_sc_ie(struct ieee80
+ void ieee80211_dfs_action(struct ieee80211com *);
+ void ieee80211_expire_channel_excl_restrictions(struct ieee80211com *);
+ void ieee80211_setpuregbasicrates(struct ieee80211_rateset *rs);
++int ieee80211_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+ /*
+  * Iterate through ic_channels to enumerate all distinct ic_ieee channel numbers.
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -5954,7 +5954,7 @@ static struct iw_handler_def ieee80211_i
+ /*
+  * Handle private ioctl requests.
+  */
+-static int
++int
+ ieee80211_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+       struct ieee80211vap *vap = netdev_priv(dev);
+@@ -6044,7 +6044,6 @@ ieee80211_ioctl_vattach(struct ieee80211
+ {
+       struct net_device *dev = vap->iv_dev;
+-      dev->do_ioctl = ieee80211_ioctl;
+ #if IW_HANDLER_VERSION < 7
+       dev->get_wireless_stats = ieee80211_iw_getstats;
+ #endif
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1188,7 +1188,11 @@ ieee80211_deliver_data(struct ieee80211_
+                       skb1->protocol = __constant_htons(ETH_P_802_2);
+                       /* XXX insert vlan tag before queue it? */
+                       ni_tmp = SKB_CB(skb1)->ni; /* remember node so we can free it */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+                       ret = dev->hard_start_xmit(skb1, dev);
++#else
++                      ret = dev->netdev_ops->ndo_start_xmit(skb1, dev);
++#endif
+                       if (ret == NETDEV_TX_BUSY)
+                               ieee80211_dev_kfree_skb(&skb1);
diff --git a/net/madwifi/patches/433-backport_remove_irq_none.patch b/net/madwifi/patches/433-backport_remove_irq_none.patch
new file mode 100644 (file)
index 0000000..5166d9e
--- /dev/null
@@ -0,0 +1,21 @@
+Fix Linux 2.6.30 compatibility
+
+Linux 2.6.30 doesn't define IRQ_NONE as a macro. Assume irqreturn_t,
+IRQ_NONE and IRQ_HANDLED to be present on Linux 2.6.29 and newer.
+http://madwifi-project.org/changeset/3986
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -83,11 +83,13 @@ typedef void *TQUEUE_ARG;
+ /*
+  * Guess how the interrupt handler should work.
+  */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ #if !defined(IRQ_NONE)
+ typedef void irqreturn_t;
+ #define       IRQ_NONE
+ #define       IRQ_HANDLED
+ #endif /* !defined(IRQ_NONE) */
++#endif /* Linux < 2.6.29 */
+ #ifndef SET_MODULE_OWNER
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
diff --git a/net/madwifi/patches/434-name-alloc-fix.patch b/net/madwifi/patches/434-name-alloc-fix.patch
new file mode 100644 (file)
index 0000000..ab27763
--- /dev/null
@@ -0,0 +1,28 @@
+--- a/ath/if_ath_ahb.c
++++ b/ath/if_ath_ahb.c
+@@ -311,6 +311,11 @@ init_ath_wmac(u_int16_t devid, u_int16_t
+       SET_MODULE_OWNER(dev);
+       sclist[wlanNum] = sc;
++      if (dev_alloc_name(dev, dev->name) < 0) {
++              printk(KERN_ERR "%s: cannot allocate name\n", dev_info);
++              goto bad3;
++      }
++
+       switch (wlanNum) {
+       case AR531X_WLAN0_NUM:
+               if (((devid & AR5315_REV_MAJ_M) == AR5315_REV_MAJ) ||
+--- a/ath/if_ath_pci.c
++++ b/ath/if_ath_pci.c
+@@ -236,6 +236,11 @@ ath_pci_probe(struct pci_dev *pdev, cons
+        */
+       sc->aps_sc.sc_invalid = 1;
++      if (dev_alloc_name(dev, dev->name) < 0) {
++              printk(KERN_ERR "%s: cannot allocate name\n", dev_info);
++              goto bad3;
++      }
++
+       dev->irq = pdev->irq;
+       SET_MODULE_OWNER(dev);
diff --git a/net/madwifi/patches/435-ibss_neighbor_fix.patch b/net/madwifi/patches/435-ibss_neighbor_fix.patch
new file mode 100644 (file)
index 0000000..d66af9b
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -313,7 +313,7 @@ ieee80211_input(struct ieee80211vap * va
+                       if (type == IEEE80211_FC0_TYPE_DATA && ni == vap->iv_bss &&
+                                       !IEEE80211_ADDR_EQ(vap->iv_bss->ni_macaddr, wh->i_addr2)) {
+                               /* Try to find sender in local node table. */
+-                              ni = ieee80211_find_node(vap->iv_bss->ni_table, wh->i_addr2);
++                              ni = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
+                               if (ni == NULL) {
+                                       /*
+                                        * Fake up a node for this newly discovered
diff --git a/net/madwifi/patches/436-injection_checks.patch b/net/madwifi/patches/436-injection_checks.patch
new file mode 100644 (file)
index 0000000..2748731
--- /dev/null
@@ -0,0 +1,26 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -3199,7 +3199,13 @@ ath_tx_startraw(struct net_device *dev,
+       struct ieee80211_frame *wh;
+       wh = (struct ieee80211_frame *)skb->data;
++
+       try0 = ph->try0;
++      if (!try0)
++              try0 = 1;
++      else if (try0 > 11)
++              try0 = 11;
++
+       rt = sc->sc_currates;
+       txrate = dot11_to_ratecode(sc, rt, ph->rate0);
+       power = ph->power > 63 ? 63 : ph->power;
+@@ -3224,7 +3230,8 @@ ath_tx_startraw(struct net_device *dev,
+       rt = sc->sc_currates;
+       KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+-      if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
++      if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) ||
++              IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+               flags |= HAL_TXDESC_NOACK;      /* no ack on broad/multicast */
+               sc->sc_stats.ast_tx_noack++;
+               try0 = 1;
diff --git a/net/madwifi/patches/437-sysctl_cleanup.patch b/net/madwifi/patches/437-sysctl_cleanup.patch
new file mode 100644 (file)
index 0000000..e35ed02
--- /dev/null
@@ -0,0 +1,73 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -11021,38 +11021,38 @@ enum {
+  * mirrored in /proc/sys.
+  */
+ enum {
+-      ATH_SLOTTIME            = 1,
+-      ATH_ACKTIMEOUT          = 2,
+-      ATH_CTSTIMEOUT          = 3,
+-      ATH_SOFTLED             = 4,
+-      ATH_LEDPIN              = 5,
+-      ATH_COUNTRYCODE         = 6,
+-      ATH_REGDOMAIN           = 7,
+-      ATH_DEBUG               = 8,
+-      ATH_TXANTENNA           = 9,
+-      ATH_RXANTENNA           = 10,
+-      ATH_DIVERSITY           = 11,
+-      ATH_TXINTRPERIOD        = 12,
+-      ATH_FFTXQMIN            = 13,
+-      ATH_XR_POLL_PERIOD      = 14,
+-      ATH_XR_POLL_COUNT       = 15,
+-      ATH_ACKRATE             = 16,
+-      ATH_RP                  = 17,
+-      ATH_RP_PRINT            = 18,
+-      ATH_RP_PRINT_ALL        = 19,
+-      ATH_RP_PRINT_MEM        = 20,
+-      ATH_RP_PRINT_MEM_ALL    = 21,
+-      ATH_RP_FLUSH            = 22,
+-      ATH_PANIC               = 23,
+-      ATH_RP_IGNORED          = 24,
+-      ATH_RADAR_IGNORED       = 25,
+-      ATH_MAXVAPS             = 26,
+-      ATH_INTMIT                      = 27,
+-      ATH_NOISE_IMMUNITY      = 28,
+-      ATH_OFDM_WEAK_DET       = 29,
+-      ATH_CHANBW              = 30,
+-      ATH_OUTDOOR             = 31,
+-      ATH_DISTANCE    = 32,
++      ATH_SLOTTIME,
++      ATH_ACKTIMEOUT,
++      ATH_CTSTIMEOUT,
++      ATH_SOFTLED,
++      ATH_LEDPIN,
++      ATH_COUNTRYCODE,
++      ATH_REGDOMAIN,
++      ATH_DEBUG,
++      ATH_TXANTENNA,
++      ATH_RXANTENNA,
++      ATH_DIVERSITY,
++      ATH_TXINTRPERIOD,
++      ATH_FFTXQMIN,
++      ATH_XR_POLL_PERIOD,
++      ATH_XR_POLL_COUNT,
++      ATH_ACKRATE,
++      ATH_RP,
++      ATH_RP_PRINT,
++      ATH_RP_PRINT_ALL,
++      ATH_RP_PRINT_MEM,
++      ATH_RP_PRINT_MEM_ALL,
++      ATH_RP_FLUSH,
++      ATH_PANIC,
++      ATH_RP_IGNORED,
++      ATH_RADAR_IGNORED,
++      ATH_MAXVAPS,
++      ATH_INTMIT,
++      ATH_NOISE_IMMUNITY,
++      ATH_OFDM_WEAK_DET,
++      ATH_CHANBW,
++      ATH_OUTDOOR,
++      ATH_DISTANCE,
+ };
+ /*
diff --git a/net/madwifi/patches/438-poweroffset_sysctl.patch b/net/madwifi/patches/438-poweroffset_sysctl.patch
new file mode 100644 (file)
index 0000000..e82046e
--- /dev/null
@@ -0,0 +1,59 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -10476,11 +10476,11 @@ set_node_txpower(void *arg, struct ieee8
+  * XXX: this function needs some locking to avoid being called 
+  * twice/interrupted. Returns the value actually stored. */
+ static u_int32_t
+-ath_set_clamped_maxtxpower(struct ath_softc *sc, 
+-              u_int32_t new_clamped_maxtxpower)
++ath_set_clamped_maxtxpower(struct ath_softc *sc, u_int32_t new_txpwr)
+ {
+-      new_clamped_maxtxpower -= sc->sc_poweroffset;
+-      (void)ath_hal_settxpowlimit(sc->sc_ah, new_clamped_maxtxpower);
++      new_txpwr = ((new_txpwr < sc->sc_poweroffset) ? 0 :
++              new_txpwr - sc->sc_poweroffset);
++      (void)ath_hal_settxpowlimit(sc->sc_ah, new_txpwr);
+       return ath_get_clamped_maxtxpower(sc);
+ }
+@@ -11031,6 +11031,7 @@ enum {
+       ATH_DEBUG,
+       ATH_TXANTENNA,
+       ATH_RXANTENNA,
++      ATH_POWEROFFSET,
+       ATH_DIVERSITY,
+       ATH_TXINTRPERIOD,
+       ATH_FFTXQMIN,
+@@ -11311,6 +11312,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+                               ath_debug_global = (val &  ATH_DEBUG_GLOBAL);
+ #endif
+                               break;
++                      case ATH_POWEROFFSET:
++                              sc->sc_poweroffset = val;
++                              break;
+                       case ATH_TXANTENNA:
+                               /*
+                                * antenna can be:
+@@ -11478,6 +11482,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+               case ATH_DEBUG:
+                       val = sc->sc_debug | ath_debug_global;
+                       break;
++              case ATH_POWEROFFSET:
++                      val = sc->sc_poweroffset;
++                      break;
+               case ATH_TXANTENNA:
+                       val = sc->sc_txantenna;
+                       break;
+@@ -11619,6 +11626,12 @@ static const ctl_table ath_sysctl_templa
+       },
+ #endif
+       { .ctl_name     = CTL_AUTO,
++        .procname     = "poweroffset",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_halparam,
++        .extra2       = (void *)ATH_POWEROFFSET,
++      },
++      { .ctl_name     = CTL_AUTO,
+         .procname     = "txantenna",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
diff --git a/net/madwifi/patches/439-wlanconfig_stack_usage.patch b/net/madwifi/patches/439-wlanconfig_stack_usage.patch
new file mode 100644 (file)
index 0000000..f346143
--- /dev/null
@@ -0,0 +1,20 @@
+--- a/tools/wlanconfig.c
++++ b/tools/wlanconfig.c
+@@ -560,7 +560,7 @@ ieee80211_ntoa(const uint8_t mac[IEEE802
+ static void
+ list_stations(const char *ifname)
+ {
+-      uint8_t buf[24*1024];
++      static uint8_t buf[24*1024];
+       struct iwreq iwr;
+       uint8_t *cp;
+       int s, len;
+@@ -653,7 +653,7 @@ list_stations(const char *ifname)
+ static void
+ list_scan(const char *ifname)
+ {
+-      uint8_t buf[24 * 1024];
++      static uint8_t buf[24 * 1024];
+       char ssid[14];
+       uint8_t *cp;
+       int len;
diff --git a/net/madwifi/patches/440-wme_cleanup.patch b/net/madwifi/patches/440-wme_cleanup.patch
new file mode 100644 (file)
index 0000000..bb81ac7
--- /dev/null
@@ -0,0 +1,136 @@
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -73,6 +73,29 @@ doprint(struct ieee80211vap *vap, int su
+ }
+ #endif
++static const int ieee802_1d_to_ac[8] = {
++      WME_AC_BE, WME_AC_BK, WME_AC_BK, WME_AC_BE,
++      WME_AC_VI, WME_AC_VI, WME_AC_VO, WME_AC_VO
++};
++
++/* Given a data frame determine the 802.1p/1d tag to use. */
++static unsigned int ieee80211_classify_ip(struct sk_buff *skb)
++{
++      const struct ether_header *eh = (struct ether_header *) skb->data;
++      const struct iphdr *ip = (struct iphdr *)
++                      (skb->data + sizeof (struct ether_header));
++      unsigned int dscp;
++
++      switch (skb->protocol) {
++      case __constant_htons(ETH_P_IP):
++              dscp = ip->tos & 0xfc;
++              break;
++      default:
++              return 0;
++      }
++
++      return dscp >> 5;
++}
+ /*
+  * Determine the priority based on VLAN and/or IP TOS. Priority is
+@@ -83,90 +106,24 @@ static int
+ ieee80211_classify(struct ieee80211_node *ni, struct sk_buff *skb)
+ {
+       struct ieee80211vap *vap = ni->ni_vap;
+-      struct ether_header *eh = (struct ether_header *) skb->data;
+-      int v_wme_ac = 0, d_wme_ac = 0;
+-      /* default priority */
+-      skb->priority = WME_AC_BE;
+-
+-      if (!(ni->ni_flags & IEEE80211_NODE_QOS))
+-              return 0;
+-
+-      /* 
+-       * If node has a vlan tag then all traffic
+-       * to it must have a matching vlan id.
++      /* skb->priority values from 256->263 are magic values to
++       * directly indicate a specific 802.1d priority.  This is used
++       * to allow 802.1d priority to be passed directly in from VLAN
++       * tags, etc.
+        */
+-      if (ni->ni_vlan != 0 && vlan_tx_tag_present(skb)) {
+-              u_int32_t tag=0;
+-              int v_pri;
+-
+-              if (vap->iv_vlgrp == NULL) {
+-                      IEEE80211_NODE_STAT(ni, tx_novlantag);
+-                      ni->ni_stats.ns_tx_novlantag++;
+-                      return 1;
+-              }
+-              if (((tag = vlan_tx_tag_get(skb)) & VLAN_VID_MASK) !=
+-                  (ni->ni_vlan & VLAN_VID_MASK)) {
+-                      IEEE80211_NODE_STAT(ni, tx_vlanmismatch);
+-                      ni->ni_stats.ns_tx_vlanmismatch++;
+-                      return 1;
+-              }
+-              if (ni->ni_flags & IEEE80211_NODE_QOS) {
+-                      v_pri = (tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
+-                      switch (v_pri) {
+-                      case 1:
+-                      case 2:         /* Background (BK) */
+-                              v_wme_ac = WME_AC_BK;
+-                              break;
+-                      case 0:
+-                      case 3:         /* Best Effort (BE) */
+-                              v_wme_ac = WME_AC_BE;
+-                              break;
+-                      case 4:
+-                      case 5:         /* Video (VI) */
+-                              v_wme_ac = WME_AC_VI;
+-                              break;
+-                      case 6:
+-                      case 7:         /* Voice (VO) */
+-                              v_wme_ac = WME_AC_VO;
+-                              break;
+-                      }
+-              }
++      if (skb->priority >= 256 && skb->priority <= 263) {
++              skb->priority = ieee802_1d_to_ac[skb->priority - 256];
++              return 0;
+       }
+-      if (eh->ether_type == __constant_htons(ETHERTYPE_IP)) {
+-              const struct iphdr *ip = (struct iphdr *)
+-                      (skb->data + sizeof (struct ether_header));
+-              /*
+-               * IP frame, map the TOS field.
+-               *
+-               * XXX: fill out these mappings???
+-               */
+-              switch (ip->tos) {
+-              case 0x08:                              /* Background */
+-              case 0x20:
+-                      d_wme_ac = WME_AC_BK;
+-                      break;
+-              case 0x28:                              /* Video */
+-              case 0xa0:
+-                      d_wme_ac = WME_AC_VI;
+-                      break;
+-              case 0x30:                              /* Voice */
+-              case 0xe0:
+-              case 0x88:                              /* XXX UPSD */
+-              case 0xb8:
+-                      d_wme_ac = WME_AC_VO;
+-                      break;
+-              default:                                /* All others */
+-                      d_wme_ac = WME_AC_BE;
+-                      break;
+-              }
+-      } else {
+-              d_wme_ac = WME_AC_BE;
++      if (!(ni->ni_flags & IEEE80211_NODE_QOS)) {
++              /* default priority */
++              skb->priority = WME_AC_BE;
++              return 0;
+       }
+-      skb->priority = d_wme_ac;
+-      if (v_wme_ac > d_wme_ac)
+-              skb->priority = v_wme_ac;
++
++      skb->priority = ieee802_1d_to_ac[ieee80211_classify_ip(skb)];
+       /* Applying ACM policy */
+       if (vap->iv_opmode == IEEE80211_M_STA) {
diff --git a/net/madwifi/patches/441-fix_ibss_node_handling.patch b/net/madwifi/patches/441-fix_ibss_node_handling.patch
new file mode 100644 (file)
index 0000000..20d59de
--- /dev/null
@@ -0,0 +1,91 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6641,10 +6641,8 @@ static void
+ ath_recv_mgmt(struct ieee80211vap * vap, struct ieee80211_node *ni_or_null,
+       struct sk_buff *skb, int subtype, int rssi, u_int64_t rtsf)
+ {
++      const struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data;
+       struct ath_softc *sc = netdev_priv(vap->iv_ic->ic_dev);
+-#ifdef AR_DEBUG
+-        struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data;
+-#endif
+       struct ieee80211_node * ni = ni_or_null;
+       u_int64_t hw_tsf, beacon_tsf;
+       u_int32_t hw_tu, beacon_tu, intval;
+@@ -6686,7 +6684,7 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+               }
+               if ((vap->iv_opmode == IEEE80211_M_IBSS) &&
+                               (sc->sc_opmode == HAL_M_HOSTAP) &&
+-                              IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) {
++                              IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid)) {
+                       /* In this mode, we drive the HAL in HOSTAP mode. Hence
+                        * we do the IBSS merging in software. Also do not merge
+                        * if the difference it too small. Otherwise we are playing
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -311,7 +311,8 @@ ieee80211_input(struct ieee80211vap * va
+                       }
+                       /* Do not try to find a node reference if the packet really did come from the BSS */
+                       if (type == IEEE80211_FC0_TYPE_DATA && ni == vap->iv_bss &&
+-                                      !IEEE80211_ADDR_EQ(vap->iv_bss->ni_macaddr, wh->i_addr2)) {
++                                      !IEEE80211_ADDR_EQ(vap->iv_bss->ni_macaddr, wh->i_addr2) &&
++                                      IEEE80211_ADDR_EQ(vap->iv_bssid, wh->i_addr3)) {
+                               /* Try to find sender in local node table. */
+                               ni = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
+                               if (ni == NULL) {
+@@ -513,6 +514,10 @@ ieee80211_input(struct ieee80211vap * va
+                       break;
+               case IEEE80211_M_IBSS:
+               case IEEE80211_M_AHDEMO:
++                      /* ignore foreign data frames */
++                      if (ni == vap->iv_bss)
++                              goto out;
++
+                       if (dir != IEEE80211_FC1_DIR_NODS) {
+                               IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
+                                       wh, "data", "invalid dir 0x%x", dir);
+@@ -3558,6 +3563,11 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                       } else if ((vap->iv_opmode == IEEE80211_M_WDS) && vap->iv_wdsnode) {
+                               found = 1;
+                               ni = ni_or_null = vap->iv_wdsnode;
++                      } else if (vap->iv_opmode == IEEE80211_M_IBSS) {
++                              ni_or_null = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
++                              if (ni_or_null)
++                                      ni = ni_or_null;
++                              found = 1;
+                       }
+                       IEEE80211_UNLOCK_IRQ(vap->iv_ic);
+@@ -3686,19 +3696,8 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                       vap->iv_stats.is_rx_ssidmismatch++; /*XXX*/
+                       return;
+               }
+-              if (ni == vap->iv_bss) {
+-                      if (vap->iv_opmode == IEEE80211_M_IBSS) {
+-                              /*
+-                               * XXX Cannot tell if the sender is operating
+-                               * in ibss mode.  But we need a new node to
+-                               * send the response so blindly add them to the
+-                               * neighbor table.
+-                               */
+-                              ni = ieee80211_fakeup_adhoc_node(vap,
+-                                      wh->i_addr2);
+-                      } else {
+-                              ni = ieee80211_dup_bss(vap, wh->i_addr2, 1);
+-                      }
++              if (ni == vap->iv_bss && vap->iv_opmode != IEEE80211_M_IBSS) {
++                      ni = ieee80211_dup_bss(vap, wh->i_addr2, 1);
+                       if (ni == NULL)
+                               return;
+                       allocbs = 1;
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -601,6 +601,8 @@ ieee80211_ibss_merge(struct ieee80211_no
+               ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long",
+               ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long",
+               ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "");
++      if (!IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bssid))
++              ieee80211_node_table_reset(&vap->iv_ic->ic_sta, vap);
+       return ieee80211_sta_join1(ieee80211_ref_node(ni));
+ }
+ EXPORT_SYMBOL(ieee80211_ibss_merge);
diff --git a/net/madwifi/patches/442-ibss_rx_filter.patch b/net/madwifi/patches/442-ibss_rx_filter.patch
new file mode 100644 (file)
index 0000000..eaf8071
--- /dev/null
@@ -0,0 +1,20 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -294,6 +294,17 @@ ieee80211_input(struct ieee80211vap * va
+                       break;
+               case IEEE80211_M_IBSS:
+               case IEEE80211_M_AHDEMO:
++                      if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid) ||
++                          (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr) &&
++                           !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
++                           (subtype != IEEE80211_FC0_SUBTYPE_BEACON))) {
++                              if (!(vap->iv_dev->flags & IFF_PROMISC)) {
++                                      IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
++                                              bssid, NULL, "%s", "not to bss");
++                                      vap->iv_stats.is_rx_wrongbss++;
++                                      goto out;
++                              }
++                      }
+                       if (dir != IEEE80211_FC1_DIR_NODS)
+                               bssid = wh->i_addr1;
+                       else if (type == IEEE80211_FC0_TYPE_CTL)
diff --git a/net/madwifi/patches/443-tx_drop_counter.patch b/net/madwifi/patches/443-tx_drop_counter.patch
new file mode 100644 (file)
index 0000000..30630ae
--- /dev/null
@@ -0,0 +1,25 @@
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -1592,10 +1592,6 @@ found:
+                               ieee80211_ref_node(ni);
+ #endif
+                       }
+-              } else {
+-                      IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, mac,
+-                              "no node, discard frame (%s)", __func__);
+-                      vap->iv_stats.is_tx_nonode++;
+               }
+       }
+       return ni;
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -208,6 +208,9 @@ ieee80211_hardstart(struct sk_buff *skb,
+       ni = ieee80211_find_txnode(vap, eh->ether_dhost);
+       if (ni == NULL) {
+               /* NB: ieee80211_find_txnode does stat+msg */
++              IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, mac,
++                      "no node, discard frame (%s)", __func__);
++              vap->iv_stats.is_tx_nonode++;
+               goto bad;
+       }
diff --git a/net/madwifi/patches/444-beacon_update_war.patch b/net/madwifi/patches/444-beacon_update_war.patch
new file mode 100644 (file)
index 0000000..6a3178a
--- /dev/null
@@ -0,0 +1,17 @@
+--- a/net80211/ieee80211_beacon.c
++++ b/net80211/ieee80211_beacon.c
+@@ -476,6 +476,14 @@ ieee80211_beacon_update(struct ieee80211
+                       tie->tim_bitctl |= BITCTL_BUFD_MCAST;
+               else
+                       tie->tim_bitctl &= ~BITCTL_BUFD_MCAST;
++
++              /* WAR: on some platforms, a race condition between beacon
++               * contents update and beacon transmission leads to beacon
++               * data not being updated in time. For most fields this is
++               * not critical, but for powersave it is. Work around this
++               * by always remapping the beacon when the TIM IE changes.
++               */
++              len_changed = 1;
+       }
+       /* Whenever we want to switch to a new channel, we need to follow the
diff --git a/net/madwifi/patches/445-fix_ps_sta_count.patch b/net/madwifi/patches/445-fix_ps_sta_count.patch
new file mode 100644 (file)
index 0000000..2751465
--- /dev/null
@@ -0,0 +1,18 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1957,6 +1957,7 @@ ath_uapsd_processtriggers(struct ath_sof
+                               if (qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) {
+                                       ni->ni_flags |=
+                                               IEEE80211_NODE_UAPSD_TRIG;
++                                      ni->ni_vap->iv_ps_sta++;
+                                       ic->ic_uapsdmaxtriggers++;
+                                       WME_UAPSD_NODE_TRIGSEQINIT(ni);
+                                       DPRINTF(sc, ATH_DEBUG_UAPSD,
+@@ -1967,6 +1968,7 @@ ath_uapsd_processtriggers(struct ath_sof
+                               } else {
+                                       ni->ni_flags &=
+                                               ~IEEE80211_NODE_UAPSD_TRIG;
++                                      ni->ni_vap->iv_ps_sta--;
+                                       ic->ic_uapsdmaxtriggers--;
+                                       DPRINTF(sc, ATH_DEBUG_UAPSD,
+                                               "Node (" MAC_FMT ") no longer U-APSD"
diff --git a/net/madwifi/patches/446-single_module.patch b/net/madwifi/patches/446-single_module.patch
new file mode 100644 (file)
index 0000000..b2898ca
--- /dev/null
@@ -0,0 +1,778 @@
+--- a/ath/Makefile
++++ b/ath/Makefile
+@@ -41,7 +41,6 @@
+ #
+ obj := $(firstword $(obj) $(SUBDIRS) .)
+-TOP = $(obj)/..
+ ifeq ($(strip $(BUS)),AHB)
+ BUSNAME=ahb
+@@ -57,7 +56,24 @@ COPTS       += -DDFS_DOMAIN_ETSI -DDFS_DOMAIN_
+ include $(TOP)/Makefile.inc
+ obj-m         += ath_$(BUSNAME).o
+-ath_$(BUSNAME)-objs   := if_ath.o if_ath_radar.o if_ath_$(BUSNAME).o
++ath_objs := if_ath.o if_ath_radar.o if_ath_$(BUSNAME).o
++ath_$(BUSNAME)-objs   := $(ath_objs)
++
++ifneq ($(SINGLE_MODULE),)
++include $(TOP)/net80211/Makefile
++include $(TOP)/ath_rate/sample/Makefile
++include $(TOP)/ath_rate/minstrel/Makefile
++RC_DECLARE=$(foreach R,$(ATH_RATE),extern void ath_rate_$(R)_init(void);extern void ath_rate_$(R)_exit(void);)
++RC_INIT=$(foreach R,$(ATH_RATE),ath_rate_$(R)_init();)
++RC_EXIT=$(foreach R,$(ATH_RATE),ath_rate_$(R)_exit();)
++
++ath_$(BUSNAME)-objs += $(patsubst %,../net80211/%,$(wlan-objs) $(foreach var,wep tkip ccmp acl xauth scan_sta scan_ap,$(wlan_$(var)-objs))) $(foreach RC,$(ATH_RATE),$(patsubst %,../ath_rate/$(RC)/%,$(ath_rate_$(RC)-objs)))
++ifdef LINUX24
++  ath_$(BUSNAME)-linkobjs := $(ath_objs) $(wlan-objs) $(foreach var,wep tkip ccmp acl xauth scan_sta scan_ap,$(wlan_$(var)-objs)) $(foreach RC,$(ATH_RATE),$(ath_rate_$(RC)-objs))
++endif
++
++EXTRA_CFLAGS += -DSINGLE_MODULE -DRC_INIT="$(RC_INIT)" -DRC_EXIT="$(RC_EXIT)" -DRC_DECLARE="$(RC_DECLARE)"
++endif
+ INCS += -I$(TOP) -I$(ATH_HAL) -I$(HAL) -I$(WLAN)
+@@ -72,13 +88,8 @@ install:
+       test -d $(DESTDIR)/$(KMODPATH) || mkdir -p $(DESTDIR)/$(KMODPATH)
+       install -m 0644 ath_$(BUSNAME).$(KMODSUF) $(DESTDIR)/$(KMODPATH)
+-clean:
+-      rm -f *~ *.o *.ko *.mod.c .*.cmd
+-      rm -f .depend .version .*.o.flags .*.o.d
+-      rm -rf .tmp_versions
+-
+ ath_$(BUSNAME).o: $(ath_$(BUSNAME)-objs)
+-      $(LD) $(LDOPTS) -o ath_$(BUSNAME).$(KMODSUF) -r $(ath_$(BUSNAME)-objs)
++      $(LD) $(LDOPTS) -o ath_$(BUSNAME).$(KMODSUF) -r $(if $(ath_$(BUSNAME)-linkobjs),$(ath_$(BUSNAME)-linkobjs),$(ath_$(BUSNAME)-objs))
+ if_ath_hal.h: $(HAL)/ah.h
+       $(TOP)/scripts/if_ath_hal_generator.pl $< $@
+--- a/net80211/ieee80211_acl.c
++++ b/net80211/ieee80211_acl.c
+@@ -281,16 +281,6 @@ acl_getpolicy(struct ieee80211vap *vap)
+       return as->as_policy;
+ }
+-/*
+- * Module glue.
+- */
+-
+-MODULE_AUTHOR("Errno Consulting, Sam Leffler");
+-MODULE_DESCRIPTION("802.11 wireless support: MAC-based ACL policy");
+-#ifdef MODULE_LICENSE
+-MODULE_LICENSE("Dual BSD/GPL");
+-#endif
+-
+ static const struct ieee80211_aclator mac = {
+       .iac_name       = "mac",
+       .iac_attach     = acl_attach,
+@@ -303,6 +293,18 @@ static const struct ieee80211_aclator ma
+       .iac_getpolicy  = acl_getpolicy,
+ };
++#include "module.h"
++/*
++ * Module glue.
++ */
++
++MODULE_AUTHOR("Errno Consulting, Sam Leffler");
++MODULE_DESCRIPTION("802.11 wireless support: MAC-based ACL policy");
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("Dual BSD/GPL");
++#endif
++
++
+ static int __init
+ init_ieee80211_acl(void)
+ {
+--- a/net80211/ieee80211_crypto_ccmp.c
++++ b/net80211/ieee80211_crypto_ccmp.c
+@@ -686,6 +686,8 @@ ccmp_decrypt(struct ieee80211_key *key,
+ }
+ #undef CCMP_DECRYPT
++#include "module.h"
++
+ /*
+  * Module glue.
+  */
+--- a/net80211/ieee80211_crypto_tkip.c
++++ b/net80211/ieee80211_crypto_tkip.c
+@@ -1046,6 +1046,8 @@ tkip_decrypt(struct tkip_ctx *ctx, struc
+       return 1;
+ }
++#include "module.h"
++
+ /*
+  * Module glue.
+  */
+--- a/net80211/ieee80211_crypto_wep.c
++++ b/net80211/ieee80211_crypto_wep.c
+@@ -497,6 +497,8 @@ wep_decrypt(struct ieee80211_key *key, s
+  * Module glue.
+  */
++#include "module.h"
++
+ MODULE_AUTHOR("Errno Consulting, Sam Leffler");
+ MODULE_DESCRIPTION("802.11 wireless support: WEP cipher");
+ #ifdef MODULE_LICENSE
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -1015,6 +1015,10 @@ static struct notifier_block ieee80211_e
+ static char *version = RELEASE_VERSION;
+ static char *dev_info = "wlan";
++extern        void ieee80211_auth_setup(void);
++
++#include "module.h"
++
+ MODULE_AUTHOR("Errno Consulting, Sam Leffler");
+ MODULE_DESCRIPTION("802.11 wireless LAN protocol support");
+ #ifdef MODULE_VERSION
+@@ -1024,8 +1028,6 @@ MODULE_VERSION(RELEASE_VERSION);
+ MODULE_LICENSE("Dual BSD/GPL");
+ #endif
+-extern        void ieee80211_auth_setup(void);
+-
+ static int __init
+ init_wlan(void)
+ {
+--- a/net80211/ieee80211_scan_ap.c
++++ b/net80211/ieee80211_scan_ap.c
+@@ -763,15 +763,6 @@ action_tasklet(IEEE80211_TQUEUE_ARG data
+       (*ss->ss_ops->scan_default)(vap, &as->as_selbss);
+ }
+-/*
+- * Module glue.
+- */
+-MODULE_AUTHOR("Errno Consulting, Sam Leffler");
+-MODULE_DESCRIPTION("802.11 wireless support: default ap scanner");
+-#ifdef MODULE_LICENSE
+-MODULE_LICENSE("Dual BSD/GPL");
+-#endif
+-
+ static const struct ieee80211_scanner ap_default = {
+       .scan_name              = "default",
+       .scan_attach            = ap_attach,
+@@ -789,6 +780,16 @@ static const struct ieee80211_scanner ap
+       .scan_default           = ap_default_action,
+ };
++#include "module.h"
++
++/*
++ * Module glue.
++ */
++MODULE_AUTHOR("Errno Consulting, Sam Leffler");
++MODULE_DESCRIPTION("802.11 wireless support: default ap scanner");
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("Dual BSD/GPL");
++#endif
+ static int __init
+ init_scanner_ap(void)
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -1208,6 +1208,8 @@ action_tasklet(IEEE80211_TQUEUE_ARG data
+               ieee80211_start_scan(vap, ss->ss_flags, ss->ss_duration, ss->ss_nssid, ss->ss_ssid);
+ }
++#include "module.h"
++
+ /*
+  * Module glue.
+  */
+@@ -1217,6 +1219,7 @@ MODULE_DESCRIPTION("802.11 wireless supp
+ MODULE_LICENSE("Dual BSD/GPL");
+ #endif
++
+ static int __init
+ init_scanner_sta(void)
+ {
+--- a/net80211/ieee80211_xauth.c
++++ b/net80211/ieee80211_xauth.c
+@@ -65,15 +65,6 @@
+ #include <net80211/ieee80211_var.h>
+ /*
+- * Module glue.
+- */
+-MODULE_AUTHOR("Errno Consulting, Sam Leffler");
+-MODULE_DESCRIPTION("802.11 wireless support: external (user mode) authenticator");
+-#ifdef MODULE_LICENSE
+-MODULE_LICENSE("Dual BSD/GPL");
+-#endif
+-
+-/*
+  * One module handles everything for now.  May want
+  * to split things up for embedded applications.
+  */
+@@ -85,6 +76,18 @@ static const struct ieee80211_authentica
+       .ia_node_leave  = NULL,
+ };
++#include "module.h"
++
++/*
++ * Module glue.
++ */
++MODULE_AUTHOR("Errno Consulting, Sam Leffler");
++MODULE_DESCRIPTION("802.11 wireless support: external (user mode) authenticator");
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("Dual BSD/GPL");
++#endif
++
++
+ static int __init
+ init_ieee80211_xauth(void)
+ {
+--- a/net80211/Makefile
++++ b/net80211/Makefile
+@@ -40,7 +40,11 @@
+ # Makefile for the 802.11 WLAN modules.
+ #
+ obj := $(firstword $(obj) $(SUBDIRS) .)
+-TOP = $(obj)/..
++
++include $(TOP)/Makefile.inc
++
++ifeq ($(SINGLE_MODULE),)
++
+ #
+ # There is one authenticator mechanism: an in-kernel implementation
+ # (wlan_xauth). 
+@@ -59,29 +63,8 @@ MOD_INSTALL := wlan.o wlan_wep.o wlan_tk
+ obj-m         += $(MOD_INSTALL)
+-wlan-objs     := if_media.o \
+-                 ieee80211_skb.o \
+-                 ieee80211.o ieee80211_beacon.o ieee80211_crypto.o \
+-                 ieee80211_crypto_none.o ieee80211_input.o ieee80211_node.o \
+-                 ieee80211_output.o ieee80211_power.o ieee80211_proto.o \
+-                 ieee80211_scan.o ieee80211_wireless.o ieee80211_linux.o \
+-                 ieee80211_monitor.o ieee80211_rate.o
+-wlan_wep-objs := ieee80211_crypto_wep.o
+-wlan_tkip-objs        := ieee80211_crypto_tkip.o
+-wlan_ccmp-objs        := ieee80211_crypto_ccmp.o
+-wlan_acl-objs := ieee80211_acl.o
+-wlan_xauth-objs       := ieee80211_xauth.o
+-wlan_scan_sta-objs :=ieee80211_scan_sta.o
+-wlan_scan_ap-objs := ieee80211_scan_ap.o
+-
+-include $(TOP)/Makefile.inc
+-
+ INCS += -I$(TOP) -I$(ATH_HAL) -I$(HAL)
+-EXTRA_CFLAGS+=$(INCS) $(COPTS) -DOPT_AH_H=\"public/$(TARGET).opt_ah.h\"
+-
+--include $(TOPDIR)/Rules.make
+-
+ all:
+       $(MAKE) -C $(KERNELPATH) SUBDIRS=$(shell pwd) modules
+@@ -108,8 +91,28 @@ install:
+               f=`basename $$i .o`; \
+               install -m 0644  $$f.$(KMODSUF) $(DESTDIR)/$(KMODPATH); \
+       done
++else
++all:
++endif
++
++wlan-objs     := if_media.o \
++                 ieee80211_skb.o \
++                 ieee80211.o ieee80211_beacon.o ieee80211_crypto.o \
++                 ieee80211_crypto_none.o ieee80211_input.o ieee80211_node.o \
++                 ieee80211_output.o ieee80211_power.o ieee80211_proto.o \
++                 ieee80211_scan.o ieee80211_wireless.o ieee80211_linux.o \
++                 ieee80211_monitor.o ieee80211_rate.o
++wlan_wep-objs := ieee80211_crypto_wep.o
++wlan_tkip-objs        := ieee80211_crypto_tkip.o
++wlan_ccmp-objs        := ieee80211_crypto_ccmp.o
++wlan_acl-objs := ieee80211_acl.o
++wlan_xauth-objs       := ieee80211_xauth.o
++wlan_scan_sta-objs :=ieee80211_scan_sta.o
++wlan_scan_ap-objs := ieee80211_scan_ap.o
++
++
++EXTRA_CFLAGS+=$(INCS) $(COPTS) -DOPT_AH_H=\"public/$(TARGET).opt_ah.h\"
++
++-include $(TOPDIR)/Rules.make
++
+-clean:
+-      -rm -f *~ *.o *.ko *.mod.c
+-      -rm -f .depend .version .*.o.flags .*.o.d .*.o.cmd .*.ko.cmd
+-      -rm -rf .tmp_versions
+--- /dev/null
++++ b/net80211/module.h
+@@ -0,0 +1,19 @@
++#ifdef SINGLE_MODULE
++
++#undef static
++#define static
++#undef module_init
++#undef module_exit
++#define module_init(...)
++#define module_exit(...)
++
++#undef MODULE_AUTHOR
++#undef MODULE_LICENSE
++#undef MODULE_VERSION
++#undef MODULE_DESCRIPTION
++#define MODULE_AUTHOR(...)
++#define MODULE_LICENSE(...)
++#define MODULE_VERSION(...)
++#define MODULE_DESCRIPTION(...)
++
++#endif
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -13780,3 +13780,5 @@ cleanup_ath_buf(struct ath_softc *sc, st
+       return bf;
+ }
++
++
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -42,6 +42,7 @@
+ #include <linux/config.h>
+ #endif
+ #include <linux/version.h>
++#include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/skbuff.h>
+ #include <linux/netdevice.h>
+@@ -2015,3 +2016,65 @@ ieee80211_build_sc_ie(struct ieee80211co
+ int ath_debug_global = 0;
+ EXPORT_SYMBOL(ath_debug_global);
++#ifdef SINGLE_MODULE
++typedef void (*initfunc)(void);
++
++extern void init_ieee80211_acl(void);
++extern void init_crypto_ccmp(void);
++extern void init_crypto_tkip(void);
++extern void init_crypto_wep(void);
++extern void init_wlan(void);
++extern void init_scanner_ap(void);
++extern void init_scanner_sta(void);
++extern void init_ieee80211_xauth(void);
++
++extern void exit_ieee80211_acl(void);
++extern void exit_crypto_ccmp(void);
++extern void exit_crypto_tkip(void);
++extern void exit_crypto_wep(void);
++extern void exit_wlan(void);
++extern void exit_scanner_ap(void);
++extern void exit_scanner_sta(void);
++extern void exit_ieee80211_xauth(void);
++
++static __initdata initfunc net80211_init[] = {
++      init_wlan,
++      init_ieee80211_acl,
++      init_crypto_ccmp,
++      init_crypto_tkip,
++      init_crypto_wep,
++      init_ieee80211_xauth,
++      init_scanner_ap,
++      init_scanner_sta,
++};
++
++static __exitdata initfunc net80211_exit[] = {
++      exit_crypto_ccmp,
++      exit_crypto_tkip,
++      exit_crypto_wep,
++      exit_scanner_ap,
++      exit_scanner_sta,
++      exit_ieee80211_xauth,
++      exit_ieee80211_acl,
++      exit_wlan,
++};
++
++void net80211_init_module(void)
++{
++      int i;
++      for (i = 0; i < sizeof(net80211_init)/sizeof(net80211_init[0]); i++) {
++              if (net80211_init[i])
++                      net80211_init[i]();
++      }
++}
++
++void net80211_exit_module(void)
++{
++      int i;
++      for (i = 0; i < sizeof(net80211_exit)/sizeof(net80211_exit[0]); i++) {
++              if (net80211_exit[i])
++                      net80211_exit[i]();
++      }
++}
++
++#endif
+--- a/ath/if_ath_ahb.c
++++ b/ath/if_ath_ahb.c
+@@ -447,10 +447,18 @@ MODULE_SUPPORTED_DEVICE("Atheros WLAN ca
+ MODULE_LICENSE("Dual BSD/GPL");
+ #endif
++#ifdef SINGLE_MODULE
++RC_DECLARE
++#endif
++
+ static int __init
+ init_ath_ahb(void)
+ {
+       printk(KERN_INFO "%s: %s\n", dev_info, version);
++#ifdef SINGLE_MODULE
++      net80211_init_module();
++      RC_INIT
++#endif
+       platform_driver_register(&ahb_wmac_driver);
+       ath_sysctl_register();
+@@ -463,6 +471,10 @@ exit_ath_ahb(void)
+ {
+       ath_sysctl_unregister();
+       platform_driver_unregister(&ahb_wmac_driver);
++#ifdef SINGLE_MODULE
++      RC_EXIT
++      net80211_exit_module();
++#endif
+       printk(KERN_INFO "%s: driver unloaded\n", dev_info);
+ }
+ module_exit(exit_ath_ahb);
+--- a/ath/if_ath_pci.c
++++ b/ath/if_ath_pci.c
+@@ -415,11 +415,19 @@ MODULE_SUPPORTED_DEVICE("Atheros WLAN ca
+ MODULE_LICENSE("Dual BSD/GPL");
+ #endif
++#ifdef SINGLE_MODULE
++RC_DECLARE
++#endif
++
+ static int __init
+ init_ath_pci(void)
+ {
+       printk(KERN_INFO "%s: %s\n", dev_info, version);
++#ifdef SINGLE_MODULE
++      net80211_init_module();
++      RC_INIT
++#endif
+       if (pci_register_driver(&ath_pci_driver) < 0) {
+               printk(KERN_ERR "%s: No devices found, driver not installed.\n", dev_info);
+               return (-ENODEV);
+@@ -434,6 +442,10 @@ exit_ath_pci(void)
+ {
+       ath_sysctl_unregister();
+       pci_unregister_driver(&ath_pci_driver);
++#ifdef SINGLE_MODULE
++      RC_EXIT
++      net80211_exit_module();
++#endif
+       printk(KERN_INFO "%s: driver unloaded\n", dev_info);
+ }
+--- a/ath_rate/minstrel/Makefile
++++ b/ath_rate/minstrel/Makefile
+@@ -39,9 +39,7 @@
+ # Makefile for the Atheros Rate Control Support.
+ #
+ obj := $(firstword $(obj) $(SUBDIRS) .)
+-TOP = $(obj)/../..
+-obj-m         += ath_rate_minstrel.o
+ ath_rate_minstrel-objs        := minstrel.o
+ include $(TOP)/Makefile.inc
+@@ -50,6 +48,10 @@ INCS += -I$(TOP) -I$(ATH) -I$(ATH_HAL) -
+ EXTRA_CFLAGS+= $(INCS) $(COPTS) -DOPT_AH_H=\"public/$(TARGET).opt_ah.h\"
++ifeq ($(SINGLE_MODULE),)
++
++obj-m         += ath_rate_minstrel.o
++
+ -include $(TOPDIR)/Rules.make
+ all:
+@@ -59,10 +61,9 @@ install:
+       test -d $(DESTDIR)/$(KMODPATH) || mkdir -p $(DESTDIR)/$(KMODPATH)
+       install -m 0644 ath_rate_minstrel.$(KMODSUF) $(DESTDIR)/$(KMODPATH)
+-clean:
+-      -rm -f *~ *.o *.ko *.mod.c
+-      -rm -f .depend .version .*.o.flags .*.o.d .*.o.cmd .*.ko.cmd
+-      -rm -rf .tmp_versions
+-
+ ath_rate_minstrel.o: $(ath_rate_minstrel-objs)
+       $(LD) $(LDOPTS) -o ath_rate_minstrel.$(KMODSUF) -r $(ath_rate_minstrel-objs)
++else
++all:
++install:
++endif
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -945,6 +945,8 @@ static struct ieee80211_rate_ops ath_rat
+               .dynamic_proc_register = ath_rate_dynamic_proc_register,
+ };
++#include <net80211/module.h>
++
+ MODULE_AUTHOR("John Bicket/Derek Smithies");
+ MODULE_DESCRIPTION("Minstrel Rate bit-rate selection algorithm for Atheros devices");
+ #ifdef MODULE_VERSION
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -47,6 +47,7 @@
+ #include <net80211/ieee80211_power.h>
+ #include <net80211/ieee80211_proto.h>
+ #include <net80211/ieee80211_scan.h>
++#include "symbol.h"
+ /* NB: 
+  * - Atheros chips use 6 bits when power is specified in whole dBm units, with 
+@@ -740,6 +741,8 @@ void ieee80211_dfs_action(struct ieee802
+ void ieee80211_expire_channel_excl_restrictions(struct ieee80211com *);
+ void ieee80211_setpuregbasicrates(struct ieee80211_rateset *rs);
+ int ieee80211_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
++void net80211_init_module(void);
++void net80211_exit_module(void);
+ /*
+  * Iterate through ic_channels to enumerate all distinct ic_ieee channel numbers.
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -521,7 +521,10 @@ extern struct sk_buff * ieee80211_getmgt
+ #define       IF_DRAIN(_q)            skb_queue_drain(_q)
+ extern        void skb_queue_drain(struct sk_buff_head *q);
+-#ifndef __MOD_INC_USE_COUNT
++#ifdef SINGLE_MODULE
++#define _MOD_DEC_USE(_m) do {} while(0)
++#define _MOD_INC_USE(_m, _err) do {} while(0)
++#elif !defined(__MOD_INC_USE_COUNT)
+ #define       _MOD_INC_USE(_m, _err)                                          \
+       if (!try_module_get(_m)) {                                      \
+               printk(KERN_WARNING "%s: try_module_get failed\n",      \
+--- a/ath_rate/sample/Makefile
++++ b/ath_rate/sample/Makefile
+@@ -39,9 +39,7 @@
+ # Makefile for the Atheros Rate Control Support.
+ #
+ obj := $(firstword $(obj) $(SUBDIRS) .)
+-TOP = $(obj)/../..
+-obj-m         += ath_rate_sample.o
+ ath_rate_sample-objs  := sample.o
+ include $(TOP)/Makefile.inc
+@@ -50,6 +48,9 @@ INCS += -I$(TOP) -I$(ATH) -I$(ATH_HAL) -
+ EXTRA_CFLAGS+= $(INCS) $(COPTS) -DOPT_AH_H=\"public/$(TARGET).opt_ah.h\"
++ifeq ($(SINGLE_MODULE),)
++obj-m         += ath_rate_sample.o
++
+ -include $(TOPDIR)/Rules.make
+ all:
+@@ -59,10 +60,9 @@ install:
+       test -d $(DESTDIR)/$(KMODPATH) || mkdir -p $(DESTDIR)/$(KMODPATH)
+       install -m 0644 ath_rate_sample.$(KMODSUF) $(DESTDIR)/$(KMODPATH)
+-clean:
+-      -rm -f *~ *.o *.ko *.mod.c
+-      -rm -f .depend .version .*.o.flags .*.o.d .*.o.cmd .*.ko.cmd
+-      -rm -rf .tmp_versions
+-
+ ath_rate_sample.o: $(ath_rate_sample-objs)
+       $(LD) $(LDOPTS) -o ath_rate_sample.$(KMODSUF) -r $(ath_rate_sample-objs)
++else
++all:
++install:
++endif
+--- a/Makefile
++++ b/Makefile
+@@ -41,7 +41,7 @@
+ #
+ obj := $(firstword $(obj) $(SUBDIRS) .)
+-TOP = $(obj)
++export TOP:=$(if $(wildcard $(firstword $(SUBDIRS))/Makefile.inc),$(firstword $(SUBDIRS)),$(CURDIR))
+ ifneq (svnversion.h,$(MAKECMDGOALS))
+ include $(TOP)/Makefile.inc
+@@ -54,7 +54,7 @@ all: modules tools
+ modules: configcheck svnversion.h
+ ifdef LINUX24
+       for i in $(obj-y); do \
+-              $(MAKE) -C $$i || exit 1; \
++              $(MAKE) -C $$i TOP="$(TOP)" || exit 1; \
+       done
+ else
+       $(MAKE) -C $(KERNELPATH) SUBDIRS=$(shell pwd) modules
+@@ -89,7 +89,7 @@ install-modules: modules
+       sh scripts/find-madwifi-modules.sh -r $(KERNELRELEASE) $(DESTDIR)
+       for i in $(obj-y); do \
+-              $(MAKE) -C $$i install || exit 1; \
++              $(MAKE) -C $$i install TOP="$(TOP)" || exit 1; \
+       done
+ ifeq ($(DESTDIR),)
+       (export KMODPATH=$(KMODPATH); /sbin/depmod -ae $(KERNELRELEASE))
+@@ -114,12 +114,21 @@ reinstall-tools: uninstall-tools install
+ reinstall-modules: uninstall-modules install-modules
+ clean:
+-      for i in $(obj-y); do \
+-              $(MAKE) -C $$i clean; \
+-      done
+-      -$(MAKE) -C $(TOOLS) clean
+-      rm -rf .tmp_versions
++      -find $(obj-y) -name '*~' \
++              -or -name '*.o' \
++              -or -name '*.o.d' \
++              -or -name '*.o.cmd' \
++              -or -name '*.o.flags' \
++              -or -name '*.ko' \
++              -or -name '*.ko.cmd' \
++              -or -name '*.mod.c' \
++              -or -name '.depend' \
++              -or -name '.version' \
++              -or -name '.symvers' | \
++              xargs -r rm -f
+       rm -f *.symvers svnversion.h
++      rm -rf .tmp_versions
++      make -C tools clean
+ info:
+       @echo "The following settings will be used for compilation:"
+@@ -135,18 +144,6 @@ info:
+       @echo "KMODPATH     : $(KMODPATH)"
+       @echo "KMODSUF      : $(KMODSUF)"
+-sanitycheck:
+-      @echo -n "Checking requirements... "
+-      
+-      @# check if specified rate control is available
+-      @if [ ! -d $(ATH_RATE) ]; then \
+-          echo "FAILED"; \
+-          echo "Selected rate control $(ATH_RATE) not available."; \
+-          exit 1; \
+-      fi
+-      
+-      @echo "ok."
+-
+ .PHONY: release
+ release:
+       sh scripts/make-release.bash
+@@ -155,7 +152,7 @@ release:
+ unload:
+       bash scripts/madwifi-unload
+-configcheck: sanitycheck
++configcheck:
+       @echo -n "Checking kernel configuration... "
+       
+       @# check version of kernel
+--- a/Makefile.inc
++++ b/Makefile.inc
+@@ -68,6 +68,9 @@ endif
+ export KERNELPATH
+ endif
++# build net80211 and ath_ahb/ath_pci into a single module
++export SINGLE_MODULE=1
++
+ # KERNELRELEASE is the target kernel's version.  It's always taken from
+ # the kernel build tree.  Kernel Makefile doesn't always know the exact
+ # kernel version (especially for vendor stock kernels), so we get it
+@@ -100,6 +103,7 @@ export ARCH
+ include $(TOP)/ath_hal/ah_target.inc
+ export TARGET
+ COPTS += -DTARGET='"$(TARGET)"'
++COPTS += -DCONFIG_ATHEROS_RATE_DEFAULT='"$(firstword $(ATH_RATE))"'
+ # KMODPATH nominates the directory where the modules will be
+ # installed to
+@@ -141,7 +145,7 @@ ATH=       $(TOP)/ath
+ #
+ # Path to the rate control algorithms.
+ #
+-ATH_RATE=     $(TOP)/ath_rate
++ATH_RATE=     minstrel
+ #
+ # Path to the userspace utilities. 
+ # 
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -991,6 +991,8 @@ static struct ieee80211_rate_ops ath_rat
+       .dynamic_proc_register = ath_rate_dynamic_proc_register,
+ };
++#include <net80211/module.h>
++
+ MODULE_AUTHOR("John Bicket");
+ MODULE_DESCRIPTION("SampleRate bit-rate selection algorithm for Atheros devices");
+ #ifdef MODULE_VERSION
+@@ -1000,18 +1002,17 @@ MODULE_VERSION(RELEASE_VERSION);
+ MODULE_LICENSE("Dual BSD/GPL");
+ #endif
+-static int __init
+-init_ath_rate_sample(void)
++static int __init ath_rate_sample_init(void)
+ {
+       printk(KERN_INFO "%s: %s\n", dev_info, version);
+       return ieee80211_rate_register(&ath_rate_ops);
+ }
+-module_init(init_ath_rate_sample);
++module_init(ath_rate_sample_init);
+ static void __exit
+-exit_ath_rate_sample(void)
++ath_rate_sample_exit(void)
+ {
+       ieee80211_rate_unregister(&ath_rate_ops);
+       printk(KERN_INFO "%s: unloaded\n", dev_info);
+ }
+-module_exit(exit_ath_rate_sample);
++module_exit(ath_rate_sample_exit);
+--- a/net80211/if_media.h
++++ b/net80211/if_media.h
+@@ -42,6 +42,7 @@
+ #define _NET_IF_MEDIA_H_
+ #include <net80211/ieee80211_linux.h>
++#include "symbol.h"
+ /*
+  * Prototypes and definitions for BSD/OS-compatible network interface
+--- /dev/null
++++ b/net80211/symbol.h
+@@ -0,0 +1,4 @@
++#ifdef SINGLE_MODULE
++#undef EXPORT_SYMBOL
++#define EXPORT_SYMBOL(...)
++#endif
+--- a/ath_rate/Makefile
++++ b/ath_rate/Makefile
+@@ -1,7 +1,7 @@
+ obj := $(firstword $(obj) $(SUBDIRS) .)
+ TOP = $(obj)/..
+-obj-y := amrr/ onoe/ sample/ minstrel/
++obj-y := sample/ minstrel/
+ include $(TOP)/Makefile.inc
diff --git a/net/madwifi/patches/447-sta_reconnect.patch b/net/madwifi/patches/447-sta_reconnect.patch
new file mode 100644 (file)
index 0000000..960d1b8
--- /dev/null
@@ -0,0 +1,25 @@
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -647,8 +647,11 @@ ieee80211_sta_join1(struct ieee80211_nod
+               (vap->iv_state == IEEE80211_S_RUN) && bssid_equal(obss, selbs)); */
+       vap->iv_bss = selbs;
+       IEEE80211_ADDR_COPY(vap->iv_bssid, selbs->ni_bssid);
+-      if (obss != NULL)
++      if (obss != NULL) {
++              if (obss->ni_table)
++                      ieee80211_node_leave(obss);
+               ieee80211_unref_node(&obss);
++      }
+       ic->ic_bsschan = selbs->ni_chan;
+       ic->ic_curchan = ic->ic_bsschan;
+       ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -1602,7 +1602,6 @@ __ieee80211_newstate(struct ieee80211vap
+                               IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
+                       break;
+               case IEEE80211_S_RUN:
+-                      ieee80211_node_leave(ni);
+                       if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
+                               /* NB: caller specifies ASSOC/REASSOC by arg */
+                               IEEE80211_SEND_MGMT(ni, arg ?
diff --git a/net/madwifi/patches/448-beacon_handling_fixes.patch b/net/madwifi/patches/448-beacon_handling_fixes.patch
new file mode 100644 (file)
index 0000000..9c0f912
--- /dev/null
@@ -0,0 +1,407 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -160,7 +160,7 @@ static int ath_check_beacon_done(struct
+ static void ath_beacon_send(struct ath_softc *, int *, uint64_t hw_tsf);
+ static void ath_beacon_return(struct ath_softc *, struct ath_buf *);
+ static void ath_beacon_free(struct ath_softc *);
+-static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *);
++static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *, int);
+ static void ath_hw_beacon_stop(struct ath_softc *sc);
+ static int ath_desc_alloc(struct ath_softc *);
+ static void ath_desc_free(struct ath_softc *);
+@@ -387,13 +387,11 @@ static void ath_set_timing(struct ath_so
+ /* calibrate every 30 secs in steady state but check every second at first. */
+ static int ath_calinterval = ATH_SHORT_CALINTERVAL;
+ static int ath_xchanmode = AH_TRUE;           /* enable extended channels */
+-static int ath_maxvaps = ATH_MAXVAPS_DEFAULT;   /* set default maximum vaps */
+ static int bstuck_thresh = BSTUCK_THRESH;       /* Stuck beacon count required for reset */
+ static char *autocreate = NULL;
+ static char *ratectl = DEF_RATE_CTL;
+ static int rfkill = 0;
+ static int tpc = 1;
+-static int maxvaps = -1;
+ static int xchanmode = -1;
+ #include "ath_wprobe.c"
+ static int beacon_cal = 1;
+@@ -432,7 +430,6 @@ static struct notifier_block ath_event_b
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+ MODULE_PARM(beacon_cal, "i");
+-MODULE_PARM(maxvaps, "i");
+ MODULE_PARM(xchanmode, "i");
+ MODULE_PARM(rfkill, "i");
+ #ifdef ATH_CAP_TPC
+@@ -444,7 +441,6 @@ MODULE_PARM(ratectl, "s");
+ #else
+ #include <linux/moduleparam.h>
+ module_param(beacon_cal, int, 0600);
+-module_param(maxvaps, int, 0600);
+ module_param(xchanmode, int, 0600);
+ module_param(rfkill, int, 0600);
+ #ifdef ATH_CAP_TPC
+@@ -454,7 +450,6 @@ module_param(bstuck_thresh, int, 0600);
+ module_param(autocreate, charp, 0600);
+ module_param(ratectl, charp, 0600);
+ #endif
+-MODULE_PARM_DESC(maxvaps, "Maximum VAPs");
+ MODULE_PARM_DESC(xchanmode, "Enable/disable extended channel mode");
+ MODULE_PARM_DESC(rfkill, "Enable/disable RFKILL capability");
+ #ifdef ATH_CAP_TPC
+@@ -512,7 +507,7 @@ MODULE_PARM_DESC(ieee80211_debug, "Load-
+  * and use the higher bits as the index of the VAP.
+  */
+ #define ATH_SET_VAP_BSSID_MASK(bssid_mask)                            \
+-      ((bssid_mask)[0] &= ~(((ath_maxvaps-1) << 2) | 0x02))
++      ((bssid_mask)[0] &= ~(((ATH_MAXVAPS_BCN-1) << 2) | 0x02))
+ #define ATH_GET_VAP_ID(bssid)                   ((bssid)[0] >> 2)
+ #define ATH_SET_VAP_BSSID(bssid, id)                                  \
+               do {                                                    \
+@@ -604,8 +599,8 @@ ath_attach(u_int16_t devid, struct net_d
+       /* Allocate space for dynamically determined maximum VAP count */
+       sc->sc_bslot = 
+-              kmalloc(ath_maxvaps * sizeof(struct ieee80211vap*), GFP_KERNEL);
+-      memset(sc->sc_bslot, 0, ath_maxvaps * sizeof(struct ieee80211vap*));
++              kmalloc(ATH_MAXVAPS_BCN * sizeof(struct ieee80211vap*), GFP_KERNEL);
++      memset(sc->sc_bslot, 0, ATH_MAXVAPS_BCN * sizeof(struct ieee80211vap*));
+       /*
+        * Cache line size is used to size and align various
+@@ -694,13 +689,6 @@ ath_attach(u_int16_t devid, struct net_d
+       for (i = 0; i < sc->sc_keymax; i++)
+               ath_hal_keyreset(ah, i);
+-      if (maxvaps != -1) {
+-              ath_maxvaps = maxvaps;
+-              if (ath_maxvaps < ATH_MAXVAPS_MIN)
+-                      ath_maxvaps = ATH_MAXVAPS_MIN;
+-              else if (ath_maxvaps > ATH_MAXVAPS_MAX)
+-                      ath_maxvaps = ATH_MAXVAPS_MAX;
+-      }
+       if (xchanmode != -1)
+               ath_xchanmode = xchanmode;
+       error = ath_getchannels(dev);
+@@ -1349,12 +1337,6 @@ ath_vap_create(struct ieee80211com *ic,
+               return NULL;
+       }
+-      if (sc->sc_nvaps >= ath_maxvaps) {
+-              EPRINTF(sc, "Too many virtual APs (%d already exist).\n", 
+-                              sc->sc_nvaps);
+-              return NULL;
+-      }
+-
+       dev = alloc_etherdev(sizeof(struct ath_vap) + sc->sc_rc->arc_vap_space);
+       if (dev == NULL) {
+               /* XXX msg */
+@@ -1424,7 +1406,7 @@ ath_vap_create(struct ieee80211com *ic,
+               TAILQ_FOREACH(v, &ic->ic_vaps, iv_next)
+                       id_mask |= (1 << ATH_GET_VAP_ID(v->iv_myaddr));
+-              for (id = 0; id < ath_maxvaps; id++) {
++              for (id = 0; id < ATH_MAXVAPS_BCN; id++) {
+                       /* get the first available slot */
+                       if ((id_mask & (1 << id)) == 0) {
+                               ATH_SET_VAP_BSSID(vap->iv_myaddr, id);
+@@ -1451,11 +1433,11 @@ ath_vap_create(struct ieee80211com *ic,
+               /* Assign the VAP to a beacon xmit slot.  As
+                * above, this cannot fail to find one. */
+               avp->av_bslot = 0;
+-              for (slot = 0; slot < ath_maxvaps; slot++)
++              for (slot = 0; slot < ATH_MAXVAPS_BCN; slot++)
+                       if (sc->sc_bslot[slot] == NULL) {
+                               /* XXX: Hack, space out slots to better
+                                * deal with misses. */
+-                              if (slot + 1 < ath_maxvaps &&
++                              if (slot + 1 < ATH_MAXVAPS_BCN &&
+                                   sc->sc_bslot[slot+1] == NULL) {
+                                       avp->av_bslot = slot + 1;
+                                       break;
+@@ -1463,8 +1445,11 @@ ath_vap_create(struct ieee80211com *ic,
+                               avp->av_bslot = slot;
+                               /* NB: keep looking for a double slot */
+                       }
+-              KASSERT(sc->sc_bslot[avp->av_bslot] == NULL,
+-                      ("beacon slot %u not empty?", avp->av_bslot));
++              if (sc->sc_bslot[avp->av_bslot]) {
++                      free_netdev(dev);
++                      return NULL;
++              }
++
+               sc->sc_bslot[avp->av_bslot] = vap;
+               sc->sc_nbcnvaps++;
+@@ -1475,15 +1460,7 @@ ath_vap_create(struct ieee80211com *ic,
+                        * of staggered beacons.
+                        */
+                       /* XXX check for beacon interval too small */
+-                      if (ath_maxvaps > 4) {
+-                              DPRINTF(sc, ATH_DEBUG_BEACON, 
+-                                              "Staggered beacons are not "
+-                                              "possible with maxvaps set "
+-                                              "to %d.\n", ath_maxvaps);
+-                              sc->sc_stagbeacons = 0;
+-                      } else {
+-                              sc->sc_stagbeacons = 1;
+-                      }
++                      sc->sc_stagbeacons = 1;
+               }
+               DPRINTF(sc, ATH_DEBUG_BEACON, "sc->sc_stagbeacons %sabled\n", 
+                               (sc->sc_stagbeacons ? "en" : "dis"));
+@@ -1553,7 +1530,7 @@ ath_vap_create(struct ieee80211com *ic,
+               if (ath_startrecv(sc) != 0)     /* restart recv */
+                       EPRINTF(sc, "Unable to start receive logic.\n");
+               if (sc->sc_beacons)
+-                      ath_beacon_config(sc, NULL);    /* restart beacons */
++                      ath_beacon_config(sc, NULL, 0); /* restart beacons */
+               ath_hal_intrset(ah, sc->sc_imask);
+       }
+@@ -1681,7 +1658,7 @@ ath_vap_delete(struct ieee80211vap *vap)
+               if (ath_startrecv(sc) != 0)             /* restart recv. */
+                       EPRINTF(sc, "Unable to start receive logic.\n");
+               if (sc->sc_beacons)
+-                      ath_beacon_config(sc, NULL);    /* restart beacons */
++                      ath_beacon_config(sc, NULL, 0); /* restart beacons */
+               ath_hal_intrset(ah, sc->sc_imask);
+       }
+ }
+@@ -3066,7 +3043,7 @@ ath_reset(struct net_device *dev)
+        */
+       ath_chan_change(sc, c);
+       if (sc->sc_beacons)
+-              ath_beacon_config(sc, NULL);    /* restart beacons */
++              ath_beacon_config(sc, NULL, 1); /* restart beacons */
+       ath_hal_intrset(ah, sc->sc_imask);
+       ath_set_ack_bitrate(sc, sc->sc_ackrate);
+       netif_wake_queue(dev);          /* restart xmit */
+@@ -4763,7 +4740,7 @@ ath_check_beacon_done(struct ath_softc *
+       /*
+        * check if the last beacon went out with the mode change flag set.
+        */
+-      for (slot = 0; slot < ath_maxvaps; slot++) {
++      for (slot = 0; slot < ATH_MAXVAPS_BCN; slot++) {
+               if (sc->sc_bslot[slot]) {
+                       vap = sc->sc_bslot[slot];
+                       break;
+@@ -4968,7 +4945,7 @@ ath_beacon_alloc_internal(struct ath_sof
+                * has a timestamp in one beacon interval while the
+                * others get a timestamp aligned to the next interval.
+                */
+-              tuadjust = (ni->ni_intval * (ath_maxvaps - avp->av_bslot)) / ath_maxvaps;
++              tuadjust = (ni->ni_intval * (ATH_MAXVAPS_BCN - avp->av_bslot)) / ATH_MAXVAPS_BCN;
+               tsfadjust = cpu_to_le64(tuadjust << 10);        /* TU->TSF */
+               DPRINTF(sc, ATH_DEBUG_BEACON,
+@@ -5361,8 +5338,8 @@ ath_beacon_send(struct ath_softc *sc, in
+               u_int32_t tsftu;
+               tsftu = hw_tsf >> 10; /* NB: 64 -> 32: See note far above. */
+-              slot = ((tsftu % ic->ic_lintval) * ath_maxvaps) / ic->ic_lintval;
+-              vap = sc->sc_bslot[(slot + 1) % ath_maxvaps];
++              slot = ((tsftu % ic->ic_lintval) * ATH_MAXVAPS_BCN) / ic->ic_lintval;
++              vap = sc->sc_bslot[(slot + 1) % ATH_MAXVAPS_BCN];
+               DPRINTF(sc, ATH_DEBUG_BEACON_PROC,
+                       "Slot %d [tsf %llu tsftu %llu intval %u] vap %p\n",
+                       slot, (unsigned long long)hw_tsf, 
+@@ -5377,7 +5354,7 @@ ath_beacon_send(struct ath_softc *sc, in
+               u_int32_t *bflink = NULL;
+               /* XXX: rotate/randomize order? */
+-              for (slot = 0; slot < ath_maxvaps; slot++) {
++              for (slot = 0; slot < ATH_MAXVAPS_BCN; slot++) {
+                       if ((vap = sc->sc_bslot[slot]) != NULL) {
+                               if ((bf = ath_beacon_generate(
+                                               sc, vap, 
+@@ -5418,7 +5395,7 @@ ath_beacon_send(struct ath_softc *sc, in
+        *     again.  If we miss a beacon for that slot then we'll be
+        *     slow to transition but we'll be sure at least one beacon
+        *     interval has passed.  When bursting slot is always left
+-       *     set to ath_maxvaps so this check is a no-op.
++       *     set to ATH_MAXVAPS_BCN so this check is a no-op.
+        */
+       /* XXX locking */
+       if (sc->sc_updateslot == UPDATE) {
+@@ -5526,7 +5503,7 @@ ath_beacon_free(struct ath_softc *sc)
+  * (2^(32 + 10 - 1) - 1)us is a really long time.
+  */
+ static void
+-ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
++ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap, int reset)
+ {
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
+@@ -5553,7 +5530,7 @@ ath_beacon_config(struct ath_softc *sc,
+       /* We should reset hw TSF only once, so we increment
+        * ni_tstamp.tsf to avoid resetting the hw TSF multiple
+        * times */
+-      if (tsf == 0) {
++      if (tsf == 0 || reset) {
+               reset_tsf = 1;
+               ni->ni_tstamp.tsf = cpu_to_le64(1);
+       }
+@@ -5567,7 +5544,7 @@ ath_beacon_config(struct ath_softc *sc,
+               /* NB: the beacon interval is kept internally in TUs */
+               intval = ic->ic_lintval & HAL_BEACON_PERIOD;
+               if (sc->sc_stagbeacons)
+-                      intval /= ath_maxvaps;  /* for staggered beacons */
++                      intval /= ATH_MAXVAPS_BCN;      /* for staggered beacons */
+               if ((sc->sc_nostabeacons) &&
+                   (vap->iv_opmode == IEEE80211_M_HOSTAP))
+                       reset_tsf = 1;
+@@ -5583,31 +5560,24 @@ ath_beacon_config(struct ath_softc *sc,
+                * time */
+               nexttbtt = intval;
+       } else if (intval) {    /* NB: can be 0 for monitor mode */
+-              if (tsf == 1) {
+-                      /* We have not received any beacons or probe
+-                       * responses. Since a beacon should be sent
+-                       * every 'intval' ms, we compute the next
+-                       * beacon timestamp using the hardware TSF. We
+-                       * ensure that it is at least FUDGE TUs ahead
+-                       * of the current TSF. Otherwise, we use the
+-                       * next beacon timestamp again */
+-                      nexttbtt = roundup(hw_tsftu + FUDGE, intval);
+-              } 
+-              else if (ic->ic_opmode == IEEE80211_M_IBSS) {
+-                      if (tsf > hw_tsf) {
+-                              /* We received a beacon, but the HW TSF has
+-                               * not been updated (otherwise hw_tsf > tsf)
+-                               * We cannot use the hardware TSF, so we
+-                               * wait to synchronize beacons again. */
+-                              sc->sc_syncbeacon = 1;
+-                              goto ath_beacon_config_debug;
+-                      } else {
+-                              /* Normal case: we received a beacon to which
+-                               * we have synchronized. Make sure that nexttbtt
+-                               * is at least FUDGE TU ahead of hw_tsf */
+-                              nexttbtt = tsftu + roundup(hw_tsftu + FUDGE - 
+-                                              tsftu, intval);
+-                      }
++              if ((tsf > hw_tsf) && (ic->ic_opmode == IEEE80211_M_IBSS)) {
++                      /* We received a beacon, but the HW TSF has
++                       * not been updated (otherwise hw_tsf > tsf)
++                       * We cannot use the hardware TSF, so we
++                       * wait to synchronize beacons again. */
++                      sc->sc_syncbeacon = 1;
++                      goto ath_beacon_config_debug;
++              } else if ((tsftu + FUDGE) > hw_tsftu) {
++                      if (tsftu > hw_tsftu + 2 * intval)
++                              nexttbtt = roundup(hw_tsftu + FUDGE, intval);
++                      else
++                              nexttbtt = tsftu;
++              } else {
++                      /* Normal case: we received a beacon to which
++                       * we have synchronized. Make sure that nexttbtt
++                       * is at least FUDGE TU ahead of hw_tsf */
++                      nexttbtt = tsftu + roundup(hw_tsftu + FUDGE -
++                                      tsftu, intval);
+               }
+       }
+@@ -5730,9 +5700,6 @@ ath_beacon_config(struct ath_softc *sc,
+               ath_beacon_dturbo_config(vap, intval &
+                               ~(HAL_BEACON_RESET_TSF | HAL_BEACON_ENA));
+ #endif
+-              if ((nexttbtt & HAL_BEACON_PERIOD) - (ath_hal_gettsf32(ah) >> 10)
+-                              <= ath_hal_sw_beacon_response_time)
+-                      nexttbtt += intval;
+               sc->sc_nexttbtt = nexttbtt;
+               /* stop beacons before reconfiguring the timers to avoid race
+@@ -5889,7 +5856,7 @@ ath_desc_alloc(struct ath_softc *sc)
+       /* XXX allocate beacon state together with VAP */
+       error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
+-                      "beacon", ath_maxvaps, 1);
++                      "beacon", ATH_MAXVAPS_BCN, 1);
+       if (error != 0) {
+               ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf,
+                       BUS_DMA_TODEVICE);
+@@ -6680,7 +6647,7 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+                       /* Resync beacon timers using the tsf of the
+                        * beacon frame we just received. */
+                       vap->iv_flags_ext &= ~IEEE80211_FEXT_APPIE_UPDATE;
+-                      ath_beacon_config(sc, vap);
++                      ath_beacon_config(sc, vap, 0);
+                       DPRINTF(sc, ATH_DEBUG_BEACON, 
+                               "Updated beacon timers\n");
+               }
+@@ -9359,7 +9326,7 @@ ath_chan_set(struct ath_softc *sc, struc
+                * HW seems to turn off beacons during turbo mode switch.
+                */
+               if (sc->sc_beacons && !sc->sc_dfs_cac)
+-                      ath_beacon_config(sc, NULL);
++                      ath_beacon_config(sc, NULL, 0);
+               /*
+                * Re-enable interrupts.
+                */
+@@ -9813,7 +9780,7 @@ ath_newstate(struct ieee80211vap *vap, e
+                                       ATH_DEBUG_BEACON_PROC, 
+                               "Beacons reconfigured by %p[%s]!\n",
+                               vap, vap->iv_nickname);
+-                      ath_beacon_config(sc, vap);
++                      ath_beacon_config(sc, vap, 1);
+                       sc->sc_beacons = 1;
+               }
+       } else {
+@@ -9948,9 +9915,6 @@ ath_dfs_cac_completed(unsigned long data
+               }
+               netif_wake_queue(dev);
+               ath_reset(dev);
+-              if (sc->sc_beacons) {
+-                      ath_beacon_config(sc, NULL);
+-              }
+               dev->watchdog_timeo = 5 * HZ; /* restore normal timeout */
+       } else {
+               do_gettimeofday(&tv);
+@@ -11473,9 +11437,6 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+               case ATH_OUTDOOR:
+                       val = ic->ic_country_outdoor;
+                       break;
+-              case ATH_MAXVAPS:
+-                      val = ath_maxvaps;
+-                      break;
+               case ATH_REGDOMAIN:
+                       ath_hal_getregdomain(ah, &val);
+                       break;
+@@ -11606,12 +11567,6 @@ static const ctl_table ath_sysctl_templa
+         .extra2       = (void *)ATH_OUTDOOR,
+       },
+       { .ctl_name     = CTL_AUTO,
+-        .procname     = "maxvaps",
+-        .mode         = 0444,
+-        .proc_handler = ath_sysctl_halparam,
+-        .extra2       = (void *)ATH_MAXVAPS,
+-      },
+-      { .ctl_name     = CTL_AUTO,
+         .procname     = "regdomain",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+@@ -11928,13 +11883,6 @@ static ctl_table ath_static_sysctls[] =
+       },
+ #endif
+       { .ctl_name     = CTL_AUTO,
+-        .procname     = "maxvaps",
+-        .mode         = 0444,
+-        .data         = &ath_maxvaps,
+-        .maxlen       = sizeof(ath_maxvaps),
+-        .proc_handler = proc_dointvec
+-      },
+-      { .ctl_name     = CTL_AUTO,
+         .procname     = "xchanmode",
+         .mode         = 0444,
+         .data         = &ath_xchanmode,
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -211,9 +211,7 @@ static inline struct net_device *_alloc_
+ #define       ATH_RXBUF       40              /* number of RX buffers */
+ #define       ATH_TXBUF       200             /* number of TX buffers */
+-#define ATH_MAXVAPS_MIN       2       /* minimum number of beacon buffers */
+-#define ATH_MAXVAPS_MAX       64      /* maximum number of beacon buffers */
+-#define ATH_MAXVAPS_DEFAULT   4       /* default number of beacon buffers */
++#define ATH_MAXVAPS_BCN               4       /* maximum number of beacon buffers */
+ /* free buffer threshold to restart net dev */
+ #define       ATH_TXBUF_FREE_THRESHOLD  (ATH_TXBUF / 20)
diff --git a/net/madwifi/patches/449-fix_txbuf_leak.patch b/net/madwifi/patches/449-fix_txbuf_leak.patch
new file mode 100644 (file)
index 0000000..31f2fef
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -3697,6 +3697,7 @@ ff_bypass:
+        */
+       skb = ieee80211_encap(ni, skb, &framecnt);
+       if (skb == NULL) {
++              STAILQ_INSERT_TAIL(&bf_head, bf, bf_list);
+               DPRINTF(sc, ATH_DEBUG_XMIT,
+                       "Dropping; encapsulation failure\n");
+               sc->sc_stats.ast_tx_encap++;
diff --git a/net/madwifi/patches/450-calibration.patch b/net/madwifi/patches/450-calibration.patch
new file mode 100644 (file)
index 0000000..8739790
--- /dev/null
@@ -0,0 +1,177 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -394,7 +394,6 @@ static int rfkill = 0;
+ static int tpc = 1;
+ static int xchanmode = -1;
+ #include "ath_wprobe.c"
+-static int beacon_cal = 1;
+ static const struct ath_hw_detect generic_hw_info = {
+       .vendor_name = "Unknown",
+@@ -429,7 +428,6 @@ static struct notifier_block ath_event_b
+ };
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+-MODULE_PARM(beacon_cal, "i");
+ MODULE_PARM(xchanmode, "i");
+ MODULE_PARM(rfkill, "i");
+ #ifdef ATH_CAP_TPC
+@@ -440,7 +438,6 @@ MODULE_PARM(autocreate, "s");
+ MODULE_PARM(ratectl, "s");
+ #else
+ #include <linux/moduleparam.h>
+-module_param(beacon_cal, int, 0600);
+ module_param(xchanmode, int, 0600);
+ module_param(rfkill, int, 0600);
+ #ifdef ATH_CAP_TPC
+@@ -825,6 +822,7 @@ ath_attach(u_int16_t devid, struct net_d
+               error = EIO;
+               goto bad2;
+       }
++      sc->sc_cal_interval = ath_calinterval;
+       init_timer(&sc->sc_cal_ch);
+       sc->sc_cal_ch.function = ath_calibrate;
+       sc->sc_cal_ch.data = (unsigned long) dev;
+@@ -2737,8 +2735,7 @@ ath_stop_locked(struct net_device *dev)
+               }
+               if (!sc->sc_invalid) {
+                       del_timer_sync(&sc->sc_dfs_cac_timer);
+-                      if (!sc->sc_beacon_cal)
+-                              del_timer_sync(&sc->sc_cal_ch);
++                      del_timer_sync(&sc->sc_cal_ch);
+               }
+               ath_draintxq(sc);
+               if (!sc->sc_invalid) {
+@@ -2763,10 +2760,9 @@ static void ath_set_beacon_cal(struct at
+       if (val) {
+               del_timer_sync(&sc->sc_cal_ch);
+       } else {
+-              sc->sc_cal_ch.expires = jiffies + (ath_calinterval * HZ);
+-              add_timer(&sc->sc_cal_ch);
++              mod_timer(&sc->sc_cal_ch, jiffies + (sc->sc_cal_interval * HZ));
+       }
+-      sc->sc_beacon_cal = !!val && beacon_cal;
++      sc->sc_beacon_cal = !!val;
+ }
+ /*
+@@ -3008,7 +3004,7 @@ ath_reset(struct net_device *dev)
+        * XXX: starting the calibration too early seems to lead to
+        * problems with the beacons.
+        */
+-      sc->sc_lastcal = jiffies;
++      sc->sc_nextcal = jiffies + msecs_to_jiffies(sc->sc_cal_interval * 1000);
+       /*
+        * Convert to a HAL channel description with the flags
+@@ -5430,10 +5426,9 @@ ath_beacon_send(struct ath_softc *sc, in
+                       "Invoking ath_hal_txstart with sc_bhalq: %d\n",
+                       sc->sc_bhalq);
+               ath_hal_txstart(ah, sc->sc_bhalq);
+-              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);
+-              }
++              if (sc->sc_beacon_cal && ((sc->sc_bmisscount == 3) ||
++                  (jiffies > sc->sc_nextcal)))
++                      mod_timer(&sc->sc_cal_ch, jiffies + 1);
+               sc->sc_stats.ast_be_xmit++;             /* XXX per-VAP? */
+       }
+@@ -9104,6 +9099,7 @@ ath_startrecv(struct ath_softc *sc)
+               dev->mtu, sc->sc_cachelsz, sc->sc_rxbufsize);
+       sc->sc_rxlink = NULL;
++      ath_set_beacon_cal(sc, IEEE80211_IS_MODE_BEACON(sc->sc_ic.ic_opmode));
+       STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
+               int error = ath_rxbuf_init(sc, bf);
+               ATH_RXBUF_RESET(bf);
+@@ -9320,7 +9316,7 @@ ath_chan_set(struct ath_softc *sc, struc
+                               jiffies + (sc->sc_dfs_cac_period * HZ));
+                       /* This is a good time to start a calibration */
+-                      ath_set_beacon_cal(sc, 1);
++                      mod_timer(&sc->sc_cal_ch, jiffies + 1);
+               }
+               /*
+                * re configure beacons when it is a turbo mode switch.
+@@ -9414,25 +9410,23 @@ ath_calibrate(unsigned long arg)
+       if (isIQdone == AH_TRUE) {
+               /* Unless user has overridden calibration interval,
+                * upgrade to less frequent calibration */
+-              if (ath_calinterval == ATH_SHORT_CALINTERVAL)
+-                      ath_calinterval = ATH_LONG_CALINTERVAL;
++              if (sc->sc_cal_interval == ATH_SHORT_CALINTERVAL)
++                      sc->sc_cal_interval = ATH_LONG_CALINTERVAL;
+       }
+       else {
+               /* Unless user has overridden calibration interval,
+                * downgrade to more frequent calibration */
+-              if (ath_calinterval == ATH_LONG_CALINTERVAL)
+-                      ath_calinterval = ATH_SHORT_CALINTERVAL;
++              if (sc->sc_cal_interval == ATH_LONG_CALINTERVAL)
++                      sc->sc_cal_interval = ATH_SHORT_CALINTERVAL;
+       }
+       DPRINTF(sc, ATH_DEBUG_CALIBRATE, "Channel %u/%x -- IQ %s.\n",
+               sc->sc_curchan.channel, sc->sc_curchan.channelFlags,
+               isIQdone ? "done" : "not done");
+-      sc->sc_lastcal = jiffies;
+-      if (!sc->sc_beacon_cal) {
+-              sc->sc_cal_ch.expires = jiffies + (ath_calinterval * HZ);
+-              add_timer(&sc->sc_cal_ch);
+-      }
++      sc->sc_nextcal = jiffies + msecs_to_jiffies(sc->sc_cal_interval * 1000);
++      if (!sc->sc_beacon_cal)
++              mod_timer(&sc->sc_cal_ch, sc->sc_nextcal);
+ }
+ static void
+@@ -9540,9 +9534,6 @@ ath_newstate(struct ieee80211vap *vap, e
+               ieee80211_state_name[vap->iv_state],
+               ieee80211_state_name[nstate]);
+-      if (!sc->sc_beacon_cal)
+-              del_timer(&sc->sc_cal_ch);              /* periodic calibration timer */
+-
+       ath_hal_setledstate(ah, leds[nstate]);  /* set LED */
+       netif_stop_queue(dev);                  /* before we do anything else */
+@@ -9764,10 +9755,7 @@ ath_newstate(struct ieee80211vap *vap, e
+                               IEEE80211_IS_MODE_DFS_MASTER(vap->iv_opmode)) {
+                       DPRINTF(sc, ATH_DEBUG_STATE | ATH_DEBUG_DOTH, 
+                               "VAP -> DFSWAIT_PENDING \n");
+-                      /* start calibration timer with a really small value 
+-                       * 1/10 sec */
+-                      if (!sc->sc_beacon_cal)
+-                              mod_timer(&sc->sc_cal_ch, jiffies + (HZ/10));
++                      mod_timer(&sc->sc_cal_ch, jiffies + 1);
+                       /* wake the receiver */
+                       netif_wake_queue(dev);
+                       /* don't do the other usual stuff... */
+@@ -9809,12 +9797,6 @@ done:
+       /* Invoke the parent method to complete the work. */
+       error = avp->av_newstate(vap, nstate, arg);
+-      /* Finally, start any timers. */
+-      if (nstate == IEEE80211_S_RUN && !sc->sc_beacon_cal) {
+-              /* start periodic recalibration timer */
+-              mod_timer(&sc->sc_cal_ch, jiffies + (ath_calinterval * HZ));
+-      }
+-
+ #ifdef ATH_SUPERG_XR
+       if (vap->iv_flags & IEEE80211_F_XR &&
+               nstate == IEEE80211_S_RUN)
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -832,7 +832,8 @@ struct ath_softc {
+       struct ieee80211_channel *sc_last_chan;
+       int sc_beacon_cal;                      /* use beacon timer for calibration */
+-      u_int64_t sc_lastcal;                   /* last time the calibration was performed */
++      u_int64_t sc_nextcal;                   /* last time the calibration was performed */
++      int sc_cal_interval;                    /* current calibration interval */
+       struct timer_list sc_cal_ch;            /* calibration timer */
+       HAL_NODE_STATS sc_halstats;             /* station-mode rssi stats */
diff --git a/net/madwifi/patches/451-ibss_race_fix.patch b/net/madwifi/patches/451-ibss_race_fix.patch
new file mode 100644 (file)
index 0000000..27e1b47
--- /dev/null
@@ -0,0 +1,342 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -294,10 +294,10 @@ ieee80211_input(struct ieee80211vap * va
+                       break;
+               case IEEE80211_M_IBSS:
+               case IEEE80211_M_AHDEMO:
+-                      if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid) ||
++                      if ((!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid) ||
+                           (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr) &&
+-                           !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+-                           (subtype != IEEE80211_FC0_SUBTYPE_BEACON))) {
++                           !IEEE80211_IS_MULTICAST(wh->i_addr1))) &&
++                           (type == IEEE80211_FC0_TYPE_DATA)) {
+                               if (!(vap->iv_dev->flags & IFF_PROMISC)) {
+                                       IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
+                                               bssid, NULL, "%s", "not to bss");
+@@ -322,22 +322,15 @@ ieee80211_input(struct ieee80211vap * va
+                       }
+                       /* Do not try to find a node reference if the packet really did come from the BSS */
+                       if (type == IEEE80211_FC0_TYPE_DATA && ni == vap->iv_bss &&
+-                                      !IEEE80211_ADDR_EQ(vap->iv_bss->ni_macaddr, wh->i_addr2) &&
+                                       IEEE80211_ADDR_EQ(vap->iv_bssid, wh->i_addr3)) {
+                               /* Try to find sender in local node table. */
+-                              ni = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
++                              if (!ni_or_null) {
++                                      ieee80211_unref_node(&ni);
++                                      ni = ieee80211_find_txnode(vap, wh->i_addr2);
++                              }
+                               if (ni == NULL) {
+-                                      /*
+-                                       * Fake up a node for this newly discovered
+-                                       * member of the IBSS.  This should probably
+-                                       * done after an ACL check.
+-                                       */
+-                                      ni = ieee80211_fakeup_adhoc_node(vap,
+-                                                      wh->i_addr2);
+-                                      if (ni == NULL) {
+-                                              /* NB: stat kept for alloc failure */
+-                                              goto err;
+-                                      }
++                                      /* NB: stat kept for alloc failure */
++                                      goto discard;
+                               }
+                       }
+                       iwspy_event(vap, ni, rssi);
+@@ -3553,8 +3546,8 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                               (((vap->iv_opmode == IEEE80211_M_HOSTAP) ||
+                                (vap->iv_opmode == IEEE80211_M_WDS)) &&
+                               (scan.capinfo & IEEE80211_CAPINFO_ESS))) {
++                      struct ieee80211_node *tni = NULL;
+                       struct ieee80211vap *avp = NULL;
+-                      int do_unref = 0;
+                       int found = 0;
+                       IEEE80211_LOCK_IRQ(vap->iv_ic);
+@@ -3570,14 +3563,12 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                                       }
+                               }
+                               if (found)
+-                                      ni = ni_or_null = avp->iv_wdsnode;
++                                      tni = ieee80211_ref_node(avp->iv_wdsnode);
+                       } else if ((vap->iv_opmode == IEEE80211_M_WDS) && vap->iv_wdsnode) {
+                               found = 1;
+-                              ni = ni_or_null = vap->iv_wdsnode;
+-                      } else if (vap->iv_opmode == IEEE80211_M_IBSS) {
+-                              ni_or_null = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
+-                              if (ni_or_null)
+-                                      ni = ni_or_null;
++                              tni = ieee80211_ref_node(vap->iv_wdsnode);
++                      } else if ((vap->iv_opmode == IEEE80211_M_IBSS) && (vap->iv_state == IEEE80211_S_RUN)) {
++                              tni = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
+                               found = 1;
+                       }
+                       IEEE80211_UNLOCK_IRQ(vap->iv_ic);
+@@ -3585,20 +3576,21 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                       if (!found)
+                               break;
+-                      if (ni_or_null == NULL) {
++                      memcpy(&SKB_CB(skb)->beacon_tsf, scan.tstamp, sizeof(u_int64_t));
++
++                      if (tni == NULL) {
+                               if (avp) {
+                                       IEEE80211_LOCK_IRQ(ic);
+-                                      ni = ieee80211_add_neighbor(avp, wh, &scan);
++                                      tni = ieee80211_add_neighbor(avp, wh, &scan);
+                                       /* force assoc */
+-                                      ni->ni_associd |= 0xc000;
+-                                      avp->iv_wdsnode = ieee80211_ref_node(ni);
++                                      tni->ni_associd |= 0xc000;
++                                      avp->iv_wdsnode = ieee80211_ref_node(tni);
+                                       IEEE80211_UNLOCK_IRQ(ic);
+                               } else if ((vap->iv_opmode == IEEE80211_M_IBSS) &&
+                                          IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid)) {
+                                       /* Create a new entry in the neighbor table. */
+-                                      ni = ieee80211_add_neighbor(vap, wh, &scan);
++                                      tni = ieee80211_add_neighbor(vap, wh, &scan);
+                               }
+-                              do_unref = 1;
+                       } else {
+                               /*
+                                * Copy data from beacon to neighbor table.
+@@ -3606,39 +3598,38 @@ ieee80211_recv_mgmt(struct ieee80211vap
+                                * ieee80211_add_neighbor(), so we just copy
+                                * everything over to be safe.
+                                */
+-                              ni->ni_esslen = scan.ssid[1];
+-                              memcpy(ni->ni_essid, scan.ssid + 2, scan.ssid[1]);
+-                              IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
+-                              memcpy(ni->ni_tstamp.data, scan.tstamp,
+-                                      sizeof(ni->ni_tstamp));
+-                              ni->ni_inact = ni->ni_inact_reload;
+-                              ni->ni_intval = 
++                              tni->ni_esslen = scan.ssid[1];
++                              memcpy(tni->ni_essid, scan.ssid + 2, scan.ssid[1]);
++                              IEEE80211_ADDR_COPY(tni->ni_bssid, wh->i_addr3);
++                              memcpy(tni->ni_tstamp.data, scan.tstamp,
++                                      sizeof(tni->ni_tstamp));
++                              tni->ni_inact = tni->ni_inact_reload;
++                              tni->ni_intval =
+                                       IEEE80211_BINTVAL_SANITISE(scan.bintval);
+-                              ni->ni_capinfo = scan.capinfo;
+-                              ni->ni_chan = ic->ic_curchan;
+-                              ni->ni_fhdwell = scan.fhdwell;
+-                              ni->ni_fhindex = scan.fhindex;
+-                              ni->ni_erp = scan.erp;
+-                              ni->ni_timoff = scan.timoff;
++                              tni->ni_capinfo = scan.capinfo;
++                              tni->ni_chan = ic->ic_curchan;
++                              tni->ni_fhdwell = scan.fhdwell;
++                              tni->ni_fhindex = scan.fhindex;
++                              tni->ni_erp = scan.erp;
++                              tni->ni_timoff = scan.timoff;
+                               if (scan.wme != NULL)
+-                                      ieee80211_saveie(&ni->ni_wme_ie, scan.wme);
++                                      ieee80211_saveie(&tni->ni_wme_ie, scan.wme);
+                               if (scan.wpa != NULL)
+-                                      ieee80211_saveie(&ni->ni_wpa_ie, scan.wpa);
++                                      ieee80211_saveie(&tni->ni_wpa_ie, scan.wpa);
+                               if (scan.rsn != NULL)
+-                                      ieee80211_saveie(&ni->ni_rsn_ie, scan.rsn);
++                                      ieee80211_saveie(&tni->ni_rsn_ie, scan.rsn);
+                               if (scan.ath != NULL)
+-                                      ieee80211_saveath(ni, scan.ath);
++                                      ieee80211_saveath(tni, scan.ath);
+                               /* NB: must be after ni_chan is setup */
+-                              ieee80211_setup_rates(ni, scan.rates,
++                              ieee80211_setup_rates(tni, scan.rates,
+                                       scan.xrates, IEEE80211_F_DOSORT);
+                       }
+-                      if (ni != NULL) {
+-                              ni->ni_rssi = rssi;
+-                              ni->ni_rtsf = rtsf;
+-                              ni->ni_last_rx = jiffies;
+-                              if (do_unref)
+-                                      ieee80211_unref_node(&ni);
++                      if (tni != NULL) {
++                              tni->ni_rssi = rssi;
++                              tni->ni_rtsf = rtsf;
++                              tni->ni_last_rx = jiffies;
++                              ieee80211_unref_node(&tni);
+                       }
+               }
+               break;
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -53,6 +53,7 @@
+ #include <net80211/ieee80211_var.h>
+ #include <net80211/if_athproto.h>
++#include <net80211/ieee80211_node.h>
+ /*
+  * Association IDs are managed with a bit vector.
+@@ -317,16 +318,11 @@ ieee80211_create_ibss(struct ieee80211va
+       /* Check to see if we already have a node for this mac
+        * NB: we gain a node reference here
+        */
+-      ni = ieee80211_find_txnode(vap, vap->iv_myaddr);
++      ieee80211_node_table_reset(&ic->ic_sta, vap);
++      ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr);
+       if (ni == NULL) {
+-              ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr);
+-              IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
+-                                "%s: ni:%p allocated for " MAC_FMT "\n",
+-                                __func__, ni, MAC_ADDR(vap->iv_myaddr));
+-              if (ni == NULL) {
+-                      /* XXX recovery? */
+-                      return;
+-              }
++              /* XXX recovery? */
++              return;
+       }
+       IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr);
+@@ -647,7 +643,7 @@ ieee80211_sta_join1(struct ieee80211_nod
+               (vap->iv_state == IEEE80211_S_RUN) && bssid_equal(obss, selbs)); */
+       vap->iv_bss = selbs;
+       IEEE80211_ADDR_COPY(vap->iv_bssid, selbs->ni_bssid);
+-      if (obss != NULL) {
++      if ((obss != NULL) && (obss != selbs)) {
+               if (obss->ni_table)
+                       ieee80211_node_leave(obss);
+               ieee80211_unref_node(&obss);
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6625,14 +6625,6 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+       sc->sc_recv_mgmt(vap, ni_or_null, skb, subtype, rssi, rtsf);
+-      /* Lookup the new node if any (this grabs a reference to it) */
+-      ni = ieee80211_find_rxnode(vap->iv_ic, vap,
+-               (const struct ieee80211_frame_min *)skb->data);
+-      if (ni == NULL) {
+-              DPRINTF(sc, ATH_DEBUG_BEACON, "Dropping; node unknown.\n");
+-              return;
+-      }
+-
+       switch (subtype) {
+       case IEEE80211_FC0_SUBTYPE_BEACON:
+               /* update RSSI statistics for use by the HAL */
+@@ -6654,11 +6646,9 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+                        * we do the IBSS merging in software. Also do not merge
+                        * if the difference it too small. Otherwise we are playing
+                        * tsf-pingpong with other vendors drivers */
+-                      beacon_tsf = le64_to_cpu(ni->ni_tstamp.tsf);
+-                      if (beacon_tsf > rtsf + 0xffff) {
++                      beacon_tsf = le64_to_cpu(SKB_CB(skb)->beacon_tsf);
++                      if (beacon_tsf > rtsf + 0xffff)
+                               ath_hal_settsf64(sc->sc_ah, beacon_tsf - rtsf);
+-                              ieee80211_ibss_merge(ni);
+-                      }
+                       break;
+               }
+               /* NB: Fall Through */
+@@ -6680,13 +6670,21 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+                       hw_tsf = ath_hal_gettsf64(sc->sc_ah);
+                       hw_tu  = hw_tsf >> 10;
+-                      beacon_tsf = le64_to_cpu(ni->ni_tstamp.tsf);
++                      beacon_tsf = le64_to_cpu(SKB_CB(skb)->beacon_tsf);
+                       beacon_tu  = beacon_tsf >> 10;
++                      if (!beacon_tsf)
++                              break;
++
++                      if (IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid))
++                              break;
++
+                       DPRINTF(sc, ATH_DEBUG_BEACON,
+-                                      "Beacon transmitted at %10llx, "
++                                      "Beacon transmitted from "MAC_FMT" ("MAC_FMT") at %10llx, "
+                                       "received at %10llx(%lld), hw TSF "
+                                       "%10llx(%lld)\n",
++                                      MAC_ADDR(wh->i_addr3),
++                                      MAC_ADDR(vap->iv_bssid),
+                                       beacon_tsf,
+                                       rtsf, rtsf - beacon_tsf,
+                                       hw_tsf, hw_tsf - beacon_tsf);
+@@ -6699,39 +6697,13 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+                               do_merge = 1;
+                       }
+-                      /* Check sc_nexttbtt */
+-                      if (sc->sc_nexttbtt < hw_tu) {
+-                              DPRINTF(sc, ATH_DEBUG_BEACON,
+-                                      "sc_nexttbtt (%8x TU) is in the past "
+-                                      "(tsf %8x TU), updating timers\n",
+-                                      sc->sc_nexttbtt, hw_tu);
+-                              do_merge = 1;
+-                      }
+-
+-                      intval = ni->ni_intval & HAL_BEACON_PERIOD;
+-#if 0
+-                      /* This code is disabled since it would produce
+-                       * unwanted merge. For instance, in a two nodes network
+-                       * A & B, A can merge to B and at the same time, B will
+-                       * merge to A, still having a split */
+-                      if (intval != 0) {
+-                              if ((sc->sc_nexttbtt % intval) !=
+-                                              (beacon_tu % intval)) {
+-                                      DPRINTF(sc, ATH_DEBUG_BEACON,
+-                                                      "ibss merge: "
+-                                                      "sc_nexttbtt %10x TU "
+-                                                      "(%3d) beacon %10x TU "
+-                                                      "(%3d)\n",
+-                                                      sc->sc_nexttbtt,
+-                                                      sc->sc_nexttbtt % intval,
+-                                                      beacon_tu,
+-                                                      beacon_tu % intval);
+-                                      do_merge = 1;
+-                              }
+-                      }
+-#endif
+-                      if (do_merge)
++                      if (do_merge) {
++                              /* Lookup the new node if any (this grabs a reference to it) */
++                              ni = ieee80211_find_txnode(vap, wh->i_addr2);
++                              memcpy(ni->ni_bssid, wh->i_addr3, IEEE80211_ADDR_LEN);
+                               ieee80211_ibss_merge(ni);
++                              ieee80211_unref_node(&ni);
++                      }
+                       if ((sc->sc_opmode == HAL_M_IBSS) &&
+                                       ath_hw_check_atim(sc, 1, vap->iv_bss->ni_intval))
+@@ -6739,8 +6711,6 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+               }
+               break;
+       }
+-
+-      ieee80211_unref_node(&ni);
+ }
+ static void
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -411,7 +411,7 @@ typedef spinlock_t acl_lock_t;
+  *     8 bytes so we reserve/avoid it.
+  */
+       struct ieee80211_cb {
+-      u_int8_t vlan[8];                       /* reserve for vlan tag info */
++      u_int64_t beacon_tsf;
+       struct ieee80211_node *ni;
+       u_int32_t flags;
+ #define       M_LINK0         0x01                    /* frame needs WEP encryption */
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -1125,11 +1125,8 @@ adhoc_default_action(struct ieee80211vap
+       u_int8_t zeroMacAddr[IEEE80211_ADDR_LEN];
+       memset(&zeroMacAddr, 0, IEEE80211_ADDR_LEN);
+-      if (IEEE80211_ADDR_EQ(se->se_bssid, &zeroMacAddr[0])) {
+-              ieee80211_create_ibss(vap, se->se_chan);
+-              return 1;
+-      } else
+-              return ieee80211_sta_join(vap, se);
++      ieee80211_create_ibss(vap, se->se_chan);
++      return 1;
+ }
+ static const struct ieee80211_scanner adhoc_default = {
diff --git a/net/madwifi/patches/452-minstrel_no_timer.patch b/net/madwifi/patches/452-minstrel_no_timer.patch
new file mode 100644 (file)
index 0000000..f0f5c26
--- /dev/null
@@ -0,0 +1,134 @@
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -119,6 +119,7 @@
+ #include "minstrel.h"
+ #define ONE_SECOND (1000 * 1000)  /* 1 second, or 1000 milliseconds; eternity, in other words */
++#define TIMER_INTERVAL 100 /* msecs */
+ #include "release.h"
+@@ -128,9 +129,6 @@ static char *dev_info = "ath_rate_minstr
+ #define STALE_FAILURE_TIMEOUT_MS 10000
+ #define ENABLE_MRR 1
+-static int ath_timer_interval = (1000 / 10); /* every 1/10 second, timer runs */
+-static void ath_timer_function(unsigned long data);
+-
+ /* 10% of the time, send a packet at something other than the optimal rate, which fills
+  * the statistics tables nicely. This percentage is applied to the first packet of the
+  * multi rate retry chain. */
+@@ -142,7 +140,7 @@ static void ath_rate_ctl_reset(struct at
+ /* Calculate the throughput and probability of success for each node
+  * we are talking on, based on the statistics collected during the
+  * last timer period. */
+-static void ath_rate_statistics(void *arg, struct ieee80211_node *ni);
++static void ath_rate_statistics(struct ieee80211_node *ni);
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+@@ -204,6 +202,11 @@ ath_rate_findrate(struct ath_softc *sc,
+               unsigned int ndx, offset;
+               int mrr;
++
++              if (abs(jiffies - sn->last_update) > msecs_to_jiffies(TIMER_INTERVAL)) {
++                      ath_rate_statistics(&an->an_node);
++                      sn->last_update = jiffies;
++              }
+               if (sn->num_rates <= 0) {
+                           printk(KERN_WARNING "%s: no rates for " MAC_FMT "?\n",
+                                  dev_info,
+@@ -640,54 +643,11 @@ ath_rate_newstate(struct ieee80211vap *v
+               }
+ }
+-static void
+-ath_timer_function(unsigned long data)
+-{
+-              struct minstrel_softc *ssc = (struct minstrel_softc *) data;
+-              struct ath_softc *sc = ssc->sc;
+-              struct ieee80211com *ic;
+-              struct net_device *dev = ssc->sc_dev;
+-              struct timer_list *timer;
+-              unsigned int interval = ath_timer_interval;
+-
+-              if (dev == NULL)
+-                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: 'dev' is null in this timer \n", __func__);
+-
+-              if (sc == NULL)
+-                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: 'sc' is null in this timer\n", __func__);
+-
+-              ic = &sc->sc_ic;
+-
+-              if (ssc->close_timer_now)
+-                      return;
+-
+-              if (dev->flags & IFF_RUNNING) {
+-                      sc->sc_stats.ast_rate_calls++;
+-
+-                      if (ic->ic_opmode == IEEE80211_M_STA) {
+-                              struct ieee80211vap *tmpvap;
+-                              TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
+-                                      ath_rate_statistics(sc, tmpvap->iv_bss);/* NB: no reference */
+-                              }
+-                      } else
+-                                  ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_statistics, sc);
+-              }
+-
+-              if (ic->ic_opmode == IEEE80211_M_STA)
+-                      interval = ath_timer_interval >> 1;
+-
+-              timer  = &(ssc->timer);
+-              if (timer == NULL)
+-                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: timer is null - leave it\n", __func__);
+-
+-              timer->expires = jiffies + ((HZ * interval) / 1000);
+-              add_timer(timer);
+-}
+ static void
+-ath_rate_statistics(void *arg, struct ieee80211_node *ni)
++ath_rate_statistics(struct ieee80211_node *ni)
+ {
+-              struct ath_node *an = (struct ath_node *) ni;
++              struct ath_node *an = ATH_NODE(ni);
+               struct ieee80211_rateset *rs = &ni->ni_rates;
+               struct minstrel_node *rn = ATH_NODE_MINSTREL(an);
+               unsigned int i;
+@@ -786,15 +746,8 @@ ath_rate_attach(struct ath_softc *sc)
+               osc->arc.arc_space = sizeof(struct minstrel_node);
+               osc->arc.arc_vap_space = 0;
+-              osc->close_timer_now = 0;
+-              init_timer(&osc->timer);
+       osc->sc          = sc;
+               osc->sc_dev      = sc->sc_dev;
+-              osc->timer.function = ath_timer_function;
+-              osc->timer.data = (unsigned long)osc;
+-
+-              osc->timer.expires = jiffies + HZ;
+-              add_timer(&osc->timer);
+               return &osc->arc;
+ }
+@@ -803,8 +756,6 @@ static void
+ ath_rate_detach(struct ath_ratectrl *arc)
+ {
+       struct minstrel_softc *osc = (struct minstrel_softc *) arc;
+-              osc->close_timer_now = 1;
+-              del_timer(&osc->timer);
+               kfree(osc);
+               _MOD_DEC_USE(THIS_MODULE);
+ }
+--- a/ath_rate/minstrel/minstrel.h
++++ b/ath_rate/minstrel/minstrel.h
+@@ -167,6 +167,8 @@ struct minstrel_node {
+              packet, or a packet at an optimal rate.*/
+       int random_n;
+       int a, b;          /**Coefficients of the random thing */
++
++      unsigned long last_update;
+ };
diff --git a/net/madwifi/patches/453-procps.patch b/net/madwifi/patches/453-procps.patch
new file mode 100644 (file)
index 0000000..5a5633b
--- /dev/null
@@ -0,0 +1,55 @@
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -640,12 +640,24 @@ static __inline unsigned long msecs_to_j
+         void __user *buffer, size_t *lenp)
+ #define       IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
+       proc_dointvec(ctl, write, filp, buffer, lenp)
+-#else
++#define IEEE80211_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
++        proc_dostring(ctl, write, filp, buffer, lenp)
++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+ #define       IEEE80211_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \
+       f(ctl_table *ctl, int write, struct file *filp, \
+         void __user *buffer, size_t *lenp, loff_t *ppos)
+ #define       IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
+       proc_dointvec(ctl, write, filp, buffer, lenp, ppos)
++#define IEEE80211_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
++        proc_dostring(ctl, write, filp, buffer, lenp, ppos)
++#else /* Linux 2.6.32+ */
++#define       IEEE80211_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \
++      f(ctl_table *ctl, int write, \
++        void __user *buffer, size_t *lenp, loff_t *ppos)
++#define       IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
++      proc_dointvec(ctl, write, buffer, lenp, ppos)
++#define IEEE80211_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
++        proc_dostring(ctl, write, buffer, lenp, ppos)
+ #endif
+ void ieee80211_virtfs_latevattach(struct ieee80211vap *);
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -173,14 +173,22 @@ static inline struct net_device *_alloc_
+       proc_dointvec(ctl, write, filp, buffer, lenp)
+ #define       ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
+       proc_dostring(ctl, write, filp, buffer, lenp)
+-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) */
++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+ #define       ATH_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \
+       f(ctl_table *ctl, int write, struct file *filp, \
+         void __user *buffer, size_t *lenp, loff_t *ppos)
+ #define       ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
+       proc_dointvec(ctl, write, filp, buffer, lenp, ppos)
++#define ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
++        proc_dostring(ctl, write, filp, buffer, lenp, ppos)
++#else /* Linux 2.6.32+ */
++#define       ATH_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \
++      f(ctl_table *ctl, int write, \
++        void __user *buffer, size_t *lenp, loff_t *ppos)
++#define       ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
++      proc_dointvec(ctl, write, buffer, lenp, ppos)
+ #define       ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
+-      proc_dostring(ctl, write, filp, buffer, lenp, ppos)
++      proc_dostring(ctl, write, buffer, lenp, ppos)
+ #endif
+ #define       ATH_TIMEOUT     1000
diff --git a/net/madwifi/patches/454-cca.patch b/net/madwifi/patches/454-cca.patch
new file mode 100644 (file)
index 0000000..53792cc
--- /dev/null
@@ -0,0 +1,186 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -383,6 +383,8 @@ static void ath_poll_disable(struct net_
+ static void ath_poll_enable(struct net_device *dev);
+ static void ath_fetch_idle_time(struct ath_softc *sc);
+ static void ath_set_timing(struct ath_softc *sc);
++static void ath_update_cca_thresh(struct ath_softc *sc);
++static int ath_hw_read_nf(struct ath_softc *sc);
+ /* calibrate every 30 secs in steady state but check every second at first. */
+ static int ath_calinterval = ATH_SHORT_CALINTERVAL;
+@@ -2623,6 +2625,10 @@ ath_init(struct net_device *dev)
+               goto done;
+       }
++      ath_hal_process_noisefloor(ah);
++      ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
++      ath_update_cca_thresh(sc);
++
+       if (sc->sc_softled)
+               ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
+@@ -3024,6 +3030,10 @@ ath_reset(struct net_device *dev)
+               EPRINTF(sc, "Unable to reset hardware: '%s' (HAL status %u)\n",
+                       ath_get_hal_status_desc(status), status);
++      ath_hal_process_noisefloor(ah);
++      ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
++      ath_update_cca_thresh(sc);
++
+       ath_setintmit(sc);
+       ath_update_txpow(sc);           /* update tx power state */
+       ath_radar_update(sc);
+@@ -9374,9 +9384,11 @@ ath_calibrate(unsigned long arg)
+                       sc->sc_curchan.channel);
+               sc->sc_stats.ast_per_calfail++;
+       }
+-      ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
+       ath_hal_process_noisefloor(ah);
++      ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
++      ath_update_cca_thresh(sc);
++
+       if (isIQdone == AH_TRUE) {
+               /* Unless user has overridden calibration interval,
+                * upgrade to less frequent calibration */
+@@ -9711,8 +9723,6 @@ ath_newstate(struct ieee80211vap *vap, e
+                       break;
+               }
+-              ath_hal_process_noisefloor(ah);
+-              ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
+               /*
+                * Reset rssi stats; maybe not the best place...
+                */
+@@ -10968,6 +10978,7 @@ enum {
+       ATH_INTMIT,
+       ATH_NOISE_IMMUNITY,
+       ATH_OFDM_WEAK_DET,
++      ATH_CCA_THRESH,
+       ATH_CHANBW,
+       ATH_OUTDOOR,
+       ATH_DISTANCE,
+@@ -11110,6 +11121,66 @@ ath_sysctl_get_intmit(struct ath_softc *
+       return 0;
+ }
++#define AR_PHY_CCA              0x9864
++#define AR_PHY_MINCCA_PWR       0x0FF80000
++#define AR_PHY_MINCCA_PWR_S     19
++#define AR_PHY_CCA_THRESH62     0x0007F000
++#define AR_PHY_CCA_THRESH62_S   12
++
++static int
++ath_nf_from_cca(u32 phy_cca)
++{
++      int nf = (phy_cca >> 19) & 0x1ff;
++      nf = -((nf ^ 0x1ff) + 1);
++      return nf;
++}
++
++static int
++ath_hw_read_nf(struct ath_softc *sc)
++{
++      return ath_nf_from_cca(OS_REG_READ(sc->sc_ah, AR_PHY_CCA));
++}
++
++static void
++ath_update_cca_thresh(struct ath_softc *sc)
++{
++      struct ath_hal *ah = sc->sc_ah;
++      int newthr = 0;
++      u32 phy_cca;
++      int nf;
++
++      phy_cca = OS_REG_READ(ah, AR_PHY_CCA);
++      if (sc->sc_cca_thresh < 0) {
++              newthr = sc->sc_cca_thresh - ath_nf_from_cca(phy_cca);
++
++              /* 0xf is a typical eeprom value for thresh62,
++               * use it as minimum for signal based thresholds
++               * to prevent complete connection drops */
++              if (newthr < 0xf)
++                      newthr = 0xf;
++      } else {
++              newthr = sc->sc_cca_thresh;
++      }
++
++      if ((newthr < 4) || (newthr >= 127))
++              return;
++
++      phy_cca &= ~AR_PHY_CCA_THRESH62;
++      phy_cca |= newthr << AR_PHY_CCA_THRESH62_S;
++      OS_REG_WRITE(ah, AR_PHY_CCA, phy_cca);
++}
++
++static int
++ath_get_cca_thresh(struct ath_softc *sc)
++{
++      struct ath_hal *ah = sc->sc_ah;
++      u32 phy_cca;
++
++      phy_cca = OS_REG_READ(ah, AR_PHY_CCA);
++      return ath_nf_from_cca(phy_cca) +
++              ((phy_cca & AR_PHY_CCA_THRESH62) >> AR_PHY_CCA_THRESH62_S);
++}
++
+ static int
+ ATH_SYSCTL_DECL(ath_sysctl_hwinfo, ctl, write, filp, buffer, lenp, ppos)
+ {
+@@ -11356,6 +11427,10 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+                       case ATH_OFDM_WEAK_DET:
+                               ret = ath_sysctl_set_intmit(sc, (long)ctl->extra2, val);
+                               break;
++                      case ATH_CCA_THRESH:
++                              sc->sc_cca_thresh = val;
++                              ath_update_cca_thresh(sc);
++                              break;
+                       default:
+                               ret = -EINVAL;
+                               break;
+@@ -11436,6 +11511,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+               case ATH_OFDM_WEAK_DET:
+                       ret = ath_sysctl_get_intmit(sc, (long)ctl->extra2, &val);
+                       break;
++              case ATH_CCA_THRESH:
++                      val = ath_get_cca_thresh(sc);
++                      break;
+               default:
+                       ret = -EINVAL;
+                       break;
+@@ -11667,6 +11745,12 @@ static const ctl_table ath_sysctl_templa
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_OFDM_WEAK_DET,
+       },
++      { .ctl_name     = CTL_AUTO,
++        .procname     = "cca_thresh",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_halparam,
++        .extra2       = (void *)ATH_CCA_THRESH,
++      },
+       { 0 }
+ };
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -844,6 +844,7 @@ struct ath_softc {
+       int sc_cal_interval;                    /* current calibration interval */
+       struct timer_list sc_cal_ch;            /* calibration timer */
+       HAL_NODE_STATS sc_halstats;             /* station-mode rssi stats */
++      int sc_cca_thresh;                              /* configured CCA threshold */
+       struct ctl_table_header *sc_sysctl_header;
+       struct ctl_table *sc_sysctls;
+--- a/ath/ath_wprobe.c
++++ b/ath/ath_wprobe.c
+@@ -133,8 +133,7 @@ ath_wprobe_sync(struct wprobe_iface *dev
+       rx = READ_CLR(ah, AR5K_RXFC);
+       tx = READ_CLR(ah, AR5K_TXFC);
+       OS_REG_WRITE(ah, AR5K_MIBC, 0);
+-      noise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan));
+-      ic->ic_channoise = noise;
++      noise = ath_hw_read_nf(sc);
+       WPROBE_FILL_BEGIN(val, ath_wprobe_globals);
+       if (cc & 0xf0000000) {
diff --git a/net/madwifi/patches/455-beacon_watchdog.patch b/net/madwifi/patches/455-beacon_watchdog.patch
new file mode 100644 (file)
index 0000000..d0b4fa6
--- /dev/null
@@ -0,0 +1,95 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -379,6 +379,7 @@ static u_int32_t ath_get_clamped_maxtxpo
+ static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc, 
+               u_int32_t new_clamped_maxtxpower);
++static void ath_bcn_timer(unsigned long arg);
+ static void ath_poll_disable(struct net_device *dev);
+ static void ath_poll_enable(struct net_device *dev);
+ static void ath_fetch_idle_time(struct ath_softc *sc);
+@@ -829,6 +830,10 @@ ath_attach(u_int16_t devid, struct net_d
+       sc->sc_cal_ch.function = ath_calibrate;
+       sc->sc_cal_ch.data = (unsigned long) dev;
++      init_timer(&sc->sc_bcntimer);
++      sc->sc_bcntimer.function = ath_bcn_timer;
++      sc->sc_bcntimer.data = (unsigned long) dev;
++
+       /* initialize DFS related variables */
+       sc->sc_dfswait = 0;
+       sc->sc_dfs_cac = 0;
+@@ -2704,6 +2709,7 @@ ath_stop_locked(struct net_device *dev)
+       DPRINTF(sc, ATH_DEBUG_RESET, "invalid=%u flags=0x%x\n",
+               sc->sc_invalid, dev->flags);
++      del_timer_sync(&sc->sc_bcntimer);
+       if (dev->flags & IFF_RUNNING) {
+               /*
+                * Shutdown the hardware and driver:
+@@ -3006,6 +3012,7 @@ ath_reset(struct net_device *dev)
+       struct ieee80211_channel *c;
+       HAL_STATUS status;
++      del_timer_sync(&sc->sc_bcntimer);
+       /*
+        * XXX: starting the calibration too early seems to lead to
+        * problems with the beacons.
+@@ -5305,6 +5312,7 @@ ath_beacon_send(struct ath_softc *sc, in
+       if (ath_chan_unavail_dbgmsg(sc))
+               return;
++      mod_timer(&sc->sc_bcntimer, jiffies + sc->sc_bcntimer_reload);
+       /*
+        * Check if the previous beacon has gone out.  If
+        * not don't try to post another, skip this period
+@@ -5487,6 +5495,18 @@ ath_beacon_free(struct ath_softc *sc)
+               cleanup_ath_buf(sc, bf, BUS_DMA_TODEVICE);
+ }
++static void ath_bcn_timer(unsigned long arg)
++{
++      struct net_device *dev = (struct net_device *)arg;
++      struct ath_softc *sc = netdev_priv(dev);
++      struct ath_hal *ah = sc->sc_ah;
++
++      if (!sc->sc_beacons)
++              return;
++
++      ath_reset(dev);
++}
++
+ /*
+  * Configure the beacon and sleep timers.
+  *
+@@ -5523,6 +5543,7 @@ ath_beacon_config(struct ath_softc *sc,
+       if (vap == NULL)
+               vap = TAILQ_FIRST(&ic->ic_vaps);   /* XXX */
++      del_timer_sync(&sc->sc_bcntimer);
+       ni = vap->iv_bss;
+       /* TSF calculation is timing critical - we don't want to be interrupted here */
+@@ -5699,6 +5720,9 @@ ath_beacon_config(struct ath_softc *sc,
+                       sc->sc_imask |= HAL_INT_SWBA;
+                       ath_set_beacon_cal(sc, 1);
+                       ath_beaconq_config(sc);
++
++                      sc->sc_bcntimer_reload = msecs_to_jiffies(10 * (intval & HAL_BEACON_PERIOD));
++                      mod_timer(&sc->sc_bcntimer, jiffies + sc->sc_bcntimer_reload);
+               } else
+                       ath_set_beacon_cal(sc, 0);
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -789,6 +789,10 @@ struct ath_softc {
+       u_int16_t sc_ledoff;                    /* off time for current blink */
+       struct timer_list sc_ledtimer;          /* led off timer */
++      /* beacon watchdog timer */
++      u_int32_t sc_bcntimer_reload;
++      struct timer_list sc_bcntimer;
++
+       struct ATH_TQ_STRUCT sc_fataltq;        /* fatal error intr tasklet */
+       int sc_rxbufsize;                       /* rx size based on mtu */
diff --git a/net/madwifi/patches/456-rfsilent.patch b/net/madwifi/patches/456-rfsilent.patch
new file mode 100644 (file)
index 0000000..21031e7
--- /dev/null
@@ -0,0 +1,85 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -2996,6 +2996,19 @@ ath_fetch_idle_time(struct ath_softc *sc
+ #undef AR5K_RXCLEAR
+ #undef AR5K_CYCLES
++static void
++ath_set_silent(struct ath_softc *sc)
++{
++      struct ath_hal *ah = sc->sc_ah;
++
++      if (!sc->sc_silent)
++              return;
++
++      del_timer_sync(&sc->sc_bcntimer);
++      ath_hal_intrset(ah, 0);
++      OS_REG_WRITE(ah, 0x8048, 0x60); /* set tx loopback and rx disable */
++}
++
+ /*
+  * Reset the hardware w/o losing operational state.  This is
+  * basically a more efficient way of doing ath_stop, ath_init,
+@@ -3073,6 +3086,7 @@ ath_reset(struct net_device *dev)
+               ath_grppoll_start(vap, sc->sc_xrpollcount);
+       }
+ #endif
++      ath_set_silent(sc);
+       return 0;
+ }
+@@ -10972,6 +10986,7 @@ enum {
+  * mirrored in /proc/sys.
+  */
+ enum {
++      ATH_SILENT,
+       ATH_SLOTTIME,
+       ATH_ACKTIMEOUT,
+       ATH_CTSTIMEOUT,
+@@ -11294,6 +11309,13 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+                                       sc->sc_ctstimeconf = 0;
+                               ath_set_timing(sc);
+                               break;
++                      case ATH_SILENT:
++                              sc->sc_silent = !!val;
++                              if (val)
++                                      ath_set_silent(sc);
++                              else
++                                      ath_reset(sc->sc_dev);
++                              break;
+                       case ATH_DISTANCE:
+                               if (val > 0) {
+                                       sc->sc_coverage = ((val - 1) / 300) + 1;
+@@ -11477,6 +11499,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+               case ATH_CTSTIMEOUT:
+                       val = ath_hal_getctstimeout(ah);
+                       break;
++              case ATH_SILENT:
++                      val = sc->sc_silent;
++                      break;
+               case ATH_SOFTLED:
+                       val = sc->sc_softled;
+                       break;
+@@ -11598,6 +11623,12 @@ static const ctl_table ath_sysctl_templa
+         .extra2       = (void *)ATH_DISTANCE,
+       },
+       { .ctl_name     = CTL_AUTO,
++        .procname     = "silent",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_halparam,
++        .extra2       = (void *)ATH_SILENT,
++      },
++      { .ctl_name     = CTL_AUTO,
+         .procname     = "softled",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -737,6 +737,7 @@ struct ath_softc {
+                                                * 'channel availability check' indefinately,
+                                                * reporting radar and interference detections.
+                                                */
++      unsigned int    sc_silent:1;    /* Turn RF silent */
+       unsigned int sc_txcont_power; /* Continuous transmit power in 0.5dBm units */
+       unsigned int sc_txcont_rate;  /* Continuous transmit rate in Mbps */
diff --git a/net/madwifi/patches/457-idletime.patch b/net/madwifi/patches/457-idletime.patch
new file mode 100644 (file)
index 0000000..429da85
--- /dev/null
@@ -0,0 +1,151 @@
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -355,6 +355,8 @@ ieee80211_ifattach(struct ieee80211com *
+       /* Arbitrarily pick the first channel */
+       ic->ic_curchan = &ic->ic_channels[0];
++      ic->ic_inact_tick = IEEE80211_INACT_WAIT;
++
+       /* Enable marking of dfs by default */
+       ic->ic_flags_ext |= IEEE80211_FEXT_MARKDFS;
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -350,6 +350,7 @@ struct ieee80211com {
+       u_int8_t ic_protmode_rssi;                      /* rssi threshold for protection mode */
+       u_int64_t ic_protmode_lasttrig;         /* last trigger for protection mode */
+       u_int16_t ic_protmode_timeout;          /* protection mode timeout */
++      u_int16_t ic_inact_tick;                        /* inact timer tick interval (seconds) */
+       /* Channel state:
+        *
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -591,6 +591,7 @@ enum {
+       IEEE80211_PARAM_INACT_AUTH              = 24,   /* station auth inact timeout */
+       IEEE80211_PARAM_INACT_INIT              = 25,   /* station init inact timeout */
+       IEEE80211_PARAM_ABOLT                   = 26,   /* Atheros Adv. Capabilities */
++      IEEE80211_PARAM_INACT_TICK              = 27,   /* station inactivity timer tick (seconds) */
+       IEEE80211_PARAM_DTIM_PERIOD             = 28,   /* DTIM period (beacons) */
+       IEEE80211_PARAM_BEACON_INTERVAL         = 29,   /* beacon interval (ms) */
+       IEEE80211_PARAM_DOTH                    = 30,   /* 11.h is on/off */
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2504,13 +2504,18 @@ ieee80211_ioctl_setparam(struct net_devi
+                       vap->iv_flags &= ~IEEE80211_F_NOBRIDGE;
+               break;
+       case IEEE80211_PARAM_INACT:
+-              vap->iv_inact_run = value / IEEE80211_INACT_WAIT;
++              vap->iv_inact_run = value / ic->ic_inact_tick;
++              break;
++      case IEEE80211_PARAM_INACT_TICK:
++              if (value <= 0)
++                      return -EINVAL;
++              ic->ic_inact_tick = value;
+               break;
+       case IEEE80211_PARAM_INACT_AUTH:
+-              vap->iv_inact_auth = value / IEEE80211_INACT_WAIT;
++              vap->iv_inact_auth = value / ic->ic_inact_tick;
+               break;
+       case IEEE80211_PARAM_INACT_INIT:
+-              vap->iv_inact_init = value / IEEE80211_INACT_WAIT;
++              vap->iv_inact_init = value / ic->ic_inact_tick;
+               break;
+       case IEEE80211_PARAM_ABOLT:
+               caps = 0;
+@@ -3050,13 +3055,16 @@ ieee80211_ioctl_getparam(struct net_devi
+               param[0] = (vap->iv_flags & IEEE80211_F_NOBRIDGE) == 0;
+               break;
+       case IEEE80211_PARAM_INACT:
+-              param[0] = vap->iv_inact_run * IEEE80211_INACT_WAIT;
++              param[0] = vap->iv_inact_run * ic->ic_inact_tick;
+               break;
+       case IEEE80211_PARAM_INACT_AUTH:
+-              param[0] = vap->iv_inact_auth * IEEE80211_INACT_WAIT;
++              param[0] = vap->iv_inact_auth * ic->ic_inact_tick;
+               break;
+       case IEEE80211_PARAM_INACT_INIT:
+-              param[0] = vap->iv_inact_init * IEEE80211_INACT_WAIT;
++              param[0] = vap->iv_inact_init * ic->ic_inact_tick;
++              break;
++      case IEEE80211_PARAM_INACT_TICK:
++              param[0] = ic->ic_inact_tick;
+               break;
+       case IEEE80211_PARAM_ABOLT:
+               /*
+@@ -4557,14 +4565,7 @@ get_sta_info(void *arg, struct ieee80211
+               si->isi_opmode = IEEE80211_STA_OPMODE_XR;
+       else
+               si->isi_opmode = IEEE80211_STA_OPMODE_NORMAL;
+-      /* NB: leave all cases in case we relax ni_associd == 0 check */
+-      if (ieee80211_node_is_authorized(ni))
+-              si->isi_inact = vap->iv_inact_run;
+-      else if (ni->ni_associd != 0)
+-              si->isi_inact = vap->iv_inact_auth;
+-      else
+-              si->isi_inact = vap->iv_inact_init;
+-      si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
++      si->isi_inact = (ni->ni_inact_reload - ni->ni_inact) * ic->ic_inact_tick;
+       cp = (u_int8_t *)(si+1);
+       if (ni->ni_rsn_ie != NULL) {
+@@ -5597,6 +5598,10 @@ static const struct iw_priv_args ieee802
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inact_init" },
+       { IEEE80211_PARAM_INACT_INIT,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_inact_init" },
++      { IEEE80211_PARAM_INACT_TICK,
++        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inact_tick" },
++      { IEEE80211_PARAM_INACT_TICK,
++        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_inact_tick" },
+       { IEEE80211_PARAM_ABOLT,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "abolt" },
+       { IEEE80211_PARAM_ABOLT,
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -137,7 +137,7 @@ ieee80211_node_attach(struct ieee80211co
+       init_timer(&ic->ic_inact);
+       ic->ic_inact.function = ieee80211_node_timeout;
+       ic->ic_inact.data = (unsigned long) ic;
+-      ic->ic_inact.expires = jiffies + IEEE80211_INACT_WAIT * HZ;
++      ic->ic_inact.expires = jiffies + ic->ic_inact_tick * HZ;
+       add_timer(&ic->ic_inact);
+ #ifdef IEEE80211_DEBUG_REFCNT
+@@ -261,7 +261,7 @@ void
+ ieee80211_node_authorize(struct ieee80211_node *ni)
+ {
+       ni->ni_flags |= IEEE80211_NODE_AUTH;
+-      ni->ni_inact_reload = ni->ni_vap->iv_inact_run;
++      ni->ni_inact = ni->ni_inact_reload = ni->ni_vap->iv_inact_run;
+ }
+ EXPORT_SYMBOL(ieee80211_node_authorize);
+@@ -1819,7 +1819,7 @@ ieee80211_node_timeout(unsigned long arg
+               }
+       }
+-      ic->ic_inact.expires = jiffies + IEEE80211_INACT_WAIT * HZ;
++      ic->ic_inact.expires = jiffies + ic->ic_inact_tick * HZ;
+       add_timer(&ic->ic_inact);
+ }
+--- a/net80211/ieee80211_power.c
++++ b/net80211/ieee80211_power.c
+@@ -148,7 +148,7 @@ ieee80211_node_saveq_age(struct ieee8021
+               IEEE80211_NODE_SAVEQ_LOCK_IRQ(ni);
+               while ((skb = skb_peek(&ni->ni_savedq)) != NULL &&
+-                   M_AGE_GET(skb) < IEEE80211_INACT_WAIT) {
++                   M_AGE_GET(skb) <  ni->ni_vap->iv_ic->ic_inact_tick) {
+                       IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
+                               "discard frame, age %u", M_AGE_GET(skb));
+@@ -159,7 +159,7 @@ ieee80211_node_saveq_age(struct ieee8021
+                       discard++;
+               }
+               if (skb != NULL)
+-                      M_AGE_SUB(skb, IEEE80211_INACT_WAIT);
++                      M_AGE_SUB(skb, ni->ni_vap->iv_ic->ic_inact_tick);
+               IEEE80211_NODE_SAVEQ_UNLOCK_IRQ(ni);
+               IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
diff --git a/net/madwifi/patches/458-ibss_wpa_none.patch b/net/madwifi/patches/458-ibss_wpa_none.patch
new file mode 100644 (file)
index 0000000..df77510
--- /dev/null
@@ -0,0 +1,13 @@
+--- a/net80211/ieee80211_crypto_ccmp.c
++++ b/net80211/ieee80211_crypto_ccmp.c
+@@ -273,7 +273,9 @@ ccmp_decap(struct ieee80211_key *k, stru
+               tid = ((struct ieee80211_qosframe *)wh)->i_qos[0] & IEEE80211_QOS_TID;
+       /* NB: assume IEEE80211_WEP_MINLEN covers the extended IV */
+       pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
+-      if (pn && pn <= k->wk_keyrsc[tid]) {
++      if ((vap->iv_opmode != IEEE80211_M_IBSS) &&
++          (vap->iv_opmode != IEEE80211_M_AHDEMO) &&
++          (pn && pn <= k->wk_keyrsc[tid])) {
+               /*
+                * Replay violation.
+                */
diff --git a/net/madwifi/patches/459-2.6.33_compile.patch b/net/madwifi/patches/459-2.6.33_compile.patch
new file mode 100644 (file)
index 0000000..4e08a01
--- /dev/null
@@ -0,0 +1,524 @@
+--- a/kernelversion.c
++++ b/kernelversion.c
+@@ -10,7 +10,11 @@
+ /* Linux 2.6.18+ uses <linux/utsrelease.h> */
+ #ifndef UTS_RELEASE
+-#include <linux/utsrelease.h>
++  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
++    #include <generated/utsrelease.h>
++  #else
++    #include <linux/utsrelease.h>
++  #endif
+ #endif
+ char *uts_release = UTS_RELEASE;
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -11580,227 +11580,231 @@ static int mincalibrate = 1;               /* once a
+ static int maxint = 0x7fffffff;               /* 32-bit big */
+ static const ctl_table ath_sysctl_template[] = {
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "dev_vendor",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_hwinfo,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+         .strategy   = &sysctl_string,
++#endif
+         .data         = "N/A",
+         .maxlen   = 1,
+         .extra2       = (void *)ATH_CARD_VENDOR,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "dev_name",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_hwinfo,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+         .strategy   = &sysctl_string,
++#endif
+         .data         = "N/A",
+         .maxlen   = 1,
+         .extra2       = (void *)ATH_CARD_NAME,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "slottime",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_SLOTTIME,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "acktimeout",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_ACKTIMEOUT,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "ctstimeout",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_CTSTIMEOUT,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "distance",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_DISTANCE,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "silent",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_SILENT,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "softled",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_SOFTLED,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "ledpin",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_LEDPIN,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "countrycode",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_COUNTRYCODE,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "outdoor",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_OUTDOOR,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "regdomain",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_REGDOMAIN,
+       },
+ #ifdef AR_DEBUG
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "debug",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_DEBUG,
+       },
+ #endif
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "poweroffset",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_POWEROFFSET,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "txantenna",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_TXANTENNA,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "rxantenna",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_RXANTENNA,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "diversity",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_DIVERSITY,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "txintrperiod",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_TXINTRPERIOD,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "fftxqmin",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_FFTXQMIN,
+       },
+ #ifdef ATH_SUPERG_XR
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "xrpollperiod",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_XR_POLL_PERIOD,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "xrpollcount",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_XR_POLL_COUNT,
+       },
+ #endif
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "ackrate",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_ACKRATE,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "channelbw",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_CHANBW,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "rp",
+         .mode         = 0200,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_RP,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "radar_print",
+         .mode         = 0200,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_RP_PRINT,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "radar_print_all",
+         .mode         = 0200,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_RP_PRINT_ALL,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "radar_dump",
+         .mode         = 0200,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_RP_PRINT_MEM,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "radar_dump_all",
+         .mode         = 0200,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_RP_PRINT_MEM_ALL,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "rp_flush",
+         .mode         = 0200,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_RP_FLUSH,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "panic",
+         .mode         = 0200,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_PANIC,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "rp_ignored",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_RP_IGNORED,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "radar_ignored",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_RADAR_IGNORED,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "intmit",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_INTMIT,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "noise_immunity",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_NOISE_IMMUNITY,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "ofdm_weak_det",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_OFDM_WEAK_DET,
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "cca_thresh",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+@@ -11838,12 +11842,16 @@ ath_dynamic_sysctl_register(struct ath_s
+       /* setup the table */
+       memset(sc->sc_sysctls, 0, space);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+       sc->sc_sysctls[0].ctl_name = CTL_DEV;
++#endif
+       sc->sc_sysctls[0].procname = "dev";
+       sc->sc_sysctls[0].mode = 0555;
+       sc->sc_sysctls[0].child = &sc->sc_sysctls[2];
+       /* [1] is NULL terminator */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+       sc->sc_sysctls[2].ctl_name = CTL_AUTO;
++#endif
+       sc->sc_sysctls[2].procname = dev_name;
+       sc->sc_sysctls[2].mode = 0555;
+       sc->sc_sysctls[2].child = &sc->sc_sysctls[4];
+@@ -11966,7 +11974,7 @@ ath_announce(struct net_device *dev)
+  */
+ static ctl_table ath_static_sysctls[] = {
+ #ifdef AR_DEBUG
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "debug",
+         .mode         = 0644,
+         .data         = &ath_debug,
+@@ -11974,14 +11982,14 @@ static ctl_table ath_static_sysctls[] =
+         .proc_handler = proc_dointvec
+       },
+ #endif
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "xchanmode",
+         .mode         = 0444,
+         .data         = &ath_xchanmode,
+         .maxlen       = sizeof(ath_xchanmode),
+         .proc_handler = proc_dointvec
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "calibrate",
+         .mode         = 0644,
+         .data         = &ath_calinterval,
+@@ -11993,14 +12001,14 @@ static ctl_table ath_static_sysctls[] =
+       { 0 }
+ };
+ static ctl_table ath_ath_table[] = {
+-      { .ctl_name     = DEV_ATH,
++      { CTLNAME(DEV_ATH)
+         .procname     = "ath",
+         .mode         = 0555,
+         .child        = ath_static_sysctls
+       }, { 0 }
+ };
+ static ctl_table ath_root_table[] = {
+-      { .ctl_name     = CTL_DEV,
++      { CTLNAME(CTL_DEV)
+         .procname     = "dev",
+         .mode         = 0555,
+         .child        = ath_ath_table
+--- a/ath/if_ath_ahb.h
++++ b/ath/if_ath_ahb.h
+@@ -112,7 +112,11 @@
+       do { (void) (start); (void) (size); } while (0)
+ #endif
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
++#define bus_dma_sync_single   dma_sync_single_for_cpu
++#else
+ #define bus_dma_sync_single   dma_sync_single
++#endif
+ #define bus_map_single                dma_map_single
+ #define bus_unmap_single      dma_unmap_single
+ #define bus_alloc_consistent(_hwdev, _sz, _hdma)              \
+--- a/ath_hal/ah_os.c
++++ b/ath_hal/ah_os.c
+@@ -518,7 +518,7 @@ EXPORT_SYMBOL(ath_hal_memcmp);
+ static ctl_table ath_hal_sysctls[] = {
+ #ifdef AH_DEBUG
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "debug",
+         .mode         = 0644,
+         .data         = &ath_hal_debug,
+@@ -526,21 +526,21 @@ static ctl_table ath_hal_sysctls[] = {
+         .proc_handler = proc_dointvec
+       },
+ #endif
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "dma_beacon_response_time",
+         .data         = &ath_hal_dma_beacon_response_time,
+         .maxlen       = sizeof(ath_hal_dma_beacon_response_time),
+         .mode         = 0644,
+         .proc_handler = proc_dointvec
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "sw_beacon_response_time",
+         .mode         = 0644,
+         .data         = &ath_hal_sw_beacon_response_time,
+         .maxlen       = sizeof(ath_hal_sw_beacon_response_time),
+         .proc_handler = proc_dointvec
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "swba_backoff",
+         .mode         = 0644,
+         .data         = &ath_hal_additional_swba_backoff,
+@@ -548,19 +548,19 @@ static ctl_table ath_hal_sysctls[] = {
+         .proc_handler = proc_dointvec
+       },
+ #ifdef AH_DEBUG_ALQ
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "alq",
+         .mode         = 0644,
+         .proc_handler = sysctl_hw_ath_hal_log
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "alq_size",
+         .mode         = 0644,
+         .data         = &ath_hal_alq_qsize,
+         .maxlen       = sizeof(ath_hal_alq_qsize),
+         .proc_handler = proc_dointvec
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "alq_lost",
+         .mode         = 0644,
+         .data         = &ath_hal_alq_lost,
+@@ -571,21 +571,21 @@ static ctl_table ath_hal_sysctls[] = {
+       { 0 }
+ };
+ static ctl_table ath_hal_table[] = {
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "hal",
+         .mode         = 0555,
+         .child        = ath_hal_sysctls
+       }, { 0 }
+ };
+ static ctl_table ath_ath_table[] = {
+-      { .ctl_name     = DEV_ATH,
++      { CTLNAME(DEV_ATH)
+         .procname     = "ath",
+         .mode         = 0555,
+         .child        = ath_hal_table
+       }, { 0 }
+ };
+ static ctl_table ath_root_table[] = {
+-      { .ctl_name     = CTL_DEV,
++      { CTLNAME(CTL_DEV)
+         .procname     = "dev",
+         .mode         = 0555,
+         .child        = ath_ath_table
+--- a/include/compat.h
++++ b/include/compat.h
+@@ -193,6 +193,12 @@ static inline int timeval_compare(struct
+ #define __skb_queue_after(_list, _old, _new)  __skb_append(_old, _new, _list)
+ #endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
++#define CTLNAME(x)    .ctl_name       = x,
++#else
++#define CTLNAME(x)
++#endif
++
+ #endif /* __KERNEL__ */
+ #endif /* _ATH_COMPAT_H_ */
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -699,39 +699,39 @@ IEEE80211_SYSCTL_DECL(ieee80211_sysctl_m
+ static const ctl_table ieee80211_sysctl_template[] = {
+ #ifdef IEEE80211_DEBUG
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "debug",
+         .mode         = 0644,
+         .proc_handler = ieee80211_sysctl_debug
+       },
+ #endif
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "dev_type",
+         .mode         = 0644,
+         .proc_handler = ieee80211_sysctl_dev_type
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "monitor_nods_only",
+         .mode         = 0644,
+         .proc_handler = ieee80211_sysctl_monitor_nods_only
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "monitor_txf_len",
+         .mode         = 0644,
+         .proc_handler = ieee80211_sysctl_monitor_txf_len
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "monitor_phy_errors",
+         .mode         = 0644,
+         .proc_handler = ieee80211_sysctl_monitor_phy_errors
+       },
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "monitor_crc_errors",
+         .mode         = 0644,
+         .proc_handler = ieee80211_sysctl_monitor_crc_errors
+       },
+       /* NB: must be last entry before NULL */
+-      { .ctl_name     = CTL_AUTO,
++      { CTLNAME(CTL_AUTO)
+         .procname     = "%parent",
+         .maxlen       = IFNAMSIZ,
+         .mode         = 0444,
+@@ -786,12 +786,16 @@ ieee80211_virtfs_latevattach(struct ieee
+       /* setup the table */
+       memset(vap->iv_sysctls, 0, space);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+       vap->iv_sysctls[0].ctl_name = CTL_NET;
++#endif
+       vap->iv_sysctls[0].procname = "net";
+       vap->iv_sysctls[0].mode = 0555;
+       vap->iv_sysctls[0].child = &vap->iv_sysctls[2];
+       /* [1] is NULL terminator */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+       vap->iv_sysctls[2].ctl_name = CTL_AUTO;
++#endif
+       vap->iv_sysctls[2].procname = devname; /* XXX bad idea? */
+       vap->iv_sysctls[2].mode = 0555;
+       vap->iv_sysctls[2].child = &vap->iv_sysctls[4];
diff --git a/net/madwifi/patches/460-pci_softled_disable.patch b/net/madwifi/patches/460-pci_softled_disable.patch
new file mode 100644 (file)
index 0000000..328e8c3
--- /dev/null
@@ -0,0 +1,18 @@
+--- a/ath/if_ath_pci.c
++++ b/ath/if_ath_pci.c
+@@ -264,6 +264,7 @@ ath_pci_probe(struct pci_dev *pdev, cons
+               }
+       }
++#if 0
+       /*
+        * Auto-enable soft led processing for IBM cards and for
+        * 5211 minipci cards.  Users can also manually enable/disable
+@@ -279,6 +280,7 @@ ath_pci_probe(struct pci_dev *pdev, cons
+               sc->aps_sc.sc_softled = 1;
+               sc->aps_sc.sc_ledpin = 1;
+       }
++#endif
+       if ((i = ath_attach(vdevice, dev, NULL)) != 0) {
+               printk(KERN_ERR "%s: ath_attach failed: %d\n", dev_info, i);
diff --git a/net/madwifi/patches/461-rx_stats_count_fix.patch b/net/madwifi/patches/461-rx_stats_count_fix.patch
new file mode 100644 (file)
index 0000000..4b5ce28
--- /dev/null
@@ -0,0 +1,23 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -202,7 +202,6 @@ ieee80211_input(struct ieee80211vap * va
+       struct ieee80211com *ic;
+       struct net_device *dev;
+       struct ieee80211_node *ni_wds = NULL;
+-      struct net_device_stats *stats;
+       struct ieee80211_frame *wh;
+       struct ieee80211_key *key;
+       struct ether_header *eh;
+@@ -685,12 +684,6 @@ ieee80211_input(struct ieee80211vap * va
+               if (! accept_data_frame(vap, ni, key, skb, eh))
+                       goto out;
+-              if (ni->ni_subif && ((eh)->ether_type != __constant_htons(ETHERTYPE_PAE)))
+-                      stats = &ni->ni_subif->iv_devstats;
+-              else
+-                      stats = &vap->iv_devstats;
+-              stats->rx_packets++;
+-              stats->rx_bytes += skb->len;
+               IEEE80211_NODE_STAT(ni, rx_data);
+               IEEE80211_NODE_STAT_ADD(ni, rx_bytes, skb->len);
+               ic->ic_lastdata = jiffies;
diff --git a/net/madwifi/patches/462-fix_ap_scan.patch b/net/madwifi/patches/462-fix_ap_scan.patch
new file mode 100644 (file)
index 0000000..8798f53
--- /dev/null
@@ -0,0 +1,26 @@
+--- a/net80211/ieee80211_scan_ap.c
++++ b/net80211/ieee80211_scan_ap.c
+@@ -595,6 +595,14 @@ ap_end(struct ieee80211_scan_state *ss,
+       ic = vap->iv_ic;
++      /* if we're already running, switch back to the home channel */
++      if ((vap->iv_state == IEEE80211_S_RUN) &&
++          (ic->ic_bsschan != IEEE80211_CHAN_ANYC)) {
++              ic->ic_curchan = ic->ic_bsschan;
++              ic->ic_set_channel(ic);
++              goto out;
++      }
++
+       /* record stats for the channel that was scanned last */
+       ic->ic_set_channel(ic);
+       spin_lock_irqsave(&channel_lock, sflags);
+@@ -648,6 +656,8 @@ ap_end(struct ieee80211_scan_state *ss,
+               IEEE80211_SCHEDULE_TQUEUE(&as->as_actiontq);
+               res = 1;
+       }
++
++out:
+       SCAN_AP_UNLOCK_IRQ(as);
+       return res;
+ }
diff --git a/net/madwifi/patches/463-fix_txrate_display.patch b/net/madwifi/patches/463-fix_txrate_display.patch
new file mode 100644 (file)
index 0000000..0889f78
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -728,6 +728,7 @@ ath_rate_statistics(struct ieee80211_nod
+               rn->max_tp_rate2  = index_max_tp2;
+               rn->max_prob_rate = index_max_prob;
+               rn->current_rate  = index_max_tp;
++              ni->ni_txrate = index_max_tp;
+ }
+ static struct ath_ratectrl *
diff --git a/net/madwifi/patches/464-0dbm_txpower_fix.patch b/net/madwifi/patches/464-0dbm_txpower_fix.patch
new file mode 100644 (file)
index 0000000..fbd1d76
--- /dev/null
@@ -0,0 +1,30 @@
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -1370,15 +1370,9 @@ ieee80211_ioctl_siwtxpow(struct net_devi
+       int fixed, disabled;
+       fixed = (ic->ic_flags & IEEE80211_F_TXPOW_FIXED);
+-      disabled = (fixed && ic->ic_txpowlimit == 0);
+-      if (rrq->disabled) {
+-              if (!disabled) {
+-                      ic->ic_flags |= IEEE80211_F_TXPOW_FIXED;
+-                      ic->ic_txpowlimit = 0;
+-                      goto done;
+-              }
+-              return 0;
+-      }
++
++      if (rrq->disabled)
++              return -EINVAL;
+       if (rrq->fixed) {
+               if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
+@@ -1571,7 +1565,7 @@ ieee80211_ioctl_giwtxpow(struct net_devi
+               rrq->fixed = 0;
+       }
+       rrq->value = txp / 2;
+-      rrq->disabled = (rrq->fixed && rrq->value == 0);
++      rrq->disabled = 0;
+       rrq->flags = IW_TXPOW_DBM;
+       return 0;
+ }
diff --git a/net/madwifi/patches/465-mc_list-2.6.35.patch b/net/madwifi/patches/465-mc_list-2.6.35.patch
new file mode 100644 (file)
index 0000000..4931cfb
--- /dev/null
@@ -0,0 +1,40 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -4466,7 +4466,11 @@ ath_merge_mcast(struct ath_softc *sc, u_
+ {
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ieee80211vap *vap;
++      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) 
++      struct netdev_hw_addr *ha; 
++      #else
+       struct dev_mc_list *mc;
++      #endif
+       u_int32_t val;
+       u_int8_t pos;
+@@ -4474,6 +4478,17 @@ ath_merge_mcast(struct ath_softc *sc, u_
+       /* XXX locking */
+       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+               struct net_device *dev = vap->iv_dev;
++              #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
++              netdev_for_each_mc_addr(ha, dev) { 
++                      /* calculate XOR of eight 6-bit values */
++                      val = LE_READ_4(ha->addr + 0);
++                      pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
++                      val = LE_READ_4(ha->addr + 3);
++                      pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
++                      pos &= 0x3f;
++                      mfilt[pos / 32] |= (1 << (pos % 32));
++              }
++              #else
+               for (mc = dev->mc_list; mc; mc = mc->next) {
+                       /* calculate XOR of eight 6-bit values */
+                       val = LE_READ_4(mc->dmi_addr + 0);
+@@ -4483,6 +4498,7 @@ ath_merge_mcast(struct ath_softc *sc, u_
+                       pos &= 0x3f;
+                       mfilt[pos / 32] |= (1 << (pos % 32));
+               }
++              #endif 
+       }
+ }
diff --git a/net/madwifi/patches/466-2.6.38_compile.patch b/net/madwifi/patches/466-2.6.38_compile.patch
new file mode 100644 (file)
index 0000000..10a6f0d
--- /dev/null
@@ -0,0 +1,14 @@
+--- a/include/compat.h
++++ b/include/compat.h
+@@ -131,6 +131,11 @@
+ #ifdef __KERNEL__
+ #include <linux/version.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
++#define AUTOCONF_INCLUDED 1
++#endif
++
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
+ #define ATH_REGISTER_SYSCTL_TABLE(t) register_sysctl_table(t, 1)
+ #else
diff --git a/net/madwifi/patches/470-mac_addresss_from_ath5k_platform_data.patch b/net/madwifi/patches/470-mac_addresss_from_ath5k_platform_data.patch
new file mode 100644 (file)
index 0000000..0c35050
--- /dev/null
@@ -0,0 +1,36 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -63,6 +63,8 @@
+ #include <linux/rtnetlink.h>
+ #include <linux/time.h>
+ #include <linux/pci.h>
++#include <linux/device.h>
++#include <linux/ath5k_platform.h>
+ #include <asm/uaccess.h>
+ #include "if_ethersubr.h"             /* for ETHER_IS_MULTICAST */
+@@ -587,6 +589,10 @@ ath_attach(u_int16_t devid, struct net_d
+       unsigned int i;
+       int autocreatemode = -1;
+       u_int8_t csz;
++#ifdef ATH_PCI
++      struct ath5k_platform_data *pdata;
++      struct pci_dev *pdev;
++#endif
+       sc->devid = devid;
+ #ifdef AR_DEBUG
+@@ -648,6 +654,13 @@ ath_attach(u_int16_t devid, struct net_d
+       }
+       sc->sc_ah = ah;
++#ifdef ATH_PCI
++      /* set MAC from ath_platform_data */
++      pdev = (struct pci_dev *)sc->sc_bdev;
++      pdata = pdev->dev.platform_data;
++      if (pdata && pdata->macaddr)
++              ath_hal_setmac(ah, pdata->macaddr);
++#endif
+       /* WAR for AR7100 PCI bug */
+ #if defined(CONFIG_ATHEROS_AR71XX) || defined(CONFIG_ATH79)
+       if ((ar_device(sc->devid) >= 5210) && (ar_device(sc->devid) < 5416)) {
diff --git a/net/madwifi/patches/471-netdev_ops_mac_mtu.patch b/net/madwifi/patches/471-netdev_ops_mac_mtu.patch
new file mode 100644 (file)
index 0000000..c7e1f40
--- /dev/null
@@ -0,0 +1,30 @@
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -47,6 +47,7 @@
+ #include <linux/skbuff.h>
+ #include <linux/netdevice.h>
+ #include <linux/rtnetlink.h>          /* XXX for rtnl_lock */
++#include <linux/etherdevice.h>
+ #include "if_media.h"
+@@ -463,6 +464,8 @@ static const struct net_device_ops ieee8
+       .ndo_set_multicast_list = ieee80211_set_multicast_list,
+       .ndo_change_mtu         = ieee80211_change_mtu,
+       .ndo_do_ioctl           = ieee80211_ioctl,
++      .ndo_validate_addr      = eth_validate_addr,
++      .ndo_set_mac_address    = eth_mac_addr,
+ };
+ #endif
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -574,6 +574,8 @@ static const struct net_device_ops ath_n
+       .ndo_get_stats          = ath_getstats,
+       .ndo_set_mac_address    = ath_set_mac_address,
+       .ndo_change_mtu         = ath_change_mtu,
++      .ndo_validate_addr      = eth_validate_addr,
++      .ndo_set_mac_address    = eth_mac_addr,
+ };
+ #endif
diff --git a/net/madwifi/patches/472-remove_11n_devids.patch b/net/madwifi/patches/472-remove_11n_devids.patch
new file mode 100644 (file)
index 0000000..cf80f06
--- /dev/null
@@ -0,0 +1,20 @@
+--- a/ath/if_ath_pci.c
++++ b/ath/if_ath_pci.c
+@@ -111,8 +111,6 @@ static struct pci_device_id ath_pci_id_t
+       { 0x168c, 0x001b, PCI_ANY_ID, PCI_ANY_ID },
+       { 0x168c, 0x001c, PCI_ANY_ID, PCI_ANY_ID }, /* PCI Express 5424 */
+       { 0x168c, 0x001d, PCI_ANY_ID, PCI_ANY_ID }, /* PCI Express ???  */
+-      { 0x168c, 0x0023, PCI_ANY_ID, PCI_ANY_ID },
+-      { 0x168c, 0x0024, PCI_ANY_ID, PCI_ANY_ID },
+       { 0x168c, 0x9013, PCI_ANY_ID, PCI_ANY_ID }, /* sonicwall */
+       { 0x168c, 0xff1a, PCI_ANY_ID, PCI_ANY_ID },
+       { 0 }
+@@ -146,8 +144,6 @@ static const struct ath_hw_detect cards[
+       { ubnt, "SR4C",    0x168c, 0x0013, 0x7777, 0x1004, 6 },
+       { ubnt, "SR5",     0x168c, 0x0013, 0x168c, 0x2042, 7 },
+       { ubnt, "SR9",     0x168c, 0x0013, 0x7777, 0x2009, 12 },
+-      { ubnt, "SR71A",   0x168c, 0x0027, 0x168c, 0x2082, 10 },
+-      { ubnt, "SR71",    0x168c, 0x0027, 0x0777, 0x4082, 10 },
+ };
+ static int
diff --git a/net/madwifi/patches/473-mutex_fix.patch b/net/madwifi/patches/473-mutex_fix.patch
new file mode 100644 (file)
index 0000000..22cea46
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -974,7 +974,7 @@ typedef void (*ath_callback) (struct ath
+ #endif
+ /* Protects the device from concurrent accesses */
+-#define       ATH_LOCK_INIT(_sc)              init_MUTEX(&(_sc)->sc_lock)
++#define       ATH_LOCK_INIT(_sc)              sema_init(&(_sc)->sc_lock, 1)
+ #define       ATH_LOCK_DESTROY(_sc)
+ #define       ATH_LOCK(_sc)                   down(&(_sc)->sc_lock)
+ #define       ATH_UNLOCK(_sc)                 up(&(_sc)->sc_lock)
diff --git a/net/madwifi/patches/474_fix_ssid_scan_length.patch b/net/madwifi/patches/474_fix_ssid_scan_length.patch
new file mode 100644 (file)
index 0000000..2e85e18
--- /dev/null
@@ -0,0 +1,29 @@
+--- a/tools/wlanconfig.c
++++ b/tools/wlanconfig.c
+@@ -654,7 +654,7 @@ static void
+ list_scan(const char *ifname)
+ {
+       static uint8_t buf[24 * 1024];
+-      char ssid[14];
++      char ssid[30];
+       uint8_t *cp;
+       int len;
+@@ -665,7 +665,7 @@ list_scan(const char *ifname)
+       if (len < sizeof(struct ieee80211req_scan_result))
+               return;
+-      printf("%-14.14s  %-17.17s  %4s %4s  %-5s %3s %4s\n",
++      printf("%-30.30s  %-17.17s  %4s %4s  %-5s %3s %4s\n",
+               "SSID",
+               "BSSID",
+               "CHAN",
+@@ -680,7 +680,7 @@ list_scan(const char *ifname)
+               sr = (struct ieee80211req_scan_result *) cp;
+               vp = (u_int8_t *)(sr+1);
+-              printf("%-14.*s  %s  %3d  %3dM %2d:%-2d  %3d %-4.4s",
++              printf("%-30.*s  %s  %3d  %3dM %2d:%-2d  %3d %-4.4s",
+                       copy_essid(ssid, sizeof(ssid), vp, sr->isr_ssid_len),
+                       ssid,
+                       ieee80211_ntoa(sr->isr_bssid),
diff --git a/net/madwifi/patches/475-2.6.39-compile.patch b/net/madwifi/patches/475-2.6.39-compile.patch
new file mode 100644 (file)
index 0000000..5b8a777
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/net80211/ieee80211_scan.c
++++ b/net80211/ieee80211_scan.c
+@@ -97,7 +97,7 @@ struct scan_state {
+ static void scan_restart_pwrsav(unsigned long);
+ static void scan_next(unsigned long);
+-spinlock_t channel_lock = SPIN_LOCK_UNLOCKED;
++DEFINE_SPINLOCK(channel_lock);
+ static LIST_HEAD(channels_inuse);
+ struct channel_inuse {
diff --git a/net/madwifi/patches/476-3.0_detection_fix.patch b/net/madwifi/patches/476-3.0_detection_fix.patch
new file mode 100644 (file)
index 0000000..2f8bfb4
--- /dev/null
@@ -0,0 +1,25 @@
+--- a/Makefile
++++ b/Makefile
+@@ -155,13 +155,15 @@ unload:
+ configcheck:
+       @echo -n "Checking kernel configuration... "
+       
+-      @# check version of kernel
+-      @echo $(KERNELRELEASE) | grep -q -i '^[2-9]\.[4-9]\.' || { \
+-          echo "FAILED"; \
+-          echo "Only kernel versions 2.4.x and above are supported."; \
+-          echo "You have $(KERNELRELEASE)."; \
+-          exit 1; \
+-      }
++      @# check kernel version
++      @case $(KERNELRELEASE) in \
++          2.[456].*) ;; \
++          [3-9].*) ;; \
++          *) echo "FAILED"; \
++             echo "Only kernel versions 2.4.x and above are supported."; \
++             echo "You have $(KERNELRELEASE)."; \
++             exit 1 ;; \
++      esac
+       
+       @# check kernel configuration
+       @if [ -z "$(CONFIG_SYSCTL)" ]; then \
diff --git a/net/madwifi/patches/477-3.2_fixes.patch b/net/madwifi/patches/477-3.2_fixes.patch
new file mode 100644 (file)
index 0000000..89cdfc6
--- /dev/null
@@ -0,0 +1,45 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -569,7 +569,11 @@ static const struct net_device_ops ath_n
+       .ndo_stop               = ath_stop,
+       .ndo_start_xmit         = ath_hardstart,
+       .ndo_tx_timeout         = ath_tx_timeout,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
++      .ndo_set_rx_mode        = ath_mode_init,
++#else
+       .ndo_set_multicast_list = ath_mode_init,
++#endif
+       .ndo_do_ioctl           = ath_ioctl,
+       .ndo_get_stats          = ath_getstats,
+       .ndo_set_mac_address    = ath_set_mac_address,
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -461,7 +461,11 @@ static const struct net_device_ops ieee8
+       .ndo_open               = ieee80211_open,
+       .ndo_stop               = ieee80211_stop,
+       .ndo_start_xmit         = ieee80211_hardstart,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
++      .ndo_set_rx_mode        = ieee80211_set_multicast_list,
++#else
+       .ndo_set_multicast_list = ieee80211_set_multicast_list,
++#endif
+       .ndo_change_mtu         = ieee80211_change_mtu,
+       .ndo_do_ioctl           = ieee80211_ioctl,
+       .ndo_validate_addr      = eth_validate_addr,
+@@ -1847,10 +1851,14 @@ ieee80211_set_multicast_list(struct net_
+       IEEE80211_UNLOCK_IRQ(ic);
+       /* XXX: Merge multicast list into parent device */
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+-      parent->set_multicast_list(ic->ic_dev);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
++      parent->netdev_ops->ndo_set_rx_mode(ic->ic_dev);
+ #else
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+       parent->netdev_ops->ndo_set_multicast_list(ic->ic_dev);
++#else
++      parent->set_multicast_list(ic->ic_dev);
++#endif
+ #endif
+ }
diff --git a/net/madwifi/patches/478-remove_vlan_code.patch b/net/madwifi/patches/478-remove_vlan_code.patch
new file mode 100644 (file)
index 0000000..9ceda4a
--- /dev/null
@@ -0,0 +1,21 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1223,6 +1223,7 @@ ieee80211_deliver_data(struct ieee80211_
+ #endif
+               vap->iv_devstats.rx_packets++;
+               vap->iv_devstats.rx_bytes += skb->len;
++#if IEEE80211_VLAN_TAG_USED
+               if (ni->ni_vlan != 0 && vap->iv_vlgrp != NULL) {
+                       /* attach vlan tag */
+                       struct ieee80211_node *ni_tmp = SKB_CB(skb)->ni;
+@@ -1236,7 +1237,9 @@ ieee80211_deliver_data(struct ieee80211_
+                               vap->iv_devstats.rx_dropped++;
+                       }
+                       skb = NULL; /* SKB is no longer ours */
+-              } else {
++              } else
++#endif
++              {
+                       struct ieee80211_node *ni_tmp = SKB_CB(skb)->ni;
+                       if (netif_receive_skb(skb) == NET_RX_DROP) {
+                               /* If netif_receive_skb dropped the packet because
diff --git a/net/siit/Makefile b/net/siit/Makefile
new file mode 100644 (file)
index 0000000..4cd147f
--- /dev/null
@@ -0,0 +1,40 @@
+# 
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=siit
+PKG_VERSION:=1.1
+PKG_RELEASE:=2
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/siit
+  SUBMENU:=Network Devices
+  TITLE:=Stateless IP ICMP Translation Algorithm
+  DEPENDS:= @(!(TARGET_ps3||TARGET_pxcab)||BROKEN)
+  FILES:=$(PKG_BUILD_DIR)/siit.ko
+  AUTOLOAD:=$(call AutoLoad,50,siit)
+endef
+
+include $(INCLUDE_DIR)/kernel-defaults.mk
+
+define KernelPackage/siit/description
+ Stateless IP ICMP Translation Algorithm
+endef
+
+define Build/Prepare
+       mkdir -p $(PKG_BUILD_DIR)
+       cp src/Makefile src/siit.h src/siit.c $(PKG_BUILD_DIR)/
+endef
+
+define Build/Compile
+       $(MAKE) $(KERNEL_MAKEOPTS) SUBDIRS="$(PKG_BUILD_DIR)" modules
+endef
+
+$(eval $(call KernelPackage,siit))
diff --git a/net/siit/src/Makefile b/net/siit/src/Makefile
new file mode 100644 (file)
index 0000000..06c36f1
--- /dev/null
@@ -0,0 +1,5 @@
+obj-m   := siit.o
+ifeq ($(MAKING_MODULES),1)
+-include $(TOPDIR)/Rules.make
+endif
+
diff --git a/net/siit/src/siit.c b/net/siit/src/siit.c
new file mode 100644 (file)
index 0000000..5362c1d
--- /dev/null
@@ -0,0 +1,1478 @@
+/*
+ * siit.c: the Stateless IP/ICMP Translator (SIIT) module for Linux.
+ *
+ *
+ */
+
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33))
+#include <generated/autoconf.h>
+#else
+#include <linux/autoconf.h>
+#endif
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>       /* printk() */
+#include <linux/slab.h>
+
+#include <linux/errno.h>        /* error codes */
+#include <linux/types.h>        /* size_t */
+#include <linux/interrupt.h>    /* mark_bh */
+#include <linux/random.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>    /* struct device, and other headers */
+#include <linux/etherdevice.h>  /* eth_type_trans */
+#include <net/ip.h>             /* struct iphdr */
+#include <net/icmp.h>           /* struct icmphdr */
+#include <net/ipv6.h>
+#include <net/udp.h>
+#include <linux/skbuff.h>
+#include <linux/in6.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
+#include <net/ip6_checksum.h>
+#endif
+#include <linux/in6.h>
+#include "siit.h"
+
+MODULE_AUTHOR("Dmitriy Moscalev, Grigory Klyuchnikov, Felix Fietkau");
+
+/*
+ * If tos_ignore_flag != 0, we don't copy TOS and Traffic Class
+ * from origin paket and set it to 0
+ */
+int tos_ignore_flag = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+static inline void
+skb_reset_mac_header(struct sk_buff *skb)
+{
+       skb->mac.raw=skb->data;
+}
+
+static struct net_device_stats *
+siit_get_stats(struct net_device *dev)
+{
+       return netdev_priv(dev);
+}
+
+static inline void random_ether_addr(u8 *addr)
+{
+       get_random_bytes (addr, ETH_ALEN);
+       addr [0] &= 0xfe;       /* clear multicast bit */
+       addr [0] |= 0x02;       /* set local assignment bit (IEEE802) */
+}
+
+
+#define siit_stats(_dev) ((struct net_device_stats *)netdev_priv(_dev))
+#else
+#define siit_stats(_dev) (&(_dev)->stats)
+#endif
+
+/*
+ * The Utility  stuff
+ */
+
+#ifdef SIIT_DEBUG
+/* print dump bytes (data point data area sizeof len and message
+ * before dump.
+ */
+static int siit_print_dump(char *data, int len, char *message)
+{
+       int i;
+       int j = 0, k = 1;
+
+       len = len > BUFF_SIZE ? BUFF_SIZE : len;
+       printk("%s:\n", message);
+       for (i=0; i < len; i++, k++) {
+               if( i == len-1 || k == 16) {
+                       printk("%02x\n", (~(~0 << 8) & *(data+i)));
+                       j = 0;
+                       k = 0;
+               }
+               else if (j) {
+                       printk("%02x ", (~(~0 << 8) & *(data+i)));
+                       j--;
+               }
+               else {
+                       printk("%02x", (~(~0 << 8) & *(data+i)));
+                       j++;
+               }
+       }
+       return 0;
+}
+#endif
+
+/*
+ * Open and close
+ */
+static int siit_open(struct net_device *dev)
+{
+       netif_start_queue(dev);
+       return 0;
+}
+
+
+static int siit_release(struct net_device *dev)
+{
+       netif_stop_queue(dev); /* can't transmit any more */
+       return 0;
+}
+
+/*
+ * Translation IPv4 to IPv6 stuff
+ *
+ * ip4_ip6 (src, len, dst, include_flag)
+ *
+ * where
+ * src - buffer with original IPv4 packet,
+ * len - size of original packet,
+ * dst - new buffer for IPv6 packet,
+ * include_flag - if = 1, dst point to IPv4 packet that is ICMP error
+ *                included IP packet, else = 0
+ */
+
+static int ip4_ip6(char *src, int len, char *dst, int include_flag)
+{
+       struct iphdr *ih4 = (struct iphdr *) src; /* point to current IPv4 header struct */
+       struct icmphdr *icmp_hdr;   /* point to current ICMPv4 header struct */
+       struct udphdr *udp_hdr;     /* point to current IPv4 UDP header struct */
+
+       struct ipv6hdr *ih6 = (struct ipv6hdr *) dst; /* point to current IPv6 header struct */
+       struct frag_hdr *ih6_frag = (struct frag_hdr *)(dst+sizeof(struct ipv6hdr));
+                                                                                     /* point to current IPv6 fragment header struct */
+       struct icmp6hdr *icmp6_hdr; /* point to current ICMPv6 header */
+
+       int hdr_len = (int)(ih4->ihl * 4); /* IPv4 header length */
+       int icmp_len;               /* ICMPv4 packet length */
+       int plen;                   /* payload length */
+
+       unsigned int csum;          /* need to calculate ICMPv6 and UDP checksum */
+       int fl_csum = 0;            /* flag to calculate UDP checksum */
+       int icmperr = 1;            /* flag to indicate ICMP error message and to need
+                                                                  translate ICMP included IP packet */
+       int fr_flag = 0;            /* fragment flag, if = 0 - don't add
+                                                                  fragment header */
+       __u16 new_tot_len;          /* need to calculate IPv6 total length */
+       __u8 new_nexthdr;           /* next header code */
+       __u16 icmp_ptr = 0;         /* Pointer field in ICMP_PARAMETERPROB */
+
+#ifdef SIIT_DEBUG              /* print IPv4 header dump */
+       siit_print_dump(src, hdr_len, "siit: ip4_ip6() (in) ip4 header dump");
+#endif
+
+       /* If DF == 1 && MF == 0 && Fragment Offset == 0
+        * or this packet is ICMP included IP packet
+        * we don't need fragment header */
+       if (ntohs(ih4->frag_off) == IP_DF || include_flag ) {
+               /* not fragment and we need not to add Fragment
+                * Header to IPv6 packet. */
+               /* total length = total length from IPv4 packet */
+               new_tot_len = ntohs(ih4->tot_len);
+
+               if (ih4->protocol == IPPROTO_ICMP)
+                       new_nexthdr = NEXTHDR_ICMP;
+               else
+                       new_nexthdr = ih4->protocol;
+       }
+       else {
+               /* need to add Fragment Header */
+               fr_flag = 1;
+               /* total length = total length from IPv4 packet +
+                  length of Fragment Header */
+               new_tot_len = ntohs(ih4->tot_len) + sizeof(struct frag_hdr);
+               /* IPv6 Header NextHeader = NEXTHDR_FRAGMENT */
+               new_nexthdr = NEXTHDR_FRAGMENT;
+               /* Fragment Header NextHeader copy from IPv4 packet */
+               if (ih4->protocol == IPPROTO_ICMP)
+                       ih6_frag->nexthdr = NEXTHDR_ICMP;
+               else
+                       ih6_frag->nexthdr = ih4->protocol;
+
+               /* copy frag offset from IPv4 packet */
+               ih6_frag->frag_off = htons((ntohs(ih4->frag_off) & IP_OFFSET) << 3);
+               /* copy MF flag from IPv4 packet */
+               ih6_frag->frag_off = htons((ntohs(ih6_frag->frag_off) |
+                                                                       ((ntohs(ih4->frag_off) & IP_MF) >> 13)));
+               /* copy Identification field from IPv4 packet */
+               ih6_frag->identification = htonl(ntohs(ih4->id));
+               /* reserved field initialized to zero */
+               ih6_frag->reserved = 0;
+       }
+
+       /* Form rest IPv6 fields */
+
+       /*
+        * At this point we need to add checking of unxpired source
+        * route optin and if it is, send ICMPv4 "destination
+        * unreacheble/source route failes" Type 3/Code 5 and
+        * drop packet. (NOT RELEASED YET)
+        */
+
+       /* IP version = 6 */
+       ih6->version = 6;
+
+       if (tos_ignore_flag) {
+               ih6->priority = 0;
+               ih6->flow_lbl[0] = 0;
+       } else {
+               ih6->priority = (ih4->tos & 0xf0) >> 4;
+               ih6->flow_lbl[0] = (ih4->tos & 0x0f) << 4;
+       }
+       ih6->flow_lbl[1] = 0;
+       ih6->flow_lbl[2] = 0;
+
+       /* Hop Limit = IPv4 TTL */
+       ih6->hop_limit = ih4->ttl;
+
+       /* Translate source destination addresses,
+          for IPv6 host it's IPv4-translated IPv6 address,
+          for IPv4 host it's IPv4-mapped IPv6 address
+
+          !!WARNING!! Instead IPv4-mapped IPv6 addresses we use addreesses
+          with unused prefix ::ffff:ffff:0:0/96, because KAME implementation
+          doesn't support IPv4-mapped addresses in IPv6 packets and discard them.
+
+       */
+
+       if (include_flag) {
+               /*
+                  It's ICMP included IP packet and there is a diffirence
+                  in src/dst addresses then src/dst in normal direction
+                */
+
+               /*
+                  Source address
+                  is IPv4-translated IPv6 address because packet traveled
+                  from IPv6 to IPv4 area
+               */
+               ih6->saddr.in6_u.u6_addr32[0] = 0;
+               ih6->saddr.in6_u.u6_addr32[1] = 0;
+               ih6->saddr.in6_u.u6_addr32[2] = htonl(TRANSLATED_PREFIX); /* to network order bytes */
+               ih6->saddr.in6_u.u6_addr32[3] = ih4->saddr;
+
+               /*
+                  Destination address
+                  is IPv4-mapped address (but it's not IPv4- mapped, we use
+                  prefix ::ffff:ffff:0:0/96
+                */
+               ih6->daddr.in6_u.u6_addr32[0] = 0;
+               ih6->daddr.in6_u.u6_addr32[1] = 0;
+               ih6->daddr.in6_u.u6_addr32[2] = htonl(MAPPED_PREFIX); /* to network order bytes */
+               ih6->daddr.in6_u.u6_addr32[3] = ih4->daddr;
+       }
+       else {
+
+               /*
+                  This is normal case (packet isn't included IP packet)
+
+                  Source address
+                  is IPv4-mapped address (but it's not IPv4- mapped, we use
+                  prefix ::ffff:ffff:0:0/96)
+               */
+               ih6->saddr.in6_u.u6_addr32[0] = 0;
+               ih6->saddr.in6_u.u6_addr32[1] = 0;
+               ih6->saddr.in6_u.u6_addr32[2] = htonl(MAPPED_PREFIX); /* to network order bytes */
+               ih6->saddr.in6_u.u6_addr32[3] = ih4->saddr;
+
+               /* Destination address
+                  is is IPv4-translated IPv6 address
+                */
+               ih6->daddr.in6_u.u6_addr32[0] = 0;
+               ih6->daddr.in6_u.u6_addr32[1] = 0;
+               ih6->daddr.in6_u.u6_addr32[2] = htonl(TRANSLATED_PREFIX); /* to network order bytes */
+               ih6->daddr.in6_u.u6_addr32[3] = ih4->daddr;
+       }
+
+       /* Payload Length */
+       plen = new_tot_len - hdr_len; /* Payload length = IPv4 total len - IPv4 header len */
+       ih6->payload_len = htons(plen);
+
+       /* Next Header */
+       ih6->nexthdr = new_nexthdr; /* Next Header */
+
+       /* Process ICMP protocols data */
+
+       switch (ih4->protocol) {
+       case IPPROTO_ICMP:
+               if ( (ntohs(ih4->frag_off) & IP_OFFSET) != 0 || (ntohs(ih4->frag_off) & IP_MF) != 0 ) {
+                       PDEBUG("ip4_ip6(): don't translate ICMPv4 fragments - packet dropped.\n");
+                       return -1;
+               }
+
+               icmp_hdr = (struct icmphdr *) (src+hdr_len); /* point to ICMPv4 header */
+               csum = 0;
+               icmp_len =  ntohs(ih4->tot_len) - hdr_len; /* ICMPv4 packet length */
+               icmp6_hdr = (struct icmp6hdr *)(dst+sizeof(struct ipv6hdr)
+                                                                           +fr_flag*sizeof(struct frag_hdr)); /* point to ICMPv6 header */
+
+               if (include_flag) {
+                       /* ICMPv4 packet cannot be included in ICMPv4 Error message */
+                       /* !!! May be it's WRONG !!! ICMPv4 QUERY packet can be included
+                          in ICMPv4 Error message */
+                       PDEBUG("ip4_ip6(): It's included ICMPv4 in ICMPv4 Error message - packet dropped.\n");
+                       return -1;
+               }
+
+               /* Check ICMPv4 Type field */
+               switch (icmp_hdr->type) {
+               /* ICMP Error messages */
+               /* Destination Unreachable (Type 3) */
+               case ICMP_DEST_UNREACH:
+                       icmp6_hdr->icmp6_type = ICMPV6_DEST_UNREACH; /* to Type 1 */
+                       icmp6_hdr->icmp6_unused = 0;
+                       switch (icmp_hdr->code)
+                       {
+                       case ICMP_NET_UNREACH: /* Code 0 */
+                       case ICMP_HOST_UNREACH: /* Code 1 */
+                       case ICMP_SR_FAILED: /* Code 5 */
+                       case ICMP_NET_UNKNOWN: /* Code 6 */
+                       case ICMP_HOST_UNKNOWN: /* Code 7 */
+                       case ICMP_HOST_ISOLATED: /* Code 8 */
+                       case ICMP_NET_UNR_TOS: /* Code 11 */
+                       case ICMP_HOST_UNR_TOS: /* Code 12 */
+                               icmp6_hdr->icmp6_code = ICMPV6_NOROUTE; /* to Code 0 */
+                               break;
+                       case ICMP_PROT_UNREACH: /* Code 2 */
+                               icmp6_hdr->icmp6_type = ICMPV6_PARAMPROB; /* to Type 4 */
+                               icmp6_hdr->icmp6_code = ICMPV6_UNK_NEXTHDR; /* to Code 1 */
+                               /* Set pointer filed to 6, it's octet offset IPv6 Next Header field */
+                               icmp6_hdr->icmp6_pointer = htonl(6);
+                               break;
+                       case ICMP_PORT_UNREACH: /* Code 3 */
+                               icmp6_hdr->icmp6_code = ICMPV6_PORT_UNREACH; /* to Code 4 */
+                               break;
+                       case ICMP_FRAG_NEEDED: /* Code 4 */
+                               icmp6_hdr->icmp6_type = ICMPV6_PKT_TOOBIG; /* to Type 2 */
+                               icmp6_hdr->icmp6_code = 0;
+                               /* Correct MTU  */
+                               if (icmp_hdr->un.frag.mtu == 0)
+                                       /* we use minimum MTU for IPv4 PMTUv4 RFC1191, section 5;
+                                          IPv6 implementation wouldn't accept Path MTU < 1280,
+                                          but it records info correctly to always include
+                                          a fragment header */
+                                       icmp6_hdr->icmp6_mtu = htonl(576);
+                               else
+                                       /* needs to adjusted for difference between IPv4/IPv6 headers
+                                        * SIIT RFC2765, section 3.3,
+                                        * we assume that difference is 20 bytes */
+                                       icmp6_hdr->icmp6_mtu = htonl(ntohs(icmp_hdr->un.frag.mtu)+IP4_IP6_HDR_DIFF);
+
+                               break;
+                       case ICMP_NET_ANO: /* Code 9 */
+                       case ICMP_HOST_ANO: /* Code 10 */
+                               icmp6_hdr->icmp6_code = ICMPV6_ADM_PROHIBITED; /* to Code 1 */
+                               break;
+                       default: /* discard any other Code */
+                               PDEBUG("ip4_ip6(): Unknown ICMPv4 Type %d Code %d - packet dropped.\n",
+                                          ICMP_DEST_UNREACH, icmp_hdr->code);
+                               return -1;
+                       }
+                       break;
+                       /* Time Exceeded (Type 11) */
+               case ICMP_TIME_EXCEEDED:
+                       icmp6_hdr->icmp6_type = ICMPV6_TIME_EXCEED;
+                       icmp6_hdr->icmp6_code = icmp_hdr->code;
+                       break;
+                       /* Parameter Problem (Type 12) */
+               case ICMP_PARAMETERPROB:
+                       icmp6_hdr->icmp6_type = ICMPV6_PARAMPROB;
+                       icmp6_hdr->icmp6_code = icmp_hdr->code;
+
+                       icmp_ptr = ntohs(icmp_hdr->un.echo.id) >> 8;
+                       switch (icmp_ptr) {
+                       case 0:
+                               icmp6_hdr->icmp6_pointer = 0; /* IPv4 Version -> IPv6 Version */
+                               break;
+                       case 2:
+                               icmp6_hdr->icmp6_pointer = __constant_htonl(4); /* IPv4 length -> IPv6 Payload Length */
+                               break;
+                       case 8:
+                               icmp6_hdr->icmp6_pointer = __constant_htonl(7); /* IPv4 TTL -> IPv6 Hop Limit */
+                               break;
+                       case 9:
+                               icmp6_hdr->icmp6_pointer = __constant_htonl(6); /* IPv4 Protocol -> IPv6 Next Header */
+                               break;
+                       case 12:
+                               icmp6_hdr->icmp6_pointer = __constant_htonl(8); /* IPv4 Src Addr -> IPv6 Src Addr */
+                               break;
+                       case 16:
+                               icmp6_hdr->icmp6_pointer = __constant_htonl(24); /* IPv4 Dst Addr -> IPv6 Dst Addr */
+                               break;
+                       default:
+                               icmp6_hdr->icmp6_pointer = 0xffffffff; /* set to all ones in any other cases */
+                               break;
+                       }
+                       break;
+               case ICMP_ECHO:
+                       icmperr = 0;
+                       icmp6_hdr->icmp6_type = ICMPV6_ECHO_REQUEST;
+                       icmp6_hdr->icmp6_code = 0;
+                       /* Copy rest ICMP data to new IPv6 packet without changing */
+                       memcpy(((char *)icmp6_hdr)+4, ((char *)icmp_hdr)+4, len - hdr_len - 4);
+                       break;
+
+               case ICMP_ECHOREPLY:
+                       icmperr = 0;
+                       icmp6_hdr->icmp6_type = ICMPV6_ECHO_REPLY;
+                       icmp6_hdr->icmp6_code = 0;
+                       /* Copy rest ICMP data to new IPv6 packet without changing */
+                       memcpy(((char *)icmp6_hdr)+4, ((char *)icmp_hdr)+4, len - hdr_len - 4);
+                       break;
+
+                       /* Discard any other ICMP messages */
+               default:
+                       PDEBUG("ip4_ip6(): Unknown ICMPv4 packet Type %x - packet dropped.\n", icmp_hdr->type);
+                       return -1;
+               }
+
+               /* Now if it's ICMPv4 Error message we must translate included IP packet */
+
+               if (icmperr) {
+                       /* Call our ip4_ip6() to translate included IP packet */
+                       if (ip4_ip6(src+hdr_len+sizeof(struct icmphdr), len - hdr_len - sizeof(struct icmphdr),
+                                               dst+sizeof(struct ipv6hdr)+fr_flag*sizeof(struct frag_hdr)
+                                               +sizeof(struct icmp6hdr), 1) == -1) {
+                               PDEBUG("ip4_ip6(): Uncorrect translation of ICMPv4 Error message - packet dropped.\n");
+                               return -1;
+                       }
+                       /* correct ICMPv6 packet length for diffirence between IPv4 and IPv6 headers
+                          in included IP packet
+                          */
+                       icmp_len += 20;
+                       /* and correct Payload length for diffirence between IPv4 and IPv6 headers */
+                       plen += 20;
+                       ih6->payload_len = htons(plen);
+               }
+
+               /* Calculate ICMPv6 checksum */
+
+               icmp6_hdr->icmp6_cksum = 0;
+               csum = 0;
+
+               csum = csum_partial((u_char *)icmp6_hdr, icmp_len, csum);
+               icmp6_hdr->icmp6_cksum = csum_ipv6_magic(&ih6->saddr, &ih6->daddr, icmp_len,
+                                                                                IPPROTO_ICMPV6, csum);
+               break;
+
+       /* Process TCP protocols data */
+       case IPPROTO_TCP:
+               /* Copy TCP data to new IPv6 packet without changing */
+               memcpy(dst+sizeof(struct ipv6hdr)+fr_flag*sizeof(struct frag_hdr),
+                                  src+hdr_len, len - hdr_len);
+               break;
+
+       /* Process UDP protocols data */
+       case IPPROTO_UDP:
+               udp_hdr = (struct udphdr *)(src+hdr_len);
+               if ((ntohs(ih4->frag_off) & IP_OFFSET) == 0) {
+                       if ((ntohs(ih4->frag_off) & IP_MF) != 0) {
+                               /* It's a first fragment */
+                               if (udp_hdr->check == 0) {
+                                       /* System management event */
+                                       printk("siit: First fragment of UDP with zero checksum - packet droped\n");
+                                       printk("siit: addr: %x src port: %d dst port: %d\n",
+                                                  htonl(ih4->saddr), htons(udp_hdr->source), htons(udp_hdr->dest));
+                                       return -1;
+                               }
+                       }
+                       else if (udp_hdr->check == 0)
+                               fl_csum = 1;
+               }
+
+               /* Copy UDP data to new IPv6 packet */
+               udp_hdr = (struct udphdr *)(dst+sizeof(struct ipv6hdr)
+                                                                       + fr_flag*sizeof(struct frag_hdr));
+               memcpy((char *)udp_hdr, src+hdr_len, len - hdr_len);
+
+               /* Calculate UDP checksum if UDP checksum in IPv4 packet was ZERO
+                  and if it isn't included IP packet
+                */
+               if (fl_csum && (!include_flag)) {
+                       udp_hdr->check = 0;
+                       csum = 0;
+                       csum = csum_partial((unsigned char *)udp_hdr, plen - fr_flag*sizeof(struct frag_hdr), csum);
+                       udp_hdr->check = csum_ipv6_magic(&ih6->saddr, &ih6->daddr, plen -
+                                                                                    fr_flag*sizeof(struct frag_hdr), IPPROTO_UDP, csum);
+               }
+               break;
+
+       /* Discard packets with any other protocol */
+       default:
+               PDEBUG("ip4_ip6(): Unknown upper protocol - packet dropped.\n");
+               return -1;
+       }
+
+#ifdef SIIT_DEBUG
+       siit_print_dump(dst, sizeof(struct ipv6hdr), "siit: ip4_ip6(): (out) ipv6 header dump");
+#endif
+
+       return 0;
+}
+
+/*
+ * Translation IPv6 to IPv4 stuff
+ *
+ * ip6_ip4(src, len, dst, include_flag)
+ *
+ * where
+ * src - buffer with original IPv6 packet,
+ * len - size of original packet,
+ * dst - new buffer for IPv4 packet,
+ * include_flag - if = 1, dst point to IPv6 packet that is ICMP error
+ *                included IP packet, else = 0
+ *
+ */
+
+static int ip6_ip4(char *src, int len, char *dst, int include_flag)
+{
+       struct ipv6hdr *ip6_hdr;    /* point to current IPv6 header struct */
+       struct iphdr *ip_hdr;       /* point to current IPv4 header struct */
+       int opts_len = 0;           /* to sum Option Headers length */
+       int icmperr = 1;            /* if = 1, indicate that packet is ICMP Error message, else = 0 */
+       int ntot_len = 0;           /* to calculate IPv6 Total Length field */
+       int real_len;
+       int len_delta;
+       int ip6_payload_len;
+       int inc_opts_len = 0;       /* to sum Option Headers length in ICMP included IP packet */
+       __u8 next_hdr;              /* Next Header */
+
+#ifdef SIIT_DEBUG
+       siit_print_dump(src, sizeof(struct ipv6hdr), "siit: ip6_ip4(): (in) ipv6 header dump");
+#endif
+
+       if ( (len_delta = len - sizeof(struct ipv6hdr)) >= 0)
+       {
+               ip6_hdr = (struct ipv6hdr *)src;
+               ip_hdr = (struct iphdr *)dst;
+
+               real_len = sizeof(struct iphdr);
+
+               /* Check validation of Saddr & Daddr? is a packet to fall under our translation? */
+               if (include_flag) { /* It's ICMP included IP packet,
+                                                          about process include_flag see comment in ip4_ip6() */
+                       if (ip6_hdr->saddr.s6_addr32[2] != htonl(MAPPED_PREFIX)) {
+                               PDEBUG("ip6_ip4(): Included IP packet Src addr isn't mapped addr: %x%x%x%x, packet dropped.\n",
+                                          ip6_hdr->saddr.s6_addr32[0], ip6_hdr->saddr.s6_addr32[1],
+                                          ip6_hdr->saddr.s6_addr32[2], ip6_hdr->saddr.s6_addr32[3]);
+                               return -1;
+                       }
+                       if ( ip6_hdr->daddr.s6_addr32[2] != htonl(TRANSLATED_PREFIX)) {
+                               PDEBUG("ip6_ip4(): Included IP packet Dst addr isn't translated addr: %x%x%x%x, packet dropped.\n",
+                                          ip6_hdr->daddr.s6_addr32[0], ip6_hdr->daddr.s6_addr32[1],
+                                          ip6_hdr->daddr.s6_addr32[2], ip6_hdr->daddr.s6_addr32[3]);
+                               return -1;
+                       }
+               }
+               else { /* It's normal IP packet (not included in ICMP) */
+                       if (ip6_hdr->saddr.s6_addr32[2] != htonl(TRANSLATED_PREFIX)) {
+                               PDEBUG("ip6_ip4(): Src addr isn't translated addr: %x%x%x%x, packet dropped.\n",
+                                          ip6_hdr->saddr.s6_addr32[0], ip6_hdr->saddr.s6_addr32[1],
+                                          ip6_hdr->saddr.s6_addr32[2], ip6_hdr->saddr.s6_addr32[3]);
+                               return -1;
+                       }
+                       if ( ip6_hdr->daddr.s6_addr32[2] != htonl(MAPPED_PREFIX)) {
+                               PDEBUG("ip6_ip4(): Dst addr isn't mapped addr: %x%x%x%x, packet dropped.\n",
+                                          ip6_hdr->daddr.s6_addr32[0], ip6_hdr->daddr.s6_addr32[1],
+                                          ip6_hdr->daddr.s6_addr32[2], ip6_hdr->daddr.s6_addr32[3]);
+                               return -1;
+                       }
+               }
+
+               /* Set IPv4 Fragment Offset and ID to 0
+                  before process any Option Headers */
+               ip_hdr->frag_off = 0;
+               ip_hdr->id = 0;
+
+               /*
+                * We process only Fragment Header. Any other options headers
+                * are ignored, i.e. there is no attempt to translate them.
+                * However, the Total Length field and the Protocol field would
+                * have to be adjusted to "skip" these extension headers.
+                */
+
+               next_hdr = ip6_hdr->nexthdr;
+
+               /* Hop_by_Hop options header (ip6_hdr->nexthdr = 0). It must
+                * appear only in IPv6 header's Next Header field.
+                */
+               if (next_hdr == NEXTHDR_HOP) {
+                       if ( (len_delta - sizeof(struct ipv6_opt_hdr)) >= 0)
+                       {
+                               struct ipv6_opt_hdr *ip6h =
+                                       (struct ipv6_opt_hdr *)(src+sizeof(struct ipv6hdr) + opts_len);
+                               if ( (len_delta -= ip6h->hdrlen*8 + 8) >= 0)
+                               {
+                                       opts_len += ip6h->hdrlen*8 + 8;  /* See  RFC 2460 page 11:
+                                                       Hdr Ext Len  8-bit unsigned integer.  Length of the Hop-by-
+                                                                                Hop Options header in 8-octet units, not
+                                                                                including the first 8 octets.
+                                                       */
+                                       next_hdr = ip6h->nexthdr;
+                               }
+                               else
+                               {
+                                       PDEBUG("ip6_ip4(): hop_by_hop header error, packet droped");
+                                       /* Generate ICMP Parameter Problem */
+                                       return -1;
+                               }
+                       }
+               }
+
+               if (len_delta > 0)
+               {
+                       while(next_hdr != NEXTHDR_ICMP && next_hdr != NEXTHDR_TCP
+                                 && next_hdr != NEXTHDR_UDP)
+                       {
+                               /* Destination options header */
+                               if (next_hdr == NEXTHDR_DEST)
+                               {
+                                       if ( (len_delta - sizeof(struct ipv6_opt_hdr)) >= 0)
+                                       {
+                                               struct ipv6_opt_hdr *ip6d =
+                                                       (struct ipv6_opt_hdr *)(src + sizeof(struct ipv6hdr) + opts_len);
+                                               if ( (len_delta -= ip6d->hdrlen*8 + 8) >= 0)
+                                               {
+                                                       opts_len += ip6d->hdrlen*8 + 8;
+                                                       next_hdr = ip6d->nexthdr;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               PDEBUG("ip6_ip4(): destination header error, packet droped");
+                                               /* Generate ICMP Parameter Problem */
+                                               return -1;
+                                       }
+                               }
+                               /* Routing options header */
+                               else if (next_hdr == NEXTHDR_ROUTING)
+                               {
+                                       if ( (len_delta - sizeof(struct ipv6_rt_hdr)) >= 0)
+                                       {
+                                               struct ipv6_rt_hdr *ip6rt =
+                                                       (struct ipv6_rt_hdr *)(src+sizeof(struct ipv6hdr) + opts_len);
+                                               /* RFC 2765 SIIT, 4.1:
+                                                  If a routing header with a non-zero Segments Left field is present
+                                                  then the packet MUST NOT be translated, and an ICMPv6 "parameter
+                                                  problem/ erroneous header field encountered" (Type 4/Code 0) error
+                                                  message, with the Pointer field indicating the first byte of the
+                                                  Segments Left field, SHOULD be returned to the sender.
+                                                  */
+                                               if (ip6rt->segments_left != 0) {
+                                                       /* Build ICMPv6 "Parameter Problem/Erroneous Header
+                                                          Field Encountered" & drop the packet */
+                                                       /* !!! We don't send ICMPv6 "Parameter Problem" !!! */
+                                                       PDEBUG("ip6_ip4(): routing header type != 0\n");
+                                                       return -1;
+                                               }
+                                               if ( (len_delta -= ip6rt->hdrlen*8 + 8) >= 0)
+                                               {
+                                                       opts_len += ip6rt->hdrlen*8 + 8;
+                                                       next_hdr = ip6rt->nexthdr;
+                                               }
+                                               else
+                                               {
+                                                       PDEBUG("ip6_ip4(): routing header error, packet droped");
+                                                       /* Generate ICMP Parameter Problem */
+                                                       return -1;
+                                               }
+                                       }
+                               }
+                               /* Fragment options header */
+                               else if (next_hdr == NEXTHDR_FRAGMENT)
+                               {
+                                       if ( (len_delta -= sizeof(struct frag_hdr)) >= 0)
+                                       {
+                                               struct frag_hdr *ip6f =
+                                                       (struct frag_hdr *)(src+sizeof(struct ipv6hdr)+opts_len);
+
+                                               opts_len += sizeof(struct frag_hdr);      /* Frag Header Length = 8 */
+                                               ip_hdr->id = htons(ntohl(ip6f->identification)); /* ID field */
+                                               ip_hdr->frag_off = htons((ntohs(ip6f->frag_off) & IP6F_OFF_MASK) >> 3);
+                                                                                                                  /* fragment offset */
+                                               ip_hdr->frag_off = htons(ntohs(ip_hdr->frag_off) |
+                                                                                        ((ntohs(ip6f->frag_off) & IP6F_MORE_FRAG) << 13));
+                                                                                                                 /* more fragments flag */
+                                               next_hdr = ip6f->nexthdr;
+                                       }
+                                       else
+                                       {
+                                               PDEBUG("ip6_ip4(): fragment header error, packet droped");
+                                               /* Generate ICMP Parameter Problem */
+                                               return -1;
+                                       }
+                               }
+                               /* No Next Header */
+                               else if (next_hdr == NEXTHDR_NONE)
+                               {
+                                       /* RFC 2460 IPv6 Specification, 4.7
+                                          4.7 No Next Header
+
+                                          The value 59 in the Next Header field of an IPv6 header or any
+                                          extension header indicates that there is nothing following that
+                                          header.  If the Payload Length field of the IPv6 header indicates the
+                                          presence of octets past the end of a header whose Next Header field
+                                          contains 59, those octets must be ignored, and passed on unchanged if
+                                          the packet is forwarded.
+                                          */
+                                       break;
+                               }
+                               else if (next_hdr == NEXTHDR_ESP || next_hdr == NEXTHDR_AUTH)
+                               {
+                                       PDEBUG("ip6_ip4(): cannot translate AUTH or ESP extention header, packet dropped\n");
+                                       return -1;
+                               }
+                               else if (next_hdr == NEXTHDR_IPV6)
+                               {
+                                       PDEBUG("ip6_ip4(): cannot translate IPv6-IPv6 packet, packet dropped\n");
+                                       return -1;
+                               }
+                               else if (next_hdr == 0)
+                               {
+                                       /* As say RFC 2460 (IPv6 Spec) we should discard the packet and send an
+                                          ICMP Parameter Problem message to the source of the packet, with an
+                                          ICMP Code value of 1 ("unrecognized Next Header type encountered")
+                                          and the ICMP Pointer field containing the offset of the unrecognized
+                                          value within the original packet
+                                          */
+                                       /* NOT IMPLEMENTED */
+                                       PDEBUG("ip6_ip4(): NEXTHDR in extention header = 0, packet dropped\n");
+                                       return -1;
+                               }
+                               else
+                               {
+                                       PDEBUG("ip6_ip4(): cannot translate extention header = %d, packet dropped\n", next_hdr);
+                                       return -1;
+                               }
+                       }
+               }
+       }
+       else
+       {
+          PDEBUG("ip6_ip4(): error packet len, packet dropped.\n");
+          return -1;
+       }
+
+       /* Building ipv4 packet */
+
+       ip_hdr->version = IPVERSION;
+       ip_hdr->ihl = 5;
+
+       /* TOS see comment about TOS in ip4_ip6() */
+       if (tos_ignore_flag)
+               ip_hdr->tos = 0;
+       else {
+               ip_hdr->tos = ip6_hdr->priority << 4;
+               ip_hdr->tos = ip_hdr->tos | (ip6_hdr->flow_lbl[0] >> 4);
+       }
+
+       /* IPv4 Total Len = IPv6 Payload Len +
+          IPv4 Header Len (without options) - Options Headers Len */
+       ip6_payload_len = ntohs(ip6_hdr->payload_len);
+
+       if (ip6_payload_len == 0)
+               ntot_len = 0;
+       else
+               ntot_len = ip6_payload_len + IP4_IP6_HDR_DIFF - opts_len;
+
+       ip_hdr->tot_len = htons(ntot_len);
+
+       /* IPv4 TTL = IPv6 Hop Limit */
+       ip_hdr->ttl = ip6_hdr->hop_limit;
+
+       /* IPv4 Protocol = Next Header that will point to upper layer protocol */
+       ip_hdr->protocol = next_hdr;
+
+       /* IPv4 Src addr = last 4 bytes from IPv6 Src addr */
+       ip_hdr->saddr = ip6_hdr->saddr.s6_addr32[3];
+       /* IPv4 Dst addr = last 4 bytes from IPv6 Dst addr */
+       ip_hdr->daddr = ip6_hdr->daddr.s6_addr32[3];
+
+       /* Calculate IPv4 header checksum */
+       ip_hdr->check = 0;
+       ip_hdr->check = ip_fast_csum((unsigned char *)ip_hdr, ip_hdr->ihl);
+
+       if (len_delta > 0)
+       {
+               /* PROCESS ICMP */
+
+               if (next_hdr == NEXTHDR_ICMP)
+               {
+                       struct icmp6hdr *icmp6_hdr;
+                       struct icmphdr *icmp_hdr;
+
+                       if ((len_delta -= sizeof(struct icmp6hdr)) >= 0)
+                       {
+                               icmp6_hdr = (struct icmp6hdr *)(src + sizeof(struct ipv6hdr) + opts_len);
+                               icmp_hdr = (struct icmphdr *)(dst + sizeof(struct iphdr));
+
+                               real_len += len_delta + sizeof(struct icmphdr);
+
+                               /* There is diffirent between ICMPv4/ICMPv6 protocol codes
+                                  IPPROTO_ICMP = 1
+                                  IPPROTO_ICMPV6 = 58        */
+                               ip_hdr->protocol = IPPROTO_ICMP;
+
+                               if (include_flag) {
+                                       /* !!! Warnig !!! We discard ICMP packets with any ICMP as included
+                                          in ICMP Error. But ICMP Error messages can include ICMP Query message
+                                          */
+                                       if (icmp6_hdr->icmp6_type != ICMPV6_ECHO_REQUEST)
+                                       {
+                                               PDEBUG("ip6_ip4(): included ICMPv6 in ICMPv6 Error message, packet dropped\n");
+                                               return -1;
+                                       }
+                               }
+
+                       /* Translate ICMPv6 to ICMPv4 */
+                               switch (icmp6_hdr->icmp6_type)
+                               {
+/* ICMP Error messages */
+                       /* Destination Unreachable (Type 1) */
+                               case ICMPV6_DEST_UNREACH: /* Type 1 */
+                                       icmp_hdr->type = ICMP_DEST_UNREACH; /* to Type 3 */
+                                       icmp_hdr->un.echo.id = 0;
+                                       icmp_hdr->un.echo.sequence = 0;
+                                       switch (icmp6_hdr->icmp6_code)
+                                       {
+                                       case ICMPV6_NOROUTE: /* Code 0 */
+                                       case ICMPV6_NOT_NEIGHBOUR: /* Code 2 */
+                                       case ICMPV6_ADDR_UNREACH: /* Code 3  */
+                                               icmp_hdr->code = ICMP_HOST_UNREACH; /* To Code 1 */
+                                               break;
+                                       case ICMPV6_ADM_PROHIBITED: /* Code 1 */
+                                               icmp_hdr->code = ICMP_HOST_ANO; /* To Code 10 */
+                                               break;
+                                       case ICMPV6_PORT_UNREACH: /* Code 4 */
+                                               icmp_hdr->code = ICMP_PORT_UNREACH; /* To Code 3 */
+
+                                               break;
+                                       default:            /* discard any other codes */
+                                               PDEBUG("ip6_ip4(): Unknown ICMPv6 Type %d Code %d - packet dropped.\n",
+                                                          ICMPV6_DEST_UNREACH, icmp6_hdr->icmp6_code);
+                                               return -1;
+                                       }
+                                       break;
+                       /* Packet Too Big (Type 2) */
+                               case ICMPV6_PKT_TOOBIG: /* Type 2 */
+                                       icmp_hdr->type = ICMP_DEST_UNREACH; /* to Type 3  */
+                                       icmp_hdr->code = ICMP_FRAG_NEEDED; /*  to Code 4 */
+                                       /* Change MTU, RFC 2765 (SIIT), 4.2:
+                                          The MTU field needs to be adjusted for the difference between
+                                          the IPv4 and IPv6 header sizes taking into account whether or
+                                          not the packet in error includes a Fragment header.
+                                          */
+                                       /* !!! Don't implement !!! */
+                                       icmp_hdr->un.frag.mtu = (__u16) icmp6_hdr->icmp6_mtu;
+                                       break;
+                       /* Time Exceeded (Type 3) */
+                               case ICMPV6_TIME_EXCEED:
+                                       icmp_hdr->type = ICMP_TIME_EXCEEDED; /* to Type 11 */
+                                       icmp_hdr->code = icmp6_hdr->icmp6_code; /* Code unchanged */
+                                       break;
+                       /* Parameter Problem (Type 4) */
+                               case ICMPV6_PARAMPROB:
+                                       switch (icmp6_hdr->icmp6_code) {
+                                       case ICMPV6_UNK_NEXTHDR: /* Code 1 */
+                                               icmp_hdr->type = ICMP_DEST_UNREACH; /* to Type 3 */
+                                               icmp_hdr->code = ICMP_PROT_UNREACH; /* to Code 2 */
+                                               break;
+                                       default: /* if Code != 1 */
+                                               icmp_hdr->type = ICMP_PARAMETERPROB; /* to Type 12 */
+                                               icmp_hdr->code = 0; /* to Code 0 */
+                                               /* Update Pointer field
+                                                  RFC 2765 (SIIT), 4.2:
+                                                  The Pointer needs to be updated to point to the corresponding
+                                                  field in the translated include IP header.
+                                                  */
+                                               switch (ntohl(icmp6_hdr->icmp6_pointer))
+                                               {
+                                               case 0: /* IPv6 Version -> IPv4 Version */
+                                                       icmp_hdr->un.echo.id = 0;
+                                                       break;
+                                               case 4: /* IPv6 PayloadLength -> IPv4 Total Length */
+                                                       icmp_hdr->un.echo.id = 0x0002; /* 2 */
+                                                       break;
+                                               case 6: /* IPv6 Next Header-> IPv4 Protocol */
+                                                       icmp_hdr->un.echo.id = 0x0009; /* 9 */
+                                                       break;
+                                               case 7: /* IPv6 Hop Limit -> IPv4 TTL */
+                                                       icmp_hdr->un.echo.id = 0x0008; /* 8 */
+                                                       break;
+                                               case 8: /* IPv6 Src addr -> IPv4 Src addr */
+                                                       icmp_hdr->un.echo.id = 0x000c; /* 12 */
+                                                       break;
+                                               case 24: /* IPv6 Dst addr -> IPv4 Dst addr*/
+                                                       icmp_hdr->un.echo.id = 0x0010; /* 16 */
+                                                       break;
+                                               default: /* set all ones in other cases */
+                                                       icmp_hdr->un.echo.id = 0xff;
+                                                       break;
+                                               }
+                                               break;
+                                       }
+                                       break;
+
+/* End of ICMP Error messages */
+
+                       /* Echo Request and Echo Reply (Type 128 and 129)  */
+                               case ICMPV6_ECHO_REQUEST:
+                                       icmperr = 0;        /* not error ICMP message */
+                                       icmp_hdr->type = ICMP_ECHO; /* to Type 8 */
+                                       icmp_hdr->code = 0; /* to Code 0 */
+                                       icmp_hdr->un.echo.id = icmp6_hdr->icmp6_identifier;
+                                       icmp_hdr->un.echo.sequence = icmp6_hdr->icmp6_sequence;
+                                       /* copy rest of ICMP data to result packet */
+                                       if (len_delta > 0)
+                                               memcpy(((char *)icmp_hdr) + sizeof(struct icmphdr),
+                                                          ((char *)icmp6_hdr) + sizeof(struct icmp6hdr), len_delta);
+                                       break;
+                               case ICMPV6_ECHO_REPLY:
+                                       icmperr = 0;        /* not error ICMP message */
+                                       icmp_hdr->type = ICMP_ECHOREPLY; /* to Type 0 */
+                                       icmp_hdr->code = 0; /* to Code 0 */
+                                       icmp_hdr->un.echo.id = icmp6_hdr->icmp6_identifier;
+                                       icmp_hdr->un.echo.sequence = icmp6_hdr->icmp6_sequence;
+                                       /* copy rest of ICMP data */
+                                       if (len_delta > 0)
+                                               memcpy(((char *)icmp_hdr) + sizeof(struct icmphdr),
+                                                          ((char *)icmp6_hdr) + sizeof(struct icmp6hdr), len_delta);
+                                       break;
+                               default:
+                                       /* Unknown error messages. Silently drop. */
+                                       PDEBUG("ip6_ip4(): unknown ICMPv6 Type %d, packet dropped.\n", icmp6_hdr->icmp6_type);
+                                       return -1;
+                               }
+
+                               if (icmperr)
+                               {
+                                       /* If ICMP Error message, we translate IP included packet*/
+                                       if (len_delta >= sizeof(struct ipv6hdr))
+                                       {
+                                               if((inc_opts_len = ip6_ip4((char *)icmp6_hdr + sizeof(struct icmp6hdr), len_delta,
+                                                                                          (char *)icmp_hdr + sizeof(struct icmphdr), 1)) == -1) {
+                                                       PDEBUG("ip6_ip4(): incorrect translation of ICMPv6 Error message, packet dropped\n");
+                                                       return -1;
+                                               }
+                                               /* correct IPv4 Total Len that = old Total Len
+                                                  - Options Headers Len in included IP packet
+                                                  - diffirence between IPv6 Header Len and IPv4 Header Len
+                                                  */
+                                               if (ntot_len != 0)
+                                                       ip_hdr->tot_len = htons(ntot_len - inc_opts_len - IP4_IP6_HDR_DIFF);
+                                               real_len = real_len - inc_opts_len - IP4_IP6_HDR_DIFF;
+                                       }
+                                       else if (len_delta > 0)
+                                       {
+                                               /* May be it need set 0x0 to rest area in result IPv4 packet,
+                                                * but we copy rest data unchanged
+                                                */
+                                               memcpy(((char *)icmp_hdr) + sizeof(struct icmphdr),
+                                                          ((char *)icmp6_hdr) + sizeof(struct icmp6hdr), len_delta);
+                                       }
+                               }
+
+                               /* Calculate IPv4 Header checksum */
+                               ip_hdr->check = 0;
+                               ip_hdr->check = ip_fast_csum((unsigned char *)ip_hdr, ip_hdr->ihl);
+
+                               /* Calculate ICMPv4 checksum */
+                               if (ntot_len != 0)
+                               {
+                                       icmp_hdr->checksum = 0;
+                                       icmp_hdr->checksum = ip_compute_csum((unsigned char *)icmp_hdr, ntohs(ip_hdr->tot_len)
+                                                                                            - sizeof(struct iphdr));
+                               }
+                       }
+                       else
+                       {
+                               PDEBUG("ip6_ip4(): error length ICMP packet, packet dropped.\n");
+                               return -1;
+                       }
+
+               }
+               /* PROCESS TCP and UDP (and rest data) */
+
+               else {
+                       real_len += len_delta;
+                       /* we copy rest data to IPv4 packet without changing */
+                       memcpy(dst+sizeof(struct iphdr), src + sizeof(struct ipv6hdr) + opts_len, len_delta);
+               }
+       }
+
+       if (include_flag)           /* if it's included IP packet */
+               return opts_len;        /* return options headers length */
+       else
+               return real_len; /* result packet len */
+}
+
+/*
+ * ip4_fragment(skb, len, hdr_len, dev, eth_h)
+ * to fragment original IPv4 packet if result IPv6 packet will be > 1280
+ */
+
+static int ip4_fragment(struct sk_buff *skb, int len, int hdr_len, struct net_device *dev, struct ethhdr *eth_h)
+{
+       struct sk_buff *skb2 = NULL;       /* pointer to new struct sk_buff for transleded packet */
+       char buff[FRAG_BUFF_SIZE+hdr_len]; /* buffer to form new fragment packet */
+       char *cur_ptr = skb->data+hdr_len; /* pointter to current packet data with len = frag_len */
+       struct iphdr *ih4 = (struct iphdr *) skb->data;
+       struct iphdr *new_ih4 = (struct iphdr *) buff; /* point to new IPv4 hdr */
+       struct ethhdr *new_eth_h;   /* point to ether hdr, need to set hard header data in fragment */
+       int data_len = len - hdr_len; /* origin packet data len */
+       int rest_len = data_len;    /* rest data to fragment */
+       int frag_len = 0;           /* current fragment len */
+       int last_frag = 0;          /* last fragment flag, if = 1, it's last fragment */
+       int flag_last_mf = 0;
+       __u16 new_id = 0;           /* to generate identification field */
+       __u16 frag_offset = 0;      /* fragment offset */
+       unsigned int csum;
+       unsigned short udp_len;
+
+#ifdef SIIT_DEBUG
+       printk("siit: it's DF == 0 and result IPv6 packet will be > 1280\n");
+       siit_print_dump(skb->data, hdr_len, "siit: (orig) ipv4_hdr dump");
+#endif
+
+       if ((ntohs(ih4->frag_off) & IP_MF) == 0 )
+               /* it's a case we'll clear MF flag in our last packet */
+               flag_last_mf = 1;
+
+       if (ih4->protocol == IPPROTO_UDP) {
+               if ( (ntohs(ih4->frag_off) & IP_OFFSET) == 0) {
+                       struct udphdr *udp_hdr = (struct udphdr *)((char *)ih4 + hdr_len);
+                       if (!flag_last_mf) {
+                               if (udp_hdr->check == 0) {
+                                       /* it's a first fragment with ZERO checksum and we drop packet */
+                                       printk("siit: First fragment of UDP with zero checksum - packet droped\n");
+                                       printk("siit: addr: %x src port: %d dst port: %d\n",
+                                                  htonl(ih4->saddr), htons(udp_hdr->source), htons(udp_hdr->dest));
+                                       return -1;
+                               }
+                       }
+                       else if (udp_hdr->check == 0) {
+                               /* Calculate UDP checksum only if it's not fragment */
+                               udp_len = ntohs(udp_hdr->len);
+                               csum = 0;
+                               csum = csum_partial((unsigned char *)udp_hdr, udp_len, csum);
+                               udp_hdr->check = csum_tcpudp_magic(ih4->saddr, ih4->daddr, udp_len, IPPROTO_UDP, csum);
+                       }
+               }
+       }
+
+       frag_offset = ntohs(ih4->frag_off) & IP_OFFSET;
+
+       new_id = ih4->id;
+
+       while(1) {
+               if (rest_len <= FRAG_BUFF_SIZE) {
+                       /* it's last fragmen */
+                       frag_len = rest_len; /* rest data */
+                       last_frag = 1;
+               }
+               else
+                       frag_len = FRAG_BUFF_SIZE;
+
+               /* copy IP header to buffer */
+               memcpy(buff, skb->data, hdr_len);
+               /* copy data to buffer with len = frag_len */
+               memcpy(buff + hdr_len, cur_ptr, frag_len);
+
+               /* set id field in new IPv4 header*/
+               new_ih4->id = new_id;
+
+               /* is it last fragmet */
+               if(last_frag && flag_last_mf)
+                       /* clear MF flag */
+                       new_ih4->frag_off = htons(frag_offset & (~IP_MF));
+               else
+                       /* set MF flag */
+                       new_ih4->frag_off = htons(frag_offset | IP_MF);
+
+               /* change packet total length */
+               new_ih4->tot_len = htons(frag_len+hdr_len);
+
+               /* rebuild the header checksum (IP needs it) */
+               new_ih4->check = 0;
+               new_ih4->check = ip_fast_csum((unsigned char *)new_ih4,new_ih4->ihl);
+
+               /* Allocate new sk_buff to compose translated packet */
+               skb2 = dev_alloc_skb(frag_len+hdr_len+dev->hard_header_len+IP4_IP6_HDR_DIFF+IP6_FRAGMENT_SIZE);
+               if (!skb2) {
+                       printk(KERN_DEBUG "%s: alloc_skb failure - packet dropped.\n", dev->name);
+                       dev_kfree_skb(skb2);
+                       return -1;
+               }
+               /* allocate skb->data portion for IP header len, fragment data len and ether header len
+                * and copy to head ether header from origin skb
+                */
+               memcpy(skb_put(skb2, frag_len+hdr_len+dev->hard_header_len+IP4_IP6_HDR_DIFF+IP6_FRAGMENT_SIZE), (char *) eth_h,
+                          dev->hard_header_len);
+               /* correct ether header data, ether protocol field to ETH_P_IPV6 */
+               new_eth_h = (struct ethhdr *)skb2->data;
+               new_eth_h->h_proto = htons(ETH_P_IPV6);
+
+               /* reset the mac header */
+               skb_reset_mac_header(skb2);
+
+               /* pull ether header from new skb->data */
+               skb_pull(skb2, dev->hard_header_len);
+               /* set skb protocol to IPV6 */
+               skb2->protocol = htons(ETH_P_IPV6);
+
+               /* call translation function */
+               if ( ip4_ip6(buff, frag_len+hdr_len, skb2->data, 0) == -1) {
+                       dev_kfree_skb(skb2);
+                       return -1;
+               }
+
+               /*
+                * Set needed fields in new sk_buff
+                */
+               skb2->dev = dev;
+               skb2->ip_summed = CHECKSUM_UNNECESSARY;
+               skb2->pkt_type = PACKET_HOST;
+
+               /* Add transmit statistic */
+               siit_stats(dev)->tx_packets++;
+               siit_stats(dev)->tx_bytes += skb2->len;
+
+               /* send packet to upper layer */
+               netif_rx(skb2);
+
+               /* exit if it was last fragment */
+               if (last_frag)
+                       break;
+
+               /* correct current data pointer */
+               cur_ptr += frag_len;
+               /* rest data len */
+               rest_len -= frag_len;
+               /* current fragment offset */
+               frag_offset = (frag_offset*8 + frag_len)/8;
+       }
+
+       return 0;
+}
+/*
+ * Transmit a packet (called by the kernel)
+ *
+ * siit_xmit(skb, dev)
+ *
+ * where
+ * skb - pointer to struct sk_buff with incomed packet
+ * dev - pointer to struct device on which packet revieved
+ *
+ * Statistic:
+ * for all incoming packes:
+ *            stats.rx_bytes+=skb->len
+ *            stats.rx_packets++
+ * for packets we can't transle:
+ *            stats.tx_errors++
+ * device busy:
+ *            stats.tx_errors++
+ * for packets we can't allocate sk_buff:
+ *            stats.tx_dropped++
+ * for outgoing packes:
+ *            stats.tx_packets++
+ *            stats.tx_bytes+=skb2->len !!! But we don't set skb2->len !!!
+ */
+
+static int siit_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct sk_buff *skb2 = NULL;/* pointer to new struct sk_buff for transleded packet */
+       struct ethhdr *eth_h;       /* pointer to incoming Ether header */
+       int len;                    /* original packets length */
+       int new_packet_len;
+       int skb_delta = 0;          /* delta size for allocate new skb */
+       char new_packet_buff[2048];
+
+       /* Check pointer to sk_buff and device structs */
+       if (skb == NULL || dev == NULL)
+               return -EINVAL;
+
+       /* Add receive statistic */
+       siit_stats(dev)->rx_bytes += skb->len;
+       siit_stats(dev)->rx_packets++;
+
+       dev->trans_start = jiffies;
+
+       /* Upper layer (IP) protocol forms sk_buff for outgoing packet
+        * and sets IP header + Ether header too. IP layer sets outgoing
+        * device in sk_buff->dev.
+        * In function (from linux/net/core/dev.c) ther is a call to
+        * device transmit function (dev->hard_start_xmit):
+        *
+        *    dev_queue_xmit(struct sk_buff *skb)
+        *    {
+        *    ...
+        *          device *dev = skb->dev;
+        *    ...
+        *          dev->hard_start_xmit(skb, dev);
+        *    ...
+        *    }
+        * We save pointer to ether header in eth_h and skb_pull ether header
+        * from data field of skb_buff
+        */
+
+       eth_h = (struct ethhdr *)skb->data; /* point to incoming packet Ether Header */
+
+#ifdef SIIT_DEBUG
+       siit_print_dump(skb->data, ETH_HLEN, "siit: eth_hdr dump");
+#endif
+
+       /* Remove hardware header from origin sk_buff */
+       skb_pull(skb,dev->hard_header_len);
+
+       /*
+        * Process IPv4 paket
+        */
+       if (ntohs(skb->protocol) == ETH_P_IP) {
+               int hdr_len;            /* IPv4 header length */
+               int data_len;           /* IPv4 data length */
+               struct iphdr *ih4;      /* pointer to IPv4 header */
+               struct icmphdr *icmp_hdr;   /* point to current ICMPv4 header struct */
+
+               ih4 = (struct iphdr *)skb->data; /* point to incoming packet's IPv4 header */
+
+               /* Check IPv4 Total Length */
+               if (skb->len != ntohs(ih4->tot_len)) {
+                       PDEBUG("siit_xmit(): Different skb_len %x and ip4 tot_len %x - packet dropped.\n",
+                                  skb->len, ih4->tot_len);
+                       siit_stats(dev)->tx_errors++;
+                       dev_kfree_skb(skb);
+                       return 0;
+               }
+
+               len = skb->len;     /* packet's total len */
+               hdr_len = (int)(ih4->ihl * 4); /* packet's header len */
+               data_len = len - hdr_len; /* packet's data len */
+
+               /* If DF == 0 */
+               if ( (ntohs(ih4->frag_off) & IP_DF) == 0 ) {
+                       /* If result IPv6 packet will be > 1280
+                          we need to fragment original IPv4 packet
+                       */
+                       if ( data_len > FRAG_BUFF_SIZE ) {
+                               /* call function that fragment packet and translate to IPv6 each fragment
+                                * and send to upper layer
+                                */
+                               if ( ip4_fragment(skb, len, hdr_len, dev, eth_h) == -1) {
+                                       siit_stats(dev)->tx_errors++;
+                               }
+                               /* Free incoming skb */
+                               dev_kfree_skb(skb);
+                               /* Device can accept a new packet */
+
+                               return 0;
+
+                       }
+               }
+               /* If DF == 1 && MF == 0 && Fragment Offset == 0
+                * we don't include fragment header
+                */
+               if ( ntohs(ih4->frag_off) == IP_DF )
+                       skb_delta = IP4_IP6_HDR_DIFF; /* delta is +20 */
+               else
+                       skb_delta = IP4_IP6_HDR_DIFF + IP6_FRAGMENT_SIZE; /* delta is +20 and +8 */
+
+               /* If it's ICMP, check is it included IP packet in it */
+               if ( ih4->protocol == IPPROTO_ICMP) {
+                       icmp_hdr = (struct icmphdr *) (skb->data+hdr_len); /* point to ICMPv4 header */
+                       if ( icmp_hdr->type != ICMP_ECHO && icmp_hdr->type != ICMP_ECHOREPLY) {
+                               /*
+                                * It's ICMP Error that has included IP packet
+                                * we'll add only +20 because we don't include Fragment Header
+                                * into translated included IP packet
+                                */
+                               skb_delta += IP4_IP6_HDR_DIFF;
+                       }
+               }
+
+               /* Allocate new sk_buff to compose translated packet */
+               skb2 = dev_alloc_skb(len+dev->hard_header_len+skb_delta);
+               if (!skb2) {
+                       printk(KERN_DEBUG "%s: alloc_skb failure - packet dropped.\n", dev->name);
+                       dev_kfree_skb(skb);
+                       siit_stats(dev)->rx_dropped++;
+
+                       return 0;
+               }
+               /* allocate skb->data portion = IPv4 packet len + ether header len
+                * + skb_delta (max = two times (diffirence between IPv4 header and
+                * IPv6 header + Frag Header), second for included packet,
+                * and copy to head of skb->data ether header from origin skb
+                */
+               memcpy(skb_put(skb2, len+dev->hard_header_len+skb_delta), (char *)eth_h, dev->hard_header_len);
+               /* correct ether header data, ether protocol field to ETH_P_IPV6 */
+               eth_h = (struct ethhdr *)skb2->data;
+               eth_h->h_proto = htons(ETH_P_IPV6);
+               skb_reset_mac_header(skb2);
+               /* remove ether header from new skb->data,
+                * NOTE! data will rest, pointer to data and data len will change
+                */
+               skb_pull(skb2,dev->hard_header_len);
+               /* set skb protocol to IPV6 */
+               skb2->protocol = htons(ETH_P_IPV6);
+
+               /* call translation function */
+               if (ip4_ip6(skb->data, len, skb2->data, 0) == -1 ) {
+                       dev_kfree_skb(skb);
+                       dev_kfree_skb(skb2);
+                       siit_stats(dev)->rx_errors++;
+
+                       return 0;
+               }
+       }
+       /*
+        * IPv6 paket
+        */
+       else if (ntohs(skb->protocol) == ETH_P_IPV6) {
+
+#ifdef SIIT_DEBUG
+               siit_print_dump(skb->data, sizeof(struct ipv6hdr), "siit: (in) ip6_hdr dump");
+#endif
+               /* packet len = skb->data len*/
+               len = skb->len;
+
+               /* call translation function */
+               if ((new_packet_len = ip6_ip4(skb->data, len, new_packet_buff, 0)) == -1 )
+               {
+                       PDEBUG("siit_xmit(): error translation ipv6->ipv4, packet dropped.\n");
+                       siit_stats(dev)->rx_dropped++;
+                       goto end;
+               }
+
+               /* Allocate new sk_buff to compose translated packet */
+               skb2 = dev_alloc_skb(new_packet_len + dev->hard_header_len);
+               if (!skb2) {
+                       printk(KERN_DEBUG "%s: alloc_skb failure, packet dropped.\n", dev->name);
+                       siit_stats(dev)->rx_dropped++;
+                       goto end;
+               }
+               memcpy(skb_put(skb2, new_packet_len + dev->hard_header_len), (char *)eth_h, dev->hard_header_len);
+               eth_h = (struct ethhdr *)skb2->data;
+               eth_h->h_proto = htons(ETH_P_IP);
+               skb_reset_mac_header(skb2);
+               skb_pull(skb2, dev->hard_header_len);
+               memcpy(skb2->data, new_packet_buff, new_packet_len);
+               skb2->protocol = htons(ETH_P_IP);
+       }
+       else {
+               PDEBUG("siit_xmit(): unsupported protocol family %x, packet dropped.\n", skb->protocol);
+               goto end;
+       }
+
+       /*
+        * Set needed fields in new sk_buff
+        */
+       skb2->pkt_type = PACKET_HOST;
+       skb2->dev = dev;
+       skb2->ip_summed = CHECKSUM_UNNECESSARY;
+
+       /* Add transmit statistic */
+       siit_stats(dev)->tx_packets++;
+       siit_stats(dev)->tx_bytes += skb2->len;
+
+       /* Send packet to upper layer protocol */
+       netif_rx(skb2);
+
+end:
+       dev_kfree_skb(skb);
+
+       return 0;
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
+static bool header_ops_init = false;
+static struct header_ops siit_header_ops ____cacheline_aligned;
+#endif
+
+#if !(defined CONFIG_COMPAT_NET_DEV_OPS) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+static const struct net_device_ops siit_netdev_ops = {
+       .ndo_open               = siit_open,
+       .ndo_stop               = siit_release,
+       .ndo_start_xmit         = siit_xmit,
+};
+#endif
+
+/*
+ * The init function initialize of the SIIT device..
+ * It is invoked by register_netdev()
+ */
+
+static void
+siit_init(struct net_device *dev)
+{
+       ether_setup(dev);    /* assign some of the fields */
+       random_ether_addr(dev->dev_addr);
+
+       /*
+        * Assign device function.
+        */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+       dev->open            = siit_open;
+       dev->stop            = siit_release;
+       dev->hard_start_xmit = siit_xmit;
+#else
+#if !(defined CONFIG_COMPAT_NET_DEV_OPS) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+       dev->netdev_ops = &siit_netdev_ops;
+#endif
+#endif
+       dev->flags           |= IFF_NOARP;     /* ARP not used */
+       dev->tx_queue_len = 10;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+       dev->hard_header_cache = NULL;        /* Disable caching */
+       memset(netdev_priv(dev), 0, sizeof(struct net_device_stats));
+       dev->get_stats = siit_get_stats;
+#else
+       if (!header_ops_init) {
+               memcpy(&siit_header_ops, dev->header_ops, sizeof(struct header_ops));
+               siit_header_ops.cache = NULL;
+       }
+       dev->header_ops = &siit_header_ops;
+#endif
+}
+
+/*
+ * Finally, the module stuff
+ */
+static struct net_device *siit_dev = NULL;
+
+int init_module(void)
+{
+       int res = -ENOMEM;
+       int priv_size;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+       priv_size = sizeof(struct net_device_stats);
+#else
+       priv_size = sizeof(struct header_ops);
+#endif
+       siit_dev = alloc_netdev(priv_size, "siit%d", siit_init);
+       if (!siit_dev)
+               goto err_alloc;
+
+       res = register_netdev(siit_dev);
+       if (res)
+               goto err_register;
+
+       return 0;
+
+err_register:
+       free_netdev(siit_dev);
+err_alloc:
+       printk(KERN_ERR "Error creating siit device: %d\n", res);
+       return res;
+}
+
+void cleanup_module(void)
+{
+       unregister_netdev(siit_dev);
+       free_netdev(siit_dev);
+}
+
+
diff --git a/net/siit/src/siit.h b/net/siit/src/siit.h
new file mode 100644 (file)
index 0000000..47cf776
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * siit.h -- definitions for the SIIT module
+ *
+ *
+ */
+
+/*
+ * Constants
+ */
+
+/* SIIT_ETH control the name of SIIT interface:
+ * 0 - interface name is siit0,
+ * 1 - interface name is ethX.
+ */
+#define SIIT_ETH 0
+
+#define BUFF_SIZE 4096
+#define FRAG_BUFF_SIZE 1232     /* IPv6 max fragment size without IPv6 header 
+                                 * to fragmanet IPv4 if result IPv6 packet will be > 1280
+                                 */
+
+#define TRANSLATED_PREFIX 0x0000ffff /* third byte in IPv4-translated addr prefix */
+#define MAPPED_PREFIX 0x0000ffff     /* third byte in IPv4-mapped addr prefix */
+
+#define IP4_IP6_HDR_DIFF 20     /* diffirence between IPv4 and IPv6 headers */
+#define IP6_FRAGMENT_SIZE 8     /* size of Fragment Header */
+
+/* IPv6 header fields masks */
+#define IP6F_OFF_MASK       0xfff8  /* mask out offset from frag_off */
+#define IP6F_RESERVED_MASK  0x0006  /* reserved bits in frag_off */
+#define IP6F_MORE_FRAG      0x0001  /* more-fragments flag */
+
+
+
+/*
+ * Macros to help debugging
+ */
+
+#undef PDEBUG             /* undef it, just in case */
+#ifdef SIIT_DEBUG
+#  ifdef __KERNEL__
+     /* This one if debugging is on, and kernel space */
+#    define PDEBUG(fmt, args...) printk(KERN_DEBUG "siit: " fmt, ## args)
+#  else
+     /* This one for user space */
+#    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
+#  endif
+#else
+#  define PDEBUG(fmt, args...) /* not debugging: nothing */
+#endif
+
+#undef PDEBUGG
+#define PDEBUGG(fmt, args...)
+
+
+
+
+
+
+
+
diff --git a/net/wprobe/Makefile b/net/wprobe/Makefile
new file mode 100644 (file)
index 0000000..de1ba6d
--- /dev/null
@@ -0,0 +1,143 @@
+#
+# Copyright (C) 2008-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=wprobe
+PKG_VERSION:=1
+PKG_RELEASE:=1
+
+PKG_BUILD_DEPENDS:=PACKAGE_wprobe-export:libipfix
+
+PKG_CONFIG_DEPENDS = \
+       CONFIG_PACKAGE_kmod-wprobe \
+       CONFIG_PACKAGE_wprobe-export \
+
+include $(INCLUDE_DIR)/package.mk
+
+# XXX: build failure on cris
+# wprobe-lib.c:145: error: 'packed' attribute ignored for field of type 'struct <anonymous>'
+# wprobe-lib.c:149: error: 'packed' attribute ignored for field of type 'struct <anonymous>'
+
+define Package/wprobe/Default
+  DEPENDS:=@(!(TARGET_ps3||TARGET_pxcab||cris)||BROKEN)
+endef
+
+define KernelPackage/wprobe
+$(call Package/wprobe/Default)
+  SUBMENU:=Network Support
+  TITLE:=Wireless driver probe infrastructure
+  MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+  FILES:= \
+       $(PKG_BUILD_DIR)/kernel/wprobe.ko
+  AUTOLOAD:=$(call AutoLoad,01,wprobe)
+endef
+
+define KernelPackage/wprobe/description
+  A module that exports measurement data from wireless driver to user space
+endef
+
+define Package/wprobe-util
+$(call Package/wprobe/Default)
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS+=+kmod-wprobe +libnl-tiny
+  TITLE:=Wireless measurement utility
+endef
+
+define Package/wprobe-util/description
+  wprobe-util uses the wprobe kernel module to query
+  wireless driver measurement data from an interface
+endef
+
+define Package/wprobe-export
+$(call Package/wprobe/Default)
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS+=+wprobe-util
+  TITLE:=Wireless measurement data exporter
+endef
+
+define Package/wprobe-export/description
+  wprobe-export uses the wprobe kernel module to export
+  wireless driver measurement data via the IPFIX protocol
+endef
+
+define Package/wprobe-export/conffiles
+/etc/config/wprobe
+endef
+
+define Build/Prepare
+       mkdir -p $(PKG_BUILD_DIR)
+       $(CP) src/* $(PKG_BUILD_DIR)/
+endef
+
+TARGET_CPPFLAGS := \
+       -D_GNU_SOURCE \
+       -I$(STAGING_DIR)/usr/include/libnl-tiny \
+       $(TARGET_CPPFLAGS)
+
+ifdef CONFIG_PACKAGE_kmod-wprobe
+  define Build/Compile/kmod
+       $(MAKE) -C $(LINUX_DIR) \
+               CROSS_COMPILE="$(KERNEL_CROSS)" \
+               ARCH="$(LINUX_KARCH)" \
+               SUBDIRS="$(PKG_BUILD_DIR)/kernel" \
+               KERNELDIR=$(LINUX_DIR) \
+               CC="$(TARGET_CC)" \
+               EXTRA_CFLAGS="-I$(PKG_BUILD_DIR)/kernel" \
+               modules
+  endef
+endif
+
+define Build/Compile/lib
+       $(MAKE) -C $(PKG_BUILD_DIR)/user \
+               $(TARGET_CONFIGURE_OPTS) \
+               CFLAGS="$(TARGET_CFLAGS)" \
+               CPPFLAGS="$(TARGET_CPPFLAGS) -I$(PKG_BUILD_DIR)/kernel" \
+               LDFLAGS="$(TARGET_LDFLAGS)" \
+               HOST_OS=Linux \
+               LIBNL="-lnl-tiny"
+endef
+
+ifdef CONFIG_PACKAGE_wprobe-export
+  define Build/Compile/exporter
+       $(MAKE) -C $(PKG_BUILD_DIR)/exporter \
+               $(TARGET_CONFIGURE_OPTS) \
+               CFLAGS="$(TARGET_CFLAGS)" \
+               CPPFLAGS="$(TARGET_CPPFLAGS) -I$(PKG_BUILD_DIR)/kernel -I$(PKG_BUILD_DIR)/user" \
+               LDFLAGS="$(TARGET_LDFLAGS)" \
+               LIBS="$(PKG_BUILD_DIR)/user/libwprobe.a $(STAGING_DIR)/usr/lib/libipfix.a $(STAGING_DIR)/usr/lib/libipfixmisc.a -lnl-tiny -lm"
+  endef
+endif
+
+define Build/Compile
+       $(Build/Compile/kmod)
+       $(Build/Compile/lib)
+       $(Build/Compile/exporter)
+endef
+
+define Build/InstallDev
+       $(INSTALL_DIR) $(1)/usr/include/wprobe
+       $(CP) $(PKG_BUILD_DIR)/kernel/linux $(1)/usr/include/wprobe
+endef
+
+define Package/wprobe-util/install
+       $(INSTALL_DIR) $(1)/sbin
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/user/wprobe-util $(1)/sbin/
+endef
+
+define Package/wprobe-export/install
+       $(INSTALL_DIR) $(1)/sbin $(1)/etc/init.d $(1)/etc/config
+       $(INSTALL_BIN) ./files/wprobe.init $(1)/etc/init.d/wprobe
+       $(INSTALL_BIN) ./files/wprobe.config $(1)/etc/config/wprobe
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/exporter/wprobe-export $(1)/sbin/
+endef
+
+$(eval $(call KernelPackage,wprobe))
+$(eval $(call BuildPackage,wprobe-util))
+$(eval $(call BuildPackage,wprobe-export))
diff --git a/net/wprobe/files/wprobe.config b/net/wprobe/files/wprobe.config
new file mode 100644 (file)
index 0000000..63518ef
--- /dev/null
@@ -0,0 +1,10 @@
+config export
+       # uncomment this line to enable ipfix export:
+       # option type ipfix
+       option ifname ath0
+       option host ipfix-col
+       option proto tcp
+
+# enable public wprobe protocol access
+config export
+       option type wprobe
diff --git a/net/wprobe/files/wprobe.init b/net/wprobe/files/wprobe.init
new file mode 100755 (executable)
index 0000000..b35246d
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/sh /etc/rc.common
+START=90
+EXPORTER=/sbin/wprobe-export
+UTIL=/sbin/wprobe-util
+
+wprobe_ssd() {
+       local cmd="$1"; shift
+       local type="$1"; shift
+       local app="$1"; shift
+       start-stop-daemon "$cmd" -p "/var/run/wprobe-$type.pid" -b ${app:+-x "$app"} -m -- "$@"
+}
+
+stop_wprobe() {
+       local type="$1"
+       [ -f "/var/run/wprobe-$type.pid" ] && wprobe_ssd -K "$type"
+       rm -f "/var/run/wprobe-$type.pid"
+}
+
+config_wprobe() {
+       config_get ifname "$cfg" ifname
+       config_get interval "$cfg" interval
+       [ -n "$interval" ] || interval=100
+       $UTIL "$ifname" -i "$interval" 2>/dev/null >/dev/null
+}
+
+start_proxy() {
+       config_get port "$cfg" port
+       wprobe_ssd -S proxy "$UTIL" -P -p "${port:-17990}"
+}
+
+start_ipfix() {
+       local cfg="$1"
+       config_get ifname "$cfg" ifname
+       config_get host "$cfg" host
+       config_get port "$cfg" port
+       config_get proto "$cfg" proto
+       case "$proto" in
+               sctp) proto="-s";;
+               tcp) proto="-t";;
+               udp) proto="-u";;
+               *) proto="-t";;
+       esac
+       [ -z "$ifname" -o -z "$host" ] && {
+               echo "wprobe-export: missing host or interface name in config $cfg"
+               return
+       }
+       config_wprobe "$cfg"
+       wprobe_ssd -S "export-$cfg" "$EXPORTER" "$proto" -i "$ifname" -c "$host" -p "${port:-4739}"
+}
+
+start_export() {
+       local cfg="$1"
+       config_get export_type "$cfg" type
+       case "$export_type" in 
+               ipfix) [ -x "$EXPORTER" ] && start_ipfix "$cfg";;
+               wprobe) start_proxy "$cfg";;
+       esac
+}
+
+stop() {
+       for f in /var/run/wprobe-*.pid; do
+               CFG="${f%%.pid}"
+               CFG="${CFG##/var/run/wprobe-}"
+               stop_wprobe "$CFG"
+       done
+}
+
+start() {
+       config_load wprobe
+       config_foreach config_wprobe interface
+       config_foreach start_export export
+}
diff --git a/net/wprobe/src/Makefile.inc b/net/wprobe/src/Makefile.inc
new file mode 100644 (file)
index 0000000..5044c0a
--- /dev/null
@@ -0,0 +1,12 @@
+HOST_OS=$(shell uname)
+
+CC=gcc
+AR=ar
+RANLIB=ranlib
+
+WFLAGS = -Wall -Werror -Wno-format
+CFLAGS?=-O2
+CPPFLAGS=
+LDFLAGS=
+LIBS=
+
diff --git a/net/wprobe/src/exporter/Makefile b/net/wprobe/src/exporter/Makefile
new file mode 100644 (file)
index 0000000..9f81507
--- /dev/null
@@ -0,0 +1,5 @@
+include ../Makefile.inc
+CPPFLAGS += -I../kernel -I../user
+
+wprobe-export: wprobe-export.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
diff --git a/net/wprobe/src/exporter/wprobe-export.c b/net/wprobe/src/exporter/wprobe-export.c
new file mode 100644 (file)
index 0000000..a0e52e2
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+**     exporter.c - example exporter
+**
+**     Copyright Fraunhofer FOKUS
+**
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <ipfix_def.h>
+#include <ipfix_def_fokus.h>
+#include <ipfix_fields_fokus.h>
+
+#include <ipfix.h>
+#include <mlog.h>
+#include <wprobe.h>
+#include <stdbool.h>
+
+static ipfix_datarecord_t g_data  = { NULL, NULL, 0 };
+static int do_close = 0;
+
+struct wprobe_mapping {
+       int id;
+       bool counter;
+       const char *wprobe_id;
+       struct wprobe_value *val;
+};
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(_array) (sizeof(_array) / sizeof((_array)[0]))
+#endif
+
+#define WMAP(_id, _name, ...) \
+       { \
+               .counter = false, \
+               .id = IPFIX_FT_WPROBE_##_id##_N, \
+               .wprobe_id = _name \
+               , ## __VA_ARGS__ \
+       }
+
+#define WMAP_COUNTER(_id, _name, ...) \
+       { \
+               .counter = true, \
+               .id = IPFIX_FT_WPROBE_##_id, \
+               .wprobe_id = _name \
+               , ## __VA_ARGS__ \
+       }
+
+
+#define WPROBE_OFFSET  2
+
+static struct wprobe_mapping map_globals[] = {
+       WMAP(NOISE, "noise"),
+       WMAP(PHY_BUSY, "phy_busy"),
+       WMAP(PHY_RX, "phy_rx"),
+       WMAP(PHY_TX, "phy_tx"),
+       WMAP_COUNTER(FRAMES, "frames"),
+       WMAP_COUNTER(PROBEREQ, "probereq"),
+};
+
+static struct wprobe_mapping map_perlink[] = {
+       WMAP(IEEE_TX_RATE, "tx_rate"),
+       WMAP(IEEE_RX_RATE, "rx_rate"),
+       WMAP(RSSI, "rssi"),
+       WMAP(SIGNAL, "signal"),
+       WMAP(RETRANSMIT_200, "retransmit_200"),
+       WMAP(RETRANSMIT_400, "retransmit_400"),
+       WMAP(RETRANSMIT_800, "retransmit_800"),
+       WMAP(RETRANSMIT_1600, "retransmit_1600"),
+};
+
+static unsigned char link_local[6];
+static char link_default[6];
+static int nfields = 0;
+
+#define FOKUS_USERID   12325
+
+static void
+match_template(struct wprobe_mapping *map, int n, struct list_head *list)
+{
+       struct wprobe_attribute *attr;
+       int i, j, last = -1;
+
+       list_for_each_entry(attr, list, list) {
+               for (i = 0; i < n; i++) {
+                       j = (last + 1 + i) % n;
+                       if (!strcmp(attr->name, map[j].wprobe_id))
+                               goto found;
+               }
+               continue;
+found:
+               last = j;
+               map[j].val = &attr->val;
+               memset(&attr->val, 0, sizeof(attr->val));
+               nfields++;
+       }
+}
+
+/* name: export_ipfix_get_template()
+ */
+static ipfix_template_t *
+prepare_template(ipfix_t *handle)
+{
+    ipfix_template_t *t = NULL;
+       int size = 3 * nfields + WPROBE_OFFSET;
+    int i;
+
+    if (ipfix_new_data_template( handle, &t, size) < 0) {
+        mlogf( 0, "ipfix_new_template() failed: %s\n", strerror(errno) ); 
+               exit(1);
+    }
+
+       ipfix_add_field(handle, t, 0, IPFIX_FT_SOURCEMACADDRESS, 6);
+       ipfix_add_field(handle, t, 0, IPFIX_FT_DESTINATIONMACADDRESS, 6);
+
+       g_data.lens = calloc(size, sizeof(g_data.lens[0]));
+       g_data.lens[0] = 6;
+       g_data.lens[1] = 6;
+       for (i = WPROBE_OFFSET; i < size; i++)
+               g_data.lens[i] = 4;
+
+       g_data.addrs = calloc(size, sizeof(g_data.addrs[0]));
+       g_data.addrs[0] = link_local;
+       g_data.maxfields = WPROBE_OFFSET;
+       return t;
+}
+
+static void
+add_template_fields(ipfix_t *handle, ipfix_template_t *t, struct wprobe_mapping *map, int n)
+{
+       int f = g_data.maxfields;
+       int i;
+
+    for (i = 0; i < n; i++) {
+               if (!map[i].val)
+                       continue;
+
+               if (map[i].counter)
+                       g_data.addrs[f++] = &map[i].val->U32;
+               else
+                       g_data.addrs[f++] = &map[i].val->n;
+
+        if (ipfix_add_field( handle, t, FOKUS_USERID, map[i].id + 0, 4) < 0)
+            exit(1);
+
+               if (map[i].counter)
+                       continue;
+
+               g_data.lens[f] = 8;
+               g_data.addrs[f++] = &map[i].val->s;
+
+               g_data.lens[f] = 8;
+               g_data.addrs[f++] = &map[i].val->ss;
+        if (ipfix_add_field( handle, t, FOKUS_USERID, map[i].id + 1, 8) < 0)
+            exit(1);
+        if (ipfix_add_field( handle, t, FOKUS_USERID, map[i].id + 2, 8) < 0)
+            exit(1);
+    }
+       g_data.maxfields = f;
+}
+
+static void
+wprobe_dump_data(ipfix_t *ipfixh, ipfix_template_t *ipfixt, struct wprobe_iface *dev)
+{
+       struct wprobe_link *link;
+
+       wprobe_update_links(dev);
+       wprobe_request_data(dev, NULL);
+       if (list_empty(&dev->links)) {
+               g_data.addrs[1] = link_default;
+               ipfix_export_array(ipfixh, ipfixt, g_data.maxfields, g_data.addrs, g_data.lens);
+               ipfix_export_flush(ipfixh);
+       }
+       list_for_each_entry(link, &dev->links, list) {
+               g_data.addrs[1] = link->addr;
+               wprobe_request_data(dev, link->addr);
+               ipfix_export_array(ipfixh, ipfixt, g_data.maxfields, g_data.addrs, g_data.lens);
+               ipfix_export_flush(ipfixh);
+       }
+}
+
+int main ( int argc, char **argv )
+{
+       struct wprobe_iface *dev = NULL;
+    ipfix_template_t  *ipfixt = NULL;
+    ipfix_t *ipfixh = NULL;
+    int protocol = IPFIX_PROTO_TCP;
+    char *chost = NULL;
+       char *ifname = NULL;
+    int sourceid = 12345;
+    int port = IPFIX_PORTNO;
+    int verbose_level = 0;
+    int opt, i = 10;
+       char *err = NULL;
+
+       while ((opt = getopt(argc, argv, "hi:c:p:vstu")) != EOF) {
+               switch (opt) {
+               case 'p':
+                       if ((port=atoi(optarg)) <0) {
+                               fprintf( stderr, "Invalid -p argument!\n" );
+                               exit(1);
+                       }
+                       break;
+               case 'i':
+                       ifname = optarg;
+                       break;
+               case 'c':
+                       chost = optarg;
+                       break;
+
+               case 's':
+                       protocol = IPFIX_PROTO_SCTP;
+                       break;
+
+               case 't':
+                       protocol = IPFIX_PROTO_TCP;
+                       break;
+
+               case 'u':
+                       protocol = IPFIX_PROTO_UDP;
+                       break;
+
+               case 'v':
+                       verbose_level ++;
+                       break;
+
+               case 'h':
+               default:
+                       fprintf(stderr, "usage: %s [-hstuv] -i <interface> -c <collector> [-p portno]\n"
+                                        "  -h               this help\n"
+                                        "  -i <interface>   wprobe interface\n"
+                                        "  -c <collector>   collector address\n"
+                                        "  -p <portno>      collector port number (default=%d)\n"
+                                        "  -s               send data via SCTP\n"
+                                        "  -t               send data via TCP (default)\n"
+                                        "  -u               send data via UDP\n"
+                                        "  -v               increase verbose level\n\n",
+                                        argv[0], IPFIX_PORTNO  );
+                       exit(1);
+               }
+       }
+
+       if (!ifname) {
+               fprintf(stderr, "No interface specified\n");
+               return -1;
+       }
+
+       if (!chost) {
+               fprintf(stderr, "No collector specified\n");
+               return -1;
+       }
+
+       dev = wprobe_get_auto(ifname, &err);
+       if (!dev || (list_empty(&dev->global_attr) && list_empty(&dev->link_attr))) {
+               fprintf(stderr, "Cannot connect to wprobe on interface '%s': %s\n", ifname, (err ? err : "Unknown error"));
+               return -1;
+       }
+
+       match_template(map_globals, ARRAY_SIZE(map_globals), &dev->global_attr);
+       match_template(map_perlink, ARRAY_SIZE(map_perlink), &dev->link_attr);
+       if (nfields == 0) {
+               fprintf(stderr, "No usable attributes found\n");
+               return -1;
+       }
+
+    mlog_set_vlevel( verbose_level );
+    if (ipfix_init() < 0) {
+        fprintf( stderr, "cannot init ipfix module: %s\n", strerror(errno) );
+        exit(1);
+    }
+
+    ipfix_add_vendor_information_elements(ipfix_ft_fokus);
+    if (ipfix_open(&ipfixh, sourceid, IPFIX_VERSION) < 0) {
+        fprintf( stderr, "ipfix_open() failed: %s\n", strerror(errno) );
+        exit(1);
+    }
+
+    if (ipfix_add_collector( ipfixh, chost, port, protocol ) < 0) {
+        fprintf( stderr, "ipfix_add_collector(%s,%d) failed: %s\n", 
+                 chost, port, strerror(errno));
+        exit(1);
+    }
+
+       fprintf(stderr, "Local link address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+               link_local[0], link_local[1], link_local[2],
+               link_local[3], link_local[4], link_local[5]);
+
+       ipfixt = prepare_template(ipfixh);
+       add_template_fields(ipfixh, ipfixt, map_globals, ARRAY_SIZE(map_globals));
+       add_template_fields(ipfixh, ipfixt, map_perlink, ARRAY_SIZE(map_perlink));
+
+       while (!do_close) {
+               sleep(1);
+               wprobe_dump_data(ipfixh, ipfixt, dev);
+    }
+
+    ipfix_delete_template( ipfixh, ipfixt );
+    ipfix_close( ipfixh );
+    ipfix_cleanup();
+    exit(0);
+}
diff --git a/net/wprobe/src/exporter/wprobe-export.h b/net/wprobe/src/exporter/wprobe-export.h
new file mode 100644 (file)
index 0000000..89da9e8
--- /dev/null
@@ -0,0 +1,34 @@
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/**
+ * struct wprobe_value: data structure for attribute values
+ * see kernel api netlink attributes for more information
+ */
+struct wprobe_value {
+       /* attribute value */
+       union data {
+               const char *STRING;
+               uint8_t U8;
+               uint16_t U16;
+               uint32_t U32;
+               uint64_t U64;
+               int8_t S8;
+               int16_t S16;
+               int32_t S32;
+               int64_t S64;
+       } data;
+       /* statistics */
+       int64_t s, ss;
+       double avg, stdev;
+       unsigned int n;
+       void *usedata;  /* Pointer to used data.something */
+};
+
+struct exporter_data {
+       int id; /* ipfix id */
+        int userid; /* focus or global */
+       int size; /* size in byte*/
+       struct wprobe_value val;
+};
diff --git a/net/wprobe/src/filter/README.txt b/net/wprobe/src/filter/README.txt
new file mode 100644 (file)
index 0000000..6fa265e
--- /dev/null
@@ -0,0 +1 @@
+To compile pfc you need at least libpcap version 1.0, as it requires proper radiotap header support
diff --git a/net/wprobe/src/filter/gen_filter.pl b/net/wprobe/src/filter/gen_filter.pl
new file mode 100755 (executable)
index 0000000..f03f477
--- /dev/null
@@ -0,0 +1,63 @@
+#!/usr/bin/perl
+use strict;
+
+# helpers for custom packet format
+# bytes 0-7 are used by a dummy radiotap header
+my $WLAN_LEN = "radio[8:2]";
+my $SNR = "radio[10:1]";
+my $DEFAULT = undef;
+
+my $MAGIC = "WPFF";
+my $VERSION = 1; # filter binary format version
+my $HDRLEN = 3; # assumed storage space for custom fields
+
+my $output = "filter.bin";
+my $config = {
+       "packetsize" => [
+               [ "small", "$WLAN_LEN < 250" ],
+               [ "medium", "$WLAN_LEN < 800" ],
+               [ "big", $DEFAULT ],
+       ],
+       "snr" => [
+               [ "low", "$SNR < 10" ],
+               [ "medium", "$SNR < 20" ],
+               [ "high", $DEFAULT ],
+       ],
+       "type" => [
+               [ "beacon", "type mgt subtype beacon" ],
+               [ "data", "type data subtype data" ],
+               [ "qosdata", "type data subtype qos-data" ],
+               [ "other", "$DEFAULT" ]
+       ]
+};
+
+sub escape_q($) {
+       my $str = shift;
+       $str =~ s/'/'\\''/g;
+       return $str;
+}
+
+my $GROUPS = scalar(keys %$config);
+open OUTPUT, ">$output" or die "Cannot open output file: $!\n";
+print OUTPUT pack("a4CCn", $MAGIC, $VERSION, $HDRLEN, $GROUPS);
+
+foreach my $groupname (keys %$config) {
+       my $default = 0;
+       my $group = $config->{$groupname};
+       print OUTPUT pack("a32N", $groupname, scalar(@$group));
+       foreach my $filter (@$group) {
+               if (!$filter->[1]) {
+                       $default > 0 and print "Cannot add more than one default filter per group: $groupname -> ".$filter->[0]."\n";
+                       print OUTPUT pack("a32N", $filter->[0], 0);
+                       $default++;
+               } else {
+                       open FILTER, "./pfc '".escape_q($filter->[0])."' '".escape_q($filter->[1])."' |"
+                               or die "Failed to run filter command for '".$filter->[0]."': $!\n";
+                       while (<FILTER>) {
+                               print OUTPUT $_;
+                       }
+                       close FILTER;
+                       $? and die "Filter '".$filter->[0]."' did not compile.\n";
+               }
+       }
+}
diff --git a/net/wprobe/src/filter/pfc.c b/net/wprobe/src/filter/pfc.c
new file mode 100644 (file)
index 0000000..76fb141
--- /dev/null
@@ -0,0 +1,58 @@
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <pcap.h>
+#include <pcap-bpf.h>
+
+struct wprobe_filter_hdr {
+       char name[32];
+       uint32_t len;
+} hdr;
+
+int main (int argc, char ** argv)
+{
+    struct  bpf_program filter;
+    pcap_t  *pc;
+       int i;
+
+    if (argc != 3)
+    {
+               fprintf(stderr, "Usage: %s <name> <expression>\n", argv[0]);
+               return 1;
+    }
+
+    pc = pcap_open_dead(DLT_IEEE802_11_RADIO, 256);
+    if (pcap_compile(pc, &filter, argv[2], 1, 0) != 0)
+       {
+               pcap_perror(pc, argv[0]);
+               exit(1);
+       }
+
+       /* fix up for linux */
+       for (i = 0; i < filter.bf_len; i++) {
+               struct bpf_insn *bi = &filter.bf_insns[i];
+               switch(BPF_CLASS(bi->code)) {
+               case BPF_RET:
+                       if (BPF_MODE(bi->code) == BPF_K) {
+                               if (bi->k != 0)
+                                       bi->k = 65535;
+                       }
+                       break;
+               }
+               bi->code = ntohs(bi->code);
+               bi->k = ntohl(bi->k);
+       }
+
+       memset(&hdr, 0, sizeof(hdr));
+       strncpy(hdr.name, argv[1], sizeof(hdr.name));
+       hdr.len = htonl(filter.bf_len);
+       fwrite(&hdr, sizeof(hdr), 1, stdout);
+       fwrite(filter.bf_insns, 8, filter.bf_len, stdout);
+       fflush(stdout);
+
+    return 0;
+}
diff --git a/net/wprobe/src/kernel/Makefile b/net/wprobe/src/kernel/Makefile
new file mode 100644 (file)
index 0000000..2a98753
--- /dev/null
@@ -0,0 +1,5 @@
+EXTRA_CFLAGS += -I.
+
+obj-m := wprobe.o wprobe-dummy.o
+
+wprobe-objs := wprobe-core.o
diff --git a/net/wprobe/src/kernel/linux/wprobe.h b/net/wprobe/src/kernel/linux/wprobe.h
new file mode 100644 (file)
index 0000000..901daf3
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * wprobe.h: API for the wireless probe interface
+ * Copyright (C) 2008-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WPROBE_H
+#define __WPROBE_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/filter.h>
+#include <net/genetlink.h>
+#endif
+
+/** 
+ * enum wprobe_attr: netlink attribute list
+ *
+ * @WPROBE_ATTR_UNSPEC: unused
+ *
+ * @WPROBE_ATTR_INTERFACE: interface name to process query on (NLA_STRING)
+ * @WPROBE_ATTR_MAC: mac address (used for wireless links) (NLA_STRING)
+ * @WPROBE_ATTR_FLAGS: interface/link/attribute flags (see enum wprobe_flags) (NLA_U32)a
+ * @WPROBE_ATTR_DURATION: sampling duration (in milliseconds) (NLA_MSECS) 
+ *
+ * @WPROBE_ATTR_ID: attribute id (NLA_U32)
+ * @WPROBE_ATTR_NAME: attribute name (NLA_STRING)
+ * @WPROBE_ATTR_TYPE: attribute type (NLA_U8)
+ *
+ * attribute values:
+ *
+ * @WPROBE_VAL_STRING: string value (NLA_STRING)
+ * @WPROBE_VAL_S8: signed 8-bit integer (NLA_U8)
+ * @WPROBE_VAL_S16: signed 16-bit integer (NLA_U16)
+ * @WPROBE_VAL_S32: signed 32-bit integer (NLA_U32)
+ * @WPROBE_VAL_S64: signed 64-bit integer (NLA_U64)
+ * @WPROBE_VAL_U8: unsigned 8-bit integer (NLA_U8)
+ * @WPROBE_VAL_U16: unsigned 16-bit integer (NLA_U16)
+ * @WPROBE_VAL_U32: unsigned 32-bit integer (NLA_U32)
+ * @WPROBE_VAL_U64: unsigned 64-bit integer (NLA_U64)
+ *
+ * statistics:
+ * @WPROBE_VAL_SUM: sum of all samples
+ * @WPROBE_VAL_SUM_SQ: sum of all samples^2
+ * @WPROBE_VAL_SAMPLES: number of samples
+ * @WPROBE_VAL_SCALE_TIME: last time the samples were scaled down
+ *
+ * configuration:
+ * @WPROBE_ATTR_INTERVAL: (measurement interval in milliseconds) (NLA_MSECS)
+ * @WPROBE_ATTR_SAMPLES_MIN: minimum samples to keep during inactivity (NLA_U32)
+ * @WPROBE_ATTR_SAMPLES_MAX: maximum samples to keep before scaling down (NLA_U32)
+ * @WPROBE_ATTR_SAMPLES_SCALE_M: multiplier for scaling down samples (NLA_U32)
+ * @WPROBE_ATTR_SAMPLES_SCALE_D: divisor for scaling down samples (NLA_U32)
+ *
+ * @WPROBE_ATTR_LAST: unused
+ */
+enum wprobe_attr {
+       /* query attributes */
+       WPROBE_ATTR_UNSPEC,
+       WPROBE_ATTR_INTERFACE,
+       WPROBE_ATTR_MAC,
+       WPROBE_ATTR_FLAGS,
+
+       /* response data */
+       WPROBE_ATTR_ID,
+       WPROBE_ATTR_NAME,
+       WPROBE_ATTR_TYPE,
+       WPROBE_ATTR_DURATION,
+
+       /* value type attributes */
+       WPROBE_VAL_STRING,
+       WPROBE_VAL_S8,
+       WPROBE_VAL_S16,
+       WPROBE_VAL_S32,
+       WPROBE_VAL_S64,
+       WPROBE_VAL_U8,
+       WPROBE_VAL_U16,
+       WPROBE_VAL_U32,
+       WPROBE_VAL_U64,
+
+       /* aggregates for statistics */
+       WPROBE_VAL_SUM,
+       WPROBE_VAL_SUM_SQ,
+       WPROBE_VAL_SAMPLES,
+       WPROBE_VAL_SCALE_TIME,
+
+       /* config attributes */
+       WPROBE_ATTR_INTERVAL,
+       WPROBE_ATTR_SAMPLES_MIN,
+       WPROBE_ATTR_SAMPLES_MAX,
+       WPROBE_ATTR_SAMPLES_SCALE_M,
+       WPROBE_ATTR_SAMPLES_SCALE_D,
+       WPROBE_ATTR_FILTER,
+
+       WPROBE_ATTR_FILTER_GROUP,
+       WPROBE_ATTR_RXCOUNT,
+       WPROBE_ATTR_TXCOUNT,
+
+       WPROBE_ATTR_LAST
+};
+
+
+/**
+ * enum wprobe_cmd: netlink commands for interacting with wprobe
+ *
+ * @WPROBE_CMD_UNSPEC: unused
+ *
+ * @WPROBE_CMD_GET_LIST: get global/link property list
+ * @WPROBE_CMD_GET_INFO: get global/link properties
+ * @WPROBE_CMD_SET_FLAGS: set global/link flags
+ * @WPROBE_CMD_MEASURE: take a snapshot of the current data
+ * @WPROBE_CMD_GET_LINKS: get a list of links
+ * @WPROBE_CMD_CONFIG: set config options
+ * @WPROBE_CMD_GET_FILTER: get counters for active filters
+ *
+ * @WPROBE_CMD_LAST: unused
+ * 
+ * options for GET_INFO and SET_FLAGS:
+ *   - mac address set: per-link
+ *   - mac address unset: globalsa
+ */
+enum wprobe_cmd {
+       WPROBE_CMD_UNSPEC,
+       WPROBE_CMD_GET_LIST,
+       WPROBE_CMD_GET_INFO,
+       WPROBE_CMD_SET_FLAGS,
+       WPROBE_CMD_MEASURE,
+       WPROBE_CMD_GET_LINKS,
+       WPROBE_CMD_CONFIG,
+       WPROBE_CMD_GET_FILTER,
+       WPROBE_CMD_LAST
+};
+
+/**
+ * enum wprobe_flags: flags for wprobe links and items
+ * @WPROBE_F_KEEPSTAT: keep statistics for this link/device
+ * @WPROBE_F_RESET: reset statistics now
+ * @WPROBE_F_NEWDATA: used to indicate that a value has been updated
+ */
+enum wprobe_flags {
+       WPROBE_F_KEEPSTAT = (1 << 0),
+       WPROBE_F_RESET = (1 << 1),
+       WPROBE_F_NEWDATA = (1 << 2),
+};
+
+#ifdef __KERNEL__
+
+struct wprobe_link;
+struct wprobe_item;
+struct wprobe_source;
+struct wprobe_value;
+
+/**
+ * struct wprobe_link - data structure describing a wireless link
+ * @iface: pointer to the wprobe_iface that this link belongs to
+ * @addr: BSSID of the remote link partner
+ * @flags: link flags (see wprobe_flags)
+ * @priv: user pointer
+ *
+ * @list: for internal use
+ * @val: for internal use
+ */
+struct wprobe_link {
+       struct list_head list;
+       struct wprobe_iface *iface;
+       char addr[ETH_ALEN];
+       u32 flags;
+       void *priv;
+       struct wprobe_value *val;
+};
+
+/** 
+ * struct wprobe_item - data structure describing the format of wprobe_link::data or wprobe_iface::data
+ * @name: name of the field
+ * @type: data type of this field
+ * @flags: measurement item flags (see wprobe_flags)
+ */
+struct wprobe_item {
+       const char *name;
+       enum wprobe_attr type;
+       u32 flags;
+};
+
+struct wprobe_value {
+       bool pending;
+       union {
+               /*
+                * the following are kept uppercase to allow
+                * for automated checking against WPROBE_VAL_*
+                * via BUG_ON()
+                */
+               const char *STRING;
+               u8 U8;
+               u16 U16;
+               u32 U32;
+               u64 U64;
+               s8 S8;
+               s16 S16;
+               s32 S32;
+               s64 S64;
+       };
+       s64 s, ss;
+       unsigned int n;
+
+       /* timestamps */
+       u64 first, last;
+       u64 scale_timestamp;
+};
+
+struct wprobe_filter_item_hdr {
+       char name[32];
+       __be32 n_items;
+} __attribute__((packed));
+
+struct wprobe_filter_item {
+       struct wprobe_filter_item_hdr hdr;
+       struct sock_filter filter[];
+} __attribute__((packed));
+
+struct wprobe_filter_counter {
+       u64 tx;
+       u64 rx;
+};
+
+struct wprobe_filter_group {
+       const char *name;
+       int n_items;
+       struct wprobe_filter_item **items;
+       struct wprobe_filter_counter *counters;
+};
+
+struct wprobe_filter_hdr {
+       __u8 magic[4];
+       __u8 version;
+       __u8 hdrlen;
+       __u16 n_groups;
+} __attribute__((packed));
+
+struct wprobe_filter {
+       spinlock_t lock;
+       struct sk_buff *skb;
+       void *data;
+       int n_groups;
+       int hdrlen;
+       struct wprobe_filter_item **items;
+       struct wprobe_filter_counter *counters;
+       struct wprobe_filter_group groups[];
+};
+
+enum {
+       WPROBE_PKT_RX = 0x00,
+       WPROBE_PKT_TX = 0x10,
+};
+
+struct wprobe_wlan_hdr {
+       u16 len;
+       u8 snr;
+       u8 type;
+} __attribute__((packed));
+
+
+/**
+ * struct wprobe_source - data structure describing a wireless interface
+ *
+ * @name: name of the interface
+ * @addr: local mac address of the interface
+ * @links: list of wireless links to poll
+ * @link_items: description of the per-link data structure
+ * @n_link_items: number of link description items
+ * @global_items: description of the per-interface data structure
+ * @n_global_items: number of per-interface description items
+ * @sync_data: callback allowing the driver to prepare data for the wprobe poll
+ *
+ * @list: head for the list of interfaces
+ * @priv: user pointer
+ * @lock: spinlock protecting value data access
+ * @val: internal use
+ * @query_val: internal use
+ *
+ * if sync_data is NULL, wprobe assumes that it can access the data structure
+ * at any time (in atomic context). if sync_data returns a negative error code,
+ * the poll request will not be handled for the given link
+ */
+struct wprobe_iface {
+       /* to be filled in by wprobe source drivers */
+       const char *name;
+       const char *addr;
+       const struct wprobe_item *link_items;
+       int n_link_items;
+       const struct wprobe_item *global_items;
+       int n_global_items;
+
+       int (*sync_data)(struct wprobe_iface *dev, struct wprobe_link *l,
+                        struct wprobe_value *val, bool measure);
+       void *priv;
+
+       /* handled by the wprobe core */
+       struct list_head list;
+       struct list_head links;
+       spinlock_t lock;
+       struct wprobe_value *val;
+       struct wprobe_value *query_val;
+       struct wprobe_filter *active_filter;
+
+       u32 measure_interval;
+       struct timer_list measure_timer;
+
+       u32 scale_min;
+       u32 scale_max;
+       u32 scale_m;
+       u32 scale_d;
+};
+
+
+#define WPROBE_FILL_BEGIN(_ptr, _list) do {                    \
+       struct wprobe_value *__val = (_ptr);                    \
+       const struct wprobe_item *__item = _list;               \
+       u64 __msecs = jiffies_to_msecs(jiffies)
+
+#define WPROBE_SET(_idx, _type, _value)                                \
+       if (__item[_idx].type != WPROBE_VAL_##_type) {          \
+               printk("ERROR: invalid data type at %s:%d\n", __FILE__, __LINE__); \
+               break;                                          \
+       }                                                       \
+       __val[_idx].pending = true;                             \
+       __val[_idx]._type = _value;                             \
+       if (!__val[_idx].first)                                 \
+               __val[_idx].first = __msecs;                    \
+       __val[_idx].first = __msecs
+
+#define WPROBE_FILL_END()                                      \
+} while(0)
+
+/**
+ * wprobe_add_iface: register an interface with the wireless probe subsystem
+ * @dev: wprobe_iface structure describing the interface
+ */
+extern int __weak wprobe_add_iface(struct wprobe_iface *dev);
+
+/**
+ * wprobe_remove_iface: deregister an interface from the wireless probe subsystem
+ * @dev: wprobe_iface structure describing the interface
+ */
+extern void __weak wprobe_remove_iface(struct wprobe_iface *dev);
+
+/**
+ * wprobe_add_link: register a new wireless link
+ * @dev: wprobe_iface structure describing the interface
+ * @l: storage space for the wprobe_link structure
+ * @addr: mac address of the new link
+ *
+ * the entire wprobe_link structure is overwritten by this function call
+ */
+extern int __weak wprobe_add_link(struct wprobe_iface *dev, struct wprobe_link *l, const char *addr);
+
+/**
+ * wprobe_remove_link: deregister a previously registered wireless link
+ * @dev: wprobe_iface structure describing the interface
+ * @l: wprobe_link data structure
+ */
+extern void __weak wprobe_remove_link(struct wprobe_iface *dev, struct wprobe_link *l);
+
+/**
+ * wprobe_update_stats: update statistics after sampling values
+ * @dev: wprobe_iface structure describing the interface
+ * @l: wprobe_link data structure
+ *
+ * if l == NULL, then the stats for globals are updated
+ */
+extern void __weak wprobe_update_stats(struct wprobe_iface *dev, struct wprobe_link *l);
+
+/**
+ * wprobe_add_frame: add frame for layer 2 analysis
+ * @dev: wprobe_iface structure describing the interface
+ * @hdr: metadata for the frame
+ * @data: 802.11 header pointer
+ * @len: length of the 802.11 header
+ */
+extern int __weak wprobe_add_frame(struct wprobe_iface *dev, const struct wprobe_wlan_hdr *hdr, void *data, int len);
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/net/wprobe/src/kernel/wprobe-core.c b/net/wprobe/src/kernel/wprobe-core.c
new file mode 100644 (file)
index 0000000..6ec847a
--- /dev/null
@@ -0,0 +1,1164 @@
+/*
+ * wprobe-core.c: Wireless probe interface core
+ * Copyright (C) 2008-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#include <linux/rculist.h>
+#else
+#include <linux/list.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
+#include <linux/prefetch.h>
+#endif
+#include <linux/skbuff.h>
+#include <linux/wprobe.h>
+#include <linux/math64.h>
+
+#define static
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+#define list_for_each_rcu(pos, head) \
+for (pos = rcu_dereference((head)->next); \
+prefetch(pos->next), pos != (head); \
+pos = rcu_dereference(pos->next))
+#endif
+
+#define WPROBE_MIN_INTERVAL            100 /* minimum measurement interval in msecs */
+#define WPROBE_MAX_FILTER_SIZE 1024
+#define WPROBE_MAX_FRAME_SIZE  1900
+
+static struct list_head wprobe_if;
+static spinlock_t wprobe_lock;
+
+static struct genl_family wprobe_fam = {
+       .id = GENL_ID_GENERATE,
+       .name = "wprobe",
+       .hdrsize = 0,
+       .version = 1,
+       /* only the first set of attributes is used for queries */
+       .maxattr = WPROBE_ATTR_LAST,
+};
+
+/* fake radiotap header */
+struct wprobe_rtap_hdr {
+       __u8 version;
+       __u8 padding;
+       __le16 len;
+       __le32 present;
+};
+
+static void wprobe_update_stats(struct wprobe_iface *dev, struct wprobe_link *l);
+static int wprobe_sync_data(struct wprobe_iface *dev, struct wprobe_link *l, bool query);
+static void wprobe_free_filter(struct wprobe_filter *f);
+
+int
+wprobe_add_link(struct wprobe_iface *s, struct wprobe_link *l, const char *addr)
+{
+       unsigned long flags;
+
+       INIT_LIST_HEAD(&l->list);
+       l->val = kzalloc(sizeof(struct wprobe_value) * s->n_link_items, GFP_ATOMIC);
+       if (!l->val)
+               return -ENOMEM;
+
+       l->iface = s;
+       memcpy(&l->addr, addr, ETH_ALEN);
+       spin_lock_irqsave(&wprobe_lock, flags);
+       list_add_tail_rcu(&l->list, &s->links);
+       spin_unlock_irqrestore(&wprobe_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(wprobe_add_link);
+
+void
+wprobe_remove_link(struct wprobe_iface *s, struct wprobe_link *l)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&wprobe_lock, flags);
+       list_del_rcu(&l->list);
+       spin_unlock_irqrestore(&wprobe_lock, flags);
+       synchronize_rcu();
+       kfree(l->val);
+}
+EXPORT_SYMBOL(wprobe_remove_link);
+
+static void
+wprobe_measure_timer(unsigned long data)
+{
+       struct wprobe_iface *dev = (struct wprobe_iface *) data;
+
+       /* set next measurement interval */
+       mod_timer(&dev->measure_timer, jiffies +
+               msecs_to_jiffies(dev->measure_interval));
+
+       /* perform measurement */
+       wprobe_sync_data(dev, NULL, false);
+}
+
+int
+wprobe_add_iface(struct wprobe_iface *s)
+{
+       unsigned long flags;
+       int vsize;
+
+       /* reset only wprobe private area */
+       memset(&s->list, 0, sizeof(struct wprobe_iface) - offsetof(struct wprobe_iface, list));
+
+       BUG_ON(!s->name);
+       INIT_LIST_HEAD(&s->list);
+       INIT_LIST_HEAD(&s->links);
+       setup_timer(&s->measure_timer, wprobe_measure_timer, (unsigned long) s);
+
+       s->val = kzalloc(sizeof(struct wprobe_value) * s->n_global_items, GFP_ATOMIC);
+       if (!s->val)
+               goto error;
+
+       vsize = max(s->n_link_items, s->n_global_items);
+       s->query_val = kzalloc(sizeof(struct wprobe_value) * vsize, GFP_ATOMIC);
+       if (!s->query_val)
+               goto error;
+
+       /* initialize defaults to be able to handle overflow,
+        * user space will need to handle this if it keeps an
+        * internal histogram */
+       s->scale_min = 20;
+       s->scale_max = (1 << 31);
+
+       s->scale_m = 1;
+       s->scale_d = 10;
+
+       spin_lock_irqsave(&wprobe_lock, flags);
+       list_add_rcu(&s->list, &wprobe_if);
+       spin_unlock_irqrestore(&wprobe_lock, flags);
+
+       return 0;
+
+error:
+       if (s->val)
+               kfree(s->val);
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(wprobe_add_iface);
+
+void
+wprobe_remove_iface(struct wprobe_iface *s)
+{
+       unsigned long flags;
+
+       BUG_ON(!list_empty(&s->links));
+
+       del_timer_sync(&s->measure_timer);
+       spin_lock_irqsave(&wprobe_lock, flags);
+       list_del_rcu(&s->list);
+       spin_unlock_irqrestore(&wprobe_lock, flags);
+
+       /* wait for all queries to finish before freeing the
+        * temporary value storage buffer */
+       synchronize_rcu();
+
+       kfree(s->val);
+       kfree(s->query_val);
+       if (s->active_filter)
+               wprobe_free_filter(s->active_filter);
+}
+EXPORT_SYMBOL(wprobe_remove_iface);
+
+static struct wprobe_iface *
+wprobe_get_dev(struct nlattr *attr)
+{
+       struct wprobe_iface *dev = NULL;
+       struct wprobe_iface *p;
+       const char *name;
+       int i = 0;
+
+       if (!attr)
+               return NULL;
+
+       name = nla_data(attr);
+       list_for_each_entry_rcu(p, &wprobe_if, list) {
+               i++;
+               if (strcmp(name, p->name) != 0)
+                       continue;
+
+               dev = p;
+               break;
+       }
+
+       return dev;
+}
+
+int
+wprobe_add_frame(struct wprobe_iface *dev, const struct wprobe_wlan_hdr *hdr, void *data, int len)
+{
+       struct wprobe_wlan_hdr *new_hdr;
+       struct wprobe_filter *f;
+       struct sk_buff *skb;
+       unsigned long flags;
+       int i, j;
+
+       rcu_read_lock();
+       f = rcu_dereference(dev->active_filter);
+       if (!f)
+               goto out;
+
+       spin_lock_irqsave(&f->lock, flags);
+
+       skb = f->skb;
+       skb->len = sizeof(struct wprobe_rtap_hdr);
+       skb->tail = skb->data + skb->len;
+       if (len + skb->len > WPROBE_MAX_FRAME_SIZE)
+               len = WPROBE_MAX_FRAME_SIZE - skb->len;
+
+       new_hdr = (struct wprobe_wlan_hdr *) skb_put(skb, f->hdrlen);
+       memcpy(new_hdr, hdr, sizeof(struct wprobe_wlan_hdr));
+       new_hdr->len = cpu_to_be16(new_hdr->len);
+
+       memcpy(skb_put(skb, len), data, len);
+
+       for(i = 0; i < f->n_groups; i++) {
+               struct wprobe_filter_group *fg = &f->groups[i];
+               bool found = false;
+               int def = -1;
+
+               for (j = 0; j < fg->n_items; j++) {
+                       struct wprobe_filter_item *fi = fg->items[j];
+
+                       if (!fi->hdr.n_items) {
+                               def = j;
+                               continue;
+                       }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+                       if (sk_run_filter(skb, fi->filter) == 0)
+                               continue;
+#else
+                       if (sk_run_filter(skb, fi->filter, fi->hdr.n_items) == 0)
+                               continue;
+#endif
+
+                       found = true;
+                       break;
+               }
+               if (!found && def >= 0) {
+                       j = def;
+                       found = true;
+               }
+               if (found) {
+                       struct wprobe_filter_counter *c = &fg->counters[j];
+
+                       if (hdr->type >= WPROBE_PKT_TX)
+                               c->tx++;
+                       else
+                               c->rx++;
+               }
+       }
+
+       spin_unlock_irqrestore(&f->lock, flags);
+out:
+       rcu_read_unlock();
+       return 0;
+}
+EXPORT_SYMBOL(wprobe_add_frame);
+
+static int
+wprobe_sync_data(struct wprobe_iface *dev, struct wprobe_link *l, bool query)
+{
+       struct wprobe_value *val;
+       unsigned long flags;
+       int n, err;
+
+       if (l) {
+               n = dev->n_link_items;
+               val = l->val;
+       } else {
+               n = dev->n_global_items;
+               val = dev->val;
+       }
+
+       spin_lock_irqsave(&dev->lock, flags);
+       err = dev->sync_data(dev, l, val, !query);
+       if (err)
+               goto done;
+
+       if (query)
+               memcpy(dev->query_val, val, sizeof(struct wprobe_value) * n);
+
+       wprobe_update_stats(dev, l);
+done:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL(wprobe_sync_data);
+
+static void
+wprobe_scale_stats(struct wprobe_iface *dev, const struct wprobe_item *item,
+                   struct wprobe_value *val, int n)
+{
+       u64 scale_ts = jiffies_64;
+       int i;
+
+       for (i = 0; i < n; i++) {
+               if (!(item[i].flags & WPROBE_F_KEEPSTAT))
+                       continue;
+
+               if (val[i].n <= dev->scale_min)
+                       continue;
+
+               /* FIXME: div_s64 seems to be very imprecise here, even when
+                * the values are scaled up */
+               val[i].s *= dev->scale_m;
+               val[i].s = div_s64(val[i].s, dev->scale_d);
+
+               val[i].ss *= dev->scale_m;
+               val[i].ss = div_s64(val[i].ss, dev->scale_d);
+
+               val[i].n = (val[i].n * dev->scale_m) / dev->scale_d;
+               val[i].scale_timestamp = scale_ts;
+       }
+}
+
+
+void
+wprobe_update_stats(struct wprobe_iface *dev, struct wprobe_link *l)
+{
+       const struct wprobe_item *item;
+       struct wprobe_value *val;
+       bool scale_stats = false;
+       int i, n;
+
+       if (l) {
+               n = dev->n_link_items;
+               item = dev->link_items;
+               val = l->val;
+       } else {
+               n = dev->n_global_items;
+               item = dev->global_items;
+               val = dev->val;
+       }
+
+       /* process statistics */
+       for (i = 0; i < n; i++) {
+               s64 v;
+
+               if (!val[i].pending)
+                       continue;
+
+               val[i].n++;
+               if ((item[i].flags & WPROBE_F_KEEPSTAT) &&
+                       (dev->scale_max > 0) && (val[i].n > dev->scale_max)) {
+                       scale_stats = true;
+               }
+
+               switch(item[i].type) {
+               case WPROBE_VAL_S8:
+                       v = val[i].S8;
+                       break;
+               case WPROBE_VAL_S16:
+                       v = val[i].S16;
+                       break;
+               case WPROBE_VAL_S32:
+                       v = val[i].S32;
+                       break;
+               case WPROBE_VAL_S64:
+                       v = val[i].S64;
+                       break;
+               case WPROBE_VAL_U8:
+                       v = val[i].U8;
+                       break;
+               case WPROBE_VAL_U16:
+                       v = val[i].U16;
+                       break;
+               case WPROBE_VAL_U32:
+                       v = val[i].U32;
+                       break;
+               case WPROBE_VAL_U64:
+                       v = val[i].U64;
+                       break;
+               default:
+                       continue;
+               }
+
+               val[i].s += v;
+               val[i].ss += v * v;
+               val[i].pending = false;
+       }
+       if (scale_stats)
+               wprobe_scale_stats(dev, item, val, n);
+}
+EXPORT_SYMBOL(wprobe_update_stats);
+
+static const struct nla_policy wprobe_policy[WPROBE_ATTR_LAST+1] = {
+       [WPROBE_ATTR_INTERFACE] = { .type = NLA_NUL_STRING },
+       [WPROBE_ATTR_MAC] = { .type = NLA_STRING },
+       [WPROBE_ATTR_FLAGS] = { .type = NLA_U32 },
+
+       /* config */
+       [WPROBE_ATTR_INTERVAL] = { .type = NLA_MSECS },
+       [WPROBE_ATTR_SAMPLES_MIN] = { .type = NLA_U32 },
+       [WPROBE_ATTR_SAMPLES_MAX] = { .type = NLA_U32 },
+       [WPROBE_ATTR_SAMPLES_SCALE_M] = { .type = NLA_U32 },
+       [WPROBE_ATTR_SAMPLES_SCALE_D] = { .type = NLA_U32 },
+       [WPROBE_ATTR_FILTER] = { .type = NLA_BINARY, .len = 32768 },
+};
+
+static bool
+wprobe_check_ptr(struct list_head *list, struct list_head *ptr)
+{
+       struct list_head *p;
+
+       list_for_each_rcu(p, list) {
+               if (ptr == p)
+                       return true;
+       }
+       return false;
+}
+
+static bool
+wprobe_send_item_value(struct sk_buff *msg, struct netlink_callback *cb,
+                       struct wprobe_iface *dev, struct wprobe_link *l,
+                       const struct wprobe_item *item,
+                       int i, u32 flags)
+{
+       struct genlmsghdr *hdr;
+       struct wprobe_value *val = dev->query_val;
+       u64 time = val[i].last - val[i].first;
+
+       hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+                       &wprobe_fam, NLM_F_MULTI, WPROBE_CMD_GET_INFO);
+
+       NLA_PUT_U32(msg, WPROBE_ATTR_ID, i);
+       NLA_PUT_U32(msg, WPROBE_ATTR_FLAGS, flags);
+       NLA_PUT_U8(msg, WPROBE_ATTR_TYPE, item[i].type);
+       NLA_PUT_U64(msg, WPROBE_ATTR_DURATION, time);
+
+       switch(item[i].type) {
+       case WPROBE_VAL_S8:
+       case WPROBE_VAL_U8:
+               NLA_PUT_U8(msg, item[i].type, val[i].U8);
+               break;
+       case WPROBE_VAL_S16:
+       case WPROBE_VAL_U16:
+               NLA_PUT_U16(msg, item[i].type, val[i].U16);
+               break;
+       case WPROBE_VAL_S32:
+       case WPROBE_VAL_U32:
+               NLA_PUT_U32(msg, item[i].type, val[i].U32);
+               break;
+       case WPROBE_VAL_S64:
+       case WPROBE_VAL_U64:
+               NLA_PUT_U64(msg, item[i].type, val[i].U64);
+               break;
+       case WPROBE_VAL_STRING:
+               if (val[i].STRING)
+                       NLA_PUT_STRING(msg, item[i].type, val[i].STRING);
+               else
+                       NLA_PUT_STRING(msg, item[i].type, "");
+               /* bypass avg/stdev */
+               goto done;
+       default:
+               /* skip unknown values */
+               goto done;
+       }
+       if (item[i].flags & WPROBE_F_KEEPSTAT) {
+               NLA_PUT_U64(msg, WPROBE_VAL_SUM, val[i].s);
+               NLA_PUT_U64(msg, WPROBE_VAL_SUM_SQ, val[i].ss);
+               NLA_PUT_U32(msg, WPROBE_VAL_SAMPLES, (u32) val[i].n);
+               NLA_PUT_MSECS(msg, WPROBE_VAL_SCALE_TIME, val[i].scale_timestamp);
+       }
+done:
+       genlmsg_end(msg, hdr);
+       return true;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return false;
+}
+
+static bool
+wprobe_send_item_info(struct sk_buff *msg, struct netlink_callback *cb,
+                       struct wprobe_iface *dev,
+                       const struct wprobe_item *item, int i)
+{
+       struct genlmsghdr *hdr;
+
+       hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+                       &wprobe_fam, NLM_F_MULTI, WPROBE_CMD_GET_LIST);
+
+       if ((i == 0) && (dev->addr != NULL))
+               NLA_PUT(msg, WPROBE_ATTR_MAC, 6, dev->addr);
+       NLA_PUT_U32(msg, WPROBE_ATTR_ID, (u32) i);
+       NLA_PUT_STRING(msg, WPROBE_ATTR_NAME, item[i].name);
+       NLA_PUT_U8(msg, WPROBE_ATTR_TYPE, item[i].type);
+       NLA_PUT_U32(msg, WPROBE_ATTR_FLAGS, item[i].flags);
+       genlmsg_end(msg, hdr);
+       return true;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return false;
+}
+
+
+static struct wprobe_link *
+wprobe_find_link(struct wprobe_iface *dev, const char *mac)
+{
+       struct wprobe_link *l;
+
+       list_for_each_entry_rcu(l, &dev->links, list) {
+               if (!memcmp(l->addr, mac, 6))
+                       return l;
+       }
+       return NULL;
+}
+
+static bool
+wprobe_dump_filter_group(struct sk_buff *msg, struct wprobe_filter_group *fg, struct netlink_callback *cb)
+{
+       struct genlmsghdr *hdr;
+       struct nlattr *group, *item;
+       int i;
+
+       hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+                       &wprobe_fam, NLM_F_MULTI, WPROBE_CMD_GET_FILTER);
+       if (!hdr)
+               return false;
+
+       NLA_PUT_STRING(msg, WPROBE_ATTR_NAME, fg->name);
+       group = nla_nest_start(msg, WPROBE_ATTR_FILTER_GROUP);
+       for (i = 0; i < fg->n_items; i++) {
+               struct wprobe_filter_item *fi = fg->items[i];
+               struct wprobe_filter_counter *fc = &fg->counters[i];
+
+               item = nla_nest_start(msg, WPROBE_ATTR_FILTER_GROUP);
+               NLA_PUT_STRING(msg, WPROBE_ATTR_NAME, fi->hdr.name);
+               NLA_PUT_U64(msg, WPROBE_ATTR_RXCOUNT, fc->rx);
+               NLA_PUT_U64(msg, WPROBE_ATTR_TXCOUNT, fc->tx);
+               nla_nest_end(msg, item);
+       }
+
+       nla_nest_end(msg, group);
+       genlmsg_end(msg, hdr);
+       return true;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return false;
+}
+
+static int
+wprobe_dump_filters(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct wprobe_iface *dev = (struct wprobe_iface *)cb->args[0];
+       struct wprobe_filter *f;
+       int err = 0;
+       int i = 0;
+
+       if (!dev) {
+               err = nlmsg_parse(cb->nlh, GENL_HDRLEN + wprobe_fam.hdrsize,
+                               wprobe_fam.attrbuf, wprobe_fam.maxattr, wprobe_policy);
+               if (err)
+                       goto done;
+
+               dev = wprobe_get_dev(wprobe_fam.attrbuf[WPROBE_ATTR_INTERFACE]);
+               if (!dev) {
+                       err = -ENODEV;
+                       goto done;
+               }
+
+               cb->args[0] = (long) dev;
+               cb->args[1] = 0;
+       } else {
+               if (!wprobe_check_ptr(&wprobe_if, &dev->list)) {
+                       err = -ENODEV;
+                       goto done;
+               }
+       }
+
+       rcu_read_lock();
+       f = rcu_dereference(dev->active_filter);
+       if (!f)
+               goto abort;
+
+       for (i = cb->args[1]; i < f->n_groups; i++) {
+               if (unlikely(!wprobe_dump_filter_group(skb, &f->groups[i], cb)))
+                       break;
+       }
+       cb->args[1] = i;
+abort:
+       rcu_read_unlock();
+       err = skb->len;
+done:
+       return err;
+}
+
+static bool
+wprobe_dump_link(struct sk_buff *msg, struct wprobe_link *l, struct netlink_callback *cb)
+{
+       struct genlmsghdr *hdr;
+
+       hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+                       &wprobe_fam, NLM_F_MULTI, WPROBE_CMD_GET_LINKS);
+       if (!hdr)
+               return false;
+
+       NLA_PUT(msg, WPROBE_ATTR_MAC, 6, l->addr);
+       genlmsg_end(msg, hdr);
+       return true;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return false;
+}
+
+static int
+wprobe_dump_links(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct wprobe_iface *dev = (struct wprobe_iface *)cb->args[0];
+       struct wprobe_link *l;
+       int err = 0;
+       int i = 0;
+
+       if (!dev) {
+               err = nlmsg_parse(cb->nlh, GENL_HDRLEN + wprobe_fam.hdrsize,
+                               wprobe_fam.attrbuf, wprobe_fam.maxattr, wprobe_policy);
+               if (err)
+                       goto done;
+
+               dev = wprobe_get_dev(wprobe_fam.attrbuf[WPROBE_ATTR_INTERFACE]);
+               if (!dev) {
+                       err = -ENODEV;
+                       goto done;
+               }
+
+               cb->args[0] = (long) dev;
+       } else {
+               if (!wprobe_check_ptr(&wprobe_if, &dev->list)) {
+                       err = -ENODEV;
+                       goto done;
+               }
+       }
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(l, &dev->links, list) {
+               if (i < cb->args[1])
+                       continue;
+
+               if (unlikely(!wprobe_dump_link(skb, l, cb)))
+                       break;
+
+               i++;
+       }
+       cb->args[1] = i;
+       rcu_read_unlock();
+       err = skb->len;
+done:
+       return err;
+}
+
+#define WPROBE_F_LINK (1 << 31) /* for internal use */
+static int
+wprobe_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct wprobe_iface *dev = (struct wprobe_iface *)cb->args[0];
+       struct wprobe_link *l = (struct wprobe_link *)cb->args[1];
+       struct wprobe_value *val;
+       const struct wprobe_item *item;
+       struct genlmsghdr *hdr;
+       unsigned long flags;
+       int cmd, n, i = cb->args[3];
+       u32     vflags = cb->args[2];
+       int err = 0;
+
+       hdr = (struct genlmsghdr *)nlmsg_data(cb->nlh);
+       cmd = hdr->cmd;
+
+       /* since the attribute value list might be too big for a single netlink
+        * message, the device, link and offset get stored in the netlink callback.
+        * if this is the first request, we need to do the full lookup for the device.
+        *
+        * access to the device and link structure is synchronized through rcu.
+        */
+       rcu_read_lock();
+       if (!dev) {
+               err = nlmsg_parse(cb->nlh, GENL_HDRLEN + wprobe_fam.hdrsize,
+                               wprobe_fam.attrbuf, wprobe_fam.maxattr, wprobe_policy);
+               if (err)
+                       goto done;
+
+               err = -ENOENT;
+               dev = wprobe_get_dev(wprobe_fam.attrbuf[WPROBE_ATTR_INTERFACE]);
+               if (!dev)
+                       goto done;
+
+               if (cmd == WPROBE_CMD_GET_INFO) {
+                       if (wprobe_fam.attrbuf[WPROBE_ATTR_MAC]) {
+                               l = wprobe_find_link(dev, nla_data(wprobe_fam.attrbuf[WPROBE_ATTR_MAC]));
+                               if (!l)
+                                       goto done;
+
+                               vflags = l->flags;
+                       }
+
+                       if (l) {
+                               item = dev->link_items;
+                               n = dev->n_link_items;
+                               val = l->val;
+                       } else {
+                               item = dev->global_items;
+                               n = dev->n_global_items;
+                               val = dev->val;
+                       }
+
+                       /* sync data and move to temp storage for the query */
+                       spin_lock_irqsave(&dev->lock, flags);
+                       err = wprobe_sync_data(dev, l, true);
+                       if (!err)
+                               memcpy(dev->query_val, val, n * sizeof(struct wprobe_value));
+                       spin_unlock_irqrestore(&dev->lock, flags);
+
+                       if (err)
+                               goto done;
+               }
+
+               if (wprobe_fam.attrbuf[WPROBE_ATTR_FLAGS])
+                       vflags |= nla_get_u32(wprobe_fam.attrbuf[WPROBE_ATTR_FLAGS]);
+
+               if (wprobe_fam.attrbuf[WPROBE_ATTR_MAC])
+                       vflags |= WPROBE_F_LINK;
+
+               cb->args[0] = (long) dev;
+               cb->args[1] = (long) l;
+               cb->args[2] = vflags;
+               cb->args[3] = 0;
+       } else {
+               /* when pulling pointers from the callback, validate them
+                * against the list using rcu to make sure that we won't
+                * dereference pointers to free'd memory after the last
+                * grace period */
+               err = -ENOENT;
+               if (!wprobe_check_ptr(&wprobe_if, &dev->list))
+                       goto done;
+
+               if (l && !wprobe_check_ptr(&dev->links, &l->list))
+                       goto done;
+       }
+
+       if (vflags & WPROBE_F_LINK) {
+               item = dev->link_items;
+               n = dev->n_link_items;
+       } else {
+               item = dev->global_items;
+               n = dev->n_global_items;
+       }
+
+       err = 0;
+       switch(cmd) {
+       case WPROBE_CMD_GET_INFO:
+               while (i < n) {
+                       if (!wprobe_send_item_value(skb, cb, dev, l, item, i, vflags))
+                               break;
+                       i++;
+               }
+               break;
+       case WPROBE_CMD_GET_LIST:
+               while (i < n) {
+                       if (!wprobe_send_item_info(skb, cb, dev, item, i))
+                               break;
+                       i++;
+               }
+               break;
+       default:
+               err = -EINVAL;
+               goto done;
+       }
+       cb->args[3] = i;
+       err = skb->len;
+
+done:
+       rcu_read_unlock();
+       return err;
+}
+#undef WPROBE_F_LINK
+
+static int
+wprobe_update_auto_measurement(struct wprobe_iface *dev, u32 interval)
+{
+       if (interval && (interval < WPROBE_MIN_INTERVAL))
+               return -EINVAL;
+
+       if (!interval && dev->measure_interval)
+               del_timer_sync(&dev->measure_timer);
+
+       dev->measure_interval = interval;
+       if (!interval)
+               return 0;
+
+       /* kick of a new measurement immediately */
+       mod_timer(&dev->measure_timer, jiffies + 1);
+
+       return 0;
+}
+
+static int
+wprobe_measure(struct sk_buff *skb, struct genl_info *info)
+{
+       struct wprobe_iface *dev;
+       struct wprobe_link *l = NULL;
+       int err = -ENOENT;
+
+       rcu_read_lock();
+       dev = wprobe_get_dev(info->attrs[WPROBE_ATTR_INTERFACE]);
+       if (!dev)
+               goto done;
+
+       if (info->attrs[WPROBE_ATTR_MAC]) {
+               l = wprobe_find_link(dev, nla_data(wprobe_fam.attrbuf[WPROBE_ATTR_MAC]));
+               if (!l)
+                       goto done;
+       }
+
+       err = wprobe_sync_data(dev, l, false);
+
+done:
+       rcu_read_unlock();
+       return err;
+}
+
+static int
+wprobe_check_filter(void *data, int datalen, int gs)
+{
+       struct wprobe_filter_item_hdr *hdr;
+       void *orig_data = data;
+       void *end = data + datalen;
+       int i, j, k, is, cur_is;
+
+       for (i = j = is = 0; i < gs; i++) {
+               hdr = data;
+               data += sizeof(*hdr);
+
+               if (data > end)
+                       goto overrun;
+
+               hdr->name[31] = 0;
+               cur_is = be32_to_cpu(hdr->n_items);
+               hdr->n_items = cur_is;
+               is += cur_is;
+               for (j = 0; j < cur_is; j++) {
+                       struct sock_filter *sf;
+                       int n_items;
+
+                       hdr = data;
+                       data += sizeof(*hdr);
+                       if (data > end)
+                               goto overrun;
+
+                       hdr->name[31] = 0;
+                       n_items = be32_to_cpu(hdr->n_items);
+                       hdr->n_items = n_items;
+
+                       if (n_items > 1024)
+                               goto overrun;
+
+                       sf = data;
+                       if (n_items > 0) {
+                               for (k = 0; k < n_items; k++) {
+                                       sf->code = be16_to_cpu(sf->code);
+                                       sf->k = be32_to_cpu(sf->k);
+                                       sf++;
+                               }
+                               if (sk_chk_filter(data, n_items) != 0) {
+                                       printk("%s: filter check failed at group %d, item %d\n", __func__, i, j);
+                                       return 0;
+                               }
+                       }
+                       data += n_items * sizeof(struct sock_filter);
+               }
+       }
+       return is;
+
+overrun:
+       printk(KERN_ERR "%s: overrun during filter check at group %d, item %d, offset=%d, len=%d\n", __func__, i, j, (data - orig_data), datalen);
+       return 0;
+}
+
+static void
+wprobe_free_filter(struct wprobe_filter *f)
+{
+       if (f->skb)
+               kfree_skb(f->skb);
+       if (f->data)
+               kfree(f->data);
+       if (f->items)
+               kfree(f->items);
+       if (f->counters)
+               kfree(f->counters);
+       kfree(f);
+}
+
+
+static int
+wprobe_set_filter(struct wprobe_iface *dev, void *data, int len)
+{
+       struct wprobe_filter_hdr *fhdr;
+       struct wprobe_rtap_hdr *rtap;
+       struct wprobe_filter *f;
+       int i, j, cur_is, is, gs;
+
+       if (len < sizeof(*fhdr))
+               return -EINVAL;
+
+       fhdr = data;
+       data += sizeof(*fhdr);
+       len -= sizeof(*fhdr);
+
+       if (memcmp(fhdr->magic, "WPFF", 4) != 0) {
+               printk(KERN_ERR "%s: filter rejected (invalid magic)\n", __func__);
+               return -EINVAL;
+       }
+
+       gs = be16_to_cpu(fhdr->n_groups);
+       is = wprobe_check_filter(data, len, gs);
+       if (is == 0)
+               return -EINVAL;
+
+       f = kzalloc(sizeof(struct wprobe_filter) +
+               gs * sizeof(struct wprobe_filter_group), GFP_ATOMIC);
+       if (!f)
+               return -ENOMEM;
+
+       f->skb = alloc_skb(WPROBE_MAX_FRAME_SIZE, GFP_ATOMIC);
+       if (!f->skb)
+               goto error;
+
+       f->data = kmalloc(len, GFP_ATOMIC);
+       if (!f->data)
+               goto error;
+
+       f->items = kzalloc(sizeof(struct wprobe_filter_item *) * is, GFP_ATOMIC);
+       if (!f->items)
+               goto error;
+
+       f->counters = kzalloc(sizeof(struct wprobe_filter_counter) * is, GFP_ATOMIC);
+       if (!f->counters)
+               goto error;
+
+       spin_lock_init(&f->lock);
+       memcpy(f->data, data, len);
+       f->n_groups = gs;
+
+       if (f->hdrlen < sizeof(struct wprobe_wlan_hdr))
+               f->hdrlen = sizeof(struct wprobe_wlan_hdr);
+
+       rtap = (struct wprobe_rtap_hdr *)skb_put(f->skb, sizeof(*rtap));
+       memset(rtap, 0, sizeof(*rtap));
+       rtap->len = cpu_to_le16(sizeof(struct wprobe_rtap_hdr) + f->hdrlen);
+       data = f->data;
+
+       cur_is = 0;
+       for (i = 0; i < gs; i++) {
+               struct wprobe_filter_item_hdr *hdr = data;
+               struct wprobe_filter_group *g = &f->groups[i];
+
+               data += sizeof(*hdr);
+               g->name = hdr->name;
+               g->items = &f->items[cur_is];
+               g->counters = &f->counters[cur_is];
+               g->n_items = hdr->n_items;
+
+               for (j = 0; j < g->n_items; j++) {
+                       hdr = data;
+                       f->items[cur_is++] = data;
+                       data += sizeof(*hdr) + hdr->n_items * sizeof(struct sock_filter);
+               }
+       }
+       rcu_assign_pointer(dev->active_filter, f);
+       return 0;
+
+error:
+       wprobe_free_filter(f);
+       return -ENOMEM;
+}
+
+static int
+wprobe_set_config(struct sk_buff *skb, struct genl_info *info)
+{
+       struct wprobe_iface *dev;
+       unsigned long flags;
+       int err = -ENOENT;
+       u32 scale_min, scale_max;
+       u32 scale_m, scale_d;
+       struct nlattr *attr;
+       struct wprobe_filter *filter_free = NULL;
+
+       rcu_read_lock();
+       dev = wprobe_get_dev(info->attrs[WPROBE_ATTR_INTERFACE]);
+       if (!dev)
+               goto done_unlocked;
+
+       err = -EINVAL;
+       spin_lock_irqsave(&dev->lock, flags);
+       if (info->attrs[WPROBE_ATTR_MAC]) {
+               /* not supported yet */
+               goto done;
+       }
+
+       if (info->attrs[WPROBE_ATTR_FLAGS]) {
+               u32 flags = nla_get_u32(info->attrs[WPROBE_ATTR_FLAGS]);
+
+               if (flags & BIT(WPROBE_F_RESET)) {
+                       struct wprobe_link *l;
+
+                       memset(dev->val, 0, sizeof(struct wprobe_value) * dev->n_global_items);
+                       list_for_each_entry_rcu(l, &dev->links, list) {
+                               memset(l->val, 0, sizeof(struct wprobe_value) * dev->n_link_items);
+                       }
+               }
+       }
+
+       if (info->attrs[WPROBE_ATTR_SAMPLES_MIN] ||
+               info->attrs[WPROBE_ATTR_SAMPLES_MAX]) {
+               if ((attr = info->attrs[WPROBE_ATTR_SAMPLES_MIN]))
+                       scale_min = nla_get_u32(attr);
+               else
+                       scale_min = dev->scale_min;
+
+               if ((attr = info->attrs[WPROBE_ATTR_SAMPLES_MAX]))
+                       scale_max = nla_get_u32(attr);
+               else
+                       scale_max = dev->scale_max;
+
+               if ((!scale_min && !scale_max) ||
+                   (scale_min && scale_max && (scale_min < scale_max))) {
+                       dev->scale_min = scale_min;
+                       dev->scale_max = scale_max;
+               } else {
+                       goto done;
+               }
+       }
+
+       if (info->attrs[WPROBE_ATTR_SAMPLES_SCALE_M] &&
+               info->attrs[WPROBE_ATTR_SAMPLES_SCALE_D]) {
+
+               scale_m = nla_get_u32(info->attrs[WPROBE_ATTR_SAMPLES_SCALE_M]);
+               scale_d = nla_get_u32(info->attrs[WPROBE_ATTR_SAMPLES_SCALE_D]);
+
+               if (!scale_d || (scale_m > scale_d))
+                       goto done;
+
+               dev->scale_m = scale_m;
+               dev->scale_d = scale_d;
+       }
+
+       if ((attr = info->attrs[WPROBE_ATTR_FILTER])) {
+               filter_free = rcu_dereference(dev->active_filter);
+               rcu_assign_pointer(dev->active_filter, NULL);
+               if (nla_len(attr) > 0)
+                       wprobe_set_filter(dev, nla_data(attr), nla_len(attr));
+       }
+
+       err = 0;
+       if (info->attrs[WPROBE_ATTR_INTERVAL]) {
+               /* change of measurement interval requested */
+               err = wprobe_update_auto_measurement(dev,
+                       (u32) nla_get_u64(info->attrs[WPROBE_ATTR_INTERVAL]));
+       }
+
+done:
+       spin_unlock_irqrestore(&dev->lock, flags);
+done_unlocked:
+       rcu_read_unlock();
+       if (filter_free) {
+               synchronize_rcu();
+               wprobe_free_filter(filter_free);
+       }
+       return err;
+}
+
+static struct genl_ops wprobe_ops[] = {
+       {
+               .cmd = WPROBE_CMD_GET_INFO,
+               .dumpit = wprobe_dump_info,
+               .policy = wprobe_policy,
+       },
+       {
+               .cmd = WPROBE_CMD_GET_LIST,
+               .dumpit = wprobe_dump_info,
+               .policy = wprobe_policy,
+       },
+       {
+               .cmd = WPROBE_CMD_MEASURE,
+               .doit = wprobe_measure,
+               .policy = wprobe_policy,
+       },
+       {
+               .cmd = WPROBE_CMD_GET_LINKS,
+               .dumpit = wprobe_dump_links,
+               .policy = wprobe_policy,
+       },
+       {
+               .cmd = WPROBE_CMD_CONFIG,
+               .doit = wprobe_set_config,
+               .policy = wprobe_policy,
+       },
+       {
+               .cmd = WPROBE_CMD_GET_FILTER,
+               .dumpit = wprobe_dump_filters,
+               .policy = wprobe_policy,
+       },
+};
+
+static void __exit
+wprobe_exit(void)
+{
+       BUG_ON(!list_empty(&wprobe_if));
+       genl_unregister_family(&wprobe_fam);
+}
+
+
+static int __init
+wprobe_init(void)
+{
+       int i, err;
+
+       spin_lock_init(&wprobe_lock);
+       INIT_LIST_HEAD(&wprobe_if);
+
+       err = genl_register_family(&wprobe_fam);
+       if (err)
+               return err;
+
+       for (i = 0; i < ARRAY_SIZE(wprobe_ops); i++) {
+               err = genl_register_ops(&wprobe_fam, &wprobe_ops[i]);
+               if (err)
+                       goto error;
+       }
+
+       return 0;
+
+error:
+       genl_unregister_family(&wprobe_fam);
+       return err;
+}
+
+module_init(wprobe_init);
+module_exit(wprobe_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/net/wprobe/src/kernel/wprobe-dummy.c b/net/wprobe/src/kernel/wprobe-dummy.c
new file mode 100644 (file)
index 0000000..4231223
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * wprobe-core.c: Wireless probe interface dummy driver
+ * Copyright (C) 2008-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/wprobe.h>
+
+static const char local_addr[] = "\x00\x13\x37\xba\xbe\x00";
+
+enum dummy_global_values {
+       DUMMY_GLOBAL_MEDIUM_BUSY
+};
+enum dummy_link_values {
+       DUMMY_LINK_SNR
+};
+
+struct wprobe_item dummy_perlink[] = {
+       [DUMMY_LINK_SNR] = {
+               .name = "snr",
+               .type = WPROBE_VAL_U8,
+               .flags = WPROBE_F_KEEPSTAT,
+       },
+};
+
+struct wprobe_item dummy_globals[] = {
+       [DUMMY_GLOBAL_MEDIUM_BUSY] = {
+               .name = "medium_busy",
+               .type = WPROBE_VAL_U8,
+               .flags = WPROBE_F_KEEPSTAT,
+       }
+};
+
+int dummy_sync(struct wprobe_iface *dev, struct wprobe_link *l, struct wprobe_value *val, bool measure)
+{
+       u8 intval = 0;
+
+       get_random_bytes(&intval, 1);
+       if (l) {
+               WPROBE_FILL_BEGIN(val, dummy_perlink);
+               WPROBE_SET(DUMMY_LINK_SNR, U8, (intval % 40));
+               WPROBE_FILL_END();
+       } else {
+               WPROBE_FILL_BEGIN(val, dummy_globals);
+               WPROBE_SET(DUMMY_GLOBAL_MEDIUM_BUSY, U8, (intval % 100));
+               WPROBE_FILL_END();
+       }
+       return 0;
+}
+
+static struct wprobe_iface dummy_dev = {
+       .name = "dummy",
+       .addr = local_addr,
+       .link_items = dummy_perlink,
+       .n_link_items = ARRAY_SIZE(dummy_perlink),
+       .global_items = dummy_globals,
+       .n_global_items = ARRAY_SIZE(dummy_globals),
+       .sync_data = dummy_sync,
+};
+
+static struct wprobe_link dummy_link;
+
+static int __init
+wprobe_dummy_init(void)
+{
+       wprobe_add_iface(&dummy_dev);
+       wprobe_add_link(&dummy_dev, &dummy_link, "\x00\x13\x37\xda\xda\x00");
+       return 0;
+}
+
+static void __exit
+wprobe_dummy_exit(void)
+{
+       wprobe_remove_link(&dummy_dev, &dummy_link);
+       wprobe_remove_iface(&dummy_dev);
+}
+
+module_init(wprobe_dummy_init);
+module_exit(wprobe_dummy_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/net/wprobe/src/user/Makefile b/net/wprobe/src/user/Makefile
new file mode 100644 (file)
index 0000000..01e83da
--- /dev/null
@@ -0,0 +1,38 @@
+include ../Makefile.inc
+
+CPPFLAGS += -I../kernel
+LDFLAGS =
+
+ifneq ($(HOST_OS),Linux)
+USE_LIBNL_MICRO=1
+else
+USE_LIBNL_MICRO=
+endif
+
+ifeq ($(USE_LIBNL_MICRO),1)
+LIBNL_PREFIX = /usr/local
+LIBNL = $(LIBNL_PREFIX)/lib/libnl-micro.a
+CPPFLAGS += -I$(LIBNL_PREFIX)/include/libnl-micro
+EXTRA_CFLAGS += -DNO_LOCAL_ACCESS
+else
+LIBNL = -lnl
+endif
+
+LIBM = -lm
+LIBS = $(LIBNL) $(LIBM)
+
+all: libwprobe.a wprobe-util
+
+libwprobe.a: wprobe-lib.o
+       rm -f $@
+       $(AR) rcu $@ $^
+       $(RANLIB) $@
+
+%.o: %.c
+       $(CC) $(WFLAGS) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) $<
+
+wprobe-util: wprobe-util.o wprobe-lib.o
+       $(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
+
+clean:
+       rm -f *.o *.a wprobe-util
diff --git a/net/wprobe/src/user/list.h b/net/wprobe/src/user/list.h
new file mode 100644 (file)
index 0000000..2959a06
--- /dev/null
@@ -0,0 +1,601 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:       the pointer to the member.
+ * @type:      the type of the container struct this is embedded in.
+ * @member:    the name of the member within the struct.
+ *
+ */
+#ifndef container_of
+#define container_of(ptr, type, member) (                      \
+       (type *)( (char *)ptr - offsetof(type,member) ))
+#endif
+
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+       struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+       list->next = list;
+       list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+                             struct list_head *prev,
+                             struct list_head *next)
+{
+       next->prev = new;
+       new->next = next;
+       new->prev = prev;
+       prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head->prev, head);
+}
+
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+       next->prev = prev;
+       prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       entry->next = NULL;
+       entry->prev = NULL;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+                               struct list_head *new)
+{
+       new->next = old->next;
+       new->next->prev = new;
+       new->prev = old->prev;
+       new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+                                       struct list_head *new)
+{
+       list_replace(old, new);
+       INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+       __list_del(list->prev, list->next);
+       list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+                                 struct list_head *head)
+{
+       __list_del(list->prev, list->next);
+       list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+                               const struct list_head *head)
+{
+       return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+       return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+       struct list_head *next = head->next;
+       return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+                                struct list_head *head)
+{
+       struct list_head *first = list->next;
+       struct list_head *last = list->prev;
+       struct list_head *at = head->next;
+
+       first->prev = head;
+       head->next = first;
+
+       last->next = at;
+       at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+       if (!list_empty(list))
+               __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+                                   struct list_head *head)
+{
+       if (!list_empty(list)) {
+               __list_splice(list, head);
+               INIT_LIST_HEAD(list);
+       }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:       the &struct list_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+       container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr:       the list head to take the element from.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+       list_entry((ptr)->next, type, member)
+
+/**
+ * list_for_each       -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop cursor.
+ * @head:      the head for your list.
+ */
+#define list_for_each(pos, head) \
+       for (pos = (head)->next; pos != (head); \
+               pos = pos->next)
+
+/**
+ * __list_for_each     -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop cursor.
+ * @head:      the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+       for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev  -       iterate over a list backwards
+ * @pos:       the &struct list_head to use as a loop cursor.
+ * @head:      the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+       for (pos = (head)->prev; pos != (head); \
+               pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:       the &struct list_head to use as a loop cursor.
+ * @n:         another &struct list_head to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+       for (pos = (head)->next, n = pos->next; pos != (head); \
+               pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos:       the &struct list_head to use as a loop cursor.
+ * @n:         another &struct list_head to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+       for (pos = (head)->prev, n = pos->prev; \
+            pos != (head); \
+            pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry -       iterate over list of given type
+ * @pos:       the type * to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)                         \
+       for (pos = list_entry((head)->next, typeof(*pos), member);      \
+            &pos->member != (head);    \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:       the type * to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)                 \
+       for (pos = list_entry((head)->prev, typeof(*pos), member);      \
+            &pos->member != (head);    \
+            pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos:       the type * to use as a start point
+ * @head:      the head of the list
+ * @member:    the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+       ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:       the type * to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member)                \
+       for (pos = list_entry(pos->member.next, typeof(*pos), member);  \
+            &pos->member != (head);    \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos:       the type * to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member)                \
+       for (pos = list_entry(pos->member.prev, typeof(*pos), member);  \
+            &pos->member != (head);    \
+            pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:       the type * to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member)                    \
+       for (; &pos->member != (head);  \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:       the type * to use as a loop cursor.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)                 \
+       for (pos = list_entry((head)->next, typeof(*pos), member),      \
+               n = list_entry(pos->member.next, typeof(*pos), member); \
+            &pos->member != (head);                                    \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos:       the type * to use as a loop cursor.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member)                \
+       for (pos = list_entry(pos->member.next, typeof(*pos), member),          \
+               n = list_entry(pos->member.next, typeof(*pos), member);         \
+            &pos->member != (head);                                            \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos:       the type * to use as a loop cursor.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member)                    \
+       for (n = list_entry(pos->member.next, typeof(*pos), member);            \
+            &pos->member != (head);                                            \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos:       the type * to use as a loop cursor.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member)         \
+       for (pos = list_entry((head)->prev, typeof(*pos), member),      \
+               n = list_entry(pos->member.prev, typeof(*pos), member); \
+            &pos->member != (head);                                    \
+            pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+       struct hlist_node *first;
+};
+
+struct hlist_node {
+       struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+       h->next = NULL;
+       h->pprev = NULL;
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+       return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+       return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+       struct hlist_node *next = n->next;
+       struct hlist_node **pprev = n->pprev;
+       *pprev = next;
+       if (next)
+               next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+       __hlist_del(n);
+       n->next = NULL;
+       n->pprev = NULL;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+       if (!hlist_unhashed(n)) {
+               __hlist_del(n);
+               INIT_HLIST_NODE(n);
+       }
+}
+
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+       struct hlist_node *first = h->first;
+       n->next = first;
+       if (first)
+               first->pprev = &n->next;
+       h->first = n;
+       n->pprev = &h->first;
+}
+
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+                                       struct hlist_node *next)
+{
+       n->pprev = next->pprev;
+       n->next = next;
+       next->pprev = &n->next;
+       *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+                                       struct hlist_node *next)
+{
+       next->next = n->next;
+       n->next = next;
+       next->pprev = &n->next;
+
+       if(next->next)
+               next->next->pprev  = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+       for (pos = (head)->first; pos; pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+       for (pos = (head)->first; pos; pos = n)
+
+/**
+ * hlist_for_each_entry        - iterate over list of given type
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member)                   \
+       for (pos = (head)->first; pos &&                                 \
+               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member)               \
+       for (pos = (pos)->next; pos &&                                  \
+            ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});   \
+            pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member)                    \
+       for (; pos &&                    \
+               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
+ * @n:         another &struct hlist_node to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member)           \
+       for (pos = (head)->first;                                        \
+            pos && ({ n = pos->next; 1; }) &&                           \
+               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = n)
+
+#endif
diff --git a/net/wprobe/src/user/wprobe-lib.c b/net/wprobe/src/user/wprobe-lib.c
new file mode 100644 (file)
index 0000000..7a5460b
--- /dev/null
@@ -0,0 +1,1210 @@
+/*
+ * wprobe.c: Wireless probe user space library
+ * Copyright (C) 2008-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define _ISOC99_SOURCE
+#define _BSD_SOURCE
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <math.h>
+#include <linux/wprobe.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/genl/genl.h>
+#ifndef NO_LOCAL_ACCESS 
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/family.h>
+#include <endian.h>
+#endif
+#include "wprobe.h"
+
+#define DEBUG 1
+#ifdef DEBUG
+#define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if defined(BYTE_ORDER) && !defined(__BYTE_ORDER)
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#define __BIG_ENDIAN BIG_ENDIAN
+#define __BYTE_ORDER BYTE_ORDER
+#endif
+
+#ifndef __BYTE_ORDER
+#error Unknown endian type
+#endif
+
+#define WPROBE_MAX_MSGLEN      65536
+
+static inline __u16 __swab16(__u16 x)
+{
+       return x<<8 | x>>8;
+}
+
+static inline __u32 __swab32(__u32 x)
+{
+       return x<<24 | x>>24 |
+               (x & (__u32)0x0000ff00UL)<<8 |
+               (x & (__u32)0x00ff0000UL)>>8;
+}
+
+static inline __u64 __swab64(__u64 x)
+{
+       return x<<56 | x>>56 |
+               (x & (__u64)0x000000000000ff00ULL)<<40 |
+               (x & (__u64)0x0000000000ff0000ULL)<<24 |
+               (x & (__u64)0x00000000ff000000ULL)<< 8 |
+               (x & (__u64)0x000000ff00000000ULL)>> 8 |
+               (x & (__u64)0x0000ff0000000000ULL)>>24 |
+               (x & (__u64)0x00ff000000000000ULL)>>40;
+}
+
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define SWAP16(var) var = __swab16(var)
+#define SWAP32(var) var = __swab32(var)
+#define SWAP64(var) var = __swab64(var)
+#else
+#define SWAP16(var) do {} while(0)
+#define SWAP32(var) do {} while(0)
+#define SWAP64(var) do {} while(0)
+#endif
+
+int wprobe_port = 17990;
+static struct nlattr *tb[WPROBE_ATTR_LAST+1];
+static struct nla_policy attribute_policy[WPROBE_ATTR_LAST+1] = {
+       [WPROBE_ATTR_ID] = { .type = NLA_U32 },
+       [WPROBE_ATTR_MAC] = { .type = NLA_UNSPEC, .minlen = 6, .maxlen = 6 },
+       [WPROBE_ATTR_NAME] = { .type = NLA_STRING },
+       [WPROBE_ATTR_FLAGS] = { .type = NLA_U32 },
+       [WPROBE_ATTR_TYPE] = { .type = NLA_U8 },
+       [WPROBE_ATTR_FLAGS] = { .type = NLA_U32 },
+       [WPROBE_VAL_S8] = { .type = NLA_U8 },
+       [WPROBE_VAL_S16] = { .type = NLA_U16 },
+       [WPROBE_VAL_S32] = { .type = NLA_U32 },
+       [WPROBE_VAL_S64] = { .type = NLA_U64 },
+       [WPROBE_VAL_U8] = { .type = NLA_U8 },
+       [WPROBE_VAL_U16] = { .type = NLA_U16 },
+       [WPROBE_VAL_U32] = { .type = NLA_U32 },
+       [WPROBE_VAL_U64] = { .type = NLA_U64 },
+       [WPROBE_VAL_SUM] = { .type = NLA_U64 },
+       [WPROBE_VAL_SUM_SQ] = { .type = NLA_U64 },
+       [WPROBE_VAL_SAMPLES] = { .type = NLA_U32 },
+       [WPROBE_VAL_SCALE_TIME] = { .type = NLA_U64 },
+       [WPROBE_ATTR_INTERVAL] = { .type = NLA_U64 },
+       [WPROBE_ATTR_SAMPLES_MIN] = { .type = NLA_U32 },
+       [WPROBE_ATTR_SAMPLES_MAX] = { .type = NLA_U32 },
+       [WPROBE_ATTR_SAMPLES_SCALE_M] = { .type = NLA_U32 },
+       [WPROBE_ATTR_SAMPLES_SCALE_D] = { .type = NLA_U32 },
+       [WPROBE_ATTR_FILTER_GROUP] = { .type = NLA_NESTED },
+       [WPROBE_ATTR_RXCOUNT] = { .type = NLA_U64 },
+       [WPROBE_ATTR_TXCOUNT] = { .type = NLA_U64 },
+};
+
+typedef int (*wprobe_cb_t)(struct nl_msg *, void *);
+
+struct wprobe_iface_ops {
+       int (*send_msg)(struct wprobe_iface *dev, struct nl_msg *msg, wprobe_cb_t cb, void *arg);
+       void (*free)(struct wprobe_iface *dev);
+};
+
+struct wprobe_attr_cb {
+       struct list_head *list;
+       char *addr;
+};
+
+#define WPROBE_MAGIC_STR "WPROBE"
+struct wprobe_init_hdr {
+       struct {
+               char magic[sizeof(WPROBE_MAGIC_STR)];
+
+               /* protocol version */
+               uint8_t version;
+
+               /* extra header length (unused for now) */
+               uint16_t extra;
+       } pre __attribute__((packed));
+       union {
+               struct {
+                       uint16_t genl_family;
+               } v0 __attribute__((packed));
+       };
+} __attribute__((packed));
+
+struct wprobe_msg_hdr {
+       __u16 status;
+       __u16 error;
+       __u32 len;
+};
+
+enum wprobe_resp_status {
+       WPROBE_MSG_DONE = 0,
+       WPROBE_MSG_DATA = 1,
+};
+
+static inline void
+wprobe_swap_msg_hdr(struct wprobe_msg_hdr *mhdr)
+{
+       SWAP16(mhdr->status);
+       SWAP16(mhdr->error);
+       SWAP32(mhdr->len);
+}
+
+static int
+save_attribute_handler(struct nl_msg *msg, void *arg)
+{
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       const char *name = "N/A";
+       struct wprobe_attribute *attr;
+       int type = 0;
+       struct wprobe_attr_cb *cb = arg;
+
+       nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0),
+                       genlmsg_attrlen(gnlh, 0), attribute_policy);
+
+       if (tb[WPROBE_ATTR_NAME])
+               name = nla_data(tb[WPROBE_ATTR_NAME]);
+
+       attr = malloc(sizeof(struct wprobe_attribute) + strlen(name) + 1);
+       if (!attr)
+               return -1;
+
+       memset(attr, 0, sizeof(struct wprobe_attribute));
+
+       if (tb[WPROBE_ATTR_ID])
+               attr->id = nla_get_u32(tb[WPROBE_ATTR_ID]);
+
+       if (tb[WPROBE_ATTR_MAC] && cb->addr)
+               memcpy(cb->addr, nla_data(tb[WPROBE_ATTR_MAC]), 6);
+
+       if (tb[WPROBE_ATTR_FLAGS])
+               attr->flags = nla_get_u32(tb[WPROBE_ATTR_FLAGS]);
+
+       if (tb[WPROBE_ATTR_TYPE])
+               type = nla_get_u8(tb[WPROBE_ATTR_TYPE]);
+
+       if ((type < WPROBE_VAL_STRING) ||
+               (type > WPROBE_VAL_U64))
+               type = 0;
+
+       attr->type = type;
+       strcpy(attr->name, name);
+       INIT_LIST_HEAD(&attr->list);
+       list_add(&attr->list, cb->list);
+       return 0;
+}
+
+static struct nl_msg *
+wprobe_new_msg(struct wprobe_iface *dev, int cmd, bool dump)
+{
+       struct nl_msg *msg;
+       uint32_t flags = 0;
+
+       msg = nlmsg_alloc_size(65536);
+       if (!msg)
+               return NULL;
+
+       if (dump)
+               flags |= NLM_F_DUMP;
+
+       genlmsg_put(msg, 0, 0, dev->genl_family,
+                       0, flags, cmd, 0);
+
+       NLA_PUT_STRING(msg, WPROBE_ATTR_INTERFACE, dev->ifname);
+nla_put_failure:
+       return msg;
+}
+
+
+static int
+dump_attributes(struct wprobe_iface *dev, bool link, struct list_head *list, char *addr)
+{
+       struct nl_msg *msg;
+       struct wprobe_attr_cb cb;
+
+       cb.list = list;
+       cb.addr = addr;
+       msg = wprobe_new_msg(dev, WPROBE_CMD_GET_LIST, true);
+       if (!msg)
+               return -ENOMEM;
+
+       if (link)
+               NLA_PUT(msg, WPROBE_ATTR_MAC, 6, "\x00\x00\x00\x00\x00\x00");
+
+       return dev->ops->send_msg(dev, msg, save_attribute_handler, &cb);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -EINVAL;
+}
+
+static struct wprobe_iface *
+wprobe_alloc_dev(void)
+{
+       struct wprobe_iface *dev;
+
+       dev = malloc(sizeof(struct wprobe_iface));
+       if (!dev)
+               return NULL;
+
+       memset(dev, 0, sizeof(struct wprobe_iface));
+
+       dev->interval = -1;
+       dev->scale_min = -1;
+       dev->scale_max = -1;
+       dev->scale_m = -1;
+       dev->scale_d = -1;
+       dev->sockfd = -1;
+
+       INIT_LIST_HEAD(&dev->global_attr);
+       INIT_LIST_HEAD(&dev->link_attr);
+       INIT_LIST_HEAD(&dev->links);
+       return dev;
+}
+
+static int
+wprobe_init_dev(struct wprobe_iface *dev)
+{
+       dump_attributes(dev, false, &dev->global_attr, NULL);
+       dump_attributes(dev, true, &dev->link_attr, NULL);
+       return 0;
+}
+
+#ifndef NO_LOCAL_ACCESS 
+static int n_devs = 0;
+static struct nl_sock *handle = NULL;
+static struct nl_cache *cache = NULL;
+static struct genl_family *family = NULL;
+
+static int
+error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
+{
+       int *ret = arg;
+       *ret = err->error;
+       return NL_STOP;
+}
+
+static int
+finish_handler(struct nl_msg *msg, void *arg)
+{
+       int *ret = arg;
+       *ret = 0;
+       return NL_SKIP;
+}
+
+static int
+ack_handler(struct nl_msg *msg, void *arg)
+{
+       int *ret = arg;
+       *ret = 0;
+       return NL_STOP;
+}
+
+static void
+wprobe_local_free(struct wprobe_iface *dev)
+{
+       /* should not happen */
+       if (n_devs == 0)
+               return;
+
+       if (--n_devs != 0)
+               return;
+
+       if (cache)
+               nl_cache_free(cache);
+       if (handle)
+               nl_socket_free(handle);
+       handle = NULL;
+       cache = NULL;
+}
+
+static int
+wprobe_local_init(void)
+{
+       int ret;
+
+       if (n_devs++ > 0)
+               return 0;
+
+       handle = nl_socket_alloc();
+       if (!handle) {
+               DPRINTF("Failed to create handle\n");
+               goto err;
+       }
+
+       if (genl_connect(handle)) {
+               DPRINTF("Failed to connect to generic netlink\n");
+               goto err;
+       }
+
+       ret = genl_ctrl_alloc_cache(handle, &cache);
+       if (ret < 0) {
+               DPRINTF("Failed to allocate netlink cache\n");
+               goto err;
+       }
+
+       family = genl_ctrl_search_by_name(cache, "wprobe");
+       if (!family) {
+               DPRINTF("wprobe API not present\n");
+               goto err;
+       }
+       return 0;
+
+err:
+       wprobe_local_free(NULL);
+       return -EINVAL;
+}
+
+
+static int
+wprobe_local_send_msg(struct wprobe_iface *dev, struct nl_msg *msg, wprobe_cb_t callback, void *arg)
+{
+       struct nl_cb *cb;
+       int err = 0;
+
+       cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (!cb)
+               goto out_no_cb;
+
+       if (callback)
+               nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, callback, arg);
+
+       err = nl_send_auto_complete(handle, msg);
+       if (err < 0)
+               goto out;
+
+       err = 1;
+
+       nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+       nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+       nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+
+       while (err > 0)
+               nl_recvmsgs(handle, cb);
+
+out:
+       nl_cb_put(cb);
+out_no_cb:
+       nlmsg_free(msg);
+       return err;
+}
+
+static const struct wprobe_iface_ops wprobe_local_ops = {
+       .send_msg = wprobe_local_send_msg,
+       .free = wprobe_local_free,
+};
+
+struct wprobe_iface *
+wprobe_get_dev(const char *ifname)
+{
+       struct wprobe_iface *dev;
+
+       if (wprobe_local_init() != 0)
+               return NULL;
+
+       dev = wprobe_alloc_dev();
+       if (!dev)
+               goto error_alloc;
+
+       dev->ifname = strdup(ifname);
+       dev->ops = &wprobe_local_ops;
+       dev->genl_family = genl_family_get_id(family);
+
+       if (wprobe_init_dev(dev) < 0)
+               goto error;
+
+       return dev;
+
+error:
+       free(dev);
+error_alloc:
+       wprobe_local_free(NULL);
+       return NULL;
+}
+
+#endif
+
+static void swap_nlmsghdr(struct nlmsghdr *nlh)
+{
+       SWAP32(nlh->nlmsg_len);
+       SWAP16(nlh->nlmsg_type);
+       SWAP16(nlh->nlmsg_flags);
+       SWAP32(nlh->nlmsg_seq);
+       SWAP32(nlh->nlmsg_pid);
+}
+
+static void swap_genlmsghdr(struct genlmsghdr *gnlh)
+{
+#if 0 /* probably unnecessary */
+       SWAP16(gnlh->reserved);
+#endif
+}
+
+static void
+wprobe_swap_nested(void *data, int len, bool outgoing)
+{
+       void *end = data + len;
+
+       while (data < end) {
+               struct nlattr *nla = data;
+               unsigned int type, len;
+
+               if (!outgoing) {
+                       SWAP16(nla->nla_len);
+                       SWAP16(nla->nla_type);
+
+                       /* required for further sanity checks */
+                       if (data + nla->nla_len > end)
+                               nla->nla_len = end - data;
+               }
+
+               len = NLA_ALIGN(nla->nla_len);
+               type = nla->nla_type & NLA_TYPE_MASK;
+
+               if (type <= WPROBE_ATTR_LAST) {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+                       switch(attribute_policy[type].type) {
+                       case NLA_U16:
+                               SWAP16(*(__u16 *)nla_data(nla));
+                               break;
+                       case NLA_U32:
+                               SWAP32(*(__u32 *)nla_data(nla));
+                               break;
+                       case NLA_U64:
+                               SWAP64(*(__u64 *)nla_data(nla));
+                               break;
+                       case NLA_NESTED:
+                               wprobe_swap_nested(nla_data(nla), nla_len(nla), outgoing);
+                               break;
+                       }
+#endif
+               }
+               data += len;
+
+               if (outgoing) {
+                       SWAP16(nla->nla_len);
+                       SWAP16(nla->nla_type);
+               }
+               if (!nla->nla_len)
+                       break;
+       }
+}
+
+static struct nl_msg *
+wprobe_msg_from_network(int socket, int len)
+{
+       struct genlmsghdr *gnlh;
+       struct nlmsghdr *nlh;
+       struct nl_msg *msg;
+       void *data;
+
+       msg = nlmsg_alloc_size(len + 32);
+       if (!msg)
+               return NULL;
+
+       nlh = nlmsg_hdr(msg);
+       if (read(socket, nlh, len) != len)
+               goto free;
+
+       swap_nlmsghdr(nlh);
+       if (nlh->nlmsg_len > len)
+               goto free;
+
+       gnlh = nlmsg_data(nlh);
+       swap_genlmsghdr(gnlh);
+
+       data = genlmsg_data(gnlh);
+       wprobe_swap_nested(data, genlmsg_len(gnlh), false);
+
+       return msg;
+free:
+       nlmsg_free(msg);
+       return NULL;
+}
+
+static int
+wprobe_msg_to_network(int socket, struct nl_msg *msg)
+{
+       struct nlmsghdr *nlh = nlmsg_hdr(msg);
+       struct wprobe_msg_hdr mhdr;
+       struct genlmsghdr *gnlh;
+       void *buf, *data;
+       int buflen, datalen;
+       int ret;
+
+       buflen = nlh->nlmsg_len;
+       buf = malloc(buflen);
+       if (!buf)
+               return -ENOMEM;
+
+       memset(&mhdr, 0, sizeof(mhdr));
+       mhdr.status = WPROBE_MSG_DATA;
+       mhdr.len = buflen;
+       wprobe_swap_msg_hdr(&mhdr);
+       ret = write(socket, &mhdr, sizeof(mhdr));
+       if (ret < 0)
+               goto out;
+
+       memcpy(buf, nlh, buflen);
+       nlh = buf;
+       gnlh = nlmsg_data(nlh);
+       data = genlmsg_data(gnlh);
+       datalen = genlmsg_len(gnlh);
+
+       wprobe_swap_nested(data, datalen, true);
+       swap_genlmsghdr(gnlh);
+       swap_nlmsghdr(nlh);
+       ret = write(socket, buf, buflen);
+
+out:
+       free(buf);
+
+       return ret;
+}
+
+static int
+wprobe_remote_send_msg(struct wprobe_iface *dev, struct nl_msg *msg, wprobe_cb_t callback, void *arg)
+{
+       struct wprobe_msg_hdr mhdr;
+       int msgs = 0;
+
+       wprobe_msg_to_network(dev->sockfd, msg);
+       nlmsg_free(msg);
+       do {
+               if (read(dev->sockfd, &mhdr, sizeof(mhdr)) != sizeof(mhdr)) {
+                       DPRINTF("Failed to read response header\n");
+                       return -1;
+               }
+               wprobe_swap_msg_hdr(&mhdr);
+
+               switch(mhdr.status) {
+               case WPROBE_MSG_DATA:
+                       if (mhdr.len > WPROBE_MAX_MSGLEN) {
+                               fprintf(stderr, "Invalid length in received response message.\n");
+                               exit(1);
+                       }
+
+                       msg = wprobe_msg_from_network(dev->sockfd, mhdr.len);
+                       if (!msg)
+                               return -EINVAL;
+
+                       msgs++;
+                       callback(msg, arg);
+                       nlmsg_free(msg);
+                       break;
+               }
+       } while (mhdr.status != WPROBE_MSG_DONE);
+
+       if (mhdr.error)
+               return -mhdr.error;
+       else
+               return msgs;
+}
+
+
+static void
+wprobe_socket_dev_free(struct wprobe_iface *dev)
+{
+       if (dev->sockfd >= 0)
+               close(dev->sockfd);
+}
+
+static const struct wprobe_iface_ops wprobe_remote_ops = {
+       .send_msg = wprobe_remote_send_msg,
+       .free = wprobe_socket_dev_free,
+};
+
+
+#ifndef NO_LOCAL_ACCESS 
+int
+wprobe_server_init(int socket)
+{
+       struct wprobe_init_hdr hdr;
+       int ret;
+
+       ret = wprobe_local_init();
+       if (ret != 0)
+               return ret;
+
+       memset(&hdr, 0, sizeof(hdr));
+       memcpy(hdr.pre.magic, WPROBE_MAGIC_STR, sizeof(WPROBE_MAGIC_STR));
+       hdr.pre.version = 0;
+       hdr.v0.genl_family = genl_family_get_id(family);
+       SWAP16(hdr.v0.genl_family);
+       write(socket, (unsigned char *)&hdr, sizeof(hdr));
+
+       return 0;
+}
+
+static int
+wprobe_server_cb(struct nl_msg *msg, void *arg)
+{
+       int *socket = arg;
+       int ret;
+
+       ret = wprobe_msg_to_network(*socket, msg);
+       if (ret > 0)
+               ret = 0;
+
+       return ret;
+}
+
+
+int
+wprobe_server_handle(int socket)
+{
+       struct wprobe_msg_hdr mhdr;
+       struct nl_msg *msg;
+       int ret;
+
+       ret = read(socket, &mhdr, sizeof(mhdr));
+       if (ret != sizeof(mhdr)) {
+               if (ret <= 0)
+                       return -1;
+
+               DPRINTF("Failed to read request header\n");
+               return -EINVAL;
+       }
+       wprobe_swap_msg_hdr(&mhdr);
+
+       switch(mhdr.status) {
+       case WPROBE_MSG_DATA:
+               if (mhdr.len > WPROBE_MAX_MSGLEN) {
+                       DPRINTF("Invalid length in received response message.\n");
+                       return -EINVAL;
+               }
+               msg = wprobe_msg_from_network(socket, mhdr.len);
+               break;
+       default:
+               DPRINTF("Invalid request header type\n");
+               return -ENOENT;
+       }
+
+       if (!msg) {
+               DPRINTF("Failed to get message\n");
+               return -EINVAL;
+       }
+
+       ret = wprobe_local_send_msg(NULL, msg, wprobe_server_cb, &socket);
+
+       memset(&mhdr, 0, sizeof(mhdr));
+       mhdr.status = WPROBE_MSG_DONE;
+       if (ret < 0)
+               mhdr.error = (uint16_t) -ret;
+
+       ret = write(socket, (unsigned char *)&mhdr, sizeof(mhdr));
+       if (ret > 0)
+               ret = 0;
+
+       return ret;
+}
+
+void
+wprobe_server_done(void)
+{
+       wprobe_local_free(NULL);
+}
+#endif
+
+struct wprobe_iface *
+wprobe_get_from_socket(int socket, const char *name)
+{
+       struct wprobe_iface *dev;
+       struct wprobe_init_hdr hdr;
+
+       dev = wprobe_alloc_dev();
+       if (!dev)
+               goto out;
+
+       dev->ops = &wprobe_remote_ops;
+       dev->sockfd = socket;
+       dev->ifname = strdup(name);
+
+       /* read version and header length */
+       if (read(socket, &hdr.pre, sizeof(hdr.pre)) != sizeof(hdr.pre)) {
+               DPRINTF("Could not read header\n");
+               goto error;
+       }
+
+       /* magic not found */
+       if (memcmp(hdr.pre.magic, WPROBE_MAGIC_STR, sizeof(hdr.pre.magic)) != 0) {
+               DPRINTF("Magic does not match\n");
+               goto error;
+       }
+
+       /* unsupported version */
+       if (hdr.pre.version != 0) {
+               DPRINTF("Protocol version does not match\n");
+               goto error;
+       }
+
+       if (read(socket, &hdr.v0, sizeof(hdr.v0)) != sizeof(hdr.v0)) {
+               DPRINTF("Could not read header data\n");
+               goto error;
+       }
+
+       SWAP16(hdr.pre.extra);
+       SWAP16(hdr.v0.genl_family);
+       dev->genl_family = hdr.v0.genl_family;
+
+       if (wprobe_init_dev(dev) < 0) {
+               DPRINTF("Could not initialize device\n");
+               goto error;
+       }
+
+out:
+       return dev;
+
+error:
+       wprobe_free_dev(dev);
+       return NULL;
+}
+
+struct wprobe_iface *
+wprobe_get_auto(const char *arg, char **err)
+{
+       static struct sockaddr_in sa;
+       static char errbuf[512];
+
+       struct wprobe_iface *dev = NULL;
+       struct hostent *h;
+       char *devstr = strdup(arg);
+       char *sep = NULL;
+       int sock = -1;
+       int len;
+
+       if (err)
+               *err = NULL;
+
+       sep = strchr(devstr, ':');
+       if (!sep) {
+#ifndef NO_LOCAL_ACCESS 
+               free(devstr);
+               return wprobe_get_dev(arg);
+#else
+               if (err)
+                       *err = "Invalid argument";
+               goto out;
+#endif
+       }
+
+       *sep = 0;
+       sep++;
+
+       sock = socket(AF_INET, SOCK_STREAM, 0);
+       if (sock < 0)
+               goto syserr;
+
+       h = gethostbyname(devstr);
+       if (!h) {
+               sprintf(errbuf, "Host not found");
+               goto out_err;
+       }
+
+       memcpy(&sa.sin_addr, h->h_addr, h->h_length);
+       sa.sin_family = AF_INET;
+       sa.sin_port = htons(wprobe_port);
+       if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0)
+               goto syserr;
+
+       dev = wprobe_get_from_socket(sock, sep);
+       if (!dev) {
+               sprintf(errbuf, "wprobe connection initialization failed");
+               goto out_err;
+       }
+       goto out;
+
+syserr:
+       if (err) {
+               strcpy(errbuf, "Connection failed: ");
+               len = strlen(errbuf);
+               strerror_r(errno, errbuf + len, sizeof(errbuf) - len - 1);
+       }
+out_err:
+       if (err)
+               *err = errbuf;
+       if (sock >= 0)
+               close(sock);
+out:
+       if (devstr)
+               free(devstr);
+       return dev;
+}
+
+static void
+free_attr_list(struct list_head *list)
+{
+       struct wprobe_attribute *attr, *tmp;
+
+       list_for_each_entry_safe(attr, tmp, list, list) {
+               list_del(&attr->list);
+               free(attr);
+       }
+}
+
+void
+wprobe_free_dev(struct wprobe_iface *dev)
+{
+       if (dev->ops->free)
+               dev->ops->free(dev);
+       free_attr_list(&dev->global_attr);
+       free_attr_list(&dev->link_attr);
+       free((void *)dev->ifname);
+       free(dev);
+}
+
+static struct wprobe_link *
+get_link(struct list_head *list, const char *addr)
+{
+       struct wprobe_link *l;
+
+       list_for_each_entry(l, list, list) {
+               if (!memcmp(l->addr, addr, 6)) {
+                       list_del_init(&l->list);
+                       goto out;
+               }
+       }
+
+       /* no previous link found, allocate a new one */
+       l = malloc(sizeof(struct wprobe_link));
+       if (!l)
+               goto out;
+
+       memset(l, 0, sizeof(struct wprobe_link));
+       memcpy(l->addr, addr, sizeof(l->addr));
+       INIT_LIST_HEAD(&l->list);
+
+out:
+       return l;
+}
+
+struct wprobe_save_cb {
+       struct list_head *list;
+       struct list_head old_list;
+};
+
+static int
+save_link_handler(struct nl_msg *msg, void *arg)
+{
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wprobe_link *link;
+       struct wprobe_save_cb *cb = arg;
+       const char *addr;
+
+       nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0),
+                       genlmsg_attrlen(gnlh, 0), attribute_policy);
+
+       if (!tb[WPROBE_ATTR_MAC] || (nla_len(tb[WPROBE_ATTR_MAC]) != 6))
+               return -1;
+
+       addr = nla_data(tb[WPROBE_ATTR_MAC]);
+       link = get_link(&cb->old_list, addr);
+       if (!link)
+               return -1;
+
+       if (tb[WPROBE_ATTR_FLAGS])
+               link->flags = nla_get_u32(tb[WPROBE_ATTR_FLAGS]);
+
+       list_add_tail(&link->list, cb->list);
+       return 0;
+}
+
+
+int
+wprobe_update_links(struct wprobe_iface *dev)
+{
+       struct wprobe_link *l, *tmp;
+       struct nl_msg *msg;
+       struct wprobe_save_cb cb;
+       int err;
+
+       INIT_LIST_HEAD(&cb.old_list);
+       list_splice_init(&dev->links, &cb.old_list);
+       cb.list = &dev->links;
+
+       msg = wprobe_new_msg(dev, WPROBE_CMD_GET_LINKS, true);
+       if (!msg)
+               return -ENOMEM;
+
+       err = dev->ops->send_msg(dev, msg, save_link_handler, &cb);
+       if (err < 0)
+               return err;
+
+       list_for_each_entry_safe(l, tmp, &cb.old_list, list) {
+               list_del(&l->list);
+               free(l);
+       }
+
+       return 0;
+}
+
+
+struct wprobe_filter_data
+{
+       wprobe_filter_cb cb;
+       void *arg;
+       struct wprobe_filter_item *buf;
+       int buflen;
+};
+
+static int
+dump_filter_handler(struct nl_msg *msg, void *arg)
+{
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wprobe_filter_data *data = arg;
+       struct nlattr *p;
+       const char *name;
+       int count = 0;
+       int len;
+
+       nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0),
+                       genlmsg_attrlen(gnlh, 0), attribute_policy);
+
+       if (!tb[WPROBE_ATTR_NAME] || !tb[WPROBE_ATTR_FILTER_GROUP])
+               return -1;
+
+       name = nla_data(tb[WPROBE_ATTR_NAME]);
+       nla_for_each_nested(p, tb[WPROBE_ATTR_FILTER_GROUP], len) {
+               count++;
+       }
+
+       if (data->buflen < count) {
+               if (data->buf)
+                       free(data->buf);
+               data->buflen = count;
+               data->buf = malloc(sizeof(struct wprobe_filter_item) * count);
+               memset(data->buf, 0, sizeof(struct wprobe_filter_item) * count);
+       }
+
+       count = 0;
+       nla_for_each_nested(p, tb[WPROBE_ATTR_FILTER_GROUP], len) {
+               struct wprobe_filter_item *fi;
+
+               nla_parse(tb, WPROBE_ATTR_LAST, nla_data(p),
+                               nla_len(p), attribute_policy);
+
+               if (!tb[WPROBE_ATTR_NAME] || !tb[WPROBE_ATTR_RXCOUNT]
+                               || !tb[WPROBE_ATTR_TXCOUNT])
+                       continue;
+
+               fi = &data->buf[count++];
+               strncpy(fi->name, nla_data(tb[WPROBE_ATTR_NAME]), sizeof(fi->name) - 1);
+               fi->name[sizeof(fi->name) - 1] = 0;
+               fi->rx = nla_get_u64(tb[WPROBE_ATTR_RXCOUNT]);
+               fi->tx = nla_get_u64(tb[WPROBE_ATTR_TXCOUNT]);
+       }
+       data->cb(data->arg, name, data->buf, count);
+
+       return 0;
+}
+
+int
+wprobe_dump_filters(struct wprobe_iface *dev, wprobe_filter_cb cb, void *arg)
+{
+       struct wprobe_filter_data data;
+       struct nl_msg *msg;
+       int err;
+
+       data.buf = 0;
+       data.buflen = 0;
+       data.cb = cb;
+       data.arg = arg;
+
+       msg = wprobe_new_msg(dev, WPROBE_CMD_GET_FILTER, true);
+       if (!msg)
+               return -ENOMEM;
+
+       err = dev->ops->send_msg(dev, msg, dump_filter_handler, &data);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+int
+wprobe_apply_config(struct wprobe_iface *dev)
+{
+       struct nl_msg *msg;
+
+       msg = wprobe_new_msg(dev, WPROBE_CMD_CONFIG, false);
+       if (!msg)
+               return -ENOMEM;
+
+       if (dev->interval >= 0)
+               NLA_PUT_MSECS(msg, WPROBE_ATTR_INTERVAL, dev->interval);
+
+       if (dev->filter_len < 0) {
+               NLA_PUT(msg, WPROBE_ATTR_FILTER, 0, NULL);
+               dev->filter_len = 0;
+       } else if (dev->filter && dev->filter_len > 0) {
+               NLA_PUT(msg, WPROBE_ATTR_FILTER, dev->filter_len, dev->filter);
+       }
+       dev->filter = NULL;
+
+       dev->ops->send_msg(dev, msg, NULL, NULL);
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOMEM;
+}
+
+int
+wprobe_measure(struct wprobe_iface *dev)
+{
+       struct nl_msg *msg;
+
+       msg = wprobe_new_msg(dev, WPROBE_CMD_MEASURE, false);
+       if (!msg)
+               return -ENOMEM;
+
+       dev->ops->send_msg(dev, msg, NULL, NULL);
+       return 0;
+}
+
+struct wprobe_request_cb {
+       struct list_head *list;
+       struct list_head old_list;
+       char *addr;
+};
+
+static int
+save_attrdata_handler(struct nl_msg *msg, void *arg)
+{
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wprobe_request_cb *cb = arg;
+       struct wprobe_attribute *attr;
+       int type, id;
+
+       nla_parse(tb, WPROBE_ATTR_LAST, genlmsg_attrdata(gnlh, 0),
+                       genlmsg_attrlen(gnlh, 0), attribute_policy);
+
+       if (!tb[WPROBE_ATTR_ID])
+               return -1;
+
+       if (!tb[WPROBE_ATTR_TYPE])
+               return -1;
+
+       id = nla_get_u32(tb[WPROBE_ATTR_ID]);
+       list_for_each_entry(attr, &cb->old_list, list) {
+               if (attr->id == id)
+                       goto found;
+       }
+       /* not found */
+       return -1;
+
+found:
+       list_del_init(&attr->list);
+
+       type = nla_get_u8(tb[WPROBE_ATTR_TYPE]);
+       if (type != attr->type) {
+               DPRINTF("WARNING: type mismatch for %s attribute '%s' (%d != %d)\n",
+                       (cb->addr ? "link" : "global"),
+                       attr->name,
+                       type, attr->type);
+               goto out;
+       }
+
+       if ((type < WPROBE_VAL_STRING) ||
+               (type > WPROBE_VAL_U64))
+               goto out;
+
+       memset(&attr->val, 0, sizeof(attr->val));
+
+#define HANDLE_INT_TYPE(_idx, _type) \
+       case WPROBE_VAL_S##_type: \
+       case WPROBE_VAL_U##_type: \
+               attr->val.U##_type = nla_get_u##_type(tb[_idx]); \
+               break
+
+       switch(type) {
+               HANDLE_INT_TYPE(type, 8);
+               HANDLE_INT_TYPE(type, 16);
+               HANDLE_INT_TYPE(type, 32);
+               HANDLE_INT_TYPE(type, 64);
+               case WPROBE_VAL_STRING:
+                       /* unimplemented */
+                       break;
+       }
+#undef HANDLE_TYPE
+
+       if (attr->flags & WPROBE_F_KEEPSTAT) {
+               if (tb[WPROBE_VAL_SUM])
+                       attr->val.s = nla_get_u64(tb[WPROBE_VAL_SUM]);
+
+               if (tb[WPROBE_VAL_SUM_SQ])
+                       attr->val.ss = nla_get_u64(tb[WPROBE_VAL_SUM_SQ]);
+
+               if (tb[WPROBE_VAL_SAMPLES])
+                       attr->val.n = nla_get_u32(tb[WPROBE_VAL_SAMPLES]);
+
+               if (attr->val.n > 0) {
+                       float avg = ((float) attr->val.s) / attr->val.n;
+                       float stdev = sqrt((((float) attr->val.ss) / attr->val.n) - (avg * avg));
+                       if (isnan(stdev))
+                               stdev = 0.0f;
+                       if (isnan(avg))
+                               avg = 0.0f;
+                       attr->val.avg = avg;
+                       attr->val.stdev = stdev;
+               }
+       }
+
+out:
+       list_add_tail(&attr->list, cb->list);
+       return 0;
+}
+
+
+int
+wprobe_request_data(struct wprobe_iface *dev, const unsigned char *addr)
+{
+       struct wprobe_request_cb cb;
+       struct list_head *attrs;
+       struct nl_msg *msg;
+       int err;
+
+       msg = wprobe_new_msg(dev, WPROBE_CMD_GET_INFO, true);
+       if (!msg)
+               return -ENOMEM;
+
+       if (addr) {
+               attrs = &dev->link_attr;
+               NLA_PUT(msg, WPROBE_ATTR_MAC, 6, addr);
+       } else {
+               attrs = &dev->global_attr;
+       }
+
+       INIT_LIST_HEAD(&cb.old_list);
+       list_splice_init(attrs, &cb.old_list);
+       cb.list = attrs;
+
+       err = dev->ops->send_msg(dev, msg, save_attrdata_handler, &cb);
+       list_splice(&cb.old_list, attrs->prev);
+       return err;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOMEM;
+}
+
+
diff --git a/net/wprobe/src/user/wprobe-util.c b/net/wprobe/src/user/wprobe-util.c
new file mode 100644 (file)
index 0000000..654442f
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * wprobe-test.c: Wireless probe user space test code
+ * Copyright (C) 2008-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <linux/wprobe.h>
+#include "wprobe.h"
+
+static bool simple_mode = false;
+
+static const char *
+wprobe_dump_value(struct wprobe_attribute *attr)
+{
+       static char buf[128];
+
+#define HANDLE_TYPE(_type, _format) \
+       case WPROBE_VAL_##_type: \
+               snprintf(buf, sizeof(buf), _format, attr->val._type); \
+               break
+
+       switch(attr->type) {
+               HANDLE_TYPE(S8, "%d");
+               HANDLE_TYPE(S16, "%d");
+               HANDLE_TYPE(S32, "%d");
+               HANDLE_TYPE(S64, "%lld");
+               HANDLE_TYPE(U8, "%d");
+               HANDLE_TYPE(U16, "%d");
+               HANDLE_TYPE(U32, "%d");
+               HANDLE_TYPE(U64, "%lld");
+               case WPROBE_VAL_STRING:
+                       /* FIXME: implement this */
+               default:
+                       strncpy(buf, "<unknown>", sizeof(buf));
+                       break;
+       }
+       if ((attr->flags & WPROBE_F_KEEPSTAT) &&
+               (attr->val.n > 0)) {
+               int len = strlen(buf);
+               if (simple_mode)
+                       snprintf(buf + len, sizeof(buf) - len, ";%.02f;%.02f;%d;%lld;%lld", attr->val.avg, attr->val.stdev, attr->val.n, attr->val.s, attr->val.ss);
+               else
+                       snprintf(buf + len, sizeof(buf) - len, " (avg: %.02f; stdev: %.02f, n=%d)", attr->val.avg, attr->val.stdev, attr->val.n);
+       }
+#undef HANDLE_TYPE
+
+       return buf;
+}
+
+
+static void
+wprobe_dump_data(struct wprobe_iface *dev)
+{
+       struct wprobe_attribute *attr;
+       struct wprobe_link *link;
+       bool first = true;
+
+       if (!simple_mode)
+               fprintf(stdout, "\n");
+       wprobe_request_data(dev, NULL);
+       list_for_each_entry(attr, &dev->global_attr, list) {
+               if (simple_mode) {
+                       if (first)
+                               fprintf(stdout, "[global]\n");
+                       fprintf(stdout, "%s=%s\n", attr->name, wprobe_dump_value(attr));
+               } else {
+                       fprintf(stdout, (first ?
+                               "Global:            %s=%s\n" :
+                               "                   %s=%s\n"),
+                               attr->name,
+                               wprobe_dump_value(attr)
+                       );
+               }
+               first = false;
+       }
+
+       list_for_each_entry(link, &dev->links, list) {
+               first = true;
+               wprobe_request_data(dev, link->addr);
+               list_for_each_entry(attr, &dev->link_attr, list) {
+                       if (first) {
+                               fprintf(stdout,
+                                       (simple_mode ?
+                                        "[%02x:%02x:%02x:%02x:%02x:%02x]\n%s=%s\n" :
+                                        "%02x:%02x:%02x:%02x:%02x:%02x: %s=%s\n"),
+                                       link->addr[0], link->addr[1], link->addr[2],
+                                       link->addr[3], link->addr[4], link->addr[5],
+                                       attr->name,
+                                       wprobe_dump_value(attr));
+                               first = false;
+                       } else {
+                               fprintf(stdout,
+                                       (simple_mode ? "%s=%s\n" :
+                                        "                   %s=%s\n"),
+                                       attr->name,
+                                       wprobe_dump_value(attr));
+                       }
+               }
+       }
+       fflush(stdout);
+}
+
+static const char *attr_typestr[] = {
+       [0] = "Unknown",
+       [WPROBE_VAL_STRING] = "String",
+       [WPROBE_VAL_U8] = "Unsigned 8 bit",
+       [WPROBE_VAL_U16] = "Unsigned 16 bit",
+       [WPROBE_VAL_U32] = "Unsigned 32 bit",
+       [WPROBE_VAL_U64] = "Unsigned 64 bit",
+       [WPROBE_VAL_S8] = "Signed 8 bit",
+       [WPROBE_VAL_S16] = "Signed 16 bit",
+       [WPROBE_VAL_S32] = "Signed 32 bit",
+       [WPROBE_VAL_S64] = "Signed 64 bit",
+};
+
+static int usage(const char *prog)
+{
+       fprintf(stderr,
+#ifndef NO_LOCAL_ACCESS
+               "Usage: %s <interface>|<host>:<device>|-P [options]\n"
+#else
+               "Usage: %s <host>:<device> [options]\n"
+#endif
+               "\n"
+               "Options:\n"
+               "  -a:            Print attributes\n"
+               "  -c:            Only apply configuration\n"
+               "  -d:            Delay between measurement dumps (in milliseconds, default: 1000)\n"
+               "                 A value of 0 (zero) prints once and exits; useful for scripts\n"
+               "  -f:            Dump contents of layer 2 filter counters during measurement\n"
+               "  -F <file>:     Apply layer 2 filters from <file>\n"
+               "  -h:            This help text\n"
+               "  -i <interval>: Set measurement interval\n"
+               "  -m:            Run measurement loop\n"
+               "  -p:            Set the TCP port for server/client (default: 17990)\n"
+#ifndef NO_LOCAL_ACCESS
+               "  -P:            Run in proxy mode (listen on network)\n"
+#endif
+               "\n"
+               , prog);
+       exit(1);
+}
+
+static void show_attributes(struct wprobe_iface *dev)
+{
+       struct wprobe_attribute *attr;
+       if (simple_mode)
+               return;
+       list_for_each_entry(attr, &dev->global_attr, list) {
+               fprintf(stdout, "Global attribute: '%s' (%s)\n",
+                       attr->name, attr_typestr[attr->type]);
+       }
+       list_for_each_entry(attr, &dev->link_attr, list) {
+               fprintf(stdout, "Link attribute: '%s' (%s)\n",
+                       attr->name, attr_typestr[attr->type]);
+       }
+}
+
+static void show_filter_simple(void *arg, const char *group, struct wprobe_filter_item *items, int n_items)
+{
+       int i;
+
+       fprintf(stdout, "[filter:%s]\n", group);
+       for (i = 0; i < n_items; i++) {
+               fprintf(stdout, "%s=%lld;%lld\n",
+                       items[i].name, items[i].tx, items[i].rx);
+       }
+       fflush(stdout);
+}
+
+
+static void show_filter(void *arg, const char *group, struct wprobe_filter_item *items, int n_items)
+{
+       int i;
+       fprintf(stdout, "Filter group: '%s' (tx/rx)\n", group);
+       for (i = 0; i < n_items; i++) {
+               fprintf(stdout, " - %s (%lld/%lld)\n",
+                       items[i].name, items[i].tx, items[i].rx);
+       }
+}
+
+static void loop_measurement(struct wprobe_iface *dev, bool print_filters, unsigned long delay)
+{
+       do {
+               wprobe_update_links(dev);
+               wprobe_dump_data(dev);
+               if (print_filters)
+                       wprobe_dump_filters(dev, simple_mode ? show_filter_simple : show_filter, NULL);
+               usleep(delay * 1000);
+       }
+       while (delay);
+}
+
+static void set_filter(struct wprobe_iface *dev, const char *filename)
+{
+       unsigned char *buf = NULL;
+       unsigned int buflen = 0;
+       unsigned int len = 0;
+       int fd;
+
+       /* clear filter */
+       if (filename[0] == 0) {
+               dev->filter_len = -1;
+               return;
+       }
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               perror("open filter");
+               return;
+       }
+
+       do {
+               int rlen;
+
+               if (!buf) {
+                       len = 0;
+                       buflen = 1024;
+                       buf = malloc(1024);
+               } else {
+                       buflen *= 2;
+                       buf = realloc(buf, buflen);
+               }
+               rlen = read(fd, buf + len, buflen - len);
+               if (rlen < 0)
+                       break;
+
+               len += rlen;
+       } while (len == buflen);
+
+       dev->filter = buf;
+       dev->filter_len = len;
+       close(fd);
+}
+
+#ifndef NO_LOCAL_ACCESS
+
+static void sigchld_handler(int s)
+{
+       while (waitpid(-1, NULL, WNOHANG) > 0);
+}
+
+static int run_proxy(int port)
+{
+       struct sockaddr_in sa;
+       struct sigaction sig;
+       int v = 1;
+       int s;
+
+       s = socket(AF_INET, SOCK_STREAM, 0);
+       if (s < 0) {
+               perror("socket");
+               return 1;
+       }
+
+       sig.sa_handler = sigchld_handler;  // Signal Handler fuer Zombie Prozesse
+       sigemptyset(&sig.sa_mask);
+       sig.sa_flags = SA_RESTART;
+       sigaction(SIGCHLD, &sig, NULL);
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sin_family = AF_INET;
+       sa.sin_addr.s_addr = htonl(INADDR_ANY);
+       sa.sin_port = htons(wprobe_port);
+
+       setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
+       if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+               perror("bind");
+               return 1;
+       }
+       if (listen(s, 10)) {
+               perror("listen");
+               return 1;
+       }
+       while(1) {
+               unsigned int addrlen = sizeof(struct sockaddr_in);
+               int ret, c;
+
+               c = accept(s, (struct sockaddr *)&sa, &addrlen);
+               if (c < 0) {
+                       if (errno == EINTR)
+                               continue;
+
+                       perror("accept");
+                       return 1;
+               }
+               if (fork() == 0) {
+                       /* close server socket, stdin, stdout, stderr */
+                       close(s);
+                       close(0);
+                       close(1);
+                       close(2);
+
+                       wprobe_server_init(c);
+                       do {
+                               ret = wprobe_server_handle(c);
+                       } while (ret >= 0);
+                       wprobe_server_done();
+                       close(c);
+                       exit(0);
+               }
+               close(c);
+       }
+
+       return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+       struct wprobe_iface *dev = NULL;
+       const char *ifname;
+       const char *prog = argv[0];
+       char *err = NULL;
+       enum {
+               CMD_NONE,
+               CMD_CONFIG,
+               CMD_MEASURE,
+               CMD_PROXY,
+       } cmd = CMD_NONE;
+       const char *filter = NULL;
+       bool print_attributes = false;
+       bool print_filters = false;
+       unsigned long delay = 1000;
+       int interval = -1;
+       int ch;
+
+       if (argc < 2)
+               return usage(prog);
+
+#ifndef NO_LOCAL_ACCESS
+       if (!strcmp(argv[1], "-P")) {
+               while ((ch = getopt(argc - 1, argv + 1, "p:")) != -1) {
+                       switch(ch) {
+                       case 'p':
+                               /* set port */
+                               wprobe_port = strtoul(optarg, NULL, 0);
+                               break;
+                       default:
+                               return usage(prog);
+                       }
+               }
+               return run_proxy(wprobe_port);
+       }
+#endif
+
+       if (argv[1][0] == '-')
+               return usage(prog);
+
+       ifname = argv[1];
+       argv++;
+       argc--;
+
+       while ((ch = getopt(argc, argv, "acd:fF:hi:msp:")) != -1) {
+               switch(ch) {
+               case 'a':
+                       print_attributes = true;
+                       break;
+               case 'c':
+                       cmd = CMD_CONFIG;
+                       break;
+               case 'd':
+                       delay = strtoul(optarg, NULL, 10);
+                       break;
+               case 'm':
+                       cmd = CMD_MEASURE;
+                       break;
+               case 'i':
+                       interval = strtoul(optarg, NULL, 10);
+                       break;
+               case 'f':
+                       print_filters = true;
+                       break;
+               case 'F':
+                       if (filter) {
+                               fprintf(stderr, "Cannot set multiple filters\n");
+                               return usage(prog);
+                       }
+                       filter = optarg;
+                       break;
+               case 's':
+                       simple_mode = true;
+                       break;
+               case 'p':
+                       /* set port */
+                       wprobe_port = strtoul(optarg, NULL, 0);
+                       break;
+               case 'h':
+               default:
+                       usage(prog);
+                       break;
+               }
+       }
+
+       dev = wprobe_get_auto(ifname, &err);
+       if (!dev || (list_empty(&dev->global_attr) &&
+               list_empty(&dev->link_attr))) {
+               if (err)
+                       fprintf(stdout, "%s\n", err);
+               else
+                       fprintf(stderr, "Interface '%s' not found\n", ifname);
+               return 1;
+       }
+
+       if (filter || interval >= 0) {
+               if (filter)
+                       set_filter(dev, filter);
+               if (interval >= 0)
+                       dev->interval = interval;
+
+               wprobe_apply_config(dev);
+       }
+
+       if (cmd != CMD_CONFIG) {
+               if (print_attributes)
+                       show_attributes(dev);
+       }
+       if (cmd == CMD_MEASURE)
+               loop_measurement(dev, print_filters, delay);
+
+       wprobe_free_dev(dev);
+
+       return 0;
+}
diff --git a/net/wprobe/src/user/wprobe.h b/net/wprobe/src/user/wprobe.h
new file mode 100644 (file)
index 0000000..706facc
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * wprobe.h: Wireless probe user space library
+ * Copyright (C) 2008-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WPROBE_USER_H
+#define __WPROBE_USER_H
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "list.h"
+
+/**
+ * struct wprobe_value: data structure for attribute values
+ * @STRING: string value (currently unsupported)
+ * @U8: unsigned 8-bit integer value
+ * @U16: unsigned 16-bit integer value
+ * @U32: unsigned 32-bit integer value
+ * @U64: unsigned 64-bit integer value
+ * @S8: signed 8-bit integer value
+ * @S16: signed 16-bit integer value
+ * @S32: signed 32-bit integer value
+ * @S64: signed 64-bit integer value
+ *
+ * @n: number of sample values 
+ * @avg: average value
+ * @stdev: standard deviation
+ * @s: sum of all sample values (internal use)
+ * @ss: sum of all sample values squared (internal use)
+ */
+struct wprobe_value {
+       /* attribute value */
+       union {
+               const char *STRING;
+               uint8_t U8;
+               uint16_t U16;
+               uint32_t U32;
+               uint64_t U64;
+               int8_t S8;
+               int16_t S16;
+               int32_t S32;
+               int64_t S64;
+       };
+       /* statistics */
+       int64_t s, ss;
+       float avg, stdev;
+       unsigned int n;
+};
+
+/**
+ * struct wprobe_attribute: data structures for attribute descriptions
+ * @list: linked list data structure for a list of attributes
+ * @id: attribute id
+ * @type: netlink type for the attribute (see kernel api documentation)
+ * @flags: attribute flags (see kernel api documentation)
+ * @val: cached version of the last netlink query, will be overwritten on each request
+ * @name: attribute name
+ */
+struct wprobe_attribute {
+       struct list_head list;
+       int id;
+       int type;
+       uint32_t flags;
+       struct wprobe_value val;
+       char name[];
+};
+
+/**
+ * struct wprobe_link: data structure for the link description
+ * @list: linked list data structure for a list of links 
+ * @flags: link flags (see kernel api documentation)
+ * @addr: mac address of the remote link partner
+ */
+struct wprobe_link {
+       struct list_head list;
+       uint32_t flags;
+       unsigned char addr[6];
+};
+
+struct wprobe_filter_item {
+       char name[32];
+       uint64_t rx;
+       uint64_t tx;
+};
+
+struct wprobe_iface_ops;
+struct wprobe_iface {
+       const struct wprobe_iface_ops *ops;
+
+       int sockfd;
+       const char *ifname;
+       unsigned int genl_family;
+       char addr[6];
+
+       struct list_head global_attr;
+       struct list_head link_attr;
+       struct list_head links;
+
+       /* config */
+       int interval;
+       int scale_min;
+       int scale_max;
+       int scale_m;
+       int scale_d;
+
+       /* filter */
+       void *filter;
+
+       /* filter_len:
+        *   set to -1 to drop the current filter
+        *   automatically reset to 0 after config apply
+        */
+       int filter_len;
+};
+
+typedef void (*wprobe_filter_cb)(void *arg, const char *group, struct wprobe_filter_item *items, int n_items);
+extern int wprobe_port;
+
+/**
+ * wprobe_update_links: get a list of all link partners
+ * @dev: wprobe device structure
+ * @list: linked list for storing link descriptions
+ *
+ * when wprobe_update_links is called multiple times, the linked list 
+ * is updated with new link partners, old entries are automatically expired
+ */
+extern int wprobe_update_links(struct wprobe_iface *dev);
+
+/**
+ * wprobe_dump_filters: dump all layer 2 filter counters
+ * @dev: wprobe device structure
+ * @cb: callback (called once per filter group)
+ * @arg: user argument for the callback
+ */
+extern int wprobe_dump_filters(struct wprobe_iface *dev, wprobe_filter_cb cb, void *arg);
+
+/**
+ * wprobe_measure: start a measurement request for all global attributes
+ * @dev: wprobe device structure
+ *
+ * not all attributes are automatically filled with data, since for some
+ * it may be desirable to control the sampling interval from user space
+ * you can use this function to do that.
+ */
+extern int wprobe_measure(struct wprobe_iface *dev);
+
+/**
+ * wprobe_get_dev: get a handle to a local wprobe device
+ * @ifname: name of the wprobe interface
+ *
+ * queries the wprobe interface for all attributes
+ * must be freed with wprobe_free_dev
+ */
+extern struct wprobe_iface *wprobe_get_dev(const char *ifname);
+
+/**
+ * wprobe_get_auto: get a handle to a local or remote wprobe device
+ * @arg: pointer to the wprobe device, either <dev> (local) or <host>:<dev> (remote)
+ */
+extern struct wprobe_iface *wprobe_get_auto(const char *arg, char **err);
+
+/**
+ * wprobe_get_dev: free all device information
+ * @dev: wprobe device structure
+ */
+extern void wprobe_free_dev(struct wprobe_iface *dev);
+
+/**
+ * wprobe_apply_config: apply configuration data
+ * @dev: wprobe device structure
+ *
+ * uploads all configuration values from @dev that are not set to -1
+ */
+extern int wprobe_apply_config(struct wprobe_iface *dev);
+
+/**
+ * wprobe_request_data: request new sampling values for the given list of attributes
+ * @dev: wprobe device structure
+ * @addr: (optional) mac address of the link partner
+ *
+ * if addr is unset, global values are stored in the global attributes list
+ * if addr is set, per-link values for the given address are stored in the link attributes list
+ */
+extern int wprobe_request_data(struct wprobe_iface *dev, const unsigned char *addr);
+
+/**
+ * wprobe_server_init: send a wprobe server init message to a server's client socket
+ * @socket: socket of the connection to the client
+ */
+extern int wprobe_server_init(int socket);
+
+/**
+ * wprobe_server_handle: read a request from the client socket, process it, send the response
+ * @socket: socket of the connection to the client
+ */
+extern int wprobe_server_handle(int socket);
+
+/**
+ * wprobe_server_done: release memory allocated for the server connection
+ */
+extern void wprobe_server_done(void);
+
+#endif
diff --git a/utils/goldfish-qemu/Makefile b/utils/goldfish-qemu/Makefile
new file mode 100644 (file)
index 0000000..e5b4083
--- /dev/null
@@ -0,0 +1,70 @@
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=goldfish-qemu
+PKG_REV:=2b8ea29e2bd12f876a4d06647e6077bf72de567e
+PKG_VERSION:=20090429
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=git://android.git.kernel.org/platform/external/qemu
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_TARGETS:=bin
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/goldfish-qemu
+  SECTION:=emulator
+  CATEGORY:=Emulators
+  DEPENDS:=@TARGET_goldfish
+  TITLE:=A modified version of the Google Android Emulator
+  URL:=http://www.android.com/
+endef
+
+LIBSDL_PATCHED:=sdl-1.2.12-android-20080919
+
+define Download/libsdl-patched
+  FILE:=$(LIBSDL_PATCHED).tar.gz
+  URL:=http://android.git.kernel.org/pub
+  MD5SUM:=22df8cbb2ecb811938eba8410e861650
+endef
+$(eval $(call Download,libsdl-patched))
+
+Build/Exports=
+
+define Build/Prepare
+       $(call Build/Prepare/Default)
+       zcat $(DL_DIR)/$(LIBSDL_PATCHED).tar.gz | tar x -C $(PKG_BUILD_DIR)
+endef
+
+define Build/Configure
+       [ -x $(PKG_BUILD_DIR)/libsdl/bin/sdl-config ] || ( \
+               cd $(PKG_BUILD_DIR)/$(LIBSDL_PATCHED); \
+               ./android-configure --prefix=$(PKG_BUILD_DIR)/libsdl; \
+               make all install; \
+       )
+endef
+
+define Build/Compile
+       (cd $(PKG_BUILD_DIR); \
+               [ -f $(PKG_BUILD_DIR)/objs/config.make ] || \
+                       ./android-configure.sh --sdl-config=$(PKG_BUILD_DIR)/libsdl/bin/sdl-config \
+       )
+       $(MAKE) -C $(PKG_BUILD_DIR)
+endef
+
+define Package/goldfish-qemu/install
+       $(INSTALL_DIR) $(1)
+       $(CP) $(PKG_BUILD_DIR)/objs/emulator $(1)/
+       $(CP) ./skins $(1)/
+endef
+
+$(eval $(call BuildPackage,goldfish-qemu))
diff --git a/utils/goldfish-qemu/patches/100-darwin_fix.patch b/utils/goldfish-qemu/patches/100-darwin_fix.patch
new file mode 100644 (file)
index 0000000..a5f56b3
--- /dev/null
@@ -0,0 +1,30 @@
+--- a/android-configure.sh
++++ b/android-configure.sh
+@@ -656,6 +656,9 @@ case "$CPU" in
+     *) HOST_CPU=$CPU
+     ;;
+ esac
++case "$OS" in
++    darwin*) echo "#define _BSD       1" >> $config_h;;
++esac
+ echo "#define HOST_$HOST_CPU    1" >> $config_h
+ log "Generate   : $config_h"
+--- a/android/utils/display-quartz.m
++++ b/android/utils/display-quartz.m
+@@ -34,6 +34,7 @@ get_monitor_resolution( int  *px_dpi, in
+ int
+ get_nearest_monitor_rect( int  *x, int  *y, int  *width, int  *height )
+ {
++#if 0
+     SDL_SysWMinfo  info;
+     NSWindow*      window;
+@@ -108,4 +109,7 @@ get_nearest_monitor_rect( int  *x, int  
+         }
+         return 0;
+     }
++#else
++      return -1;
++#endif
+ };
diff --git a/utils/goldfish-qemu/patches/110-single_image.patch b/utils/goldfish-qemu/patches/110-single_image.patch
new file mode 100644 (file)
index 0000000..92a9e54
--- /dev/null
@@ -0,0 +1,233 @@
+--- a/android/cmdline-option.c
++++ b/android/cmdline-option.c
+@@ -50,16 +50,6 @@ android_parse_options( int  *pargc, char
+         char   arg2_tab[64], *arg2 = arg2_tab;
+         int    nn;
+-        /* process @<name> as a special exception meaning
+-         * '-avd <name>'
+-         */
+-        if (aread[0][0] == '@') {
+-            opt->avd = aread[0]+1;
+-            nargs--;
+-            aread++;
+-            continue;
+-        }
+-
+         /* anything that isn't an option past this points
+          * exits the loop
+          */
+--- a/android/cmdline-options.h
++++ b/android/cmdline-options.h
+@@ -60,21 +60,16 @@
+  */
+ CFG_PARAM( sysdir,  "<dir>",  "search for system disk images in <dir>" )
+-CFG_PARAM( system,  "<file>", "read initial system image from <file>" )
+-CFG_PARAM( datadir, "<dir>",  "write user data into <dir>" )
+-CFG_PARAM( kernel,  "<file>", "use specific emulated kernel" )
+-CFG_PARAM( ramdisk, "<file>", "ramdisk image (default <system>/ramdisk.img" )
+-CFG_PARAM( image,   "<file>", "obsolete, use -system <file> instead" )
+-CFG_PARAM( init_data, "<file>", "initial data image (default <system>/userdata.img" )
+-CFG_PARAM( initdata, "<file>", "same as '-init-data <file>'" )
+-CFG_PARAM( data,     "<file>", "data image (default <datadir>/userdata-qemu.img" )
++CFG_PARAM( system,  "<file>", "read system image from <file>, default: <system>/system.img" )
++CFG_PARAM( data,     "<file>", "data image, default: <system>/data.img" )
++CFG_PARAM( kernel,  "<file>", "use specific emulated kernel, default: kernel.bin" )
++CFG_PARAM( ramdisk, "<file>", "ramdisk image (default <system>/ramdisk.bin" )
+ CFG_PARAM( partition_size, "<size>", "system/data partition size in MBs" )
+ CFG_PARAM( cache,    "<file>", "cache partition image (default is temporary file)" )
+ CFG_FLAG ( no_cache, "disable the cache partition" )
+ CFG_FLAG ( nocache,  "same as -no-cache" )
+ OPT_PARAM( sdcard, "<file>", "SD card image (default <system>/sdcard.img")
+ OPT_FLAG ( wipe_data, "reset the use data image (copy it from initdata)" )
+-CFG_PARAM( avd, "<name>", "use a specific android virtual device" )
+ CFG_PARAM( skindir, "<dir>", "search skins in <dir> (default <system>/skins)" )
+ CFG_PARAM( skin, "<name>", "select a given skin" )
+ CFG_FLAG ( no_skin, "don't use any emulator skin" )
+--- a/android/main.c
++++ b/android/main.c
+@@ -1606,6 +1606,7 @@ report_console( const char*  proto_port,
+  *       containing 'fileName'. this is *not* the full
+  *       path to 'fileName'.
+  */
++
+ static char*
+ _getSdkImagePath( const char*  fileName )
+ {
+@@ -1617,8 +1618,6 @@ _getSdkImagePath( const char*  fileName 
+     static const char* const  searchPaths[] = {
+         "",                                  /* program's directory */
+-        "/lib/images",                       /* this is for SDK 1.0 */
+-        "/../platforms/android-1.1/images",  /* this is for SDK 1.1 */
+         NULL
+     };
+@@ -1841,25 +1840,7 @@ int main(int argc, char **argv)
+         }
+     }
+-    /* legacy support: we used to use -system <dir> and -image <file>
+-     * instead of -sysdir <dir> and -system <file>, so handle this by checking
+-     * whether the options point to directories or files.
+-     */
+-    if (opts->image != NULL) {
+-        if (opts->system != NULL) {
+-            if (opts->sysdir != NULL) {
+-                derror( "You can't use -sysdir, -system and -image at the same time.\n"
+-                        "You should probably use '-sysdir <path> -system <file>'.\n" );
+-                exit(2);
+-            }
+-        }
+-        dwarning( "Please note that -image is obsolete and that -system is now used to point\n"
+-                  "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" );
+-        opts->sysdir = opts->system;
+-        opts->system = opts->image;
+-        opts->image  = NULL;
+-    }
+-    else if (opts->system != NULL && path_is_dir(opts->system)) {
++    if (opts->system != NULL && path_is_dir(opts->system)) {
+         if (opts->sysdir != NULL) {
+             derror( "Option -system should now be followed by a file path, not a directory one.\n"
+                     "Please use '-sysdir <path>' to point to the system directory.\n" );
+@@ -1885,49 +1866,11 @@ int main(int argc, char **argv)
+     if (opts->noskin)
+         opts->no_skin = opts->noskin;
+-    if (opts->initdata) {
+-        opts->init_data = opts->initdata;
+-        opts->initdata  = NULL;
+-    }
+-
+-    /* If no AVD name was given, try to find the top of the
+-     * Android build tree
+-     */
+-    if (opts->avd == NULL) {
+-        do {
+-            char*  out = getenv("ANDROID_PRODUCT_OUT");
+-
+-            if (out == NULL || out[0] == 0)
+-                break;
+-
+-            if (!path_exists(out)) {
+-                derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n"
+-                    "You need to build the Android system before launching the emulator",
+-                    out);
+-                exit(2);
+-            }
+-
+-            android_build_root = path_parent( out, 4 );
+-            if (android_build_root == NULL || !path_exists(android_build_root)) {
+-                derror("Can't find the Android build root from '%s'\n"
+-                    "Please check the definition of the ANDROID_PRODUCT_OUT variable.\n"
+-                    "It should point to your product-specific build output directory.\n",
+-                    out );
+-                exit(2);
+-            }
+-            android_build_out = out;
+-            D( "found Android build root: %s", android_build_root );
+-            D( "found Android build out:  %s", android_build_out );
+-        } while (0);
+-    }
+     /* if no virtual device name is given, and we're not in the
+      * Android build system, we'll need to perform some auto-detection
+      * magic :-)
+      */
+-    if (opts->avd == NULL && !android_build_out) 
+     {
+-        char   dataDirIsSystem = 0;
+-
+         if (!opts->sysdir) {
+             opts->sysdir = _getSdkImagePath("system.img");
+             if (!opts->sysdir) {
+@@ -1945,47 +1888,30 @@ int main(int argc, char **argv)
+         }
+         if (!opts->system) {
+-            opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");
+-            D("autoconfig: -image %s", opts->image);
++            opts->system = _getSdkSystemImage(opts->sysdir, "-system", "system.img");
++            D("autoconfig: -system %s", opts->system);
+         }
+         if (!opts->kernel) {
+-            opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");
++            opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel.bin");
+             D("autoconfig: -kernel %s", opts->kernel);
+         }
+         if (!opts->ramdisk) {
+-            opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");
++            opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.bin");
+             D("autoconfig: -ramdisk %s", opts->ramdisk);
+         }
+-        /* if no data directory is specified, use the system directory */
+-        if (!opts->datadir) {
+-            opts->datadir   = qemu_strdup(opts->sysdir);
+-            dataDirIsSystem = 1;
+-            D("autoconfig: -datadir %s", opts->sysdir);
+-        }
+-
+         if (!opts->data) {
+             /* check for userdata-qemu.img in the data directory */
+-            bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir);
+-            if (!path_exists(tmp)) {
+-                derror(
+-                "You did not provide the name of an Android Virtual Device\n"
+-                "with the '-avd <name>' option. Read -help-avd for more information.\n\n"
+-
+-                "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n"
+-                "to specify a data partition image file (I hope you know what you're doing).\n"
+-                );
+-                exit(2);
+-            }
++            bufprint(tmp, tmpend, "%s/data.img", opts->sysdir);
+             opts->data = qemu_strdup(tmp);
+             D("autoconfig: -data %s", opts->data);
+         }
+-        if (!opts->sdcard && opts->datadir) {
+-            bufprint(tmp, tmpend, "%s/sdcard.img", opts->datadir);
++        if (!opts->sdcard && opts->sysdir) {
++            bufprint(tmp, tmpend, "%s/sdcard.img", opts->sysdir);
+             if (path_exists(tmp)) {
+                 opts->sdcard = qemu_strdup(tmp);
+                 D("autoconfig: -sdcard %s", opts->sdcard);
+@@ -2029,19 +1955,6 @@ int main(int argc, char **argv)
+     android_avdParams->skinName     = opts->skin;
+     android_avdParams->skinRootPath = opts->skindir;
+-    /* setup the virtual device differently depending on whether
+-     * we are in the Android build system or not
+-     */
+-    if (opts->avd != NULL)
+-    {
+-        android_avdInfo = avdInfo_new( opts->avd, android_avdParams );
+-        if (android_avdInfo == NULL) {
+-            /* an error message has already been printed */
+-            dprint("could not find virtual device named '%s'", opts->avd);
+-            exit(1);
+-        }
+-    }
+-    else
+     {
+         if (!android_build_out) {
+             android_build_out = android_build_root = opts->sysdir;
+--- a/android/avd/info.c
++++ b/android/avd/info.c
+@@ -1233,10 +1233,8 @@ _getBuildImagePaths( AvdInfo*  i, AvdInf
+      ** take care of checking the state
+      **/
+     imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
+-    imageLoader_load( l, IMAGE_REQUIRED | IMAGE_DONT_LOCK );
+-
+-    /* force the system image to read-only status */
+-    l->pState[0] = IMAGE_STATE_READONLY;
++    l->pState[0] = IMAGE_STATE_MUSTLOCK;
++    imageLoader_load( l, IMAGE_REQUIRED );
+     /** cache partition handling
+      **/
diff --git a/utils/goldfish-qemu/skins/HVGA/arrow_down.png b/utils/goldfish-qemu/skins/HVGA/arrow_down.png
new file mode 100644 (file)
index 0000000..19b3764
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/arrow_down.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/arrow_left.png b/utils/goldfish-qemu/skins/HVGA/arrow_left.png
new file mode 100644 (file)
index 0000000..113e584
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/arrow_left.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/arrow_right.png b/utils/goldfish-qemu/skins/HVGA/arrow_right.png
new file mode 100644 (file)
index 0000000..ffe3356
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/arrow_right.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/arrow_up.png b/utils/goldfish-qemu/skins/HVGA/arrow_up.png
new file mode 100644 (file)
index 0000000..81c54df
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/arrow_up.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/back.png b/utils/goldfish-qemu/skins/HVGA/back.png
new file mode 100644 (file)
index 0000000..41034d9
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/back.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/device.png b/utils/goldfish-qemu/skins/HVGA/device.png
new file mode 100644 (file)
index 0000000..465eb02
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/device.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/end.png b/utils/goldfish-qemu/skins/HVGA/end.png
new file mode 100644 (file)
index 0000000..6830a60
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/end.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/home.png b/utils/goldfish-qemu/skins/HVGA/home.png
new file mode 100644 (file)
index 0000000..7d02136
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/home.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/key.png b/utils/goldfish-qemu/skins/HVGA/key.png
new file mode 100644 (file)
index 0000000..7a3f563
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/key.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/keyboard.png b/utils/goldfish-qemu/skins/HVGA/keyboard.png
new file mode 100644 (file)
index 0000000..bb076d3
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/keyboard.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/layout b/utils/goldfish-qemu/skins/HVGA/layout
new file mode 100644 (file)
index 0000000..4c3d764
--- /dev/null
@@ -0,0 +1,380 @@
+parts {
+    device {
+        background {
+            image   device.png
+        }
+        display {
+            width   320
+            height  480
+            x       31
+            y       72
+        }
+
+        buttons {
+            soft-left {
+                    image menu.png
+                    x 147
+                    y 555
+            }
+            home {
+                    image home.png
+                    x 48
+                    y 590
+            }
+            back {
+                    image back.png
+                    x 286
+                    y 590
+            }
+            dpad-up {
+                    image arrow_up.png
+                    x 140
+                    y 595
+            }
+            dpad-down {
+                    image arrow_down.png
+                    x 140
+                    y 656
+            }
+            dpad-left {
+                    image arrow_left.png
+                    x 111
+                    y 598
+            }
+            dpad-right {
+                    image arrow_right.png
+                    x 222
+                    y 598
+            }
+            dpad-center {
+                    image select.png
+                    x 142
+                    y 626
+            }
+            phone-dial {
+                    image send.png
+                    x 48
+                    y 646
+            }
+            phone-hangup {
+                    image end.png
+                    x 286
+                    y 646
+            }
+
+            power {
+                    image power.png
+                    x -38
+                    y 52
+            }
+
+            volume-up {
+                    image volume_up.png
+                    x 362
+                    y 260
+            }
+
+            volume-down {
+                    image volume_down.png
+                    x 362
+                    y 310
+            }
+        }
+    }
+
+    keyboard {
+        background {
+            image   keyboard.png
+        }
+        buttons {
+            1 {
+                image  key.png
+                x  0
+                y  0
+            }
+            2 {
+                image  key.png
+                x 37
+                y 0
+            }
+            3 {
+                image  key.png
+                x 74
+                y 0
+            }
+            4 {
+                image  key.png
+                x 111
+                y 0
+            }
+            5 {
+                image  key.png
+                x 148
+                y 0
+            }
+            6 {
+                image  key.png
+                x 185
+                y 0
+            }
+            7 {
+                image  key.png
+                x 222
+                y 0
+            }
+            8 {
+                image  key.png
+                x 259
+                y 0
+            }
+            9 {
+                image  key.png
+                x 296
+                y 0
+            }
+            0 {
+                image  key.png
+                x 333
+                y 0
+            }
+
+            q {
+                image  key.png
+                x  0
+                y  36
+            }
+            w {
+                image  key.png
+                x 37
+                y 36
+            }
+            e {
+                image  key.png
+                x 74
+                y 36
+            }
+            r {
+                image  key.png
+                x 111
+                y 36
+            }
+            t {
+                image  key.png
+                x 148
+                y 36
+            }
+            y {
+                image  key.png
+                x 185
+                y 36
+            }
+            u {
+                image  key.png
+                x 222
+                y 36
+            }
+            i {
+                image  key.png
+                x 259
+                y 36
+            }
+            o {
+                image  key.png
+                x 296
+                y 36
+            }
+            p {
+                image  key.png
+                x 333
+                y 36
+            }
+
+            a {
+                image  key.png
+                x  0
+                y  72
+            }
+            s {
+                image  key.png
+                x 37
+                y 72
+            }
+            d {
+                image  key.png
+                x 74
+                y 72
+            }
+            f {
+                image  key.png
+                x 111
+                y 72
+            }
+            g {
+                image  key.png
+                x 148
+                y 72
+            }
+            h {
+                image  key.png
+                x 185
+                y 72
+            }
+            j {
+                image  key.png
+                x 222
+                y 72
+            }
+            k {
+                image  key.png
+                x 259
+                y 72
+            }
+            l {
+                image  key.png
+                x 296
+                y 72
+            }
+            DEL {
+                image  key.png
+                x 333
+                y 72
+            }
+
+            CAP {
+                image  key.png
+                x  0
+                y  108
+            }
+            z {
+                image  key.png
+                x 37
+                y 108
+            }
+            x {
+                image  key.png
+                x 74
+                y 108
+            }
+            c {
+                image  key.png
+                x 111
+                y 108
+            }
+            v {
+                image  key.png
+                x 148
+                y 108
+            }
+            b {
+                image  key.png
+                x 185
+                y 108
+            }
+            n {
+                image  key.png
+                x 222
+                y 108
+            }
+            m {
+                image  key.png
+                x 259
+                y 108
+            }
+            PERIOD {
+                image  key.png
+                x 296
+                y 108
+            }
+            ENTER {
+                image  key.png
+                x 333
+                y 108
+            }
+
+            ALT {
+                image  key.png
+                x  0
+                y  144
+            }
+            SYM {
+                image  key.png
+                x 37
+                y 144
+            }
+            AT {
+                image  key.png
+                x 74
+                y 144
+            }
+            SPACE {
+                image  spacebar.png
+                x 111
+                y 144
+            }
+            SLASH {
+                image  key.png
+                x 259
+                y 144
+            }
+            COMMA {
+                image  key.png
+                x 296
+                y 144
+            }
+            ALT2 {
+                image  key.png
+                x 333
+                y 144
+            }
+
+        }
+    }
+}
+
+layouts {
+    portrait {
+        width     900
+        height    730
+        color     0xe0e0e0
+        event     EV_SW:0:1
+
+        part1 {
+            name    device
+            x       40
+            y       -18
+        }
+        part2 {
+            name    keyboard
+            x       480
+            y       200
+        }
+    }
+
+    landscape {
+        width     900
+        height    670
+        color     0xe0e0e0
+        event     EV_SW:0:0
+
+        part1 {
+            name      device
+            x         50
+            y         440
+            rotation  3
+        }
+        part2 {
+            name     keyboard
+            x        250
+            y        470
+        }
+    }
+}
+
+keyboard {
+    charmap qwerty2
+}
+
+network {
+    speed  full
+    delay  none
+}
diff --git a/utils/goldfish-qemu/skins/HVGA/menu.png b/utils/goldfish-qemu/skins/HVGA/menu.png
new file mode 100644 (file)
index 0000000..e81d8ab
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/menu.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/power.png b/utils/goldfish-qemu/skins/HVGA/power.png
new file mode 100644 (file)
index 0000000..5894288
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/power.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/select.png b/utils/goldfish-qemu/skins/HVGA/select.png
new file mode 100644 (file)
index 0000000..803d493
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/select.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/send.png b/utils/goldfish-qemu/skins/HVGA/send.png
new file mode 100644 (file)
index 0000000..f547c88
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/send.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/spacebar.png b/utils/goldfish-qemu/skins/HVGA/spacebar.png
new file mode 100644 (file)
index 0000000..19fe604
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/spacebar.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/volume_down.png b/utils/goldfish-qemu/skins/HVGA/volume_down.png
new file mode 100644 (file)
index 0000000..f8a88de
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/volume_down.png differ
diff --git a/utils/goldfish-qemu/skins/HVGA/volume_up.png b/utils/goldfish-qemu/skins/HVGA/volume_up.png
new file mode 100644 (file)
index 0000000..940457f
Binary files /dev/null and b/utils/goldfish-qemu/skins/HVGA/volume_up.png differ
diff --git a/utils/ps3-utils/Makefile b/utils/ps3-utils/Makefile
new file mode 100644 (file)
index 0000000..3d3ea1b
--- /dev/null
@@ -0,0 +1,70 @@
+#
+# Copyright (C) 2008-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ps3-utils
+PKG_REV:=6488134e48cf2d6f2d6471ced8346ac8cb1b855a
+PKG_VERSION:=20090320
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=git://git.kernel.org/pub/scm/linux/kernel/git/geoff/ps3-utils.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=$(PKG_REV)
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ps3-utils
+       SECTION:=utils
+       CATEGORY:=Utilities
+       TITLE:=PS3 Linux Utilities
+       URL:=http://kernel.org/pub/linux/kernel/people/geoff/cell/ps3-utils/
+       MAINTAINER:=Geoff Levand <geoffrey.levand@am.sony.com>
+       DEPENDS:=@TARGET_ps3||TARGET_ps3chk||TARGET_powerpc
+endef
+
+define Package/ps3-utils/description
+     The ps3-utils package is a set of system administration utilites for the
+     PS3 game console.
+endef
+
+define Build/Configure
+       (cd $(PKG_BUILD_DIR) && $(BASH) -x ./bootstrap)
+       $(call Build/Configure/Default)
+endef
+
+define Build/InstallDev
+       $(INSTALL_DIR) $(1)/usr/include
+       $(INSTALL_DATA) \
+               $(PKG_INSTALL_DIR)/usr/include/ps3*.h \
+               $(1)/usr/include
+
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(INSTALL_BIN) \
+               $(PKG_INSTALL_DIR)/usr/lib/libps3-utils.{la,a,so*} \
+               $(1)/usr/lib/
+endef
+
+define Package/ps3-utils/install
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(INSTALL_DIR) $(1)/usr/lib
+
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ps3-boot-game-os $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ps3-dump-bootloader $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ps3-flash-util $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/ps3-video-mode $(1)/usr/bin
+
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libps3-utils.so.* $(1)/usr/lib
+endef
+
+$(eval $(call BuildPackage,ps3-utils))
diff --git a/utils/redboot-ar231x/Makefile b/utils/redboot-ar231x/Makefile
new file mode 100644 (file)
index 0000000..b07b5a3
--- /dev/null
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=redboot-ar231x
+PKG_VERSION:=2010-10-26
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_TARGETS:=bin
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=git://nbd.name/redboot-ar231x.git
+PKG_SOURCE_VERSION:=327f02ce1645d3427f26cf8116353332c81564a9
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.bz2
+
+include $(INCLUDE_DIR)/package.mk
+
+export GCC_HONOUR_COPTS=s
+
+define Package/redboot-ar231x
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  DEPENDS:=@TARGET_atheros @BROKEN
+  TITLE:=Tiny redboot for AR231x/AR531x
+endef
+
+define Build/Configure
+       mkdir -p $(PKG_BUILD_DIR)/host-build
+       if [ \! -x $(PKG_BUILD_DIR)/host-install/bin/ecosconfig ]; then ( \
+               cd $(PKG_BUILD_DIR)/host-build; \
+               ../ecos/host/configure \
+                       --prefix=$(PKG_BUILD_DIR)/host-install \
+                       --exec-prefix=$(PKG_BUILD_DIR)/host-install; \
+               CFLAGS="$(HOST_CFLAGS)" $(MAKE) all install; \
+       ) fi
+endef
+
+define Build/Compile
+       $(MAKE) -C $(PKG_BUILD_DIR) all
+endef
+
+define Package/redboot-ar231x/install
+       $(CP) $(PKG_BUILD_DIR)/bin/* $(1)/
+endef
+
+$(eval $(call BuildPackage,redboot-ar231x))
diff --git a/utils/redboot-ar231x/patches/010-fix-compile.patch b/utils/redboot-ar231x/patches/010-fix-compile.patch
new file mode 100644 (file)
index 0000000..962b133
--- /dev/null
@@ -0,0 +1,181 @@
+--- a/ecos/packages/hal/mips/ap30/current/cdl/hal_mips_ap30.cdl
++++ b/ecos/packages/hal/mips/ap30/current/cdl/hal_mips_ap30.cdl
+@@ -98,7 +98,7 @@ cdl_package CYGPKG_HAL_MIPS_AP30 {\r
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<\r
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@\r
+         @echo $@ ": \\" > $(notdir $@).deps\r
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps\r
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps\r
+         @echo >> $(notdir $@).deps\r
+         @rm plf_defs.tmp plf_mk_defs.tmp\r
+     }\r
+--- a/ecos/packages/hal/mips/ap43/current/cdl/hal_mips_ap43.cdl
++++ b/ecos/packages/hal/mips/ap43/current/cdl/hal_mips_ap43.cdl
+@@ -98,7 +98,7 @@ cdl_package CYGPKG_HAL_MIPS_AP43 {\r
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<\r
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@\r
+         @echo $@ ": \\" > $(notdir $@).deps\r
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps\r
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps\r
+         @echo >> $(notdir $@).deps\r
+         @rm plf_defs.tmp plf_mk_defs.tmp\r
+     }\r
+--- a/ecos/packages/hal/mips/ap48/current/cdl/hal_mips_ap48.cdl
++++ b/ecos/packages/hal/mips/ap48/current/cdl/hal_mips_ap48.cdl
+@@ -98,7 +98,7 @@ cdl_package CYGPKG_HAL_MIPS_AP48 {\r
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<\r
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@\r
+         @echo $@ ": \\" > $(notdir $@).deps\r
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps\r
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps\r
+         @echo >> $(notdir $@).deps\r
+         @rm plf_defs.tmp plf_mk_defs.tmp\r
+     }\r
+--- a/ecos/packages/hal/mips/ap51/current/cdl/hal_mips_ap51.cdl
++++ b/ecos/packages/hal/mips/ap51/current/cdl/hal_mips_ap51.cdl
+@@ -93,7 +93,7 @@ cdl_package CYGPKG_HAL_MIPS_AP51 {
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@
+         @echo $@ ": \\" > $(notdir $@).deps
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps
+         @echo >> $(notdir $@).deps
+         @rm plf_defs.tmp plf_mk_defs.tmp
+     }
+--- a/ecos/packages/hal/mips/ap53/current/cdl/hal_mips_ap53.cdl
++++ b/ecos/packages/hal/mips/ap53/current/cdl/hal_mips_ap53.cdl
+@@ -93,7 +93,7 @@ cdl_package CYGPKG_HAL_MIPS_AP53 {
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@
+         @echo $@ ": \\" > $(notdir $@).deps
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps
+         @echo >> $(notdir $@).deps
+         @rm plf_defs.tmp plf_mk_defs.tmp
+     }
+--- a/ecos/packages/hal/mips/ap61/current/cdl/hal_mips_ap61.cdl
++++ b/ecos/packages/hal/mips/ap61/current/cdl/hal_mips_ap61.cdl
+@@ -93,7 +93,7 @@ cdl_package CYGPKG_HAL_MIPS_AP61 {
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@
+         @echo $@ ": \\" > $(notdir $@).deps
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps
+         @echo >> $(notdir $@).deps
+         @rm plf_defs.tmp plf_mk_defs.tmp
+     }
+--- a/ecos/packages/hal/mips/ap65/current/cdl/hal_mips_ap65.cdl
++++ b/ecos/packages/hal/mips/ap65/current/cdl/hal_mips_ap65.cdl
+@@ -93,7 +93,7 @@ cdl_package CYGPKG_HAL_MIPS_AP65 {
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@
+         @echo $@ ": \\" > $(notdir $@).deps
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps
+         @echo >> $(notdir $@).deps
+         @rm plf_defs.tmp plf_mk_defs.tmp
+     }
+--- a/ecos/packages/hal/mips/pb32/current/cdl/hal_mips_pb32.cdl
++++ b/ecos/packages/hal/mips/pb32/current/cdl/hal_mips_pb32.cdl
+@@ -91,7 +91,7 @@ cdl_package CYGPKG_HAL_MIPS_PB32 {
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@
+         @echo $@ ": \\" > $(notdir $@).deps
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps
+         @echo >> $(notdir $@).deps
+         @rm plf_defs.tmp plf_mk_defs.tmp
+     }
+--- a/ecos/packages/hal/mips/pb44/current/cdl/hal_mips_pb44.cdl
++++ b/ecos/packages/hal/mips/pb44/current/cdl/hal_mips_pb44.cdl
+@@ -99,7 +99,7 @@ cdl_package CYGPKG_HAL_MIPS_PB44 {
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@
+         @echo $@ ": \\" > $(notdir $@).deps
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps
+         @echo >> $(notdir $@).deps
+         @rm plf_defs.tmp plf_mk_defs.tmp
+     }
+--- a/ecos/packages/hal/mips/pb45/current/cdl/hal_mips_pb45.cdl
++++ b/ecos/packages/hal/mips/pb45/current/cdl/hal_mips_pb45.cdl
+@@ -99,7 +99,7 @@ cdl_package CYGPKG_HAL_MIPS_PB45 {
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@
+         @echo $@ ": \\" > $(notdir $@).deps
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps
+         @echo >> $(notdir $@).deps
+         @rm plf_defs.tmp plf_mk_defs.tmp
+     }
+--- a/ecos/packages/hal/mips/tb225/current/cdl/hal_mips_tb225.cdl
++++ b/ecos/packages/hal/mips/tb225/current/cdl/hal_mips_tb225.cdl
+@@ -99,7 +99,7 @@ cdl_package CYGPKG_HAL_MIPS_TB225 {\r
+         $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,plf_defs.tmp -o plf_mk_defs.tmp -S $<\r
+         fgrep .equ plf_mk_defs.tmp | sed s/#// > $@\r
+         @echo $@ ": \\" > $(notdir $@).deps\r
+-        @tail +2 plf_defs.tmp >> $(notdir $@).deps\r
++        @tail -n +2 plf_defs.tmp >> $(notdir $@).deps\r
+         @echo >> $(notdir $@).deps\r
+         @rm plf_defs.tmp plf_mk_defs.tmp\r
+     }\r
+--- a/ecos/host/tools/configtool/standalone/common/cdl_exec.cxx
++++ b/ecos/host/tools/configtool/standalone/common/cdl_exec.cxx
+@@ -51,6 +51,7 @@
+ #endif
+ #include "build.hxx"
+ #include "cdl_exec.hxx"
++#include <linux/limits.h>
+ // ----------------------------------------------------------------------------
+ bool cdl_exec::quiet            = false;
+--- a/ecos/host/tools/configtool/standalone/common/ecosconfig.cxx
++++ b/ecos/host/tools/configtool/standalone/common/ecosconfig.cxx
+@@ -50,6 +50,7 @@
+ #endif
+ #include "cdl_exec.hxx"
+ #include "ecosconfig.hxx"
++#include <cstring>
+ #define TOOL_VERSION "2.net"
+ #define TOOL_COPYRIGHT "Copyright (c) 2002 Red Hat, Inc."
+--- a/ecos/host/libcdl/build.cxx
++++ b/ecos/host/libcdl/build.cxx
+@@ -57,6 +57,7 @@
+ // It implicitly supplies <string>, <vector> and <map> because
+ // the class definitions rely on these headers.
+ #include <cdlcore.hxx>
++#include <cstring>
+ //}}}
+--- a/ecos/host/libcdl/parse.cxx
++++ b/ecos/host/libcdl/parse.cxx
+@@ -58,6 +58,7 @@
+ // It implicitly supplies <string>, <vector> and <map> because
+ // the class definitions rely on these headers.
+ #include <cdlcore.hxx>
++#include <cstring> 
+ //}}}
+--- a/ecos/host/libcdl/cdlmisc.cxx
++++ b/ecos/host/libcdl/cdlmisc.cxx
+@@ -66,6 +66,7 @@
+ // For access to strtod()
+ #include <cstdlib>
++#include <cstring> 
+ // strtod() involves errno...
+ #include <cerrno>
+--- a/ecos/host/infra/assert.cxx
++++ b/ecos/host/infra/assert.cxx
+@@ -61,6 +61,7 @@
+ // STDLIB is needed for exit() and the status codes.
+ #include <cstdio>
+ #include <cstdlib>
++#include <cstring>
+ #if defined(__unix__) || defined(__CYGWIN32__)
+ extern "C" {