From c9df9a2a76346096f134585c5028f4bb160f7b25 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 7 Oct 2012 12:50:15 +0000 Subject: [PATCH] move a few unmaintained packages from trunk to /packages SVN-Revision: 33634 --- libs/libipfix/Makefile | 47 + libs/libipfix/extra/append-wprobe-ie.pl | 38 + libs/libipfix/extra/wprobe-ie.txt | 14 + libs/libipfix/patches/100-openimp_sync.patch | 474 ++++ libs/libipfix/patches/110-wprobe_ie.patch | 44 + libs/libipfix/patches/120-ipfixmisc.patch | 27 + net/bridge-utils/Makefile | 51 + .../patches/001-libbridge_cflags.patch | 11 + net/crda/Makefile | 74 + net/crda/files/hotplug.rule | 6 + .../101-make_crypto_use_optional.patch | 13 + net/madwifi/Config.in | 55 + net/madwifi/Makefile | 266 ++ .../files/etc/hotplug.d/net/10-madwifi | 12 + net/madwifi/files/lib/wifi/madwifi.sh | 498 ++++ .../files/lib/wifi/madwifi_countrycodes.txt | 239 ++ .../patches/102-multicall_binary.patch | 315 +++ net/madwifi/patches/104-autocreate_none.patch | 11 + net/madwifi/patches/105-ratectl_attach.patch | 23 + net/madwifi/patches/106-get_arch.patch | 21 + net/madwifi/patches/111-minstrel_crash.patch | 12 + net/madwifi/patches/113-no_ibss_pwrsave.patch | 12 + .../patches/122-replayfail_workaround.patch | 12 + net/madwifi/patches/123-ccmp_checks.patch | 95 + net/madwifi/patches/124-linux24_compat.patch | 202 ++ net/madwifi/patches/126-rxerr_frames.patch | 13 + net/madwifi/patches/200-no_debug.patch | 408 +++ net/madwifi/patches/201-debug_fix.patch | 20 + net/madwifi/patches/202-debug_variables.patch | 204 ++ net/madwifi/patches/300-napi_polling.patch | 536 ++++ net/madwifi/patches/305-pureg_fix.patch | 168 ++ net/madwifi/patches/309-micfail_detect.patch | 321 +++ net/madwifi/patches/310-noise_get.patch | 55 + net/madwifi/patches/311-bssid_alloc.patch | 11 + net/madwifi/patches/312-erpupdate.patch | 68 + net/madwifi/patches/317-bmask.patch | 13 + net/madwifi/patches/323-dfs_optional.patch | 38 + net/madwifi/patches/324-alignment.patch | 19 + net/madwifi/patches/325-channel_spam.patch | 28 + net/madwifi/patches/327-queue.patch | 40 + net/madwifi/patches/330-beaconcal.patch | 166 ++ net/madwifi/patches/331-memory_alloc.patch | 36 + net/madwifi/patches/332-reset_beacons.patch | 11 + net/madwifi/patches/333-apscan_mode.patch | 15 + net/madwifi/patches/334-input.patch | 12 + net/madwifi/patches/340-maxrate.patch | 98 + net/madwifi/patches/341-minrate.patch | 114 + net/madwifi/patches/342-performance.patch | 263 ++ net/madwifi/patches/343-txqueue_races.patch | 34 + .../patches/344-minstrel_failcnt.patch | 11 + .../patches/345-minstrel_sampling.patch | 80 + net/madwifi/patches/346-protmode_trig.patch | 135 + net/madwifi/patches/347-tuning.patch | 99 + net/madwifi/patches/348-ackcts.patch | 38 + net/madwifi/patches/349-reset.patch | 12 + net/madwifi/patches/350-wisoc_softled.patch | 11 + net/madwifi/patches/351-scanlist.patch | 904 +++++++ net/madwifi/patches/352-ani_fix.patch | 265 ++ net/madwifi/patches/353-devid.patch | 19 + net/madwifi/patches/354-lantiq_eeprom.patch | 95 + .../patches/355-eap_auth_disassoc.patch | 77 + net/madwifi/patches/356-hidden_ssid.patch | 49 + net/madwifi/patches/357-bgscan_thresh.patch | 160 ++ .../patches/358-ignore_broken_bssid.patch | 18 + net/madwifi/patches/359-disable_reassoc.patch | 31 + net/madwifi/patches/360-sta_nodes.patch | 242 ++ net/madwifi/patches/361-bmiss_handling.patch | 102 + net/madwifi/patches/362-rssithr.patch | 93 + net/madwifi/patches/363-fix_turbo.patch | 11 + net/madwifi/patches/364-memory_alloc.patch | 13 + .../patches/365-turbo_channelsearch.patch | 10 + net/madwifi/patches/366-bstuck_thresh.patch | 52 + net/madwifi/patches/367-roaming.patch | 77 + net/madwifi/patches/368-sta_ie_preserve.patch | 49 + net/madwifi/patches/369-mlme_assoc.patch | 10 + net/madwifi/patches/370-wdsvap.patch | 1665 ++++++++++++ net/madwifi/patches/372-queue_vif.patch | 39 + net/madwifi/patches/373-sanity_check.patch | 12 + net/madwifi/patches/374-nbtt_fix.patch | 22 + net/madwifi/patches/375-atim_tsf_update.patch | 141 + .../patches/377-disable_vlan_code.patch | 25 + net/madwifi/patches/378-adhoc_crash_fix.patch | 14 + .../patches/379-invalid_rate_fix.patch | 405 +++ net/madwifi/patches/380-noderef_hack.patch | 13 + net/madwifi/patches/381-ibss_modes.patch | 23 + net/madwifi/patches/382-relax_bintval.patch | 13 + net/madwifi/patches/383-ibss_hostap.patch | 105 + net/madwifi/patches/384-hwdetect.patch | 325 +++ net/madwifi/patches/385-antenna_fix.patch | 10 + net/madwifi/patches/386-acl_crashfix.patch | 116 + net/madwifi/patches/387-maxassoc.patch | 85 + net/madwifi/patches/388-apsta_fix.patch | 60 + net/madwifi/patches/389-autochannel.patch | 249 ++ net/madwifi/patches/390-frame_type.patch | 13 + net/madwifi/patches/391-vap_auth.patch | 29 + .../patches/392-remove_wds_nodetracking.patch | 388 +++ net/madwifi/patches/393-mbss_vap_auth.patch | 491 ++++ net/madwifi/patches/394-probereq.patch | 64 + net/madwifi/patches/395-ath_ff_unmap.patch | 11 + net/madwifi/patches/396-napi_ff_fix.patch | 65 + net/madwifi/patches/400-new_hal.patch | 153 ++ net/madwifi/patches/401-changeset_r3602.patch | 11 + net/madwifi/patches/402-changeset_r3603.patch | 176 ++ net/madwifi/patches/403-changeset_r3605.patch | 70 + net/madwifi/patches/404-linux24_fix.patch | 15 + .../patches/405-retransmit_check.patch | 22 + net/madwifi/patches/406-monitor_r3711.patch | 20 + net/madwifi/patches/407-new_athinfo.patch | 2352 +++++++++++++++++ net/madwifi/patches/408-changeset_r3337.patch | 34 + net/madwifi/patches/409-wext_compat.patch | 133 + net/madwifi/patches/410-ar231x_2.6.28.patch | 281 ++ .../patches/411-autochannel_multi.patch | 347 +++ .../patches/412-fragmentation_fix.patch | 10 + net/madwifi/patches/413-rxorn.patch | 31 + net/madwifi/patches/414-txpower.patch | 262 ++ net/madwifi/patches/415-chan_switch.patch | 187 ++ net/madwifi/patches/416-wprobe.patch | 549 ++++ net/madwifi/patches/417-beacon_txpower.patch | 81 + net/madwifi/patches/419-skb_unmap_crash.patch | 20 + net/madwifi/patches/420-diversity_fix.patch | 86 + .../patches/421-channel_handling.patch | 1351 ++++++++++ .../patches/422-confchange_reset.patch | 31 + net/madwifi/patches/423-phyerr_handling.patch | 28 + net/madwifi/patches/424-timing.patch | 764 ++++++ net/madwifi/patches/425-rc_rexmit.patch | 506 ++++ net/madwifi/patches/426-header_len.patch | 12 + .../patches/427-ignore_eeprom_ff.patch | 11 + net/madwifi/patches/430-use_netdev_priv.patch | 1936 ++++++++++++++ net/madwifi/patches/431-compile_fixes.patch | 35 + net/madwifi/patches/432-netdev_ops.patch | 184 ++ .../433-backport_remove_irq_none.patch | 21 + net/madwifi/patches/434-name-alloc-fix.patch | 28 + .../patches/435-ibss_neighbor_fix.patch | 11 + .../patches/436-injection_checks.patch | 26 + net/madwifi/patches/437-sysctl_cleanup.patch | 73 + .../patches/438-poweroffset_sysctl.patch | 59 + .../patches/439-wlanconfig_stack_usage.patch | 20 + net/madwifi/patches/440-wme_cleanup.patch | 136 + .../patches/441-fix_ibss_node_handling.patch | 91 + net/madwifi/patches/442-ibss_rx_filter.patch | 20 + net/madwifi/patches/443-tx_drop_counter.patch | 25 + .../patches/444-beacon_update_war.patch | 17 + .../patches/445-fix_ps_sta_count.patch | 18 + net/madwifi/patches/446-single_module.patch | 778 ++++++ net/madwifi/patches/447-sta_reconnect.patch | 25 + .../patches/448-beacon_handling_fixes.patch | 407 +++ net/madwifi/patches/449-fix_txbuf_leak.patch | 10 + net/madwifi/patches/450-calibration.patch | 177 ++ net/madwifi/patches/451-ibss_race_fix.patch | 342 +++ .../patches/452-minstrel_no_timer.patch | 134 + net/madwifi/patches/453-procps.patch | 55 + net/madwifi/patches/454-cca.patch | 186 ++ net/madwifi/patches/455-beacon_watchdog.patch | 95 + net/madwifi/patches/456-rfsilent.patch | 85 + net/madwifi/patches/457-idletime.patch | 151 ++ net/madwifi/patches/458-ibss_wpa_none.patch | 13 + net/madwifi/patches/459-2.6.33_compile.patch | 524 ++++ .../patches/460-pci_softled_disable.patch | 18 + .../patches/461-rx_stats_count_fix.patch | 23 + net/madwifi/patches/462-fix_ap_scan.patch | 26 + .../patches/463-fix_txrate_display.patch | 10 + .../patches/464-0dbm_txpower_fix.patch | 30 + net/madwifi/patches/465-mc_list-2.6.35.patch | 40 + net/madwifi/patches/466-2.6.38_compile.patch | 14 + ...ac_addresss_from_ath5k_platform_data.patch | 36 + .../patches/471-netdev_ops_mac_mtu.patch | 30 + .../patches/472-remove_11n_devids.patch | 20 + net/madwifi/patches/473-mutex_fix.patch | 11 + .../patches/474_fix_ssid_scan_length.patch | 29 + net/madwifi/patches/475-2.6.39-compile.patch | 11 + .../patches/476-3.0_detection_fix.patch | 25 + net/madwifi/patches/477-3.2_fixes.patch | 45 + .../patches/478-remove_vlan_code.patch | 21 + net/siit/Makefile | 40 + net/siit/src/Makefile | 5 + net/siit/src/siit.c | 1478 +++++++++++ net/siit/src/siit.h | 61 + net/wprobe/Makefile | 143 + net/wprobe/files/wprobe.config | 10 + net/wprobe/files/wprobe.init | 72 + net/wprobe/src/Makefile.inc | 12 + net/wprobe/src/exporter/Makefile | 5 + net/wprobe/src/exporter/wprobe-export.c | 304 +++ net/wprobe/src/exporter/wprobe-export.h | 34 + net/wprobe/src/filter/README.txt | 1 + net/wprobe/src/filter/gen_filter.pl | 63 + net/wprobe/src/filter/pfc.c | 58 + net/wprobe/src/kernel/Makefile | 5 + net/wprobe/src/kernel/linux/wprobe.h | 397 +++ net/wprobe/src/kernel/wprobe-core.c | 1164 ++++++++ net/wprobe/src/kernel/wprobe-dummy.c | 96 + net/wprobe/src/user/Makefile | 38 + net/wprobe/src/user/list.h | 601 +++++ net/wprobe/src/user/wprobe-lib.c | 1210 +++++++++ net/wprobe/src/user/wprobe-util.c | 450 ++++ net/wprobe/src/user/wprobe.h | 213 ++ utils/goldfish-qemu/Makefile | 70 + .../patches/100-darwin_fix.patch | 30 + .../patches/110-single_image.patch | 233 ++ utils/goldfish-qemu/skins/HVGA/arrow_down.png | Bin 0 -> 3438 bytes utils/goldfish-qemu/skins/HVGA/arrow_left.png | Bin 0 -> 4122 bytes .../goldfish-qemu/skins/HVGA/arrow_right.png | Bin 0 -> 4147 bytes utils/goldfish-qemu/skins/HVGA/arrow_up.png | Bin 0 -> 3493 bytes utils/goldfish-qemu/skins/HVGA/back.png | Bin 0 -> 3564 bytes utils/goldfish-qemu/skins/HVGA/device.png | Bin 0 -> 45511 bytes utils/goldfish-qemu/skins/HVGA/end.png | Bin 0 -> 3562 bytes utils/goldfish-qemu/skins/HVGA/home.png | Bin 0 -> 3578 bytes utils/goldfish-qemu/skins/HVGA/key.png | Bin 0 -> 2857 bytes utils/goldfish-qemu/skins/HVGA/keyboard.png | Bin 0 -> 11032 bytes utils/goldfish-qemu/skins/HVGA/layout | 380 +++ utils/goldfish-qemu/skins/HVGA/menu.png | Bin 0 -> 3079 bytes utils/goldfish-qemu/skins/HVGA/power.png | Bin 0 -> 3782 bytes utils/goldfish-qemu/skins/HVGA/select.png | Bin 0 -> 3374 bytes utils/goldfish-qemu/skins/HVGA/send.png | Bin 0 -> 3561 bytes utils/goldfish-qemu/skins/HVGA/spacebar.png | Bin 0 -> 2916 bytes .../goldfish-qemu/skins/HVGA/volume_down.png | Bin 0 -> 3586 bytes utils/goldfish-qemu/skins/HVGA/volume_up.png | Bin 0 -> 3856 bytes utils/ps3-utils/Makefile | 70 + utils/redboot-ar231x/Makefile | 52 + .../patches/010-fix-compile.patch | 181 ++ 220 files changed, 33399 insertions(+) create mode 100644 libs/libipfix/Makefile create mode 100644 libs/libipfix/extra/append-wprobe-ie.pl create mode 100644 libs/libipfix/extra/wprobe-ie.txt create mode 100644 libs/libipfix/patches/100-openimp_sync.patch create mode 100644 libs/libipfix/patches/110-wprobe_ie.patch create mode 100644 libs/libipfix/patches/120-ipfixmisc.patch create mode 100644 net/bridge-utils/Makefile create mode 100644 net/bridge-utils/patches/001-libbridge_cflags.patch create mode 100644 net/crda/Makefile create mode 100644 net/crda/files/hotplug.rule create mode 100644 net/crda/patches/101-make_crypto_use_optional.patch create mode 100644 net/madwifi/Config.in create mode 100644 net/madwifi/Makefile create mode 100644 net/madwifi/files/etc/hotplug.d/net/10-madwifi create mode 100755 net/madwifi/files/lib/wifi/madwifi.sh create mode 100644 net/madwifi/files/lib/wifi/madwifi_countrycodes.txt create mode 100644 net/madwifi/patches/102-multicall_binary.patch create mode 100644 net/madwifi/patches/104-autocreate_none.patch create mode 100644 net/madwifi/patches/105-ratectl_attach.patch create mode 100644 net/madwifi/patches/106-get_arch.patch create mode 100644 net/madwifi/patches/111-minstrel_crash.patch create mode 100644 net/madwifi/patches/113-no_ibss_pwrsave.patch create mode 100644 net/madwifi/patches/122-replayfail_workaround.patch create mode 100644 net/madwifi/patches/123-ccmp_checks.patch create mode 100644 net/madwifi/patches/124-linux24_compat.patch create mode 100644 net/madwifi/patches/126-rxerr_frames.patch create mode 100644 net/madwifi/patches/200-no_debug.patch create mode 100644 net/madwifi/patches/201-debug_fix.patch create mode 100644 net/madwifi/patches/202-debug_variables.patch create mode 100644 net/madwifi/patches/300-napi_polling.patch create mode 100644 net/madwifi/patches/305-pureg_fix.patch create mode 100644 net/madwifi/patches/309-micfail_detect.patch create mode 100644 net/madwifi/patches/310-noise_get.patch create mode 100644 net/madwifi/patches/311-bssid_alloc.patch create mode 100644 net/madwifi/patches/312-erpupdate.patch create mode 100644 net/madwifi/patches/317-bmask.patch create mode 100644 net/madwifi/patches/323-dfs_optional.patch create mode 100644 net/madwifi/patches/324-alignment.patch create mode 100644 net/madwifi/patches/325-channel_spam.patch create mode 100644 net/madwifi/patches/327-queue.patch create mode 100644 net/madwifi/patches/330-beaconcal.patch create mode 100644 net/madwifi/patches/331-memory_alloc.patch create mode 100644 net/madwifi/patches/332-reset_beacons.patch create mode 100644 net/madwifi/patches/333-apscan_mode.patch create mode 100644 net/madwifi/patches/334-input.patch create mode 100644 net/madwifi/patches/340-maxrate.patch create mode 100644 net/madwifi/patches/341-minrate.patch create mode 100644 net/madwifi/patches/342-performance.patch create mode 100644 net/madwifi/patches/343-txqueue_races.patch create mode 100644 net/madwifi/patches/344-minstrel_failcnt.patch create mode 100644 net/madwifi/patches/345-minstrel_sampling.patch create mode 100644 net/madwifi/patches/346-protmode_trig.patch create mode 100644 net/madwifi/patches/347-tuning.patch create mode 100644 net/madwifi/patches/348-ackcts.patch create mode 100644 net/madwifi/patches/349-reset.patch create mode 100644 net/madwifi/patches/350-wisoc_softled.patch create mode 100644 net/madwifi/patches/351-scanlist.patch create mode 100644 net/madwifi/patches/352-ani_fix.patch create mode 100644 net/madwifi/patches/353-devid.patch create mode 100644 net/madwifi/patches/354-lantiq_eeprom.patch create mode 100644 net/madwifi/patches/355-eap_auth_disassoc.patch create mode 100644 net/madwifi/patches/356-hidden_ssid.patch create mode 100644 net/madwifi/patches/357-bgscan_thresh.patch create mode 100644 net/madwifi/patches/358-ignore_broken_bssid.patch create mode 100644 net/madwifi/patches/359-disable_reassoc.patch create mode 100644 net/madwifi/patches/360-sta_nodes.patch create mode 100644 net/madwifi/patches/361-bmiss_handling.patch create mode 100644 net/madwifi/patches/362-rssithr.patch create mode 100644 net/madwifi/patches/363-fix_turbo.patch create mode 100644 net/madwifi/patches/364-memory_alloc.patch create mode 100644 net/madwifi/patches/365-turbo_channelsearch.patch create mode 100644 net/madwifi/patches/366-bstuck_thresh.patch create mode 100644 net/madwifi/patches/367-roaming.patch create mode 100644 net/madwifi/patches/368-sta_ie_preserve.patch create mode 100644 net/madwifi/patches/369-mlme_assoc.patch create mode 100644 net/madwifi/patches/370-wdsvap.patch create mode 100644 net/madwifi/patches/372-queue_vif.patch create mode 100644 net/madwifi/patches/373-sanity_check.patch create mode 100644 net/madwifi/patches/374-nbtt_fix.patch create mode 100644 net/madwifi/patches/375-atim_tsf_update.patch create mode 100644 net/madwifi/patches/377-disable_vlan_code.patch create mode 100644 net/madwifi/patches/378-adhoc_crash_fix.patch create mode 100644 net/madwifi/patches/379-invalid_rate_fix.patch create mode 100644 net/madwifi/patches/380-noderef_hack.patch create mode 100644 net/madwifi/patches/381-ibss_modes.patch create mode 100644 net/madwifi/patches/382-relax_bintval.patch create mode 100644 net/madwifi/patches/383-ibss_hostap.patch create mode 100644 net/madwifi/patches/384-hwdetect.patch create mode 100644 net/madwifi/patches/385-antenna_fix.patch create mode 100644 net/madwifi/patches/386-acl_crashfix.patch create mode 100644 net/madwifi/patches/387-maxassoc.patch create mode 100644 net/madwifi/patches/388-apsta_fix.patch create mode 100644 net/madwifi/patches/389-autochannel.patch create mode 100644 net/madwifi/patches/390-frame_type.patch create mode 100644 net/madwifi/patches/391-vap_auth.patch create mode 100644 net/madwifi/patches/392-remove_wds_nodetracking.patch create mode 100644 net/madwifi/patches/393-mbss_vap_auth.patch create mode 100644 net/madwifi/patches/394-probereq.patch create mode 100644 net/madwifi/patches/395-ath_ff_unmap.patch create mode 100644 net/madwifi/patches/396-napi_ff_fix.patch create mode 100644 net/madwifi/patches/400-new_hal.patch create mode 100644 net/madwifi/patches/401-changeset_r3602.patch create mode 100644 net/madwifi/patches/402-changeset_r3603.patch create mode 100644 net/madwifi/patches/403-changeset_r3605.patch create mode 100644 net/madwifi/patches/404-linux24_fix.patch create mode 100644 net/madwifi/patches/405-retransmit_check.patch create mode 100644 net/madwifi/patches/406-monitor_r3711.patch create mode 100644 net/madwifi/patches/407-new_athinfo.patch create mode 100644 net/madwifi/patches/408-changeset_r3337.patch create mode 100644 net/madwifi/patches/409-wext_compat.patch create mode 100644 net/madwifi/patches/410-ar231x_2.6.28.patch create mode 100644 net/madwifi/patches/411-autochannel_multi.patch create mode 100644 net/madwifi/patches/412-fragmentation_fix.patch create mode 100644 net/madwifi/patches/413-rxorn.patch create mode 100644 net/madwifi/patches/414-txpower.patch create mode 100644 net/madwifi/patches/415-chan_switch.patch create mode 100644 net/madwifi/patches/416-wprobe.patch create mode 100644 net/madwifi/patches/417-beacon_txpower.patch create mode 100644 net/madwifi/patches/419-skb_unmap_crash.patch create mode 100644 net/madwifi/patches/420-diversity_fix.patch create mode 100644 net/madwifi/patches/421-channel_handling.patch create mode 100644 net/madwifi/patches/422-confchange_reset.patch create mode 100644 net/madwifi/patches/423-phyerr_handling.patch create mode 100644 net/madwifi/patches/424-timing.patch create mode 100644 net/madwifi/patches/425-rc_rexmit.patch create mode 100644 net/madwifi/patches/426-header_len.patch create mode 100644 net/madwifi/patches/427-ignore_eeprom_ff.patch create mode 100644 net/madwifi/patches/430-use_netdev_priv.patch create mode 100644 net/madwifi/patches/431-compile_fixes.patch create mode 100644 net/madwifi/patches/432-netdev_ops.patch create mode 100644 net/madwifi/patches/433-backport_remove_irq_none.patch create mode 100644 net/madwifi/patches/434-name-alloc-fix.patch create mode 100644 net/madwifi/patches/435-ibss_neighbor_fix.patch create mode 100644 net/madwifi/patches/436-injection_checks.patch create mode 100644 net/madwifi/patches/437-sysctl_cleanup.patch create mode 100644 net/madwifi/patches/438-poweroffset_sysctl.patch create mode 100644 net/madwifi/patches/439-wlanconfig_stack_usage.patch create mode 100644 net/madwifi/patches/440-wme_cleanup.patch create mode 100644 net/madwifi/patches/441-fix_ibss_node_handling.patch create mode 100644 net/madwifi/patches/442-ibss_rx_filter.patch create mode 100644 net/madwifi/patches/443-tx_drop_counter.patch create mode 100644 net/madwifi/patches/444-beacon_update_war.patch create mode 100644 net/madwifi/patches/445-fix_ps_sta_count.patch create mode 100644 net/madwifi/patches/446-single_module.patch create mode 100644 net/madwifi/patches/447-sta_reconnect.patch create mode 100644 net/madwifi/patches/448-beacon_handling_fixes.patch create mode 100644 net/madwifi/patches/449-fix_txbuf_leak.patch create mode 100644 net/madwifi/patches/450-calibration.patch create mode 100644 net/madwifi/patches/451-ibss_race_fix.patch create mode 100644 net/madwifi/patches/452-minstrel_no_timer.patch create mode 100644 net/madwifi/patches/453-procps.patch create mode 100644 net/madwifi/patches/454-cca.patch create mode 100644 net/madwifi/patches/455-beacon_watchdog.patch create mode 100644 net/madwifi/patches/456-rfsilent.patch create mode 100644 net/madwifi/patches/457-idletime.patch create mode 100644 net/madwifi/patches/458-ibss_wpa_none.patch create mode 100644 net/madwifi/patches/459-2.6.33_compile.patch create mode 100644 net/madwifi/patches/460-pci_softled_disable.patch create mode 100644 net/madwifi/patches/461-rx_stats_count_fix.patch create mode 100644 net/madwifi/patches/462-fix_ap_scan.patch create mode 100644 net/madwifi/patches/463-fix_txrate_display.patch create mode 100644 net/madwifi/patches/464-0dbm_txpower_fix.patch create mode 100644 net/madwifi/patches/465-mc_list-2.6.35.patch create mode 100644 net/madwifi/patches/466-2.6.38_compile.patch create mode 100644 net/madwifi/patches/470-mac_addresss_from_ath5k_platform_data.patch create mode 100644 net/madwifi/patches/471-netdev_ops_mac_mtu.patch create mode 100644 net/madwifi/patches/472-remove_11n_devids.patch create mode 100644 net/madwifi/patches/473-mutex_fix.patch create mode 100644 net/madwifi/patches/474_fix_ssid_scan_length.patch create mode 100644 net/madwifi/patches/475-2.6.39-compile.patch create mode 100644 net/madwifi/patches/476-3.0_detection_fix.patch create mode 100644 net/madwifi/patches/477-3.2_fixes.patch create mode 100644 net/madwifi/patches/478-remove_vlan_code.patch create mode 100644 net/siit/Makefile create mode 100644 net/siit/src/Makefile create mode 100644 net/siit/src/siit.c create mode 100644 net/siit/src/siit.h create mode 100644 net/wprobe/Makefile create mode 100644 net/wprobe/files/wprobe.config create mode 100755 net/wprobe/files/wprobe.init create mode 100644 net/wprobe/src/Makefile.inc create mode 100644 net/wprobe/src/exporter/Makefile create mode 100644 net/wprobe/src/exporter/wprobe-export.c create mode 100644 net/wprobe/src/exporter/wprobe-export.h create mode 100644 net/wprobe/src/filter/README.txt create mode 100755 net/wprobe/src/filter/gen_filter.pl create mode 100644 net/wprobe/src/filter/pfc.c create mode 100644 net/wprobe/src/kernel/Makefile create mode 100644 net/wprobe/src/kernel/linux/wprobe.h create mode 100644 net/wprobe/src/kernel/wprobe-core.c create mode 100644 net/wprobe/src/kernel/wprobe-dummy.c create mode 100644 net/wprobe/src/user/Makefile create mode 100644 net/wprobe/src/user/list.h create mode 100644 net/wprobe/src/user/wprobe-lib.c create mode 100644 net/wprobe/src/user/wprobe-util.c create mode 100644 net/wprobe/src/user/wprobe.h create mode 100644 utils/goldfish-qemu/Makefile create mode 100644 utils/goldfish-qemu/patches/100-darwin_fix.patch create mode 100644 utils/goldfish-qemu/patches/110-single_image.patch create mode 100644 utils/goldfish-qemu/skins/HVGA/arrow_down.png create mode 100644 utils/goldfish-qemu/skins/HVGA/arrow_left.png create mode 100644 utils/goldfish-qemu/skins/HVGA/arrow_right.png create mode 100644 utils/goldfish-qemu/skins/HVGA/arrow_up.png create mode 100644 utils/goldfish-qemu/skins/HVGA/back.png create mode 100644 utils/goldfish-qemu/skins/HVGA/device.png create mode 100644 utils/goldfish-qemu/skins/HVGA/end.png create mode 100644 utils/goldfish-qemu/skins/HVGA/home.png create mode 100644 utils/goldfish-qemu/skins/HVGA/key.png create mode 100644 utils/goldfish-qemu/skins/HVGA/keyboard.png create mode 100644 utils/goldfish-qemu/skins/HVGA/layout create mode 100644 utils/goldfish-qemu/skins/HVGA/menu.png create mode 100644 utils/goldfish-qemu/skins/HVGA/power.png create mode 100644 utils/goldfish-qemu/skins/HVGA/select.png create mode 100644 utils/goldfish-qemu/skins/HVGA/send.png create mode 100644 utils/goldfish-qemu/skins/HVGA/spacebar.png create mode 100644 utils/goldfish-qemu/skins/HVGA/volume_down.png create mode 100644 utils/goldfish-qemu/skins/HVGA/volume_up.png create mode 100644 utils/ps3-utils/Makefile create mode 100644 utils/redboot-ar231x/Makefile create mode 100644 utils/redboot-ar231x/patches/010-fix-compile.patch diff --git a/libs/libipfix/Makefile b/libs/libipfix/Makefile new file mode 100644 index 000000000..e4c931591 --- /dev/null +++ b/libs/libipfix/Makefile @@ -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 index 000000000..8bb658bbb --- /dev/null +++ b/libs/libipfix/extra/append-wprobe-ie.pl @@ -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 \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 () { + /^(%?)(\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 index 000000000..26d64d213 --- /dev/null +++ b/libs/libipfix/extra/wprobe-ie.txt @@ -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 index 000000000..5b6e2e379 --- /dev/null +++ b/libs/libipfix/patches/100-openimp_sync.patch @@ -0,0 +1,474 @@ +--- a/lib/ipfix.c ++++ b/lib/ipfix.c +@@ -37,6 +37,9 @@ $$LIC$$ + #ifdef SCTPSUPPORT + #include + #endif ++#ifndef NOTHREADS ++#include ++#endif + #include + #include + +@@ -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; itid == 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; ifields[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 index 000000000..5e3728081 --- /dev/null +++ b/libs/libipfix/patches/110-wprobe_ie.patch @@ -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 index 000000000..e3f5a05c6 --- /dev/null +++ b/libs/libipfix/patches/120-ipfixmisc.patch @@ -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 index 000000000..f87551c6c --- /dev/null +++ b/net/bridge-utils/Makefile @@ -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 index 000000000..e35a64947 --- /dev/null +++ b/net/bridge-utils/patches/001-libbridge_cflags.patch @@ -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 index 000000000..0d075f1da --- /dev/null +++ b/net/crda/Makefile @@ -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 index 000000000..1ec033f46 --- /dev/null +++ b/net/crda/files/hotplug.rule @@ -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 index 000000000..c7ace42c8 --- /dev/null +++ b/net/crda/patches/101-make_crypto_use_optional.patch @@ -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 index 000000000..7b72eb854 --- /dev/null +++ b/net/madwifi/Config.in @@ -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 index 000000000..f915f56f9 --- /dev/null +++ b/net/madwifi/Makefile @@ -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 index 000000000..f5afce3f2 --- /dev/null +++ b/net/madwifi/files/etc/hotplug.d/net/10-madwifi @@ -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 index 000000000..2e3732551 --- /dev/null +++ b/net/madwifi/files/lib/wifi/madwifi.sh @@ -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 < + #include + #include ++#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 + + #include ++#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 + #include + #include ++#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 ++#include ++#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 + #include + #include ++#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 index 000000000..b2181b68e --- /dev/null +++ b/net/madwifi/patches/104-autocreate_none.patch @@ -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 index 000000000..80aad835e --- /dev/null +++ b/net/madwifi/patches/105-ratectl_attach.patch @@ -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 index 000000000..3140f3679 --- /dev/null +++ b/net/madwifi/patches/106-get_arch.patch @@ -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 index 000000000..975bc4e94 --- /dev/null +++ b/net/madwifi/patches/111-minstrel_crash.patch @@ -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 index 000000000..af23ceb7a --- /dev/null +++ b/net/madwifi/patches/113-no_ibss_pwrsave.patch @@ -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 index 000000000..c4eb28c94 --- /dev/null +++ b/net/madwifi/patches/122-replayfail_workaround.patch @@ -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 index 000000000..6178a3f78 --- /dev/null +++ b/net/madwifi/patches/123-ccmp_checks.patch @@ -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 index 000000000..88601a4c7 --- /dev/null +++ b/net/madwifi/patches/124-linux24_compat.patch @@ -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 ++ */ ++ ++#include ++#include ++#include ++ ++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 index 000000000..762a7bc81 --- /dev/null +++ b/net/madwifi/patches/126-rxerr_frames.patch @@ -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 index 000000000..3f46ec88b --- /dev/null +++ b/net/madwifi/patches/200-no_debug.patch @@ -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 +--- 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 + #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 index 000000000..bcfbba82c --- /dev/null +++ b/net/madwifi/patches/201-debug_fix.patch @@ -0,0 +1,20 @@ +--- a/ath_hal/ah_os.c ++++ b/ath_hal/ah_os.c +@@ -65,7 +65,7 @@ + #include + + #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 index 000000000..33e6efad1 --- /dev/null +++ b/net/madwifi/patches/202-debug_variables.patch @@ -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 index 000000000..bde768494 --- /dev/null +++ b/net/madwifi/patches/300-napi_polling.patch @@ -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 + #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 index 000000000..8adb8a716 --- /dev/null +++ b/net/madwifi/patches/305-pureg_fix.patch @@ -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 index 000000000..ca4103a20 --- /dev/null +++ b/net/madwifi/patches/309-micfail_detect.patch @@ -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 index 000000000..d8821583b --- /dev/null +++ b/net/madwifi/patches/310-noise_get.patch @@ -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 index 000000000..005a67738 --- /dev/null +++ b/net/madwifi/patches/311-bssid_alloc.patch @@ -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 index 000000000..f878acd8f --- /dev/null +++ b/net/madwifi/patches/312-erpupdate.patch @@ -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 index 000000000..3355dc722 --- /dev/null +++ b/net/madwifi/patches/317-bmask.patch @@ -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 index 000000000..2336d7484 --- /dev/null +++ b/net/madwifi/patches/323-dfs_optional.patch @@ -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 index 000000000..c01135f3e --- /dev/null +++ b/net/madwifi/patches/324-alignment.patch @@ -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 index 000000000..e34b7a409 --- /dev/null +++ b/net/madwifi/patches/325-channel_spam.patch @@ -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 index 000000000..228aae349 --- /dev/null +++ b/net/madwifi/patches/327-queue.patch @@ -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 index 000000000..a338dc743 --- /dev/null +++ b/net/madwifi/patches/330-beaconcal.patch @@ -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 ++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 index 000000000..6b01d79c0 --- /dev/null +++ b/net/madwifi/patches/331-memory_alloc.patch @@ -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 index 000000000..b776426f2 --- /dev/null +++ b/net/madwifi/patches/332-reset_beacons.patch @@ -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 index 000000000..877eea6ce --- /dev/null +++ b/net/madwifi/patches/333-apscan_mode.patch @@ -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 index 000000000..7c1336701 --- /dev/null +++ b/net/madwifi/patches/334-input.patch @@ -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 index 000000000..ae93f02d2 --- /dev/null +++ b/net/madwifi/patches/340-maxrate.patch @@ -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 index 000000000..cc04ae074 --- /dev/null +++ b/net/madwifi/patches/341-minrate.patch @@ -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_minrateindexni_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_minrateindexni_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 index 000000000..88cec182d --- /dev/null +++ b/net/madwifi/patches/342-performance.patch @@ -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 index 000000000..a2b14d69a --- /dev/null +++ b/net/madwifi/patches/343-txqueue_races.patch @@ -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 index 000000000..ea92dc4d6 --- /dev/null +++ b/net/madwifi/patches/344-minstrel_failcnt.patch @@ -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 index 000000000..63fcb8a61 --- /dev/null +++ b/net/madwifi/patches/345-minstrel_sampling.patch @@ -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 index 000000000..5b5cec6e9 --- /dev/null +++ b/net/madwifi/patches/346-protmode_trig.patch @@ -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 index 000000000..1a73c4274 --- /dev/null +++ b/net/madwifi/patches/347-tuning.patch @@ -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 index 000000000..42b6fe261 --- /dev/null +++ b/net/madwifi/patches/348-ackcts.patch @@ -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 index 000000000..06e3fa86f --- /dev/null +++ b/net/madwifi/patches/349-reset.patch @@ -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 index 000000000..dae9f218d --- /dev/null +++ b/net/madwifi/patches/350-wisoc_softled.patch @@ -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 index 000000000..c11f28e39 --- /dev/null +++ b/net/madwifi/patches/351-scanlist.patch @@ -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 index 000000000..938d11c62 --- /dev/null +++ b/net/madwifi/patches/352-ani_fix.patch @@ -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 index 000000000..ee149ff0c --- /dev/null +++ b/net/madwifi/patches/353-devid.patch @@ -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 index 000000000..59036b1b4 --- /dev/null +++ b/net/madwifi/patches/354-lantiq_eeprom.patch @@ -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 index 000000000..8bb1e9323 --- /dev/null +++ b/net/madwifi/patches/355-eap_auth_disassoc.patch @@ -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 + +--- 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 index 000000000..b87569e76 --- /dev/null +++ b/net/madwifi/patches/356-hidden_ssid.patch @@ -0,0 +1,49 @@ +This patch fixes the detection of hidden SSIDs as transmitted +by some cisco systems. + +Signed-off-by: Felix Fietkau + +--- 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 index 000000000..bf3483776 --- /dev/null +++ b/net/madwifi/patches/357-bgscan_thresh.patch @@ -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 + +--- 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 index 000000000..b54927220 --- /dev/null +++ b/net/madwifi/patches/358-ignore_broken_bssid.patch @@ -0,0 +1,18 @@ +Some misconfigured APs broadcast NULL BSSIDs, which can confuse the STA +Ignore those when scanning. + +Signed-off-by: Felix Fietkau + +--- 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 index 000000000..8d25dc2a8 --- /dev/null +++ b/net/madwifi/patches/359-disable_reassoc.patch @@ -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 + +--- 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 index 000000000..8d2dd9ddd --- /dev/null +++ b/net/madwifi/patches/360-sta_nodes.patch @@ -0,0 +1,242 @@ +Drop stale AP nodes from the client list when disconnecting. +Fixes some reassoc issues. + +Signed-off-by: Felix Fietkau + +--- 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 index 000000000..15d238f7b --- /dev/null +++ b/net/madwifi/patches/361-bmiss_handling.patch @@ -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 + +--- 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 index 000000000..5a86833bb --- /dev/null +++ b/net/madwifi/patches/362-rssithr.patch @@ -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 + +--- 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 index 000000000..880f2d614 --- /dev/null +++ b/net/madwifi/patches/363-fix_turbo.patch @@ -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 index 000000000..53fbc7709 --- /dev/null +++ b/net/madwifi/patches/364-memory_alloc.patch @@ -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 index 000000000..df4306b21 --- /dev/null +++ b/net/madwifi/patches/365-turbo_channelsearch.patch @@ -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 index 000000000..cde1f5c98 --- /dev/null +++ b/net/madwifi/patches/366-bstuck_thresh.patch @@ -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 index 000000000..5950f9fd4 --- /dev/null +++ b/net/madwifi/patches/367-roaming.patch @@ -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 index 000000000..fbd779ea0 --- /dev/null +++ b/net/madwifi/patches/368-sta_ie_preserve.patch @@ -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 index 000000000..43aac668c --- /dev/null +++ b/net/madwifi/patches/369-mlme_assoc.patch @@ -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 index 000000000..8a0e823ae --- /dev/null +++ b/net/madwifi/patches/370-wdsvap.patch @@ -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 ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) ++#include ++#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 ++ ++#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 + #include + #include ++#include + + #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 +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) +-#include +-#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 +- +-#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 index 000000000..8b13abc33 --- /dev/null +++ b/net/madwifi/patches/372-queue_vif.patch @@ -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 index 000000000..06c6acf08 --- /dev/null +++ b/net/madwifi/patches/373-sanity_check.patch @@ -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 index 000000000..38a1c59d5 --- /dev/null +++ b/net/madwifi/patches/374-nbtt_fix.patch @@ -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 index 000000000..d1313aa56 --- /dev/null +++ b/net/madwifi/patches/375-atim_tsf_update.patch @@ -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 index 000000000..8a132484e --- /dev/null +++ b/net/madwifi/patches/377-disable_vlan_code.patch @@ -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 index 000000000..5b9168367 --- /dev/null +++ b/net/madwifi/patches/378-adhoc_crash_fix.patch @@ -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 index 000000000..c96c04daf --- /dev/null +++ b/net/madwifi/patches/379-invalid_rate_fix.patch @@ -0,0 +1,405 @@ +--- a/ath_rate/minstrel/minstrel.c ++++ b/ath_rate/minstrel/minstrel.c +@@ -111,27 +111,13 @@ + #include + #include + ++#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 + #include + ++#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 + #include + ++#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 + #include + ++#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 index 000000000..7c082d414 --- /dev/null +++ b/net/madwifi/patches/380-noderef_hack.patch @@ -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 index 000000000..38969b053 --- /dev/null +++ b/net/madwifi/patches/381-ibss_modes.patch @@ -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 index 000000000..0901949d9 --- /dev/null +++ b/net/madwifi/patches/382-relax_bintval.patch @@ -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 index 000000000..d449c3037 --- /dev/null +++ b/net/madwifi/patches/383-ibss_hostap.patch @@ -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 index 000000000..3b67615b0 --- /dev/null +++ b/net/madwifi/patches/384-hwdetect.patch @@ -0,0 +1,325 @@ +--- a/ath/if_ath.c ++++ b/ath/if_ath.c +@@ -62,6 +62,7 @@ + #include + #include + #include ++#include + #include + + #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 + #include + #include ++#include + + #include + #include +@@ -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 index 000000000..16c7d95c7 --- /dev/null +++ b/net/madwifi/patches/385-antenna_fix.patch @@ -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 index 000000000..04a1ec911 --- /dev/null +++ b/net/madwifi/patches/386-acl_crashfix.patch @@ -0,0 +1,116 @@ +fixes ACL race condition caused by acl list modifications at run time + +Signed-off-by: Sebastian Gottschall + +--- 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 index 000000000..79e5b2f4f --- /dev/null +++ b/net/madwifi/patches/387-maxassoc.patch @@ -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 index 000000000..b0cb8e9df --- /dev/null +++ b/net/madwifi/patches/388-apsta_fix.patch @@ -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 index 000000000..548f09e7d --- /dev/null +++ b/net/madwifi/patches/389-autochannel.patch @@ -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 index 000000000..6de01102c --- /dev/null +++ b/net/madwifi/patches/390-frame_type.patch @@ -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 index 000000000..832f9e116 --- /dev/null +++ b/net/madwifi/patches/391-vap_auth.patch @@ -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 index 000000000..fb9fb6a22 --- /dev/null +++ b/net/madwifi/patches/392-remove_wds_nodetracking.patch @@ -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 index 000000000..a2637cccb --- /dev/null +++ b/net/madwifi/patches/393-mbss_vap_auth.patch @@ -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 index 000000000..706d5a5ac --- /dev/null +++ b/net/madwifi/patches/394-probereq.patch @@ -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 index 000000000..85ddc7bd9 --- /dev/null +++ b/net/madwifi/patches/395-ath_ff_unmap.patch @@ -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 index 000000000..ca35d4cca --- /dev/null +++ b/net/madwifi/patches/396-napi_ff_fix.patch @@ -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 index 000000000..12a59687b --- /dev/null +++ b/net/madwifi/patches/400-new_hal.patch @@ -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 index 000000000..cf9c87966 --- /dev/null +++ b/net/madwifi/patches/401-changeset_r3602.patch @@ -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 index 000000000..92f6e6ea4 --- /dev/null +++ b/net/madwifi/patches/402-changeset_r3603.patch @@ -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 index 000000000..57ce521c1 --- /dev/null +++ b/net/madwifi/patches/403-changeset_r3605.patch @@ -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 index 000000000..4ea20b3cb --- /dev/null +++ b/net/madwifi/patches/404-linux24_fix.patch @@ -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 index 000000000..11e78aba8 --- /dev/null +++ b/net/madwifi/patches/405-retransmit_check.patch @@ -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 index 000000000..4e2c6aefb --- /dev/null +++ b/net/madwifi/patches/406-monitor_r3711.patch @@ -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 index 000000000..6c512ad9e --- /dev/null +++ b/net/madwifi/patches/407-new_athinfo.patch @@ -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 . + */ + +-/* 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 X +- * +- * with ::= 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 + #include +@@ -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 "" 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 ""; +-} /* 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] " ++ fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] [-d] [-R addr] [-W addr val] " + "[ [ ...]]\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 read register at (hex)\n" ++ "-W write (hex) into register at (hex)\n" + " device base address (see lspci output)\n\n"); + + fprintf(stderr, +@@ -725,8 +1514,8 @@ static void usage(const char *n) + " %s -w regdomain N\n\n" + "- set a PCI id field to value N:\n" + " %s -w N\n" +- " where is on of:\n ", n, n, n); +- for (i = 0; i < eeprom_addr_len; i++) ++ " where 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, ®domain, +- 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 index 000000000..53e76a9e8 --- /dev/null +++ b/net/madwifi/patches/408-changeset_r3337.patch @@ -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 index 000000000..449709232 --- /dev/null +++ b/net/madwifi/patches/409-wext_compat.patch @@ -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 index 000000000..30d1c56a4 --- /dev/null +++ b/net/madwifi/patches/410-ar231x_2.6.28.patch @@ -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 + #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 index 000000000..d05c447f7 --- /dev/null +++ b/net/madwifi/patches/411-autochannel_multi.patch @@ -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 index 000000000..92c411b2b --- /dev/null +++ b/net/madwifi/patches/412-fragmentation_fix.patch @@ -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 index 000000000..0e8d885da --- /dev/null +++ b/net/madwifi/patches/413-rxorn.patch @@ -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 index 000000000..3c18bd6fe --- /dev/null +++ b/net/madwifi/patches/414-txpower.patch @@ -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 index 000000000..6dc5da838 --- /dev/null +++ b/net/madwifi/patches/415-chan_switch.patch @@ -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 index 000000000..0b378d7e2 --- /dev/null +++ b/net/madwifi/patches/416-wprobe.patch @@ -0,0 +1,549 @@ +--- /dev/null ++++ b/ath/ath_wprobe.c +@@ -0,0 +1,433 @@ ++#include ++#include ++ ++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 + #include "net80211/ieee80211.h" /* XXX for WME_NUM_AC */ + #include + #include +@@ -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 index 000000000..8a59c1211 --- /dev/null +++ b/net/madwifi/patches/417-beacon_txpower.patch @@ -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 index 000000000..37602e491 --- /dev/null +++ b/net/madwifi/patches/419-skb_unmap_crash.patch @@ -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 index 000000000..90bcd0e16 --- /dev/null +++ b/net/madwifi/patches/420-diversity_fix.patch @@ -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 index 000000000..2a8ec27ce --- /dev/null +++ b/net/madwifi/patches/421-channel_handling.patch @@ -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 + 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 index 000000000..33040ae0d --- /dev/null +++ b/net/madwifi/patches/422-confchange_reset.patch @@ -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 index 000000000..7f3cbafe2 --- /dev/null +++ b/net/madwifi/patches/423-phyerr_handling.patch @@ -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 index 000000000..8369db618 --- /dev/null +++ b/net/madwifi/patches/424-timing.patch @@ -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 +-#include +- +-#include +- +-#include +-#include +-#include +-#include +- +-#include +-#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 index 000000000..252767a8c --- /dev/null +++ b/net/madwifi/patches/425-rc_rexmit.patch @@ -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 index 000000000..acfbc18c6 --- /dev/null +++ b/net/madwifi/patches/426-header_len.patch @@ -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 index 000000000..eead70c99 --- /dev/null +++ b/net/madwifi/patches/427-ignore_eeprom_ff.patch @@ -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 index 000000000..3f65424a5 --- /dev/null +++ b/net/madwifi/patches/430-use_netdev_priv.patch @@ -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], ¶ms[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 index 000000000..b11d406a0 --- /dev/null +++ b/net/madwifi/patches/431-compile_fixes.patch @@ -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 index 000000000..af829b164 --- /dev/null +++ b/net/madwifi/patches/432-netdev_ops.patch @@ -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 index 000000000..5166d9e10 --- /dev/null +++ b/net/madwifi/patches/433-backport_remove_irq_none.patch @@ -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 index 000000000..ab277630d --- /dev/null +++ b/net/madwifi/patches/434-name-alloc-fix.patch @@ -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 index 000000000..d66af9b24 --- /dev/null +++ b/net/madwifi/patches/435-ibss_neighbor_fix.patch @@ -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 index 000000000..274873111 --- /dev/null +++ b/net/madwifi/patches/436-injection_checks.patch @@ -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 index 000000000..e35ed0293 --- /dev/null +++ b/net/madwifi/patches/437-sysctl_cleanup.patch @@ -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 index 000000000..e82046ec6 --- /dev/null +++ b/net/madwifi/patches/438-poweroffset_sysctl.patch @@ -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 index 000000000..f346143c3 --- /dev/null +++ b/net/madwifi/patches/439-wlanconfig_stack_usage.patch @@ -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 index 000000000..bb81ac7f8 --- /dev/null +++ b/net/madwifi/patches/440-wme_cleanup.patch @@ -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 index 000000000..20d59de26 --- /dev/null +++ b/net/madwifi/patches/441-fix_ibss_node_handling.patch @@ -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 index 000000000..eaf807118 --- /dev/null +++ b/net/madwifi/patches/442-ibss_rx_filter.patch @@ -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 index 000000000..30630ae43 --- /dev/null +++ b/net/madwifi/patches/443-tx_drop_counter.patch @@ -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 index 000000000..6a3178a6d --- /dev/null +++ b/net/madwifi/patches/444-beacon_update_war.patch @@ -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 index 000000000..27514650a --- /dev/null +++ b/net/madwifi/patches/445-fix_ps_sta_count.patch @@ -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 index 000000000..b2898ca7e --- /dev/null +++ b/net/madwifi/patches/446-single_module.patch @@ -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 + + /* +- * 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 + #endif + #include ++#include + #include + #include + #include +@@ -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 ++ + 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 + #include + #include ++#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 ++ + 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 ++#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 index 000000000..960d1b8ed --- /dev/null +++ b/net/madwifi/patches/447-sta_reconnect.patch @@ -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 index 000000000..9c0f912e4 --- /dev/null +++ b/net/madwifi/patches/448-beacon_handling_fixes.patch @@ -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 + 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 index 000000000..31f2fef3a --- /dev/null +++ b/net/madwifi/patches/449-fix_txbuf_leak.patch @@ -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 index 000000000..87397903d --- /dev/null +++ b/net/madwifi/patches/450-calibration.patch @@ -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 +-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 index 000000000..27e1b47da --- /dev/null +++ b/net/madwifi/patches/451-ibss_race_fix.patch @@ -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 + #include ++#include + + /* + * 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 index 000000000..f0f5c26f9 --- /dev/null +++ b/net/madwifi/patches/452-minstrel_no_timer.patch @@ -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 index 000000000..5a5633b1c --- /dev/null +++ b/net/madwifi/patches/453-procps.patch @@ -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 index 000000000..53792cc8f --- /dev/null +++ b/net/madwifi/patches/454-cca.patch @@ -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 index 000000000..d0b4fa63e --- /dev/null +++ b/net/madwifi/patches/455-beacon_watchdog.patch @@ -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 index 000000000..21031e7ca --- /dev/null +++ b/net/madwifi/patches/456-rfsilent.patch @@ -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 index 000000000..429da8522 --- /dev/null +++ b/net/madwifi/patches/457-idletime.patch @@ -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 index 000000000..df77510b2 --- /dev/null +++ b/net/madwifi/patches/458-ibss_wpa_none.patch @@ -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 index 000000000..4e08a011a --- /dev/null +++ b/net/madwifi/patches/459-2.6.33_compile.patch @@ -0,0 +1,524 @@ +--- a/kernelversion.c ++++ b/kernelversion.c +@@ -10,7 +10,11 @@ + + /* Linux 2.6.18+ uses */ + #ifndef UTS_RELEASE +-#include ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) ++ #include ++ #else ++ #include ++ #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 index 000000000..328e8c350 --- /dev/null +++ b/net/madwifi/patches/460-pci_softled_disable.patch @@ -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 index 000000000..4b5ce28cc --- /dev/null +++ b/net/madwifi/patches/461-rx_stats_count_fix.patch @@ -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 index 000000000..8798f534e --- /dev/null +++ b/net/madwifi/patches/462-fix_ap_scan.patch @@ -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 index 000000000..0889f78fe --- /dev/null +++ b/net/madwifi/patches/463-fix_txrate_display.patch @@ -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 index 000000000..fbd1d7673 --- /dev/null +++ b/net/madwifi/patches/464-0dbm_txpower_fix.patch @@ -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 index 000000000..4931cfb28 --- /dev/null +++ b/net/madwifi/patches/465-mc_list-2.6.35.patch @@ -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 index 000000000..10a6f0deb --- /dev/null +++ b/net/madwifi/patches/466-2.6.38_compile.patch @@ -0,0 +1,14 @@ +--- a/include/compat.h ++++ b/include/compat.h +@@ -131,6 +131,11 @@ + #ifdef __KERNEL__ + + #include ++ ++#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 index 000000000..0c35050c5 --- /dev/null +++ b/net/madwifi/patches/470-mac_addresss_from_ath5k_platform_data.patch @@ -0,0 +1,36 @@ +--- a/ath/if_ath.c ++++ b/ath/if_ath.c +@@ -63,6 +63,8 @@ + #include + #include + #include ++#include ++#include + #include + + #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 index 000000000..c7e1f404a --- /dev/null +++ b/net/madwifi/patches/471-netdev_ops_mac_mtu.patch @@ -0,0 +1,30 @@ +--- a/net80211/ieee80211.c ++++ b/net80211/ieee80211.c +@@ -47,6 +47,7 @@ + #include + #include + #include /* XXX for rtnl_lock */ ++#include + + #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 index 000000000..cf80f06bf --- /dev/null +++ b/net/madwifi/patches/472-remove_11n_devids.patch @@ -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 index 000000000..22cea46a2 --- /dev/null +++ b/net/madwifi/patches/473-mutex_fix.patch @@ -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 index 000000000..2e85e18c6 --- /dev/null +++ b/net/madwifi/patches/474_fix_ssid_scan_length.patch @@ -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 index 000000000..5b8a77718 --- /dev/null +++ b/net/madwifi/patches/475-2.6.39-compile.patch @@ -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 index 000000000..2f8bfb4a5 --- /dev/null +++ b/net/madwifi/patches/476-3.0_detection_fix.patch @@ -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 index 000000000..89cdfc649 --- /dev/null +++ b/net/madwifi/patches/477-3.2_fixes.patch @@ -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 index 000000000..9ceda4aa0 --- /dev/null +++ b/net/madwifi/patches/478-remove_vlan_code.patch @@ -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 index 000000000..4cd147f77 --- /dev/null +++ b/net/siit/Makefile @@ -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 index 000000000..06c36f1e3 --- /dev/null +++ b/net/siit/src/Makefile @@ -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 index 000000000..5362c1daa --- /dev/null +++ b/net/siit/src/siit.c @@ -0,0 +1,1478 @@ +/* + * siit.c: the Stateless IP/ICMP Translator (SIIT) module for Linux. + * + * + */ + +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) +#include +#else +#include +#endif +#include +#include +#include /* printk() */ +#include + +#include /* error codes */ +#include /* size_t */ +#include /* mark_bh */ +#include +#include +#include /* struct device, and other headers */ +#include /* eth_type_trans */ +#include /* struct iphdr */ +#include /* struct icmphdr */ +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) +#include +#endif +#include +#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 index 000000000..47cf77645 --- /dev/null +++ b/net/siit/src/siit.h @@ -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 index 000000000..de1ba6d63 --- /dev/null +++ b/net/wprobe/Makefile @@ -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 ' +# wprobe-lib.c:149: error: 'packed' attribute ignored for field of type 'struct ' + +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 + 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 index 000000000..63518ef6e --- /dev/null +++ b/net/wprobe/files/wprobe.config @@ -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 index 000000000..b35246d42 --- /dev/null +++ b/net/wprobe/files/wprobe.init @@ -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 index 000000000..5044c0a55 --- /dev/null +++ b/net/wprobe/src/Makefile.inc @@ -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 index 000000000..9f8150729 --- /dev/null +++ b/net/wprobe/src/exporter/Makefile @@ -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 index 000000000..a0e52e2f4 --- /dev/null +++ b/net/wprobe/src/exporter/wprobe-export.c @@ -0,0 +1,304 @@ +/* +** exporter.c - example exporter +** +** Copyright Fraunhofer FOKUS +** +*/ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +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 -c [-p portno]\n" + " -h this help\n" + " -i wprobe interface\n" + " -c collector address\n" + " -p 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 index 000000000..89da9e86e --- /dev/null +++ b/net/wprobe/src/exporter/wprobe-export.h @@ -0,0 +1,34 @@ +#include +#include +#include + +/** + * 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 index 000000000..6fa265e4f --- /dev/null +++ b/net/wprobe/src/filter/README.txt @@ -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 index 000000000..f03f477a4 --- /dev/null +++ b/net/wprobe/src/filter/gen_filter.pl @@ -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 () { + 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 index 000000000..76fb1412a --- /dev/null +++ b/net/wprobe/src/filter/pfc.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +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 \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 index 000000000..2a9875311 --- /dev/null +++ b/net/wprobe/src/kernel/Makefile @@ -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 index 000000000..901daf3d1 --- /dev/null +++ b/net/wprobe/src/kernel/linux/wprobe.h @@ -0,0 +1,397 @@ +/* + * wprobe.h: API for the wireless probe interface + * Copyright (C) 2008-2009 Felix Fietkau + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#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 index 000000000..6ec847a7a --- /dev/null +++ b/net/wprobe/src/kernel/wprobe-core.c @@ -0,0 +1,1164 @@ +/* + * wprobe-core.c: Wireless probe interface core + * Copyright (C) 2008-2009 Felix Fietkau + * + * 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 +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#include +#else +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) +#include +#endif +#include +#include +#include + +#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 index 000000000..4231223e0 --- /dev/null +++ b/net/wprobe/src/kernel/wprobe-dummy.c @@ -0,0 +1,96 @@ +/* + * wprobe-core.c: Wireless probe interface dummy driver + * Copyright (C) 2008-2009 Felix Fietkau + * + * 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 +#include +#include +#include +#include +#include +#include + +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 index 000000000..01e83da3e --- /dev/null +++ b/net/wprobe/src/user/Makefile @@ -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 index 000000000..2959a061d --- /dev/null +++ b/net/wprobe/src/user/list.h @@ -0,0 +1,601 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#include +/** + * 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 index 000000000..7a5460bb0 --- /dev/null +++ b/net/wprobe/src/user/wprobe-lib.c @@ -0,0 +1,1210 @@ +/* + * wprobe.c: Wireless probe user space library + * Copyright (C) 2008-2009 Felix Fietkau + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef NO_LOCAL_ACCESS +#include +#include +#include +#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 index 000000000..654442f9c --- /dev/null +++ b/net/wprobe/src/user/wprobe-util.c @@ -0,0 +1,450 @@ +/* + * wprobe-test.c: Wireless probe user space test code + * Copyright (C) 2008-2009 Felix Fietkau + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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, "", 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 |:|-P [options]\n" +#else + "Usage: %s : [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 : Apply layer 2 filters from \n" + " -h: This help text\n" + " -i : 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 index 000000000..706facc80 --- /dev/null +++ b/net/wprobe/src/user/wprobe.h @@ -0,0 +1,213 @@ +/* + * wprobe.h: Wireless probe user space library + * Copyright (C) 2008-2009 Felix Fietkau + * + * 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 +#include +#include +#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 (local) or : (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 index 000000000..e5b4083ea --- /dev/null +++ b/utils/goldfish-qemu/Makefile @@ -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 index 000000000..a5f56b3cf --- /dev/null +++ b/utils/goldfish-qemu/patches/100-darwin_fix.patch @@ -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 index 000000000..92a9e543d --- /dev/null +++ b/utils/goldfish-qemu/patches/110-single_image.patch @@ -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 @ as a special exception meaning +- * '-avd ' +- */ +- 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, "", "search for system disk images in " ) +-CFG_PARAM( system, "", "read initial system image from " ) +-CFG_PARAM( datadir, "", "write user data into " ) +-CFG_PARAM( kernel, "", "use specific emulated kernel" ) +-CFG_PARAM( ramdisk, "", "ramdisk image (default /ramdisk.img" ) +-CFG_PARAM( image, "", "obsolete, use -system instead" ) +-CFG_PARAM( init_data, "", "initial data image (default /userdata.img" ) +-CFG_PARAM( initdata, "", "same as '-init-data '" ) +-CFG_PARAM( data, "", "data image (default /userdata-qemu.img" ) ++CFG_PARAM( system, "", "read system image from , default: /system.img" ) ++CFG_PARAM( data, "", "data image, default: /data.img" ) ++CFG_PARAM( kernel, "", "use specific emulated kernel, default: kernel.bin" ) ++CFG_PARAM( ramdisk, "", "ramdisk image (default /ramdisk.bin" ) + CFG_PARAM( partition_size, "", "system/data partition size in MBs" ) + CFG_PARAM( cache, "", "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, "", "SD card image (default /sdcard.img") + OPT_FLAG ( wipe_data, "reset the use data image (copy it from initdata)" ) +-CFG_PARAM( avd, "", "use a specific android virtual device" ) + CFG_PARAM( skindir, "", "search skins in (default /skins)" ) + CFG_PARAM( skin, "", "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 and -image +- * instead of -sysdir and -system , 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 -system '.\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 -system ' 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 ' 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 ' option. Read -help-avd for more information.\n\n" +- +- "If you *really* want to *NOT* run an AVD, consider using '-data '\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 index 0000000000000000000000000000000000000000..19b3764e8337ba08cc2910ce9a9b77cae0c29155 GIT binary patch literal 3438 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 Q^8f$<07*qoM6N<$f_jc(fdBvi literal 0 HcmV?d00001 diff --git a/utils/goldfish-qemu/skins/HVGA/arrow_left.png b/utils/goldfish-qemu/skins/HVGA/arrow_left.png new file mode 100644 index 0000000000000000000000000000000000000000..113e58427aca1ebce4bdc7bc671e8e4be09434ad GIT binary patch literal 4122 zcmV+#5asWQP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000F=Nkl zmSPD)BZ+|oDg`?ZN{BWdpv4i4CNzpiYccb!?s~`W?9Jcq%-0OCWPiSS`@Q#O-pros zxV5mbzn3rsHJzkQe<5vtg|u7OWZy|eyoqj^CT-U<`g@Q2c%hNBJBy?}?X|>*LMlbt zOcS;6YIFlqei$F z$bch5eAEf|hMRaEZHb4|j5^`}S^ikLPFE1|PFPr#h$ZlRcSbcMeqc~;!lOFeWE~sg zPCPPAUE*+Q;byZU;xV?ND$`Vr)D6~fvrOWh(ZbDy1(W5MNqpD18Co6`kXZk4GbHf{ z6HS#CU(0Xw3pYa&FK@yi+D^B0xXDO7oCmKNpSa`hSgCN6k$8S%6=tD-+xwRaMoX`@ zB!&SLqU9H9b0YyQ9tA)aWm^7LK#PYqAwjSx4^AapQ$?_h)PfBKT9KBc;r8K*`*?oH zhxqgX{h`T{c^0yCYH)*w*@u3kvLh8|CrCBRmejL|UZa`&@k7=#lpwx!+FE)s>6o3R z64GAo8B0VpsaKZlL?V&M*OB(|GQvP!XHK3ScbZQ4%n51vmv1MFCrYMEia5ec5a0SD z8pIsG6LWrOxcCJM9^xDBX>N(XDe>?5o_}YTw}vwkuiJ!%m+-?{G1pnzm;Gc(J)Np7 z!V!;)k}l?`Chmj-yMwBpG^s~4Bb#tX+jkTbZyMn_<#WYJvj}$*q*}v>S4}u@S}=@w zBq)cH zh?lodi(Va&-d9Y#lUUT5)d8p%lJDd_#LFM0Q`-T~MnU6>iT4)XXxjm=IZKY}je(9!P9v z#p1NU36vkugNXAj-1u#)7LTlFP5<@&dxG0!-C&QgI zTY6A^9K7tCb6w3`yO~kX8|G>S&cx#tdpT={_9I+mFTxd6NroFiiX7K)aVhjZK7vd5 zkZ{52#4TJ5UkE0tb`s7PuV&Q4#nq#7&m_5Mb-q2?9l$SRS5z&G4v2~bAzT!`dxtDQ zg629jxAdF5{q7U6{Rw1f^D{;OW%zd>i*j=5JAYqqi*VW_h)kD~Rc2p3n!MO{JD zPtGAsoB2sv*<(Stp0xdHbOpk<=iOr81WeIwOp1P@h<#QRQiL}FPMO!xguLxjBK{#= zIA!<*NCay~DBmb3s(=KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000GENklz)hnXmZ*2mAPav)^NO=DQO& zZ@quNwn`L9^D@=-?NrY;P`&$^#9XS>oc81d)twiquFg{3!aiU5PWALN_H&;F&qdk> z81Vh#pC^Z@?qxsk-lKYQo$6dJ>fjS{Pgir7jqGf&|Lg8%206`OH{w?aG%e3@STlv&Qm?%c1fL=bbS&8gKxXw_R+Ehv84C3 z+Ut-89wY4bsvfslzeDwtDXQ!K#1wpIgZt6fMQ}Y&r`!cxWHF=b~Lt!T^Nb&%zZ=M?8XPTR(}FzyRWca7gfX9_f~*@s-|FqV6vs zcwC4s>7ww0tVa{@s0gbkh!KK10QW5&JkrI~HDaWo5)MBXln6G`O_v9A?&Lxkc;^+} zj)i{I#o~nycktdZ?qA{r9_eChzlG{6=@@n=AA!O1dPQfN z_@Aq)DxNMT&sd0|M*cslOD{|DjQGrgg~ui6ZuoRHEis>Sku4}NOY>ylH*2Y$8FcI1 zBGm_77G@AhFCXLM;fq$hpTBl%zay5(+FqqUV+Pc%--T}p0m&iAtd!iFnGuz8}Xxi)&NKI zd*R?q8NhTGl%Gtt5mLTPM%S)nJ)78u8fOfo_>Eh;0>)c({=C z4+fm|fviE#F}q2vX!^MIumpIgbbseA;p^G&F^QE#-reZYR*DMt7ZeHue?7(WYwYst zw$OM8dL@&!5{xaIQn%D>UU=ad1` z&G>(Jhd+S_m<;^t(kFN)-CVcO3CZt#4?YkpoFv1tYE#oqxR%+Wuty3wJNaSFEZ`W~ z<7r+;3p~+V zaY0itcqix%s7*KF^3b?QpRXsC)URe{Q0{Hve4~GP7d{aI4?%h+s#6n2_KObHzFRZ! zPGQ1njt8y_K@uZ-tCmDWB(IN$kIk{J9e#I&9C#|^ucvf%A)12sj{H*Kop+cE9?)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0008eNklmHRFjb(Auv=Bu?(J5IBB2f`{{S08 zS;zts42X{|ZNi#LT^a#Pt4dU5K?O!Lyn6yRauVC`#ZGd5%aNk^BiHBHe)rjVG?Wfs>2>(gE(dVy~v&r}D2_Ei3f(%fejTSpM?+J3?hC4~xW6oz$ zZx9%aXf)cYXHnM>GY}Z0uq|sQ2nz_MPTH)M`r6?qU!a43ofT@LhZ|h79sj>8Cz9FqkhWtR=i7eKv0apIO>& z)on97ihH^vPTUa#z*qXmthU)5-}$JNZCRoN_z1qzkKsU|{k6+ypoj)`+kPe~rGaQ% z;`p>I(Qyl2G`%Ievp;NoiU*gZ**6^y1Yb=hVF-TJvqu5}_$LM=ojyq@5V$AgV4E}> zJa>M~X(#)`@k$@tvgE!G4vR_cK_=M(pnbOD`)^LtpIj`8FB0oU-U0vs|NjF3ruWuc TEP9sB00000NkvXXu0mjfMx=ux literal 0 HcmV?d00001 diff --git a/utils/goldfish-qemu/skins/HVGA/back.png b/utils/goldfish-qemu/skins/HVGA/back.png new file mode 100644 index 0000000000000000000000000000000000000000..41034d9105e4fc077ea8620862828cc0e76c7938 GIT binary patch literal 3564 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 AmjD0& literal 0 HcmV?d00001 diff --git a/utils/goldfish-qemu/skins/HVGA/key.png b/utils/goldfish-qemu/skins/HVGA/key.png new file mode 100644 index 0000000000000000000000000000000000000000..7a3f563bdeeaee0a604e964edf60cd2facc39b4a GIT binary patch literal 2857 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 PS^*6eUFAxI-OK+2E`~%c literal 0 HcmV?d00001 diff --git a/utils/goldfish-qemu/skins/HVGA/layout b/utils/goldfish-qemu/skins/HVGA/layout new file mode 100644 index 000000000..4c3d76420 --- /dev/null +++ b/utils/goldfish-qemu/skins/HVGA/layout @@ -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 index 0000000000000000000000000000000000000000..e81d8abcffd3f8eaf515449e27b8f9c8480ca323 GIT binary patch literal 3079 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 literal 0 HcmV?d00001 diff --git a/utils/goldfish-qemu/skins/HVGA/spacebar.png b/utils/goldfish-qemu/skins/HVGA/spacebar.png new file mode 100644 index 0000000000000000000000000000000000000000..19fe604765b984dd1df424c25b9ba0c42f678276 GIT binary patch literal 2916 zcmb`J_dgZ>7suZ>vUm3AW77@Smd(BP3|IFGWnU$$loj2Ztn|T6c2^{OWaR3Gx<y9@7VbcT$ z4ANnZS9gDI7jBt=ePJ1B&%+>U4^P5!xAUpB{;fig%cM zkkC->B|EO*WTTvCJIY1kiSXx_K1+?9dM(b&9n$E{tAU!^dXPxGe5tD^&2LK?4s-~4 zaUX!~roh%OvJ5m>--m{h<|8-tCveG*HaG{I$qOrd*X>f}W4LVGK#d604fe%AM3rpk8~j*-@|o8f}H*mMHK<0)DqnSn1m_CT!FjFu}&QnV+5+fLjPuV$uX z{}d_eXeP3)d-t4Xyo<>PymmKGetZuPNhz<=&u0({g3@P=TdF>nI2-k?oNPxY>np|0~s+pifTF~O6^ErV#xEHaj^%`_8xBGam@@6s z_;O5XAX5KLw9|1Som0D2yDj34U4HG&rRGjiW>10oFgYt1 z$0AKhy5(gBng|sO6;!?b&I=!X`lYPkgO?#TjH|LGnLE)>=eU1fTD&AwtZGG4@^dKO7KDhq{Q=d)UH zppFQvi~7qB;o5G1C~{AC&s=zdCk^Wqj+y*x!v5@5r^}M$l7FXvXQ4Emw3xJ|^}6*| zj=eRh_)@X9m9|yaK>xt&f$?m$TwSFJ<<;EP+=<-zMz`x>*X4+%#P{Cjb<5X_owkV0 z0kPLLor=(o*InyPst8q5<4sjfC7dNBn>3q>ym3r>%`ajPv8+*`W@VC&T21sPM!91= z_%My1tJ}BITGFCEME!fLOV1iV#a1D5T_pP6ySv<4*R0ZoELQ;(ZHutQVH#E?V4g5Ms%oO9 zu_&~B-~A__-fz9Tua@+dbTsCa=bUc#Ymghe8~beA1M_ai&LbX4oO+!`oDPE$tP})8 zlZZ3KIiEW`hixTJYSZvpKFN^BFy(R8_d)S!814V^MMX$w3Kd!C|FLwb0=i#Jzc=zeX8GbGaBLTg|uf7HUwv za)sME(;6RCKj?QV_&D{Cp$Ta7JC?$l3ealxfIA=Ok2ZJW7YU2ZOObq8ux{6&@B&KP zZfpr}nF5!bR)&F9g3Xl||1so%mhwK6+P)AfmCO|0CenrxhYhO_Crlz-pcien&7js1 z&wt>X)xsq|s}#wtkerOrgBsIb=rqlQM)u&dTcamo!!i&EnuggwA>FY4wD4$OQiM^T`6?vBjHv8*) zsi_(-f4(~1oP3@$TSj^2w@kJG)~V@ttn=62ZSMUxrou7@ zWT{OtL<_W#b>b*+nx#b4)M6Mw}ph850@NMcSu~U*0ff z>-y*83E^j`JgYjZ!k5?f8Rz#evT98~cotc?KtKA=0}+e}>^3}SJI5r~ zA?MK9!})`4zuxfp`dq}3DfJ)rm#R8W;TAi{o?Fvvk4Mum+k?*t>4d0gg+DWH)Yrtw zRZq(NZT7&QA2>o5MvPCBR<)b8DK6XZL$>RvD;H4jQ8{n5Zu+l>tm~YljoNlKy==;< zCb{^Lwjx>@B7OGPgz_{fv%4+fzj#l_$MQ6FXIpk60{1`f@6GehM&Fe=rt~#Uh01JI zHQP4d+%?!VoI=dTkLf#~%uN2Ad32i`n!htVW4ccl8#8!<-%DXfoKMM4>5F5H+sM13 zr>VK9fA@Ips011M|DUlz e13Lhxr!)Z7ao$klwv_N$G+=IQV^j@yd;DLCO-#%H literal 0 HcmV?d00001 diff --git a/utils/goldfish-qemu/skins/HVGA/volume_down.png b/utils/goldfish-qemu/skins/HVGA/volume_down.png new file mode 100644 index 0000000000000000000000000000000000000000..f8a88dec810c5e3a33ba6d1c1919acb00fa97feb GIT binary patch literal 3586 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 IM6N<$f_nU^82|tP literal 0 HcmV?d00001 diff --git a/utils/goldfish-qemu/skins/HVGA/volume_up.png b/utils/goldfish-qemu/skins/HVGA/volume_up.png new file mode 100644 index 0000000000000000000000000000000000000000..940457f707bdc589883be0d8fd7c49930195a23e GIT binary patch literal 3856 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 + 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 index 000000000..b07b5a3d2 --- /dev/null +++ b/utils/redboot-ar231x/Makefile @@ -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 index 000000000..f7c6e9745 --- /dev/null +++ b/utils/redboot-ar231x/patches/010-fix-compile.patch @@ -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 { + $(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/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 { + $(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/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 { + $(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/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 { + $(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/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 + + // ---------------------------------------------------------------------------- + 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 + + #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 , and because + // the class definitions rely on these headers. + #include ++#include + + //}}} + +--- a/ecos/host/libcdl/parse.cxx ++++ b/ecos/host/libcdl/parse.cxx +@@ -58,6 +58,7 @@ + // It implicitly supplies , and because + // the class definitions rely on these headers. + #include ++#include + + //}}} + +--- a/ecos/host/libcdl/cdlmisc.cxx ++++ b/ecos/host/libcdl/cdlmisc.cxx +@@ -66,6 +66,7 @@ + + // For access to strtod() + #include ++#include + + // strtod() involves errno... + #include +--- 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 + #include ++#include + + #if defined(__unix__) || defined(__CYGWIN32__) + extern "C" { -- 2.30.2