]> err.no Git - linux-2.6/commitdiff
Merge branch 'r8169-next' of git://git.kernel.org/pub/scm/linux/kernel/git/romieu...
authorJeff Garzik <jeff@garzik.org>
Fri, 4 Jul 2008 12:35:57 +0000 (08:35 -0400)
committerJeff Garzik <jgarzik@redhat.com>
Fri, 4 Jul 2008 12:35:57 +0000 (08:35 -0400)
156 files changed:
Documentation/feature-removal-schedule.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/s2io.txt
Documentation/rfkill.txt
MAINTAINERS
drivers/connector/connector.c
drivers/net/3c59x.c
drivers/net/b44.c
drivers/net/e100.c
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000e/netdev.c
drivers/net/hamradio/dmascc.c
drivers/net/igb/igb_main.c
drivers/net/ipg.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/niu.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pppoe.c
drivers/net/ps3_gelic_wireless.c
drivers/net/qla3xxx.c
drivers/net/r6040.c
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/tc35815.c
drivers/net/wan/x25_asy.c
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/adm8211.c
drivers/net/wireless/airo.c
drivers/net/wireless/ath5k/Kconfig
drivers/net/wireless/ath5k/base.c
drivers/net/wireless/ath5k/base.h
drivers/net/wireless/ath5k/hw.c
drivers/net/wireless/atmel.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/debugfs.c
drivers/net/wireless/b43/debugfs.h
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/leds.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/main.h
drivers/net/wireless/b43/pio.c
drivers/net/wireless/b43/rfkill.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43legacy/dma.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/rfkill.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/hostap/hostap.h
drivers/net/wireless/hostap/hostap_ap.c
drivers/net/wireless/hostap/hostap_ioctl.c
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/iwl-rfkill.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/libertas/scan.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/orinoco.c
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/prism54/islpci_eth.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00pci.h
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00rfkill.c
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt2x00usb.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/strip.c [deleted file]
drivers/net/wireless/wl3501_cs.c
drivers/net/wireless/zd1201.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/ssb/Kconfig
drivers/ssb/main.c
fs/compat_ioctl.c
include/linux/ethtool.h
include/linux/ieee80211.h
include/linux/igmp.h
include/linux/inet_lro.h
include/linux/ipv6.h
include/linux/mroute.h
include/linux/mroute6.h
include/linux/netdevice.h
include/linux/nl80211.h
include/linux/rfkill.h
include/linux/ssb/ssb.h
include/linux/wireless.h
include/net/ipv6.h
include/net/iw_handler.h
include/net/mac80211.h
include/net/net_namespace.h
include/net/wext.h
net/core/dev.c
net/core/ethtool.c
net/core/net_namespace.c
net/core/skbuff.c
net/ieee80211/ieee80211_wx.c
net/ipv4/af_inet.c
net/ipv4/inet_fragment.c
net/ipv4/inet_lro.c
net/ipv4/ip_fragment.c
net/ipv4/ipmr.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/icmp.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ip6mr.c
net/ipv6/ipv6_sockglue.c
net/ipv6/netfilter/ip6table_mangle.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/mac80211/Kconfig
net/mac80211/ieee80211_i.h
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tkip.c
net/mac80211/tx.c
net/mac80211/wep.c
net/mac80211/wext.c
net/mac80211/wpa.c
net/netlabel/netlabel_unlabeled.c
net/netlink/attr.c
net/rfkill/rfkill-input.c
net/rfkill/rfkill-input.h
net/rfkill/rfkill.c
net/sched/Kconfig
net/sched/sch_generic.c
net/sctp/socket.c
net/socket.c
net/unix/af_unix.c
net/wireless/wext.c

index 5b3f31faed56872b84fbd293494613f6d627a987..5378511a5f9fe699ea211b3d2323cce11cd9583e 100644 (file)
@@ -312,3 +312,15 @@ When:      2.6.26
 Why:   Implementation became generic; users should now include
        linux/semaphore.h instead.
 Who:   Matthew Wilcox <willy@linux.intel.com>
+
+---------------------------
+
+What:  SCTP_GET_PEER_ADDRS_NUM_OLD, SCTP_GET_PEER_ADDRS_OLD,
+       SCTP_GET_LOCAL_ADDRS_NUM_OLD, SCTP_GET_LOCAL_ADDRS_OLD
+When:  June 2009
+Why:    A newer version of the options have been introduced in 2005 that
+       removes the limitions of the old API.  The sctp library has been
+        converted to use these new options at the same time.  Any user
+       space app that directly uses the old options should convert to using
+       the new options.
+Who:   Vlad Yasevich <vladislav.yasevich@hp.com>
index 17a6e46fbd43abfce8ad5558f99200f8389ac650..72f6d52e52e6e6886321fa3af37248819a41262c 100644 (file)
@@ -548,8 +548,9 @@ icmp_echo_ignore_broadcasts - BOOLEAN
 icmp_ratelimit - INTEGER
        Limit the maximal rates for sending ICMP packets whose type matches
        icmp_ratemask (see below) to specific targets.
-       0 to disable any limiting, otherwise the maximal rate in jiffies(1)
-       Default: 100
+       0 to disable any limiting,
+       otherwise the minimal space between responses in milliseconds.
+       Default: 1000
 
 icmp_ratemask - INTEGER
        Mask made of ICMP types for which rates are being limited.
@@ -1024,11 +1025,23 @@ max_addresses - INTEGER
        autoconfigured addresses.
        Default: 16
 
+disable_ipv6 - BOOLEAN
+       Disable IPv6 operation.
+       Default: FALSE (enable IPv6 operation)
+
+accept_dad - INTEGER
+       Whether to accept DAD (Duplicate Address Detection).
+       0: Disable DAD
+       1: Enable DAD (default)
+       2: Enable DAD, and disable IPv6 operation if MAC-based duplicate
+          link-local address has been found.
+
 icmp/*:
 ratelimit - INTEGER
        Limit the maximal rates for sending ICMPv6 packets.
-       0 to disable any limiting, otherwise the maximal rate in jiffies(1)
-       Default: 100
+       0 to disable any limiting,
+       otherwise the minimal space between responses in milliseconds.
+       Default: 1000
 
 
 IPv6 Update by:
index 4bde53e85f3f02df27191234af82b3ba06b9f7a5..1e28e2ddb90a6e202ce65bd60778ff701afa8ee1 100644 (file)
@@ -83,9 +83,9 @@ Valid range: Limited by memory on system
 Default: 30 
 
 e. intr_type
-Specifies interrupt type. Possible values 1(INTA), 2(MSI), 3(MSI-X)
-Valid range: 1-3
-Default: 
+Specifies interrupt type. Possible values 0(INTA), 2(MSI-X)
+Valid values: 0, 2
+Default: 2
 
 5.  Performance suggestions
 General:
index a83ff23cd68cea84d4476a43df7b9e9e91f10cf8..0843ed0163a5810fc564844b1929cf4fbe7673eb 100644 (file)
 rfkill - RF switch subsystem support
 ====================================
 
-1 Implementation details
-2 Driver support
-3 Userspace support
+1 Introduction
+2 Implementation details
+3 Kernel driver guidelines
+3.1 wireless device drivers
+3.2 platform/switch drivers
+3.3 input device drivers
+4 Kernel API
+5 Userspace support
 
-===============================================================================
-1: Implementation details
 
-The rfkill switch subsystem offers support for keys often found on laptops
-to enable wireless devices like WiFi and Bluetooth.
+1. Introduction:
+
+The rfkill switch subsystem exists to add a generic interface to circuitry that
+can enable or disable the signal output of a wireless *transmitter* of any
+type.  By far, the most common use is to disable radio-frequency transmitters.
 
-This is done by providing the user 3 possibilities:
- 1 - The rfkill system handles all events; userspace is not aware of events.
- 2 - The rfkill system handles all events; userspace is informed about the events.
- 3 - The rfkill system does not handle events; userspace handles all events.
+Note that disabling the signal output means that the the transmitter is to be
+made to not emit any energy when "blocked".  rfkill is not about blocking data
+transmissions, it is about blocking energy emission.
 
-The buttons to enable and disable the wireless radios are important in
+The rfkill subsystem offers support for keys and switches often found on
+laptops to enable wireless devices like WiFi and Bluetooth, so that these keys
+and switches actually perform an action in all wireless devices of a given type
+attached to the system.
+
+The buttons to enable and disable the wireless transmitters are important in
 situations where the user is for example using his laptop on a location where
-wireless radios _must_ be disabled (e.g. airplanes).
-Because of this requirement, userspace support for the keys should not be
-made mandatory. Because userspace might want to perform some additional smarter
-tasks when the key is pressed, rfkill still provides userspace the possibility
-to take over the task to handle the key events.
+radio-frequency transmitters _must_ be disabled (e.g. airplanes).
+
+Because of this requirement, userspace support for the keys should not be made
+mandatory.  Because userspace might want to perform some additional smarter
+tasks when the key is pressed, rfkill provides userspace the possibility to
+take over the task to handle the key events.
+
+===============================================================================
+2: Implementation details
+
+The rfkill subsystem is composed of various components: the rfkill class, the
+rfkill-input module (an input layer handler), and some specific input layer
+events.
+
+The rfkill class provides kernel drivers with an interface that allows them to
+know when they should enable or disable a wireless network device transmitter.
+This is enabled by the CONFIG_RFKILL Kconfig option.
+
+The rfkill class support makes sure userspace will be notified of all state
+changes on rfkill devices through uevents.  It provides a notification chain
+for interested parties in the kernel to also get notified of rfkill state
+changes in other drivers.  It creates several sysfs entries which can be used
+by userspace.  See section "Userspace support".
+
+The rfkill-input module provides the kernel with the ability to implement a
+basic response when the user presses a key or button (or toggles a switch)
+related to rfkill functionality.  It is an in-kernel implementation of default
+policy of reacting to rfkill-related input events and neither mandatory nor
+required for wireless drivers to operate.  It is enabled by the
+CONFIG_RFKILL_INPUT Kconfig option.
+
+rfkill-input is a rfkill-related events input layer handler.  This handler will
+listen to all rfkill key events and will change the rfkill state of the
+wireless devices accordingly.  With this option enabled userspace could either
+do nothing or simply perform monitoring tasks.
+
+The rfkill-input module also provides EPO (emergency power-off) functionality
+for all wireless transmitters.  This function cannot be overridden, and it is
+always active.  rfkill EPO is related to *_RFKILL_ALL input layer events.
+
+
+Important terms for the rfkill subsystem:
+
+In order to avoid confusion, we avoid the term "switch" in rfkill when it is
+referring to an electronic control circuit that enables or disables a
+transmitter.  We reserve it for the physical device a human manipulates
+(which is an input device, by the way):
+
+rfkill switch:
+
+       A physical device a human manipulates.  Its state can be perceived by
+       the kernel either directly (through a GPIO pin, ACPI GPE) or by its
+       effect on a rfkill line of a wireless device.
+
+rfkill controller:
+
+       A hardware circuit that controls the state of a rfkill line, which a
+       kernel driver can interact with *to modify* that state (i.e. it has
+       either write-only or read/write access).
+
+rfkill line:
+
+       An input channel (hardware or software) of a wireless device, which
+       causes a wireless transmitter to stop emitting energy (BLOCK) when it
+       is active.  Point of view is extremely important here: rfkill lines are
+       always seen from the PoV of a wireless device (and its driver).
+
+soft rfkill line/software rfkill line:
+
+       A rfkill line the wireless device driver can directly change the state
+       of.  Related to rfkill_state RFKILL_STATE_SOFT_BLOCKED.
+
+hard rfkill line/hardware rfkill line:
+
+       A rfkill line that works fully in hardware or firmware, and that cannot
+       be overridden by the kernel driver.  The hardware device or the
+       firmware just exports its status to the driver, but it is read-only.
+       Related to rfkill_state RFKILL_STATE_HARD_BLOCKED.
+
+The enum rfkill_state describes the rfkill state of a transmitter:
+
+When a rfkill line or rfkill controller is in the RFKILL_STATE_UNBLOCKED state,
+the wireless transmitter (radio TX circuit for example) is *enabled*.  When the
+it is in the RFKILL_STATE_SOFT_BLOCKED or RFKILL_STATE_HARD_BLOCKED, the
+wireless transmitter is to be *blocked* from operating.
+
+RFKILL_STATE_SOFT_BLOCKED indicates that a call to toggle_radio() can change
+that state.  RFKILL_STATE_HARD_BLOCKED indicates that a call to toggle_radio()
+will not be able to change the state and will return with a suitable error if
+attempts are made to set the state to RFKILL_STATE_UNBLOCKED.
+
+RFKILL_STATE_HARD_BLOCKED is used by drivers to signal that the device is
+locked in the BLOCKED state by a hardwire rfkill line (typically an input pin
+that, when active, forces the transmitter to be disabled) which the driver
+CANNOT override.
+
+Full rfkill functionality requires two different subsystems to cooperate: the
+input layer and the rfkill class.  The input layer issues *commands* to the
+entire system requesting that devices registered to the rfkill class change
+state.  The way this interaction happens is not complex, but it is not obvious
+either:
+
+Kernel Input layer:
+
+       * Generates KEY_WWAN, KEY_WLAN, KEY_BLUETOOTH, SW_RFKILL_ALL, and
+         other such events when the user presses certain keys, buttons, or
+         toggles certain physical switches.
+
+       THE INPUT LAYER IS NEVER USED TO PROPAGATE STATUS, NOTIFICATIONS OR THE
+       KIND OF STUFF AN ON-SCREEN-DISPLAY APPLICATION WOULD REPORT.  It is
+       used to issue *commands* for the system to change behaviour, and these
+       commands may or may not be carried out by some kernel driver or
+       userspace application.  It follows that doing user feedback based only
+       on input events is broken, as there is no guarantee that an input event
+       will be acted upon.
+
+       Most wireless communication device drivers implementing rfkill
+       functionality MUST NOT generate these events, and have no reason to
+       register themselves with the input layer.  Doing otherwise is a common
+       misconception.  There is an API to propagate rfkill status change
+       information, and it is NOT the input layer.
+
+rfkill class:
+
+       * Calls a hook in a driver to effectively change the wireless
+         transmitter state;
+       * Keeps track of the wireless transmitter state (with help from
+         the driver);
+       * Generates userspace notifications (uevents) and a call to a
+         notification chain (kernel) when there is a wireless transmitter
+         state change;
+       * Connects a wireless communications driver with the common rfkill
+         control system, which, for example, allows actions such as
+         "switch all bluetooth devices offline" to be carried out by
+         userspace or by rfkill-input.
+
+       THE RFKILL CLASS NEVER ISSUES INPUT EVENTS.  THE RFKILL CLASS DOES
+       NOT LISTEN TO INPUT EVENTS.  NO DRIVER USING THE RFKILL CLASS SHALL
+       EVER LISTEN TO, OR ACT ON RFKILL INPUT EVENTS.  Doing otherwise is
+       a layering violation.
+
+       Most wireless data communication drivers in the kernel have just to
+       implement the rfkill class API to work properly.  Interfacing to the
+       input layer is not often required (and is very often a *bug*) on
+       wireless drivers.
+
+       Platform drivers often have to attach to the input layer to *issue*
+       (but never to listen to) rfkill events for rfkill switches, and also to
+       the rfkill class to export a control interface for the platform rfkill
+       controllers to the rfkill subsystem.  This does NOT mean the rfkill
+       switch is attached to a rfkill class (doing so is almost always wrong).
+       It just means the same kernel module is the driver for different
+       devices (rfkill switches and rfkill controllers).
+
+
+Userspace input handlers (uevents) or kernel input handlers (rfkill-input):
+
+       * Implements the policy of what should happen when one of the input
+         layer events related to rfkill operation is received.
+       * Uses the sysfs interface (userspace) or private rfkill API calls
+         to tell the devices registered with the rfkill class to change
+         their state (i.e. translates the input layer event into real
+         action).
+       * rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0
+         (power off all transmitters) in a special way: it ignores any
+         overrides and local state cache and forces all transmitters to the
+         RFKILL_STATE_SOFT_BLOCKED state (including those which are already
+         supposed to be BLOCKED).  Note that the opposite event (power on all
+         transmitters) is handled normally.
+
+Userspace uevent handler or kernel platform-specific drivers hooked to the
+rfkill notifier chain:
+
+       * Taps into the rfkill notifier chain or to KOBJ_CHANGE uevents,
+         in order to know when a device that is registered with the rfkill
+         class changes state;
+       * Issues feedback notifications to the user;
+       * In the rare platforms where this is required, synthesizes an input
+         event to command all *OTHER* rfkill devices to also change their
+         statues when a specific rfkill device changes state.
+
+
+===============================================================================
+3: Kernel driver guidelines
+
+Remember: point-of-view is everything for a driver that connects to the rfkill
+subsystem.  All the details below must be measured/perceived from the point of
+view of the specific driver being modified.
+
+The first thing one needs to know is whether his driver should be talking to
+the rfkill class or to the input layer.  In rare cases (platform drivers), it
+could happen that you need to do both, as platform drivers often handle a
+variety of devices in the same driver.
+
+Do not mistake input devices for rfkill controllers.  The only type of "rfkill
+switch" device that is to be registered with the rfkill class are those
+directly controlling the circuits that cause a wireless transmitter to stop
+working (or the software equivalent of them), i.e. what we call a rfkill
+controller.  Every other kind of "rfkill switch" is just an input device and
+MUST NOT be registered with the rfkill class.
+
+A driver should register a device with the rfkill class when ALL of the
+following conditions are met (they define a rfkill controller):
+
+1. The device is/controls a data communications wireless transmitter;
+
+2. The kernel can interact with the hardware/firmware to CHANGE the wireless
+   transmitter state (block/unblock TX operation);
+
+3. The transmitter can be made to not emit any energy when "blocked":
+   rfkill is not about blocking data transmissions, it is about blocking
+   energy emission;
+
+A driver should register a device with the input subsystem to issue
+rfkill-related events (KEY_WLAN, KEY_BLUETOOTH, KEY_WWAN, KEY_WIMAX,
+SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met:
+
+1. It is directly related to some physical device the user interacts with, to
+   command the O.S./firmware/hardware to enable/disable a data communications
+   wireless transmitter.
+
+   Examples of the physical device are: buttons, keys and switches the user
+   will press/touch/slide/switch to enable or disable the wireless
+   communication device.
+
+2. It is NOT slaved to another device, i.e. there is no other device that
+   issues rfkill-related input events in preference to this one.
 
-The system inside the kernel has been split into 2 separate sections:
-       1 - RFKILL
-       2 - RFKILL_INPUT
+   Please refer to the corner cases and examples section for more details.
 
-The first option enables rfkill support and will make sure userspace will
-be notified of any events through the input device. It also creates several
-sysfs entries which can be used by userspace. See section "Userspace support".
+When in doubt, do not issue input events.  For drivers that should generate
+input events in some platforms, but not in others (e.g. b43), the best solution
+is to NEVER generate input events in the first place.  That work should be
+deferred to a platform-specific kernel module (which will know when to generate
+events through the rfkill notifier chain) or to userspace.  This avoids the
+usual maintenance problems with DMI whitelisting.
 
-The second option provides an rfkill input handler. This handler will
-listen to all rfkill key events and will toggle the radio accordingly.
-With this option enabled userspace could either do nothing or simply
-perform monitoring tasks.
 
+Corner cases and examples:
 ====================================
-2: Driver support
 
-To build a driver with rfkill subsystem support, the driver should
-depend on the Kconfig symbol RFKILL; it should _not_ depend on
-RKFILL_INPUT.
+1. If the device is an input device that, because of hardware or firmware,
+causes wireless transmitters to be blocked regardless of the kernel's will, it
+is still just an input device, and NOT to be registered with the rfkill class.
 
-Unless key events trigger an interrupt to which the driver listens, polling
-will be required to determine the key state changes. For this the input
-layer providers the input-polldev handler.
+2. If the wireless transmitter switch control is read-only, it is an input
+device and not to be registered with the rfkill class (and maybe not to be made
+an input layer event source either, see below).
 
-A driver should implement a few steps to correctly make use of the
-rfkill subsystem. First for non-polling drivers:
+3. If there is some other device driver *closer* to the actual hardware the
+user interacted with (the button/switch/key) to issue an input event, THAT is
+the device driver that should be issuing input events.
 
-       - rfkill_allocate()
-       - input_allocate_device()
-       - rfkill_register()
-       - input_register_device()
+E.g:
+  [RFKILL slider switch] -- [GPIO hardware] -- [WLAN card rf-kill input]
+                           (platform driver)    (wireless card driver)
+
+The user is closer to the RFKILL slide switch plaform driver, so the driver
+which must issue input events is the platform driver looking at the GPIO
+hardware, and NEVER the wireless card driver (which is just a slave).  It is
+very likely that there are other leaves than just the WLAN card rf-kill input
+(e.g. a bluetooth card, etc)...
+
+On the other hand, some embedded devices do this:
+
+  [RFKILL slider switch] -- [WLAN card rf-kill input]
+                             (wireless card driver)
+
+In this situation, the wireless card driver *could* register itself as an input
+device and issue rf-kill related input events... but in order to AVOID the need
+for DMI whitelisting, the wireless card driver does NOT do it.  Userspace (HAL)
+or a platform driver (that exists only on these embedded devices) will do the
+dirty job of issuing the input events.
+
+
+COMMON MISTAKES in kernel drivers, related to rfkill:
+====================================
+
+1. NEVER confuse input device keys and buttons with input device switches.
+
+  1a. Switches are always set or reset.  They report the current state
+      (on position or off position).
+
+  1b. Keys and buttons are either in the pressed or not-pressed state, and
+      that's it.  A "button" that latches down when you press it, and
+      unlatches when you press it again is in fact a switch as far as input
+      devices go.
+
+Add the SW_* events you need for switches, do NOT try to emulate a button using
+KEY_* events just because there is no such SW_* event yet.  Do NOT try to use,
+for example, KEY_BLUETOOTH when you should be using SW_BLUETOOTH instead.
+
+2. Input device switches (sources of EV_SW events) DO store their current state
+(so you *must* initialize it by issuing a gratuitous input layer event on
+driver start-up and also when resuming from sleep), and that state CAN be
+queried from userspace through IOCTLs.  There is no sysfs interface for this,
+but that doesn't mean you should break things trying to hook it to the rfkill
+class to get a sysfs interface :-)
+
+3. Do not issue *_RFKILL_ALL events by default, unless you are sure it is the
+correct event for your switch/button.  These events are emergency power-off
+events when they are trying to turn the transmitters off.  An example of an
+input device which SHOULD generate *_RFKILL_ALL events is the wireless-kill
+switch in a laptop which is NOT a hotkey, but a real switch that kills radios
+in hardware, even if the O.S. has gone to lunch.  An example of an input device
+which SHOULD NOT generate *_RFKILL_ALL events by default, is any sort of hot
+key that does nothing by itself, as well as any hot key that is type-specific
+(e.g. the one for WLAN).
+
+
+3.1 Guidelines for wireless device drivers
+------------------------------------------
+
+1. Each independent transmitter in a wireless device (usually there is only one
+transmitter per device) should have a SINGLE rfkill class attached to it.
+
+2. If the device does not have any sort of hardware assistance to allow the
+driver to rfkill the device, the driver should emulate it by taking all actions
+required to silence the transmitter.
+
+3. If it is impossible to silence the transmitter (i.e. it still emits energy,
+even if it is just in brief pulses, when there is no data to transmit and there
+is no hardware support to turn it off) do NOT lie to the users.  Do not attach
+it to a rfkill class.  The rfkill subsystem does not deal with data
+transmission, it deals with energy emission.  If the transmitter is emitting
+energy, it is not blocked in rfkill terms.
+
+4. It doesn't matter if the device has multiple rfkill input lines affecting
+the same transmitter, their combined state is to be exported as a single state
+per transmitter (see rule 1).
+
+This rule exists because users of the rfkill subsystem expect to get (and set,
+when possible) the overall transmitter rfkill state, not of a particular rfkill
+line.
+
+Example of a WLAN wireless driver connected to the rfkill subsystem:
+--------------------------------------------------------------------
+
+A certain WLAN card has one input pin that causes it to block the transmitter
+and makes the status of that input pin available (only for reading!) to the
+kernel driver.  This is a hard rfkill input line (it cannot be overridden by
+the kernel driver).
+
+The card also has one PCI register that, if manipulated by the driver, causes
+it to block the transmitter.  This is a soft rfkill input line.
+
+It has also a thermal protection circuitry that shuts down its transmitter if
+the card overheats, and makes the status of that protection available (only for
+reading!) to the kernel driver.  This is also a hard rfkill input line.
+
+If either one of these rfkill lines are active, the transmitter is blocked by
+the hardware and forced offline.
+
+The driver should allocate and attach to its struct device *ONE* instance of
+the rfkill class (there is only one transmitter).
+
+It can implement the get_state() hook, and return RFKILL_STATE_HARD_BLOCKED if
+either one of its two hard rfkill input lines are active.  If the two hard
+rfkill lines are inactive, it must return RFKILL_STATE_SOFT_BLOCKED if its soft
+rfkill input line is active.  Only if none of the rfkill input lines are
+active, will it return RFKILL_STATE_UNBLOCKED.
 
-For polling drivers:
+If it doesn't implement the get_state() hook, it must make sure that its calls
+to rfkill_force_state() are enough to keep the status always up-to-date, and it
+must do a rfkill_force_state() on resume from sleep.
 
+Every time the driver gets a notification from the card that one of its rfkill
+lines changed state (polling might be needed on badly designed cards that don't
+generate interrupts for such events), it recomputes the rfkill state as per
+above, and calls rfkill_force_state() to update it.
+
+The driver should implement the toggle_radio() hook, that:
+
+1. Returns an error if one of the hardware rfkill lines are active, and the
+caller asked for RFKILL_STATE_UNBLOCKED.
+
+2. Activates the soft rfkill line if the caller asked for state
+RFKILL_STATE_SOFT_BLOCKED.  It should do this even if one of the hard rfkill
+lines are active, effectively double-blocking the transmitter.
+
+3. Deactivates the soft rfkill line if none of the hardware rfkill lines are
+active and the caller asked for RFKILL_STATE_UNBLOCKED.
+
+===============================================================================
+4: Kernel API
+
+To build a driver with rfkill subsystem support, the driver should depend on
+(or select) the Kconfig symbol RFKILL; it should _not_ depend on RKFILL_INPUT.
+
+The hardware the driver talks to may be write-only (where the current state
+of the hardware is unknown), or read-write (where the hardware can be queried
+about its current state).
+
+The rfkill class will call the get_state hook of a device every time it needs
+to know the *real* current state of the hardware.  This can happen often.
+
+Some hardware provides events when its status changes.  In these cases, it is
+best for the driver to not provide a get_state hook, and instead register the
+rfkill class *already* with the correct status, and keep it updated using
+rfkill_force_state() when it gets an event from the hardware.
+
+There is no provision for a statically-allocated rfkill struct.  You must
+use rfkill_allocate() to allocate one.
+
+You should:
        - rfkill_allocate()
-       - input_allocate_polled_device()
+       - modify rfkill fields (flags, name)
+       - modify state to the current hardware state (THIS IS THE ONLY TIME
+         YOU CAN ACCESS state DIRECTLY)
        - rfkill_register()
-       - input_register_polled_device()
 
-When a key event has been detected, the correct event should be
-sent over the input device which has been registered by the driver.
+The only way to set a device to the RFKILL_STATE_HARD_BLOCKED state is through
+a suitable return of get_state() or through rfkill_force_state().
 
-====================================
-3: Userspace support
+When a device is in the RFKILL_STATE_HARD_BLOCKED state, the only way to switch
+it to a different state is through a suitable return of get_state() or through
+rfkill_force_state().
+
+If toggle_radio() is called to set a device to state RFKILL_STATE_SOFT_BLOCKED
+when that device is already at the RFKILL_STATE_HARD_BLOCKED state, it should
+not return an error.  Instead, it should try to double-block the transmitter,
+so that its state will change from RFKILL_STATE_HARD_BLOCKED to
+RFKILL_STATE_SOFT_BLOCKED should the hardware blocking cease.
 
-For each key an input device will be created which will send out the correct
-key event when the rfkill key has been pressed.
+Please refer to the source for more documentation.
+
+===============================================================================
+5: Userspace support
+
+rfkill devices issue uevents (with an action of "change"), with the following
+environment variables set:
+
+RFKILL_NAME
+RFKILL_STATE
+RFKILL_TYPE
+
+The ABI for these variables is defined by the sysfs attributes.  It is best
+to take a quick look at the source to make sure of the possible values.
+
+It is expected that HAL will trap those, and bridge them to DBUS, etc.  These
+events CAN and SHOULD be used to give feedback to the user about the rfkill
+status of the system.
+
+Input devices may issue events that are related to rfkill.  These are the
+various KEY_* events and SW_* events supported by rfkill-input.c.
+
+******IMPORTANT******
+When rfkill-input is ACTIVE, userspace is NOT TO CHANGE THE STATE OF AN RFKILL
+SWITCH IN RESPONSE TO AN INPUT EVENT also handled by rfkill-input, unless it
+has set to true the user_claim attribute for that particular switch.  This rule
+is *absolute*; do NOT violate it.
+******IMPORTANT******
+
+Userspace must not assume it is the only source of control for rfkill switches.
+Their state CAN and WILL change due to firmware actions, direct user actions,
+and the rfkill-input EPO override for *_RFKILL_ALL.
+
+When rfkill-input is not active, userspace must initiate a rfkill status
+change by writing to the "state" attribute in order for anything to happen.
+
+Take particular care to implement EV_SW SW_RFKILL_ALL properly.  When that
+switch is set to OFF, *every* rfkill device *MUST* be immediately put into the
+RFKILL_STATE_SOFT_BLOCKED state, no questions asked.
 
 The following sysfs entries will be created:
 
        name: Name assigned by driver to this key (interface or driver name).
        type: Name of the key type ("wlan", "bluetooth", etc).
-       state: Current state of the key. 1: On, 0: Off.
+       state: Current state of the transmitter
+               0: RFKILL_STATE_SOFT_BLOCKED
+                       transmitter is forced off, but one can override it
+                       by a write to the state attribute;
+               1: RFKILL_STATE_UNBLOCKED
+                       transmiter is NOT forced off, and may operate if
+                       all other conditions for such operation are met
+                       (such as interface is up and configured, etc);
+               2: RFKILL_STATE_HARD_BLOCKED
+                       transmitter is forced off by something outside of
+                       the driver's control.  One cannot set a device to
+                       this state through writes to the state attribute;
        claim: 1: Userspace handles events, 0: Kernel handles events
 
 Both the "state" and "claim" entries are also writable. For the "state" entry
-this means that when 1 or 0 is written all radios, not yet in the requested
-state, will be will be toggled accordingly.
+this means that when 1 or 0 is written, the device rfkill state (if not yet in
+the requested state), will be will be toggled accordingly.
+
 For the "claim" entry writing 1 to it means that the kernel no longer handles
 key events even though RFKILL_INPUT input was enabled. When "claim" has been
 set to 0, userspace should make sure that it listens for the input events or
-check the sysfs "state" entry regularly to correctly perform the required
-tasks when the rkfill key is pressed.
+check the sysfs "state" entry regularly to correctly perform the required tasks
+when the rkfill key is pressed.
+
+A note about input devices and EV_SW events:
+
+In order to know the current state of an input device switch (like
+SW_RFKILL_ALL), you will need to use an IOCTL.  That information is not
+available through sysfs in a generic way at this time, and it is not available
+through the rfkill class AT ALL.
index d0ea6ec2552fc4df2ce82a61ab769930ea8b96d7..5ae19d502e0bcfed7f1d1bfa25d087b0c4fa2cd0 100644 (file)
@@ -3854,10 +3854,6 @@ P:       Ion Badulescu
 M:     ionut@cs.columbia.edu
 S:     Maintained
 
-STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
-W:     http://mosquitonet.Stanford.EDU/strip.html
-S:     Unsupported ?
-
 STRADIS MPEG-2 DECODER DRIVER
 P:     Nathan Laredo
 M:     laredo@gnu.org
index 85e2ba7fcfbab1b4533079da8bd812f22203952d..bf4830082a135e126d9f35f1a72a7bf5b18fbecf 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/moduleparam.h>
 #include <linux/connector.h>
 #include <linux/mutex.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
 
 #include <net/sock.h>
 
@@ -403,6 +405,40 @@ static void cn_callback(void *data)
        mutex_unlock(&notify_lock);
 }
 
+static int cn_proc_show(struct seq_file *m, void *v)
+{
+       struct cn_queue_dev *dev = cdev.cbdev;
+       struct cn_callback_entry *cbq;
+
+       seq_printf(m, "Name            ID\n");
+
+       spin_lock_bh(&dev->queue_lock);
+
+       list_for_each_entry(cbq, &dev->queue_list, callback_entry) {
+               seq_printf(m, "%-15s %u:%u\n",
+                          cbq->id.name,
+                          cbq->id.id.idx,
+                          cbq->id.id.val);
+       }
+
+       spin_unlock_bh(&dev->queue_lock);
+
+       return 0;
+}
+
+static int cn_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, cn_proc_show, NULL);
+}
+
+static const struct file_operations cn_file_ops = {
+       .owner   = THIS_MODULE,
+       .open    = cn_proc_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = single_release
+};
+
 static int __devinit cn_init(void)
 {
        struct cn_dev *dev = &cdev;
@@ -434,6 +470,8 @@ static int __devinit cn_init(void)
                return -EINVAL;
        }
 
+       proc_net_fops_create(&init_net, "connector", S_IRUGO, &cn_file_ops);
+
        return 0;
 }
 
@@ -443,6 +481,8 @@ static void __devexit cn_fini(void)
 
        cn_already_initialized = 0;
 
+       proc_net_remove(&init_net, "connector");
+
        cn_del_callback(&dev->id);
        cn_queue_free_dev(dev->cbdev);
        netlink_kernel_release(dev->nls);
index 2edda8cc7f9999af1e5f772df389c20719373190..aabad8ce7458c852a496422991c0683c0fe43d26 100644 (file)
@@ -1768,9 +1768,10 @@ vortex_timer(unsigned long data)
        case XCVR_MII: case XCVR_NWAY:
                {
                        ok = 1;
-                       spin_lock_bh(&vp->lock);
+                       /* Interrupts are already disabled */
+                       spin_lock(&vp->lock);
                        vortex_check_media(dev, 0);
-                       spin_unlock_bh(&vp->lock);
+                       spin_unlock(&vp->lock);
                }
                break;
          default:                                      /* Other media types handled by Tx timeouts. */
index 59dce6aa08659cf6b8fce2ad876962d27eae7529..c3bda5ce67c488dba1fc7f51469f16522c5b1080 100644 (file)
@@ -148,9 +148,9 @@ static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
                                                unsigned long offset,
                                                enum dma_data_direction dir)
 {
-       dma_sync_single_range_for_device(sdev->dma_dev, dma_base,
-                                        offset & dma_desc_align_mask,
-                                        dma_desc_sync_size, dir);
+       ssb_dma_sync_single_range_for_device(sdev, dma_base,
+                                            offset & dma_desc_align_mask,
+                                            dma_desc_sync_size, dir);
 }
 
 static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
@@ -158,9 +158,9 @@ static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
                                             unsigned long offset,
                                             enum dma_data_direction dir)
 {
-       dma_sync_single_range_for_cpu(sdev->dma_dev, dma_base,
-                                     offset & dma_desc_align_mask,
-                                     dma_desc_sync_size, dir);
+       ssb_dma_sync_single_range_for_cpu(sdev, dma_base,
+                                         offset & dma_desc_align_mask,
+                                         dma_desc_sync_size, dir);
 }
 
 static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
@@ -613,10 +613,10 @@ static void b44_tx(struct b44 *bp)
 
                BUG_ON(skb == NULL);
 
-               dma_unmap_single(bp->sdev->dma_dev,
-                                rp->mapping,
-                                skb->len,
-                                DMA_TO_DEVICE);
+               ssb_dma_unmap_single(bp->sdev,
+                                    rp->mapping,
+                                    skb->len,
+                                    DMA_TO_DEVICE);
                rp->skb = NULL;
                dev_kfree_skb_irq(skb);
        }
@@ -653,29 +653,29 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
        if (skb == NULL)
                return -ENOMEM;
 
-       mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
-                                RX_PKT_BUF_SZ,
-                                DMA_FROM_DEVICE);
+       mapping = ssb_dma_map_single(bp->sdev, skb->data,
+                                    RX_PKT_BUF_SZ,
+                                    DMA_FROM_DEVICE);
 
        /* Hardware bug work-around, the chip is unable to do PCI DMA
           to/from anything above 1GB :-( */
-       if (dma_mapping_error(mapping) ||
+       if (ssb_dma_mapping_error(bp->sdev, mapping) ||
                mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
                /* Sigh... */
-               if (!dma_mapping_error(mapping))
-                       dma_unmap_single(bp->sdev->dma_dev, mapping,
-                                       RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
+               if (!ssb_dma_mapping_error(bp->sdev, mapping))
+                       ssb_dma_unmap_single(bp->sdev, mapping,
+                                            RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
                dev_kfree_skb_any(skb);
                skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
                if (skb == NULL)
                        return -ENOMEM;
-               mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
-                                        RX_PKT_BUF_SZ,
-                                        DMA_FROM_DEVICE);
-               if (dma_mapping_error(mapping) ||
+               mapping = ssb_dma_map_single(bp->sdev, skb->data,
+                                            RX_PKT_BUF_SZ,
+                                            DMA_FROM_DEVICE);
+               if (ssb_dma_mapping_error(bp->sdev, mapping) ||
                        mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
-                       if (!dma_mapping_error(mapping))
-                               dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
+                       if (!ssb_dma_mapping_error(bp->sdev, mapping))
+                               ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
                        dev_kfree_skb_any(skb);
                        return -ENOMEM;
                }
@@ -750,9 +750,9 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
                                             dest_idx * sizeof(dest_desc),
                                             DMA_BIDIRECTIONAL);
 
-       dma_sync_single_for_device(bp->sdev->dma_dev, le32_to_cpu(src_desc->addr),
-                                  RX_PKT_BUF_SZ,
-                                  DMA_FROM_DEVICE);
+       ssb_dma_sync_single_for_device(bp->sdev, le32_to_cpu(src_desc->addr),
+                                      RX_PKT_BUF_SZ,
+                                      DMA_FROM_DEVICE);
 }
 
 static int b44_rx(struct b44 *bp, int budget)
@@ -772,7 +772,7 @@ static int b44_rx(struct b44 *bp, int budget)
                struct rx_header *rh;
                u16 len;
 
-               dma_sync_single_for_cpu(bp->sdev->dma_dev, map,
+               ssb_dma_sync_single_for_cpu(bp->sdev, map,
                                            RX_PKT_BUF_SZ,
                                            DMA_FROM_DEVICE);
                rh = (struct rx_header *) skb->data;
@@ -806,8 +806,8 @@ static int b44_rx(struct b44 *bp, int budget)
                        skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
                        if (skb_size < 0)
                                goto drop_it;
-                       dma_unmap_single(bp->sdev->dma_dev, map,
-                                        skb_size, DMA_FROM_DEVICE);
+                       ssb_dma_unmap_single(bp->sdev, map,
+                                            skb_size, DMA_FROM_DEVICE);
                        /* Leave out rx_header */
                        skb_put(skb, len + RX_PKT_OFFSET);
                        skb_pull(skb, RX_PKT_OFFSET);
@@ -966,25 +966,25 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
                goto err_out;
        }
 
-       mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE);
-       if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
+       mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE);
+       if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_30BIT_MASK) {
                struct sk_buff *bounce_skb;
 
                /* Chip can't handle DMA to/from >1GB, use bounce buffer */
-               if (!dma_mapping_error(mapping))
-                       dma_unmap_single(bp->sdev->dma_dev, mapping, len,
-                                       DMA_TO_DEVICE);
+               if (!ssb_dma_mapping_error(bp->sdev, mapping))
+                       ssb_dma_unmap_single(bp->sdev, mapping, len,
+                                            DMA_TO_DEVICE);
 
                bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb)
                        goto err_out;
 
-               mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data,
-                                        len, DMA_TO_DEVICE);
-               if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
-                       if (!dma_mapping_error(mapping))
-                               dma_unmap_single(bp->sdev->dma_dev, mapping,
-                                        len, DMA_TO_DEVICE);
+               mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data,
+                                            len, DMA_TO_DEVICE);
+               if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_30BIT_MASK) {
+                       if (!ssb_dma_mapping_error(bp->sdev, mapping))
+                               ssb_dma_unmap_single(bp->sdev, mapping,
+                                                    len, DMA_TO_DEVICE);
                        dev_kfree_skb_any(bounce_skb);
                        goto err_out;
                }
@@ -1082,8 +1082,8 @@ static void b44_free_rings(struct b44 *bp)
 
                if (rp->skb == NULL)
                        continue;
-               dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ,
-                                       DMA_FROM_DEVICE);
+               ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ,
+                                    DMA_FROM_DEVICE);
                dev_kfree_skb_any(rp->skb);
                rp->skb = NULL;
        }
@@ -1094,8 +1094,8 @@ static void b44_free_rings(struct b44 *bp)
 
                if (rp->skb == NULL)
                        continue;
-               dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len,
-                                       DMA_TO_DEVICE);
+               ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len,
+                                    DMA_TO_DEVICE);
                dev_kfree_skb_any(rp->skb);
                rp->skb = NULL;
        }
@@ -1117,14 +1117,14 @@ static void b44_init_rings(struct b44 *bp)
        memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
 
        if (bp->flags & B44_FLAG_RX_RING_HACK)
-               dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma,
-                                         DMA_TABLE_BYTES,
-                                         DMA_BIDIRECTIONAL);
+               ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma,
+                                              DMA_TABLE_BYTES,
+                                              DMA_BIDIRECTIONAL);
 
        if (bp->flags & B44_FLAG_TX_RING_HACK)
-               dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma,
-                                         DMA_TABLE_BYTES,
-                                         DMA_TO_DEVICE);
+               ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma,
+                                              DMA_TABLE_BYTES,
+                                              DMA_TO_DEVICE);
 
        for (i = 0; i < bp->rx_pending; i++) {
                if (b44_alloc_rx_skb(bp, -1, i) < 0)
@@ -1144,25 +1144,27 @@ static void b44_free_consistent(struct b44 *bp)
        bp->tx_buffers = NULL;
        if (bp->rx_ring) {
                if (bp->flags & B44_FLAG_RX_RING_HACK) {
-                       dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma,
-                                       DMA_TABLE_BYTES,
-                                       DMA_BIDIRECTIONAL);
+                       ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma,
+                                            DMA_TABLE_BYTES,
+                                            DMA_BIDIRECTIONAL);
                        kfree(bp->rx_ring);
                } else
-                       dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
-                                           bp->rx_ring, bp->rx_ring_dma);
+                       ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
+                                               bp->rx_ring, bp->rx_ring_dma,
+                                               GFP_KERNEL);
                bp->rx_ring = NULL;
                bp->flags &= ~B44_FLAG_RX_RING_HACK;
        }
        if (bp->tx_ring) {
                if (bp->flags & B44_FLAG_TX_RING_HACK) {
-                       dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma,
-                                       DMA_TABLE_BYTES,
-                                       DMA_TO_DEVICE);
+                       ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma,
+                                            DMA_TABLE_BYTES,
+                                            DMA_TO_DEVICE);
                        kfree(bp->tx_ring);
                } else
-                       dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
-                                           bp->tx_ring, bp->tx_ring_dma);
+                       ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
+                                               bp->tx_ring, bp->tx_ring_dma,
+                                               GFP_KERNEL);
                bp->tx_ring = NULL;
                bp->flags &= ~B44_FLAG_TX_RING_HACK;
        }
@@ -1187,7 +1189,7 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
                goto out_err;
 
        size = DMA_TABLE_BYTES;
-       bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->rx_ring_dma, gfp);
+       bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp);
        if (!bp->rx_ring) {
                /* Allocation may have failed due to pci_alloc_consistent
                   insisting on use of GFP_DMA, which is more restrictive
@@ -1199,11 +1201,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
                if (!rx_ring)
                        goto out_err;
 
-               rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring,
-                                           DMA_TABLE_BYTES,
-                                           DMA_BIDIRECTIONAL);
+               rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring,
+                                                DMA_TABLE_BYTES,
+                                                DMA_BIDIRECTIONAL);
 
-               if (dma_mapping_error(rx_ring_dma) ||
+               if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) ||
                        rx_ring_dma + size > DMA_30BIT_MASK) {
                        kfree(rx_ring);
                        goto out_err;
@@ -1214,9 +1216,9 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
                bp->flags |= B44_FLAG_RX_RING_HACK;
        }
 
-       bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->tx_ring_dma, gfp);
+       bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp);
        if (!bp->tx_ring) {
-               /* Allocation may have failed due to dma_alloc_coherent
+               /* Allocation may have failed due to ssb_dma_alloc_consistent
                   insisting on use of GFP_DMA, which is more restrictive
                   than necessary...  */
                struct dma_desc *tx_ring;
@@ -1226,11 +1228,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
                if (!tx_ring)
                        goto out_err;
 
-               tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring,
+               tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring,
                                            DMA_TABLE_BYTES,
                                            DMA_TO_DEVICE);
 
-               if (dma_mapping_error(tx_ring_dma) ||
+               if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) ||
                        tx_ring_dma + size > DMA_30BIT_MASK) {
                        kfree(tx_ring);
                        goto out_err;
index f3cba5e24ec511a7a08ea6c0659155850a165b00..1037b1332312998aa36274b279381263419f0371 100644 (file)
@@ -1803,6 +1803,8 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
        if (rx->prev->skb) {
                struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
                put_unaligned_le32(rx->dma_addr, &prev_rfd->link);
+               pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
+                       sizeof(struct rfd), PCI_DMA_TODEVICE);
        }
 
        return 0;
index 701531e72e7b3b4d1ddab378e5b05795c320d052..a3f6a9c72ec8546b11ab987b27ea330ca1fba5e2 100644 (file)
@@ -347,7 +347,7 @@ e1000_set_tso(struct net_device *netdev, u32 data)
        else
                netdev->features &= ~NETIF_F_TSO;
 
-       if (data)
+       if (data && (adapter->hw.mac_type > e1000_82547_rev_2))
                netdev->features |= NETIF_F_TSO6;
        else
                netdev->features &= ~NETIF_F_TSO6;
index 22f2fc906354d1370f586a60c83ac788be0dcf31..acdd616c96f64865c91792b593c3e536b6305736 100644 (file)
@@ -2535,7 +2535,8 @@ void e1000e_down(struct e1000_adapter *adapter)
        adapter->link_speed = 0;
        adapter->link_duplex = 0;
 
-       e1000e_reset(adapter);
+       if (!pci_channel_offline(adapter->pdev))
+               e1000e_reset(adapter);
        e1000_clean_tx_ring(adapter);
        e1000_clean_rx_ring(adapter);
 
index 0b94833e23f7a48b76d16e3f5419d24d7f0556a7..e8cfadefa4b6751dbb74bd663a0f101e76a98d54 100644 (file)
@@ -1077,8 +1077,6 @@ static inline void rx_off(struct scc_priv *priv)
 
 static void start_timer(struct scc_priv *priv, int t, int r15)
 {
-       unsigned long flags;
-
        outb(priv->tmr_mode, priv->tmr_ctrl);
        if (t == 0) {
                tm_isr(priv);
index e13b8db67b7c36e13b8c294c2cfacce4a8527c90..171d1fc1fbf8dc6028e7fbf5d4b027cc8780c8b9 100644 (file)
@@ -718,7 +718,8 @@ void igb_down(struct igb_adapter *adapter)
        adapter->link_speed = 0;
        adapter->link_duplex = 0;
 
-       igb_reset(adapter);
+       if (!pci_channel_offline(adapter->pdev))
+               igb_reset(adapter);
        igb_clean_all_tx_rings(adapter);
        igb_clean_all_rx_rings(adapter);
 }
index 679a0826780e3471346a902c516daf534811e80c..2c03f4e2ccc44427206e8a868412be0bb92fac49 100644 (file)
@@ -1271,7 +1271,7 @@ static void ipg_nic_rx_with_end(struct net_device *dev,
 
                        framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
 
-                       endframeLen = framelen - jumbo->current_size;
+                       endframelen = framelen - jumbo->current_size;
                        /*
                        if (framelen > IPG_RXFRAG_SIZE)
                                framelen=IPG_RXFRAG_SIZE;
@@ -1279,8 +1279,8 @@ static void ipg_nic_rx_with_end(struct net_device *dev,
                        if (framelen > IPG_RXSUPPORT_SIZE)
                                dev_kfree_skb_irq(jumbo->skb);
                        else {
-                               memcpy(skb_put(jumbo->skb, endframeLen),
-                                      skb->data, endframeLen);
+                               memcpy(skb_put(jumbo->skb, endframelen),
+                                      skb->data, endframelen);
 
                                jumbo->skb->protocol =
                                    eth_type_trans(jumbo->skb, dev);
@@ -1352,16 +1352,16 @@ static int ipg_nic_rx(struct net_device *dev)
 
                switch (ipg_nic_rx_check_frame_type(dev)) {
                case FRAME_WITH_START_WITH_END:
-                       ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry);
+                       ipg_nic_rx_with_start_and_end(dev, sp, rxfd, entry);
                        break;
                case FRAME_WITH_START:
-                       ipg_nic_rx_with_start(dev, tp, rxfd, entry);
+                       ipg_nic_rx_with_start(dev, sp, rxfd, entry);
                        break;
                case FRAME_WITH_END:
-                       ipg_nic_rx_with_end(dev, tp, rxfd, entry);
+                       ipg_nic_rx_with_end(dev, sp, rxfd, entry);
                        break;
                case FRAME_NO_START_NO_END:
-                       ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry);
+                       ipg_nic_rx_no_start_no_end(dev, sp, rxfd, entry);
                        break;
                }
        }
@@ -1808,7 +1808,7 @@ static int ipg_nic_open(struct net_device *dev)
        /* initialize JUMBO Frame control variable */
        sp->jumbo.found_start = 0;
        sp->jumbo.current_size = 0;
-       sp->jumbo.skb = 0;
+       sp->jumbo.skb = NULL;
        dev->mtu = IPG_TXFRAG_SIZE;
 #endif
 
index f429c9a4754f615a3b8f55ef2f05f71284283d1f..b37d618d8e2a90cc68a328d991caddfe1a1b3309 100644 (file)
@@ -2023,7 +2023,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
 
-       ixgbe_reset(adapter);
+       if (!pci_channel_offline(adapter->pdev))
+               ixgbe_reset(adapter);
        ixgbe_clean_all_tx_rings(adapter);
        ixgbe_clean_all_rx_rings(adapter);
 
index 6797ed069f1f43ed659147da5d925bda1036e9e8..63cd67b931e7537cde2c407c63812c9fd3ffac02 100644 (file)
@@ -71,14 +71,18 @@ static irqreturn_t netxen_intr(int irq, void *data);
 static irqreturn_t netxen_msi_intr(int irq, void *data);
 
 /*  PCI Device ID Table  */
+#define ENTRY(device) \
+       {PCI_DEVICE(0x4040, (device)), \
+       .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
+
 static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
-       {PCI_DEVICE(0x4040, 0x0001), PCI_DEVICE_CLASS(0x020000, ~0)},
-       {PCI_DEVICE(0x4040, 0x0002), PCI_DEVICE_CLASS(0x020000, ~0)},
-       {PCI_DEVICE(0x4040, 0x0003), PCI_DEVICE_CLASS(0x020000, ~0)},
-       {PCI_DEVICE(0x4040, 0x0004), PCI_DEVICE_CLASS(0x020000, ~0)},
-       {PCI_DEVICE(0x4040, 0x0005), PCI_DEVICE_CLASS(0x020000, ~0)},
-       {PCI_DEVICE(0x4040, 0x0024), PCI_DEVICE_CLASS(0x020000, ~0)},
-       {PCI_DEVICE(0x4040, 0x0025), PCI_DEVICE_CLASS(0x020000, ~0)},
+       ENTRY(0x0001),
+       ENTRY(0x0002),
+       ENTRY(0x0003),
+       ENTRY(0x0004),
+       ENTRY(0x0005),
+       ENTRY(0x0024),
+       ENTRY(0x0025),
        {0,}
 };
 
index 918f802fe089d060247bb21e72b8a651fa0ef333..de2a8a30199d8377fb73f006879d9aef04f93099 100644 (file)
@@ -6385,6 +6385,162 @@ static int niu_get_eeprom(struct net_device *dev,
        return 0;
 }
 
+static int niu_ethflow_to_class(int flow_type, u64 *class)
+{
+       switch (flow_type) {
+       case TCP_V4_FLOW:
+               *class = CLASS_CODE_TCP_IPV4;
+               break;
+       case UDP_V4_FLOW:
+               *class = CLASS_CODE_UDP_IPV4;
+               break;
+       case AH_ESP_V4_FLOW:
+               *class = CLASS_CODE_AH_ESP_IPV4;
+               break;
+       case SCTP_V4_FLOW:
+               *class = CLASS_CODE_SCTP_IPV4;
+               break;
+       case TCP_V6_FLOW:
+               *class = CLASS_CODE_TCP_IPV6;
+               break;
+       case UDP_V6_FLOW:
+               *class = CLASS_CODE_UDP_IPV6;
+               break;
+       case AH_ESP_V6_FLOW:
+               *class = CLASS_CODE_AH_ESP_IPV6;
+               break;
+       case SCTP_V6_FLOW:
+               *class = CLASS_CODE_SCTP_IPV6;
+               break;
+       default:
+               return -1;
+       }
+
+       return 1;
+}
+
+static u64 niu_flowkey_to_ethflow(u64 flow_key)
+{
+       u64 ethflow = 0;
+
+       if (flow_key & FLOW_KEY_PORT)
+               ethflow |= RXH_DEV_PORT;
+       if (flow_key & FLOW_KEY_L2DA)
+               ethflow |= RXH_L2DA;
+       if (flow_key & FLOW_KEY_VLAN)
+               ethflow |= RXH_VLAN;
+       if (flow_key & FLOW_KEY_IPSA)
+               ethflow |= RXH_IP_SRC;
+       if (flow_key & FLOW_KEY_IPDA)
+               ethflow |= RXH_IP_DST;
+       if (flow_key & FLOW_KEY_PROTO)
+               ethflow |= RXH_L3_PROTO;
+       if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT))
+               ethflow |= RXH_L4_B_0_1;
+       if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT))
+               ethflow |= RXH_L4_B_2_3;
+
+       return ethflow;
+
+}
+
+static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key)
+{
+       u64 key = 0;
+
+       if (ethflow & RXH_DEV_PORT)
+               key |= FLOW_KEY_PORT;
+       if (ethflow & RXH_L2DA)
+               key |= FLOW_KEY_L2DA;
+       if (ethflow & RXH_VLAN)
+               key |= FLOW_KEY_VLAN;
+       if (ethflow & RXH_IP_SRC)
+               key |= FLOW_KEY_IPSA;
+       if (ethflow & RXH_IP_DST)
+               key |= FLOW_KEY_IPDA;
+       if (ethflow & RXH_L3_PROTO)
+               key |= FLOW_KEY_PROTO;
+       if (ethflow & RXH_L4_B_0_1)
+               key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT);
+       if (ethflow & RXH_L4_B_2_3)
+               key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT);
+
+       *flow_key = key;
+
+       return 1;
+
+}
+
+static int niu_get_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+       struct niu *np = netdev_priv(dev);
+       u64 class;
+
+       cmd->data = 0;
+
+       if (!niu_ethflow_to_class(cmd->flow_type, &class))
+               return -EINVAL;
+
+       if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] &
+           TCAM_KEY_DISC)
+               cmd->data = RXH_DISCARD;
+       else
+
+               cmd->data = niu_flowkey_to_ethflow(np->parent->flow_key[class -
+                                                     CLASS_CODE_USER_PROG1]);
+       return 0;
+}
+
+static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+       struct niu *np = netdev_priv(dev);
+       u64 class;
+       u64 flow_key = 0;
+       unsigned long flags;
+
+       if (!niu_ethflow_to_class(cmd->flow_type, &class))
+               return -EINVAL;
+
+       if (class < CLASS_CODE_USER_PROG1 ||
+           class > CLASS_CODE_SCTP_IPV6)
+               return -EINVAL;
+
+       if (cmd->data & RXH_DISCARD) {
+               niu_lock_parent(np, flags);
+               flow_key = np->parent->tcam_key[class -
+                                              CLASS_CODE_USER_PROG1];
+               flow_key |= TCAM_KEY_DISC;
+               nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1), flow_key);
+               np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] = flow_key;
+               niu_unlock_parent(np, flags);
+               return 0;
+       } else {
+               /* Discard was set before, but is not set now */
+               if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] &
+                   TCAM_KEY_DISC) {
+                       niu_lock_parent(np, flags);
+                       flow_key = np->parent->tcam_key[class -
+                                              CLASS_CODE_USER_PROG1];
+                       flow_key &= ~TCAM_KEY_DISC;
+                       nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1),
+                            flow_key);
+                       np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] =
+                               flow_key;
+                       niu_unlock_parent(np, flags);
+               }
+       }
+
+       if (!niu_ethflow_to_flowkey(cmd->data, &flow_key))
+               return -EINVAL;
+
+       niu_lock_parent(np, flags);
+       nw64(FLOW_KEY(class - CLASS_CODE_USER_PROG1), flow_key);
+       np->parent->flow_key[class - CLASS_CODE_USER_PROG1] = flow_key;
+       niu_unlock_parent(np, flags);
+
+       return 0;
+}
+
 static const struct {
        const char string[ETH_GSTRING_LEN];
 } niu_xmac_stat_keys[] = {
@@ -6615,6 +6771,8 @@ static const struct ethtool_ops niu_ethtool_ops = {
        .get_stats_count        = niu_get_stats_count,
        .get_ethtool_stats      = niu_get_ethtool_stats,
        .phys_id                = niu_phys_id,
+       .get_rxhash             = niu_get_hash_opts,
+       .set_rxhash             = niu_set_hash_opts,
 };
 
 static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
index d7018ff9e171b58a925d15786cd6fffeb81d98ca..3f682d49a4e6f7796450d891a7052dceb82e0a74 100644 (file)
@@ -525,12 +525,14 @@ static int axnet_open(struct net_device *dev)
     int ret;
     axnet_dev_t *info = PRIV(dev);
     struct pcmcia_device *link = info->p_dev;
+    unsigned int nic_base = dev->base_addr;
     
     DEBUG(2, "axnet_open('%s')\n", dev->name);
 
     if (!pcmcia_dev_present(link))
        return -ENODEV;
 
+    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
     ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
     if (ret)
            return ret;
index fd8158a86f6490ce7dbaf389595b8e34a3d51821..2d4c4ad89b8dbda9fdcd773b7c9825d4de1889b8 100644 (file)
@@ -969,6 +969,7 @@ static int pcnet_open(struct net_device *dev)
     int ret;
     pcnet_dev_t *info = PRIV(dev);
     struct pcmcia_device *link = info->p_dev;
+    unsigned int nic_base = dev->base_addr;
 
     DEBUG(2, "pcnet_open('%s')\n", dev->name);
 
@@ -976,6 +977,8 @@ static int pcnet_open(struct net_device *dev)
        return -ENODEV;
 
     set_misc_reg(dev);
+
+    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
     ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev_info, dev);
     if (ret)
            return ret;
index bafb69b6f7cbdeb26ea7975a2d46d2f04f7bdb24..fc6f4b8c64b35cc169ab228c9c130b6ed0a4c821 100644 (file)
@@ -942,7 +942,7 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
        m->msg_namelen = 0;
 
        if (skb) {
-               total_len = min(total_len, skb->len);
+               total_len = min_t(size_t, total_len, skb->len);
                error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len);
                if (error == 0)
                        error = total_len;
index aa963ac1e37b2086bc677724664f7a7368bef3d0..6b2dee0cf3a9b60cee6e22f275a804e65598f0dc 100644 (file)
@@ -571,6 +571,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
  * independent format
  */
 static char *gelic_wl_translate_scan(struct net_device *netdev,
+                                    struct iw_request_info *info,
                                     char *ev,
                                     char *stop,
                                     struct gelic_wl_scan_info *network)
@@ -588,26 +589,26 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN);
-       ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_ADDR_LEN);
+       ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_ADDR_LEN);
 
        /* ESSID */
        iwe.cmd = SIOCGIWESSID;
        iwe.u.data.flags = 1;
        iwe.u.data.length = strnlen(scan->essid, 32);
-       ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
+       ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
 
        /* FREQUENCY */
        iwe.cmd = SIOCGIWFREQ;
        iwe.u.freq.m = be16_to_cpu(scan->channel);
        iwe.u.freq.e = 0; /* table value in MHz */
        iwe.u.freq.i = 0;
-       ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_FREQ_LEN);
+       ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_FREQ_LEN);
 
        /* RATES */
        iwe.cmd = SIOCGIWRATE;
        iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
        /* to stuff multiple values in one event */
-       tmp = ev + IW_EV_LCP_LEN;
+       tmp = ev + iwe_stream_lcp_len(info);
        /* put them in ascendant order (older is first) */
        i = 0;
        j = 0;
@@ -620,16 +621,16 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
                else
                    rate = scan->rate[i++] & 0x7f;
                iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */
-               tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
+               tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
                                           IW_EV_PARAM_LEN);
        }
        while (j < network->rate_ext_len) {
                iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000;
-               tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
+               tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
                                           IW_EV_PARAM_LEN);
        }
        /* Check if we added any rate */
-       if (IW_EV_LCP_LEN < (tmp - ev))
+       if (iwe_stream_lcp_len(info) < (tmp - ev))
                ev = tmp;
 
        /* ENCODE */
@@ -639,7 +640,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
        else
                iwe.u.data.flags = IW_ENCODE_DISABLED;
        iwe.u.data.length = 0;
-       ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
+       ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
 
        /* MODE */
        iwe.cmd = SIOCGIWMODE;
@@ -649,7 +650,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
-               ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_UINT_LEN);
+               ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_UINT_LEN);
        }
 
        /* QUAL */
@@ -659,7 +660,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
        iwe.u.qual.level = be16_to_cpu(scan->rssi);
        iwe.u.qual.qual = be16_to_cpu(scan->rssi);
        iwe.u.qual.noise = 0;
-       ev  = iwe_stream_add_event(ev, stop, &iwe, IW_EV_QUAL_LEN);
+       ev  = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_QUAL_LEN);
 
        /* RSN */
        memset(&iwe, 0, sizeof(iwe));
@@ -669,7 +670,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
                if (len) {
                        iwe.cmd = IWEVGENIE;
                        iwe.u.data.length = len;
-                       ev = iwe_stream_add_point(ev, stop, &iwe, buf);
+                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
                }
        } else {
                /* this scan info has IE data */
@@ -684,7 +685,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
                        memcpy(buf, ie_info.wpa.data, ie_info.wpa.len);
                        iwe.cmd = IWEVGENIE;
                        iwe.u.data.length = ie_info.wpa.len;
-                       ev = iwe_stream_add_point(ev, stop, &iwe, buf);
+                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
                }
 
                if (ie_info.rsn.len && (ie_info.rsn.len <= sizeof(buf))) {
@@ -692,7 +693,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
                        memcpy(buf, ie_info.rsn.data, ie_info.rsn.len);
                        iwe.cmd = IWEVGENIE;
                        iwe.u.data.length = ie_info.rsn.len;
-                       ev = iwe_stream_add_point(ev, stop, &iwe, buf);
+                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
                }
        }
 
@@ -737,7 +738,8 @@ static int gelic_wl_get_scan(struct net_device *netdev,
                if (wl->scan_age == 0 ||
                    time_after(scan_info->last_scanned + wl->scan_age,
                               this_time))
-                       ev = gelic_wl_translate_scan(netdev, ev, stop,
+                       ev = gelic_wl_translate_scan(netdev, info,
+                                                    ev, stop,
                                                     scan_info);
                else
                        pr_debug("%s:entry too old\n", __func__);
index 5f608780c3e8aafee63c91f255a9bb57a2db9c17..e7d48a352beb0dabe4f3a70e5f4512949eae1f6a 100644 (file)
@@ -3701,7 +3701,9 @@ static int ql_cycle_adapter(struct ql3_adapter *qdev, int reset)
                printk(KERN_ERR PFX
                                "%s: Driver up/down cycle failed, "
                                "closing device\n",qdev->ndev->name);
+               rtnl_lock();
                dev_close(qdev->ndev);
+               rtnl_unlock();
                return -1;
        }
        return 0;
index 858b191517b3dfc17800147191d0afe4e3f22b1b..504a48ff73c83e5cbac2eaa96c25bdc754bbd40e 100644 (file)
@@ -273,7 +273,7 @@ static void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,
        dma_addr_t mapping = desc_dma;
 
        while (size-- > 0) {
-               mapping += sizeof(sizeof(*desc));
+               mapping += sizeof(*desc);
                desc->ndesc = cpu_to_le32(mapping);
                desc->vndescp = desc + 1;
                desc++;
index 5694e894fc7a3d7dd2bb117c8f40299f68c2f282..e7a3dbec674c56ed08e3109895b690e203c20ea6 100644 (file)
@@ -2625,9 +2625,7 @@ static int fill_rx_buffers(struct ring_info *ring)
                        rxdp1->Buffer0_ptr = pci_map_single
                            (ring->pdev, skb->data, size - NET_IP_ALIGN,
                                PCI_DMA_FROMDEVICE);
-                       if( (rxdp1->Buffer0_ptr == 0) ||
-                               (rxdp1->Buffer0_ptr ==
-                               DMA_ERROR_CODE))
+                       if(pci_dma_mapping_error(rxdp1->Buffer0_ptr))
                                goto pci_map_failed;
 
                        rxdp->Control_2 =
@@ -2657,6 +2655,7 @@ static int fill_rx_buffers(struct ring_info *ring)
                        skb->data = (void *) (unsigned long)tmp;
                        skb_reset_tail_pointer(skb);
 
+                       /* AK: check is wrong. 0 can be valid dma address */
                        if (!(rxdp3->Buffer0_ptr))
                                rxdp3->Buffer0_ptr =
                                   pci_map_single(ring->pdev, ba->ba_0,
@@ -2665,8 +2664,7 @@ static int fill_rx_buffers(struct ring_info *ring)
                                pci_dma_sync_single_for_device(ring->pdev,
                                (dma_addr_t) rxdp3->Buffer0_ptr,
                                    BUF0_LEN, PCI_DMA_FROMDEVICE);
-                       if( (rxdp3->Buffer0_ptr == 0) ||
-                               (rxdp3->Buffer0_ptr == DMA_ERROR_CODE))
+                       if (pci_dma_mapping_error(rxdp3->Buffer0_ptr))
                                goto pci_map_failed;
 
                        rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
@@ -2681,18 +2679,17 @@ static int fill_rx_buffers(struct ring_info *ring)
                                (ring->pdev, skb->data, ring->mtu + 4,
                                                PCI_DMA_FROMDEVICE);
 
-                               if( (rxdp3->Buffer2_ptr == 0) ||
-                                       (rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
+                               if (pci_dma_mapping_error(rxdp3->Buffer2_ptr))
                                        goto pci_map_failed;
 
+                               /* AK: check is wrong */
                                if (!rxdp3->Buffer1_ptr)
                                        rxdp3->Buffer1_ptr =
                                                pci_map_single(ring->pdev,
                                                ba->ba_1, BUF1_LEN,
                                                PCI_DMA_FROMDEVICE);
 
-                               if( (rxdp3->Buffer1_ptr == 0) ||
-                                       (rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+                               if (pci_dma_mapping_error(rxdp3->Buffer1_ptr)) {
                                        pci_unmap_single
                                                (ring->pdev,
                                                (dma_addr_t)(unsigned long)
@@ -4264,16 +4261,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
                txdp->Buffer_Pointer = pci_map_single(sp->pdev,
                                        fifo->ufo_in_band_v,
                                        sizeof(u64), PCI_DMA_TODEVICE);
-               if((txdp->Buffer_Pointer == 0) ||
-                       (txdp->Buffer_Pointer == DMA_ERROR_CODE))
+               if (pci_dma_mapping_error(txdp->Buffer_Pointer))
                        goto pci_map_failed;
                txdp++;
        }
 
        txdp->Buffer_Pointer = pci_map_single
            (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
-       if((txdp->Buffer_Pointer == 0) ||
-               (txdp->Buffer_Pointer == DMA_ERROR_CODE))
+       if (pci_dma_mapping_error(txdp->Buffer_Pointer))
                goto pci_map_failed;
 
        txdp->Host_Control = (unsigned long) skb;
@@ -6884,10 +6879,8 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
                                pci_map_single( sp->pdev, (*skb)->data,
                                        size - NET_IP_ALIGN,
                                        PCI_DMA_FROMDEVICE);
-                       if( (rxdp1->Buffer0_ptr == 0) ||
-                               (rxdp1->Buffer0_ptr == DMA_ERROR_CODE)) {
+                       if (pci_dma_mapping_error(rxdp1->Buffer0_ptr))
                                goto memalloc_failed;
-                       }
                        rxdp->Host_Control = (unsigned long) (*skb);
                }
        } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
@@ -6913,15 +6906,12 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
                                pci_map_single(sp->pdev, (*skb)->data,
                                               dev->mtu + 4,
                                               PCI_DMA_FROMDEVICE);
-                       if( (rxdp3->Buffer2_ptr == 0) ||
-                               (rxdp3->Buffer2_ptr == DMA_ERROR_CODE)) {
+                       if (pci_dma_mapping_error(rxdp3->Buffer2_ptr))
                                goto memalloc_failed;
-                       }
                        rxdp3->Buffer0_ptr = *temp0 =
                                pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
                                                PCI_DMA_FROMDEVICE);
-                       if( (rxdp3->Buffer0_ptr == 0) ||
-                               (rxdp3->Buffer0_ptr == DMA_ERROR_CODE)) {
+                       if (pci_dma_mapping_error(rxdp3->Buffer0_ptr)) {
                                pci_unmap_single (sp->pdev,
                                        (dma_addr_t)rxdp3->Buffer2_ptr,
                                        dev->mtu + 4, PCI_DMA_FROMDEVICE);
@@ -6933,8 +6923,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
                        rxdp3->Buffer1_ptr = *temp1 =
                                pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
                                                PCI_DMA_FROMDEVICE);
-                       if( (rxdp3->Buffer1_ptr == 0) ||
-                               (rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+                       if (pci_dma_mapping_error(rxdp3->Buffer1_ptr)) {
                                pci_unmap_single (sp->pdev,
                                        (dma_addr_t)rxdp3->Buffer0_ptr,
                                        BUF0_LEN, PCI_DMA_FROMDEVICE);
index d0a84ba887a53d81121e3a1a66789a4838a9686f..483b17c34ae81ec807efc0f6853e9462c415ca6c 100644 (file)
@@ -75,10 +75,6 @@ static int debug_level = ERR_DBG;
 /* DEBUG message print. */
 #define DBG_PRINT(dbg_level, args...)  if(!(debug_level<dbg_level)) printk(args)
 
-#ifndef DMA_ERROR_CODE
-#define DMA_ERROR_CODE          (~(dma_addr_t)0x0)
-#endif
-
 /* Protocol assist features of the NIC */
 #define L3_CKSUM_OK 0xFFFF
 #define L4_CKSUM_OK 0xFFFF
index 10e4e85da3fcae7af7e9435145f06dad72abd35f..b07b8cbadeaf8eb4a34dbbfe848ad5499f2a628b 100644 (file)
@@ -1394,6 +1394,7 @@ tc35815_open(struct net_device *dev)
        tc35815_chip_init(dev);
        spin_unlock_irq(&lp->lock);
 
+       netif_carrier_off(dev);
        /* schedule a link state check */
        phy_start(lp->phy_dev);
 
@@ -1735,7 +1736,6 @@ tc35815_rx(struct net_device *dev)
                        skb = lp->rx_skbs[cur_bd].skb;
                        prefetch(skb->data);
                        lp->rx_skbs[cur_bd].skb = NULL;
-                       lp->fbl_count--;
                        pci_unmap_single(lp->pci_dev,
                                         lp->rx_skbs[cur_bd].skb_dma,
                                         RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
@@ -1791,6 +1791,7 @@ tc35815_rx(struct net_device *dev)
 #ifdef TC35815_USE_PACKEDBUFFER
                        while (lp->fbl_curid != id)
 #else
+                       lp->fbl_count--;
                        while (lp->fbl_count < RX_BUF_NUM)
 #endif
                        {
@@ -2453,6 +2454,7 @@ static int tc35815_resume(struct pci_dev *pdev)
                return 0;
        pci_set_power_state(pdev, PCI_D0);
        tc35815_restart(dev);
+       netif_carrier_off(dev);
        if (lp->phy_dev)
                phy_start(lp->phy_dev);
        netif_device_attach(dev);
index 249e18053d5fa4a2d6e29a60e33878bbe1f78c90..069f8bb0a99fa401e254a03ff94a77a4217d58b5 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/x25.h>
 #include <linux/lapb.h>
 #include <linux/init.h>
+#include <linux/rtnetlink.h>
 #include "x25_asy.h"
 
 #include <net/x25device.h>
@@ -601,8 +602,10 @@ static void x25_asy_close_tty(struct tty_struct *tty)
        if (!sl || sl->magic != X25_ASY_MAGIC)
                return;
 
+       rtnl_lock();
        if (sl->dev->flags & IFF_UP)
                dev_close(sl->dev);
+       rtnl_unlock();
 
        tty->disc_data = NULL;
        sl->tty = NULL;
index 22e1e9a1fb73dc62be30a4dfb2b950c87212106d..865f2980c273dd576ece4bf4917bd6edd9c0743c 100644 (file)
@@ -14,30 +14,6 @@ config WLAN_PRE80211
          This option does not affect the kernel build, it only
          lets you choose drivers.
 
-config STRIP
-       tristate "STRIP (Metricom starmode radio IP)"
-       depends on INET && WLAN_PRE80211
-       select WIRELESS_EXT
-       ---help---
-         Say Y if you have a Metricom radio and intend to use Starmode Radio
-         IP. STRIP is a radio protocol developed for the MosquitoNet project
-         (on the WWW at <http://mosquitonet.stanford.edu/>) to send Internet
-         traffic using Metricom radios.  Metricom radios are small, battery
-         powered, 100kbit/sec packet radio transceivers, about the size and
-         weight of a cellular telephone. (You may also have heard them called
-         "Metricom modems" but we avoid the term "modem" because it misleads
-         many people into thinking that you can plug a Metricom modem into a
-         phone line and use it as a modem.)
-
-         You can use STRIP on any Linux machine with a serial port, although
-         it is obviously most useful for people with laptop computers. If you
-         think you might get a Metricom radio in the future, there is no harm
-         in saying Y to STRIP now, except that it makes the kernel a bit
-         bigger.
-
-         To compile this as a module, choose M here: the module will be
-         called strip.
-
 config ARLAN
        tristate "Aironet Arlan 655 & IC2200 DS support"
        depends on ISA && !64BIT && WLAN_PRE80211
index 54a4f6f1db677432ca71768333a536b61a988b6a..2668934abbff757ae810d813c2687f2b6a13e9af 100644 (file)
@@ -6,7 +6,6 @@ obj-$(CONFIG_IPW2100) += ipw2100.o
 
 obj-$(CONFIG_IPW2200) += ipw2200.o
 
-obj-$(CONFIG_STRIP) += strip.o
 obj-$(CONFIG_ARLAN) += arlan.o 
 
 arlan-objs := arlan-main.o arlan-proc.o
index 0ba55ba9395884570a795632bcd34c1156716d5c..3333d4596b8d1cabcd40dbc8d0ec67c8b588a0fc 100644 (file)
@@ -1685,7 +1685,6 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
 static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct adm8211_tx_hdr *txhdr;
-       u16 fc;
        size_t payload_len, hdrlen;
        int plcp, dur, len, plcp_signal, short_preamble;
        struct ieee80211_hdr *hdr;
@@ -1696,8 +1695,7 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        plcp_signal = txrate->bitrate;
 
        hdr = (struct ieee80211_hdr *)skb->data;
-       fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
-       hdrlen = ieee80211_get_hdrlen(fc);
+       hdrlen = ieee80211_hdrlen(hdr->frame_control);
        memcpy(skb->cb, skb->data, hdrlen);
        hdr = (struct ieee80211_hdr *)skb->cb;
        skb_pull(skb, hdrlen);
@@ -1711,8 +1709,6 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        txhdr->frame_control = hdr->frame_control;
 
        len = hdrlen + payload_len + FCS_LEN;
-       if (fc & IEEE80211_FCTL_PROTECTED)
-               len += 8;
 
        txhdr->frag = cpu_to_le16(0x0FFF);
        adm8211_calc_durations(&dur, &plcp, payload_len,
@@ -1730,9 +1726,6 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
                txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
 
-       if (fc & IEEE80211_FCTL_PROTECTED)
-               txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
-
        txhdr->retry_limit = info->control.retry_limit;
 
        adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
index e30f8b79ea89e94f48f967950abbee7fabc1c70e..b5cd850a4a59e8995c68bfa80717614515531e69 100644 (file)
@@ -85,10 +85,10 @@ static struct pci_driver airo_driver = {
 
 /* Include Wireless Extension definition and check version - Jean II */
 #include <linux/wireless.h>
-#define WIRELESS_SPY           // enable iwspy support
-#include <net/iw_handler.h>    // New driver API
+#define WIRELESS_SPY           /* enable iwspy support */
+#include <net/iw_handler.h>    /* New driver API */
 
-#define CISCO_EXT              // enable Cisco extensions
+#define CISCO_EXT              /* enable Cisco extensions */
 #ifdef CISCO_EXT
 #include <linux/delay.h>
 #endif
@@ -281,7 +281,7 @@ MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc");
 /* This is a kind of sloppy hack to get this information to OUT4500 and
    IN4500.  I would be extremely interested in the situation where this
    doesn't work though!!! */
-static int do8bitIO = 0;
+static int do8bitIO /* = 0 */;
 
 /* Return codes */
 #define SUCCESS 0
@@ -398,8 +398,8 @@ static int do8bitIO = 0;
 #define MAXTXQ 64
 
 /* BAP selectors */
-#define BAP0 0 // Used for receiving packets
-#define BAP1 2 // Used for xmiting packets and working with RIDS
+#define BAP0 0 /* Used for receiving packets */
+#define BAP1 2 /* Used for xmiting packets and working with RIDS */
 
 /* Flags */
 #define COMMAND_BUSY 0x8000
@@ -5522,11 +5522,13 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        Cmd cmd;
        Resp rsp;
 
-       if ((ai->APList == NULL) &&
-               (ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL)
+       if (!ai->APList)
+               ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL);
+       if (!ai->APList)
                return -ENOMEM;
-       if ((ai->SSID == NULL) &&
-               (ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL)
+       if (!ai->SSID)
+               ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL);
+       if (!ai->SSID)
                return -ENOMEM;
        readAPListRid(ai, ai->APList);
        readSsidRid(ai, ai->SSID);
@@ -5537,7 +5539,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        disable_MAC(ai, 0);
        netif_device_detach(dev);
        ai->power = state;
-       cmd.cmd=HOSTSLEEP;
+       cmd.cmd = HOSTSLEEP;
        issuecommand(ai, &cmd, &rsp);
 
        pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
@@ -5567,7 +5569,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
                msleep(100);
        }
 
-       set_bit (FLAG_COMMIT, &ai->flags);
+       set_bit(FLAG_COMMIT, &ai->flags);
        disable_MAC(ai, 0);
         msleep(200);
        if (ai->SSID) {
@@ -5594,9 +5596,6 @@ static int airo_pci_resume(struct pci_dev *pdev)
 static int __init airo_init_module( void )
 {
        int i;
-#if 0
-       int have_isa_dev = 0;
-#endif
 
        airo_entry = create_proc_entry("driver/aironet",
                                       S_IFDIR | airo_perm,
@@ -5607,15 +5606,11 @@ static int __init airo_init_module( void )
                airo_entry->gid = proc_gid;
        }
 
-       for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
+       for (i = 0; i < 4 && io[i] && irq[i]; i++) {
                airo_print_info("", "Trying to configure ISA adapter at irq=%d "
                        "io=0x%x", irq[i], io[i] );
                if (init_airo_card( irq[i], io[i], 0, NULL ))
-#if 0
-                       have_isa_dev = 1;
-#else
                        /* do nothing */ ;
-#endif
        }
 
 #ifdef CONFIG_PCI
@@ -5661,7 +5656,7 @@ static void __exit airo_cleanup_module( void )
 
 static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
 {
-       if( !rssi_rid )
+       if (!rssi_rid)
                return 0;
 
        return (0x100 - rssi_rid[rssi].rssidBm);
@@ -5671,10 +5666,10 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
 {
        int i;
 
-       if( !rssi_rid )
+       if (!rssi_rid)
                return 0;
 
-       for( i = 0; i < 256; i++ )
+       for (i = 0; i < 256; i++)
                if (rssi_rid[i].rssidBm == dbm)
                        return rssi_rid[i].rssipct;
 
@@ -7156,6 +7151,7 @@ out:
  * format that the Wireless Tools will understand - Jean II
  */
 static inline char *airo_translate_scan(struct net_device *dev,
+                                       struct iw_request_info *info,
                                        char *current_ev,
                                        char *end_buf,
                                        BSSListRid *bss)
@@ -7172,7 +7168,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_ADDR_LEN);
 
        /* Other entries will be displayed in the order we give them */
 
@@ -7182,7 +7179,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
                iwe.u.data.length = 32;
        iwe.cmd = SIOCGIWESSID;
        iwe.u.data.flags = 1;
-       current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, bss->ssid);
 
        /* Add mode */
        iwe.cmd = SIOCGIWMODE;
@@ -7192,7 +7190,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
-               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_UINT_LEN);
        }
 
        /* Add frequency */
@@ -7203,7 +7202,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
         */
        iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000;
        iwe.u.freq.e = 1;
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_FREQ_LEN);
 
        dBm = le16_to_cpu(bss->dBm);
 
@@ -7223,7 +7223,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
                                | IW_QUAL_DBM;
        }
        iwe.u.qual.noise = ai->wstats.qual.noise;
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_QUAL_LEN);
 
        /* Add encryption capability */
        iwe.cmd = SIOCGIWENCODE;
@@ -7232,11 +7233,12 @@ static inline char *airo_translate_scan(struct net_device *dev,
        else
                iwe.u.data.flags = IW_ENCODE_DISABLED;
        iwe.u.data.length = 0;
-       current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, bss->ssid);
 
        /* Rate : stuffing multiple values in a single event require a bit
         * more of magic - Jean II */
-       current_val = current_ev + IW_EV_LCP_LEN;
+       current_val = current_ev + iwe_stream_lcp_len(info);
 
        iwe.cmd = SIOCGIWRATE;
        /* Those two flags are ignored... */
@@ -7249,10 +7251,12 @@ static inline char *airo_translate_scan(struct net_device *dev,
                /* Bit rate given in 500 kb/s units (+ 0x80) */
                iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
                /* Add new value to event */
-               current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
+               current_val = iwe_stream_add_value(info, current_ev,
+                                                  current_val, end_buf,
+                                                  &iwe, IW_EV_PARAM_LEN);
        }
        /* Check if we added any event */
-       if((current_val - current_ev) > IW_EV_LCP_LEN)
+       if ((current_val - current_ev) > iwe_stream_lcp_len(info))
                current_ev = current_val;
 
        /* Beacon interval */
@@ -7261,7 +7265,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
                iwe.cmd = IWEVCUSTOM;
                sprintf(buf, "bcn_int=%d", bss->beaconInterval);
                iwe.u.data.length = strlen(buf);
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, buf);
                kfree(buf);
        }
 
@@ -7295,8 +7300,10 @@ static inline char *airo_translate_scan(struct net_device *dev,
                                        iwe.cmd = IWEVGENIE;
                                        iwe.u.data.length = min(info_element->len + 2,
                                                                  MAX_WPA_IE_LEN);
-                                       current_ev = iwe_stream_add_point(current_ev, end_buf,
-                                                       &iwe, (char *) info_element);
+                                       current_ev = iwe_stream_add_point(
+                                                       info, current_ev,
+                                                       end_buf, &iwe,
+                                                       (char *) info_element);
                                }
                                break;
 
@@ -7304,8 +7311,9 @@ static inline char *airo_translate_scan(struct net_device *dev,
                                iwe.cmd = IWEVGENIE;
                                iwe.u.data.length = min(info_element->len + 2,
                                                          MAX_WPA_IE_LEN);
-                               current_ev = iwe_stream_add_point(current_ev, end_buf,
-                                               &iwe, (char *) info_element);
+                               current_ev = iwe_stream_add_point(
+                                       info, current_ev, end_buf,
+                                       &iwe, (char *) info_element);
                                break;
 
                        default:
@@ -7344,7 +7352,7 @@ static int airo_get_scan(struct net_device *dev,
 
        list_for_each_entry (net, &ai->network_list, list) {
                /* Translate to WE format this entry */
-               current_ev = airo_translate_scan(dev, current_ev,
+               current_ev = airo_translate_scan(dev, info, current_ev,
                                                 extra + dwrq->length,
                                                 &net->bss);
 
index f1f2aea2eab4f8ee86e880fd46a8685b8d683157..75383a5df992da8626471bcd9244e632f8fa8917 100644 (file)
@@ -1,6 +1,9 @@
 config ATH5K
        tristate "Atheros 5xxx wireless cards support"
        depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+       select MAC80211_LEDS
+       select LEDS_CLASS
+       select NEW_LEDS
        ---help---
          This module adds support for wireless adapters based on
          Atheros 5xxx chipset.
index 85045afc1ba718fbc2794f2c896af6c26fbe1032..a43e9b25169b1e78e5b05662202a015a15d7174d 100644 (file)
 #include "reg.h"
 #include "debug.h"
 
-enum {
-       ATH_LED_TX,
-       ATH_LED_RX,
-};
-
 static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
 
 
@@ -309,13 +304,10 @@ static void       ath5k_tasklet_reset(unsigned long data);
 
 static void    ath5k_calibrate(unsigned long data);
 /* LED functions */
-static void    ath5k_led_off(unsigned long data);
-static void    ath5k_led_blink(struct ath5k_softc *sc,
-                               unsigned int on,
-                               unsigned int off);
-static void    ath5k_led_event(struct ath5k_softc *sc,
-                               int event);
-
+static int     ath5k_init_leds(struct ath5k_softc *sc);
+static void    ath5k_led_enable(struct ath5k_softc *sc);
+static void    ath5k_led_off(struct ath5k_softc *sc);
+static void    ath5k_unregister_leds(struct ath5k_softc *sc);
 
 /*
  * Module init/exit functions
@@ -596,8 +588,7 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
        struct ath5k_softc *sc = hw->priv;
 
-       if (test_bit(ATH_STAT_LEDSOFT, sc->status))
-               ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1);
+       ath5k_led_off(sc);
 
        ath5k_stop_hw(sc);
        pci_save_state(pdev);
@@ -632,10 +623,7 @@ ath5k_pci_resume(struct pci_dev *pdev)
        pci_write_config_byte(pdev, 0x41, 0);
 
        ath5k_init(sc);
-       if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
-               ath5k_hw_set_gpio_output(ah, sc->led_pin);
-               ath5k_hw_set_gpio(ah, sc->led_pin, 0);
-       }
+       ath5k_led_enable(sc);
 
        /*
         * Reset the key cache since some parts do not
@@ -742,27 +730,6 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
        tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
        setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
-       setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc);
-
-       sc->led_on = 0; /* low true */
-       /*
-        * Auto-enable soft led processing for IBM cards and for
-        * 5211 minipci cards.
-        */
-       if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM ||
-                       pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
-               __set_bit(ATH_STAT_LEDSOFT, sc->status);
-               sc->led_pin = 0;
-       }
-       /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
-       if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
-               __set_bit(ATH_STAT_LEDSOFT, sc->status);
-               sc->led_pin = 0;
-       }
-       if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
-               ath5k_hw_set_gpio_output(ah, sc->led_pin);
-               ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
-       }
 
        ath5k_hw_get_lladdr(ah, mac);
        SET_IEEE80211_PERM_ADDR(hw, mac);
@@ -776,6 +743,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
                goto err_queues;
        }
 
+       ath5k_init_leds(sc);
+
        return 0;
 err_queues:
        ath5k_txq_release(sc);
@@ -809,6 +778,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        ath5k_desc_free(sc, pdev);
        ath5k_txq_release(sc);
        ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
+       ath5k_unregister_leds(sc);
 
        /*
         * NB: can't reclaim these until after ieee80211_ifdetach
@@ -1060,65 +1030,9 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
        return 0;
 }
 
-/*
- * TODO: CLEAN THIS !!!
- */
 static void
 ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
 {
-       if (unlikely(test_bit(ATH_STAT_LEDSOFT, sc->status))) {
-               /* from Atheros NDIS driver, w/ permission */
-               static const struct {
-                       u16 rate;       /* tx/rx 802.11 rate */
-                       u16 timeOn;     /* LED on time (ms) */
-                       u16 timeOff;    /* LED off time (ms) */
-               } blinkrates[] = {
-                       { 108,  40,  10 },
-                       {  96,  44,  11 },
-                       {  72,  50,  13 },
-                       {  48,  57,  14 },
-                       {  36,  67,  16 },
-                       {  24,  80,  20 },
-                       {  22, 100,  25 },
-                       {  18, 133,  34 },
-                       {  12, 160,  40 },
-                       {  10, 200,  50 },
-                       {   6, 240,  58 },
-                       {   4, 267,  66 },
-                       {   2, 400, 100 },
-                       {   0, 500, 130 }
-               };
-               const struct ath5k_rate_table *rt =
-                               ath5k_hw_get_rate_table(sc->ah, mode);
-               unsigned int i, j;
-
-               BUG_ON(rt == NULL);
-
-               memset(sc->hwmap, 0, sizeof(sc->hwmap));
-               for (i = 0; i < 32; i++) {
-                       u8 ix = rt->rate_code_to_index[i];
-                       if (ix == 0xff) {
-                               sc->hwmap[i].ledon = msecs_to_jiffies(500);
-                               sc->hwmap[i].ledoff = msecs_to_jiffies(130);
-                               continue;
-                       }
-                       sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD;
-                       /* receive frames include FCS */
-                       sc->hwmap[i].rxflags = sc->hwmap[i].txflags |
-                                       IEEE80211_RADIOTAP_F_FCS;
-                       /* setup blink rate table to avoid per-packet lookup */
-                       for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++)
-                               if (blinkrates[j].rate == /* XXX why 7f? */
-                                               (rt->rates[ix].dot11_rate&0x7f))
-                                       break;
-
-                       sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j].
-                                       timeOn);
-                       sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j].
-                                       timeOff);
-               }
-       }
-
        sc->curmode = mode;
 
        if (mode == AR5K_MODE_11A) {
@@ -1691,9 +1605,9 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
        /* Apparently when a default key is used to decrypt the packet
           the hw does not set the index used to decrypt.  In such cases
           get the index from the packet. */
-       if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) &&
-                       !(rs->rs_status & AR5K_RXERR_DECRYPT) &&
-                       skb->len >= hlen + 4) {
+       if (ieee80211_has_protected(hdr->frame_control) &&
+           !(rs->rs_status & AR5K_RXERR_DECRYPT) &&
+           skb->len >= hlen + 4) {
                keyix = skb->data[hlen + 3] >> 6;
 
                if (test_bit(keyix, sc->keymap))
@@ -1712,10 +1626,7 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
        u32 hw_tu;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 
-       if ((le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_FTYPE) ==
-               IEEE80211_FTYPE_MGMT &&
-           (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) ==
-               IEEE80211_STYPE_BEACON &&
+       if (ieee80211_is_beacon(mgmt->frame_control) &&
            le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
            memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
                /*
@@ -1903,8 +1814,6 @@ accept:
                        ath5k_check_ibss_tsf(sc, skb, &rxs);
 
                __ieee80211_rx(sc->hw, skb, &rxs);
-               sc->led_rxrate = rs.rs_rate;
-               ath5k_led_event(sc, ATH_LED_RX);
 next:
                list_move_tail(&bf->list, &sc->rxbuf);
        } while (ath5k_rxbuf_setup(sc, bf) == 0);
@@ -1985,13 +1894,9 @@ ath5k_tasklet_tx(unsigned long data)
        struct ath5k_softc *sc = (void *)data;
 
        ath5k_tx_processq(sc, sc->txq);
-
-       ath5k_led_event(sc, ATH_LED_TX);
 }
 
 
-
-
 /*****************\
 * Beacon handling *
 \*****************/
@@ -2366,11 +2271,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
        ieee80211_stop_queues(sc->hw);
 
        if (!test_bit(ATH_STAT_INVALID, sc->status)) {
-               if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
-                       del_timer_sync(&sc->led_tim);
-                       ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
-                       __clear_bit(ATH_STAT_LEDBLINKING, sc->status);
-               }
+               ath5k_led_off(sc);
                ath5k_hw_set_intr(ah, 0);
        }
        ath5k_txq_cleanup(sc);
@@ -2566,55 +2467,124 @@ ath5k_calibrate(unsigned long data)
 \***************/
 
 static void
-ath5k_led_off(unsigned long data)
+ath5k_led_enable(struct ath5k_softc *sc)
 {
-       struct ath5k_softc *sc = (void *)data;
-
-       if (test_bit(ATH_STAT_LEDENDBLINK, sc->status))
-               __clear_bit(ATH_STAT_LEDBLINKING, sc->status);
-       else {
-               __set_bit(ATH_STAT_LEDENDBLINK, sc->status);
-               ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on);
-               mod_timer(&sc->led_tim, jiffies + sc->led_off);
+       if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
+               ath5k_hw_set_gpio_output(sc->ah, sc->led_pin);
+               ath5k_led_off(sc);
        }
 }
 
-/*
- * Blink the LED according to the specified on/off times.
- */
 static void
-ath5k_led_blink(struct ath5k_softc *sc, unsigned int on,
-               unsigned int off)
+ath5k_led_on(struct ath5k_softc *sc)
 {
-       ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off);
+       if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
+               return;
        ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
-       __set_bit(ATH_STAT_LEDBLINKING, sc->status);
-       __clear_bit(ATH_STAT_LEDENDBLINK, sc->status);
-       sc->led_off = off;
-       mod_timer(&sc->led_tim, jiffies + on);
 }
 
 static void
-ath5k_led_event(struct ath5k_softc *sc, int event)
+ath5k_led_off(struct ath5k_softc *sc)
 {
-       if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status)))
+       if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
                return;
-       if (unlikely(test_bit(ATH_STAT_LEDBLINKING, sc->status)))
-               return; /* don't interrupt active blink */
-       switch (event) {
-       case ATH_LED_TX:
-               ath5k_led_blink(sc, sc->hwmap[sc->led_txrate].ledon,
-                       sc->hwmap[sc->led_txrate].ledoff);
-               break;
-       case ATH_LED_RX:
-               ath5k_led_blink(sc, sc->hwmap[sc->led_rxrate].ledon,
-                       sc->hwmap[sc->led_rxrate].ledoff);
-               break;
+       ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on);
+}
+
+static void
+ath5k_led_brightness_set(struct led_classdev *led_dev,
+       enum led_brightness brightness)
+{
+       struct ath5k_led *led = container_of(led_dev, struct ath5k_led,
+               led_dev);
+
+       if (brightness == LED_OFF)
+               ath5k_led_off(led->sc);
+       else
+               ath5k_led_on(led->sc);
+}
+
+static int
+ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led,
+                  const char *name, char *trigger)
+{
+       int err;
+
+       led->sc = sc;
+       strncpy(led->name, name, sizeof(led->name));
+       led->led_dev.name = led->name;
+       led->led_dev.default_trigger = trigger;
+       led->led_dev.brightness_set = ath5k_led_brightness_set;
+
+       err = led_classdev_register(&sc->pdev->dev, &led->led_dev);
+       if (err)
+       {
+               ATH5K_WARN(sc, "could not register LED %s\n", name);
+               led->sc = NULL;
        }
+       return err;
+}
+
+static void
+ath5k_unregister_led(struct ath5k_led *led)
+{
+       if (!led->sc)
+               return;
+       led_classdev_unregister(&led->led_dev);
+       ath5k_led_off(led->sc);
+       led->sc = NULL;
 }
 
+static void
+ath5k_unregister_leds(struct ath5k_softc *sc)
+{
+       ath5k_unregister_led(&sc->rx_led);
+       ath5k_unregister_led(&sc->tx_led);
+}
 
 
+static int
+ath5k_init_leds(struct ath5k_softc *sc)
+{
+       int ret = 0;
+       struct ieee80211_hw *hw = sc->hw;
+       struct pci_dev *pdev = sc->pdev;
+       char name[ATH5K_LED_MAX_NAME_LEN + 1];
+
+       sc->led_on = 0;  /* active low */
+
+       /*
+        * Auto-enable soft led processing for IBM cards and for
+        * 5211 minipci cards.
+        */
+       if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM ||
+           pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
+               __set_bit(ATH_STAT_LEDSOFT, sc->status);
+               sc->led_pin = 0;
+       }
+       /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
+       if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
+               __set_bit(ATH_STAT_LEDSOFT, sc->status);
+               sc->led_pin = 1;
+       }
+       if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
+               goto out;
+
+       ath5k_led_enable(sc);
+
+       snprintf(name, sizeof(name), "ath5k-%s::rx", wiphy_name(hw->wiphy));
+       ret = ath5k_register_led(sc, &sc->rx_led, name,
+               ieee80211_get_rx_led_name(hw));
+       if (ret)
+               goto out;
+
+       snprintf(name, sizeof(name), "ath5k-%s::tx", wiphy_name(hw->wiphy));
+       ret = ath5k_register_led(sc, &sc->tx_led, name,
+               ieee80211_get_tx_led_name(hw));
+out:
+       return ret;
+}
+
 
 /********************\
 * Mac80211 functions *
@@ -2625,7 +2595,6 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ath5k_softc *sc = hw->priv;
        struct ath5k_buf *bf;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        unsigned long flags;
        int hdrlen;
        int pad;
@@ -2651,8 +2620,6 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                memmove(skb->data, skb->data+pad, hdrlen);
        }
 
-       sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value;
-
        spin_lock_irqsave(&sc->txbuflock, flags);
        if (list_empty(&sc->txbuf)) {
                ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
index bb4b26d523ab06177c695c9ed3fe1ec546344472..47f414b09e67f30032e3a67ca055ca1a650be458 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/list.h>
 #include <linux/wireless.h>
 #include <linux/if_ether.h>
+#include <linux/leds.h>
 
 #include "ath5k.h"
 #include "debug.h"
@@ -79,6 +80,19 @@ struct ath5k_txq {
        bool                    setup;
 };
 
+#define ATH5K_LED_MAX_NAME_LEN 31
+
+/*
+ * State for LED triggers
+ */
+struct ath5k_led
+{
+       char name[ATH5K_LED_MAX_NAME_LEN + 1];  /* name of the LED in sysfs */
+       struct ath5k_softc *sc;                 /* driver state */
+       struct led_classdev led_dev;            /* led classdev */
+};
+
+
 #if CHAN_DEBUG
 #define ATH_CHAN_MAX   (26+26+26+200+200)
 #else
@@ -118,13 +132,11 @@ struct ath5k_softc {
        size_t                  desc_len;       /* size of TX/RX descriptors */
        u16                     cachelsz;       /* cache line size */
 
-       DECLARE_BITMAP(status, 6);
+       DECLARE_BITMAP(status, 4);
 #define ATH_STAT_INVALID       0               /* disable hardware accesses */
 #define ATH_STAT_MRRETRY       1               /* multi-rate retry support */
 #define ATH_STAT_PROMISC       2
-#define ATH_STAT_LEDBLINKING   3               /* LED blink operation active */
-#define ATH_STAT_LEDENDBLINK   4               /* finish LED blink operation */
-#define ATH_STAT_LEDSOFT       5               /* enable LED gpio status */
+#define ATH_STAT_LEDSOFT       3               /* enable LED gpio status */
 
        unsigned int            filter_flags;   /* HW flags, AR5K_RX_FILTER_* */
        unsigned int            curmode;        /* current phy mode */
@@ -132,13 +144,6 @@ struct ath5k_softc {
 
        struct ieee80211_vif *vif;
 
-       struct {
-               u8      rxflags;        /* radiotap rx flags */
-               u8      txflags;        /* radiotap tx flags */
-               u16     ledon;          /* softled on time */
-               u16     ledoff;         /* softled off time */
-       } hwmap[32];                            /* h/w rate ix mappings */
-
        enum ath5k_int          imask;          /* interrupt mask copy */
 
        DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */
@@ -148,9 +153,6 @@ struct ath5k_softc {
        unsigned int            led_pin,        /* GPIO pin for driving LED */
                                led_on,         /* pin setting for LED on */
                                led_off;        /* off time for current blink */
-       struct timer_list       led_tim;        /* led off timer */
-       u8                      led_rxrate;     /* current rx rate for LED */
-       u8                      led_txrate;     /* current tx rate for LED */
 
        struct tasklet_struct   restq;          /* reset tasklet */
 
@@ -159,6 +161,7 @@ struct ath5k_softc {
        spinlock_t              rxbuflock;
        u32                     *rxlink;        /* link ptr in last RX desc */
        struct tasklet_struct   rxtq;           /* rx intr tasklet */
+       struct ath5k_led        rx_led;         /* rx led */
 
        struct list_head        txbuf;          /* transmit buffer */
        spinlock_t              txbuflock;
@@ -167,6 +170,7 @@ struct ath5k_softc {
 
        struct ath5k_txq        *txq;           /* beacon and tx*/
        struct tasklet_struct   txtq;           /* tx intr tasklet */
+       struct ath5k_led        tx_led;         /* tx led */
 
        struct ath5k_buf        *bbuf;          /* beacon buffer */
        unsigned int            bhalq,          /* SW q for outgoing beacons */
index 77990b56860b9109caaa978b451c7898406f2092..c6d12c53bda42b2d78b711599eec30ff41142b21 100644 (file)
 #include "base.h"
 #include "debug.h"
 
-/*Rate tables*/
+/* Rate tables */
 static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A;
 static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B;
 static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G;
 static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO;
 static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR;
 
-/*Prototypes*/
+/* Prototypes */
 static int ath5k_hw_nic_reset(struct ath5k_hw *, u32);
 static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool);
 static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
index 7bb2646ae0ef4bb67ea9b651bfedd1ad5a7d8070..28b6ff3eaa3764467d877c802d5529ad72ca7fce 100644 (file)
@@ -2310,30 +2310,40 @@ static int atmel_get_scan(struct net_device *dev,
                iwe.cmd = SIOCGIWAP;
                iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
                memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6);
-               current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev,
+                                                 extra + IW_SCAN_MAX_DATA,
+                                                 &iwe, IW_EV_ADDR_LEN);
 
                iwe.u.data.length =  priv->BSSinfo[i].SSIDsize;
                if (iwe.u.data.length > 32)
                        iwe.u.data.length = 32;
                iwe.cmd = SIOCGIWESSID;
                iwe.u.data.flags = 1;
-               current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, priv->BSSinfo[i].SSID);
+               current_ev = iwe_stream_add_point(info, current_ev,
+                                                 extra + IW_SCAN_MAX_DATA,
+                                                 &iwe, priv->BSSinfo[i].SSID);
 
                iwe.cmd = SIOCGIWMODE;
                iwe.u.mode = priv->BSSinfo[i].BSStype;
-               current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev,
+                                                 extra + IW_SCAN_MAX_DATA,
+                                                 &iwe, IW_EV_UINT_LEN);
 
                iwe.cmd = SIOCGIWFREQ;
                iwe.u.freq.m = priv->BSSinfo[i].channel;
                iwe.u.freq.e = 0;
-               current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev,
+                                                 extra + IW_SCAN_MAX_DATA,
+                                                 &iwe, IW_EV_FREQ_LEN);
 
                /* Add quality statistics */
                iwe.cmd = IWEVQUAL;
                iwe.u.qual.level = priv->BSSinfo[i].RSSI;
                iwe.u.qual.qual  = iwe.u.qual.level;
                /* iwe.u.qual.noise  = SOMETHING */
-               current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA , &iwe, IW_EV_QUAL_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev,
+                                                 extra + IW_SCAN_MAX_DATA,
+                                                 &iwe, IW_EV_QUAL_LEN);
 
 
                iwe.cmd = SIOCGIWENCODE;
@@ -2342,7 +2352,9 @@ static int atmel_get_scan(struct net_device *dev,
                else
                        iwe.u.data.flags = IW_ENCODE_DISABLED;
                iwe.u.data.length = 0;
-               current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL);
+               current_ev = iwe_stream_add_point(info, current_ev,
+                                                 extra + IW_SCAN_MAX_DATA,
+                                                 &iwe, NULL);
        }
 
        /* Length of data */
index 532365f5ecefeb3f858bf9d0412650ac1769dd1f..edcdfa366452b7ce34b4acb6e622c3402c7fdb23 100644 (file)
@@ -441,6 +441,8 @@ enum {
 #define B43_FWPANIC_DIE                        0 /* Firmware died. Don't auto-restart it. */
 #define B43_FWPANIC_RESTART            1 /* Firmware died. Schedule a controller reset. */
 
+/* The firmware register that contains the watchdog counter. */
+#define B43_WATCHDOG_REG               1
 
 /* Device specific rate values.
  * The actual values defined here are (rate_in_mbps * 2).
index 210e2789c1c366fe116092f49720c1072ce80480..29851bc1101ff7a849e35362b4a0804738d15db8 100644 (file)
@@ -74,70 +74,327 @@ struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
        } while (0)
 
 
-/* wl->irq_lock is locked */
-static ssize_t tsf_read_file(struct b43_wldev *dev,
-                            char *buf, size_t bufsize)
+/* The biggest address values for SHM access from the debugfs files. */
+#define B43_MAX_SHM_ROUTING    4
+#define B43_MAX_SHM_ADDR       0xFFFF
+
+static ssize_t shm16read__read_file(struct b43_wldev *dev,
+                                   char *buf, size_t bufsize)
 {
        ssize_t count = 0;
-       u64 tsf;
+       unsigned int routing, addr;
+       u16 val;
 
-       b43_tsf_read(dev, &tsf);
-       fappend("0x%08x%08x\n",
-               (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
-               (unsigned int)(tsf & 0xFFFFFFFFULL));
+       routing = dev->dfsentry->shm16read_routing_next;
+       addr = dev->dfsentry->shm16read_addr_next;
+       if ((routing > B43_MAX_SHM_ROUTING) ||
+           (addr > B43_MAX_SHM_ADDR))
+               return -EDESTADDRREQ;
+
+       val = b43_shm_read16(dev, routing, addr);
+       fappend("0x%04X\n", val);
 
        return count;
 }
 
-/* wl->irq_lock is locked */
-static int tsf_write_file(struct b43_wldev *dev,
-                         const char *buf, size_t count)
+static int shm16read__write_file(struct b43_wldev *dev,
+                                const char *buf, size_t count)
 {
-       u64 tsf;
+       unsigned int routing, addr;
+       int res;
 
-       if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
+       res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
+       if (res != 2)
                return -EINVAL;
-       b43_tsf_write(dev, tsf);
+       if (routing > B43_MAX_SHM_ROUTING)
+               return -EADDRNOTAVAIL;
+       if (addr > B43_MAX_SHM_ADDR)
+               return -EADDRNOTAVAIL;
+       if (routing == B43_SHM_SHARED) {
+               if ((addr % 2) != 0)
+                       return -EADDRNOTAVAIL;
+       }
+
+       dev->dfsentry->shm16read_routing_next = routing;
+       dev->dfsentry->shm16read_addr_next = addr;
 
        return 0;
 }
 
-/* wl->irq_lock is locked */
-static ssize_t ucode_regs_read_file(struct b43_wldev *dev,
+static int shm16write__write_file(struct b43_wldev *dev,
+                                 const char *buf, size_t count)
+{
+       unsigned int routing, addr, mask, set;
+       u16 val;
+       int res;
+       unsigned long flags;
+
+       res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
+                    &routing, &addr, &mask, &set);
+       if (res != 4)
+               return -EINVAL;
+       if (routing > B43_MAX_SHM_ROUTING)
+               return -EADDRNOTAVAIL;
+       if (addr > B43_MAX_SHM_ADDR)
+               return -EADDRNOTAVAIL;
+       if (routing == B43_SHM_SHARED) {
+               if ((addr % 2) != 0)
+                       return -EADDRNOTAVAIL;
+       }
+       if ((mask > 0xFFFF) || (set > 0xFFFF))
+               return -E2BIG;
+
+       spin_lock_irqsave(&dev->wl->shm_lock, flags);
+       if (mask == 0)
+               val = 0;
+       else
+               val = __b43_shm_read16(dev, routing, addr);
+       val &= mask;
+       val |= set;
+       __b43_shm_write16(dev, routing, addr, val);
+       spin_unlock_irqrestore(&dev->wl->shm_lock, flags);
+
+       return 0;
+}
+
+static ssize_t shm32read__read_file(struct b43_wldev *dev,
                                    char *buf, size_t bufsize)
 {
        ssize_t count = 0;
-       int i;
+       unsigned int routing, addr;
+       u32 val;
+
+       routing = dev->dfsentry->shm32read_routing_next;
+       addr = dev->dfsentry->shm32read_addr_next;
+       if ((routing > B43_MAX_SHM_ROUTING) ||
+           (addr > B43_MAX_SHM_ADDR))
+               return -EDESTADDRREQ;
 
-       for (i = 0; i < 64; i++) {
-               fappend("r%d = 0x%04x\n", i,
-                       b43_shm_read16(dev, B43_SHM_SCRATCH, i));
+       val = b43_shm_read32(dev, routing, addr);
+       fappend("0x%08X\n", val);
+
+       return count;
+}
+
+static int shm32read__write_file(struct b43_wldev *dev,
+                                const char *buf, size_t count)
+{
+       unsigned int routing, addr;
+       int res;
+
+       res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
+       if (res != 2)
+               return -EINVAL;
+       if (routing > B43_MAX_SHM_ROUTING)
+               return -EADDRNOTAVAIL;
+       if (addr > B43_MAX_SHM_ADDR)
+               return -EADDRNOTAVAIL;
+       if (routing == B43_SHM_SHARED) {
+               if ((addr % 2) != 0)
+                       return -EADDRNOTAVAIL;
+       }
+
+       dev->dfsentry->shm32read_routing_next = routing;
+       dev->dfsentry->shm32read_addr_next = addr;
+
+       return 0;
+}
+
+static int shm32write__write_file(struct b43_wldev *dev,
+                                 const char *buf, size_t count)
+{
+       unsigned int routing, addr, mask, set;
+       u32 val;
+       int res;
+       unsigned long flags;
+
+       res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
+                    &routing, &addr, &mask, &set);
+       if (res != 4)
+               return -EINVAL;
+       if (routing > B43_MAX_SHM_ROUTING)
+               return -EADDRNOTAVAIL;
+       if (addr > B43_MAX_SHM_ADDR)
+               return -EADDRNOTAVAIL;
+       if (routing == B43_SHM_SHARED) {
+               if ((addr % 2) != 0)
+                       return -EADDRNOTAVAIL;
        }
+       if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
+               return -E2BIG;
+
+       spin_lock_irqsave(&dev->wl->shm_lock, flags);
+       if (mask == 0)
+               val = 0;
+       else
+               val = __b43_shm_read32(dev, routing, addr);
+       val &= mask;
+       val |= set;
+       __b43_shm_write32(dev, routing, addr, val);
+       spin_unlock_irqrestore(&dev->wl->shm_lock, flags);
+
+       return 0;
+}
+
+/* The biggest MMIO address that we allow access to from the debugfs files. */
+#define B43_MAX_MMIO_ACCESS    (0xF00 - 1)
+
+static ssize_t mmio16read__read_file(struct b43_wldev *dev,
+                                    char *buf, size_t bufsize)
+{
+       ssize_t count = 0;
+       unsigned int addr;
+       u16 val;
+
+       addr = dev->dfsentry->mmio16read_next;
+       if (addr > B43_MAX_MMIO_ACCESS)
+               return -EDESTADDRREQ;
+
+       val = b43_read16(dev, addr);
+       fappend("0x%04X\n", val);
+
+       return count;
+}
+
+static int mmio16read__write_file(struct b43_wldev *dev,
+                                 const char *buf, size_t count)
+{
+       unsigned int addr;
+       int res;
+
+       res = sscanf(buf, "0x%X", &addr);
+       if (res != 1)
+               return -EINVAL;
+       if (addr > B43_MAX_MMIO_ACCESS)
+               return -EADDRNOTAVAIL;
+       if ((addr % 2) != 0)
+               return -EINVAL;
+
+       dev->dfsentry->mmio16read_next = addr;
+
+       return 0;
+}
+
+static int mmio16write__write_file(struct b43_wldev *dev,
+                                  const char *buf, size_t count)
+{
+       unsigned int addr, mask, set;
+       int res;
+       u16 val;
+
+       res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
+       if (res != 3)
+               return -EINVAL;
+       if (addr > B43_MAX_MMIO_ACCESS)
+               return -EADDRNOTAVAIL;
+       if ((mask > 0xFFFF) || (set > 0xFFFF))
+               return -E2BIG;
+       if ((addr % 2) != 0)
+               return -EINVAL;
+
+       if (mask == 0)
+               val = 0;
+       else
+               val = b43_read16(dev, addr);
+       val &= mask;
+       val |= set;
+       b43_write16(dev, addr, val);
+
+       return 0;
+}
+
+static ssize_t mmio32read__read_file(struct b43_wldev *dev,
+                                    char *buf, size_t bufsize)
+{
+       ssize_t count = 0;
+       unsigned int addr;
+       u32 val;
+
+       addr = dev->dfsentry->mmio32read_next;
+       if (addr > B43_MAX_MMIO_ACCESS)
+               return -EDESTADDRREQ;
+
+       val = b43_read32(dev, addr);
+       fappend("0x%08X\n", val);
 
        return count;
 }
 
+static int mmio32read__write_file(struct b43_wldev *dev,
+                                 const char *buf, size_t count)
+{
+       unsigned int addr;
+       int res;
+
+       res = sscanf(buf, "0x%X", &addr);
+       if (res != 1)
+               return -EINVAL;
+       if (addr > B43_MAX_MMIO_ACCESS)
+               return -EADDRNOTAVAIL;
+       if ((addr % 4) != 0)
+               return -EINVAL;
+
+       dev->dfsentry->mmio32read_next = addr;
+
+       return 0;
+}
+
+static int mmio32write__write_file(struct b43_wldev *dev,
+                                  const char *buf, size_t count)
+{
+       unsigned int addr, mask, set;
+       int res;
+       u32 val;
+
+       res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
+       if (res != 3)
+               return -EINVAL;
+       if (addr > B43_MAX_MMIO_ACCESS)
+               return -EADDRNOTAVAIL;
+       if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
+               return -E2BIG;
+       if ((addr % 4) != 0)
+               return -EINVAL;
+
+       if (mask == 0)
+               val = 0;
+       else
+               val = b43_read32(dev, addr);
+       val &= mask;
+       val |= set;
+       b43_write32(dev, addr, val);
+
+       return 0;
+}
+
 /* wl->irq_lock is locked */
-static ssize_t shm_read_file(struct b43_wldev *dev,
+static ssize_t tsf_read_file(struct b43_wldev *dev,
                             char *buf, size_t bufsize)
 {
        ssize_t count = 0;
-       int i;
-       u16 tmp;
-       __le16 *le16buf = (__le16 *)buf;
+       u64 tsf;
 
-       for (i = 0; i < 0x1000; i++) {
-               if (bufsize < sizeof(tmp))
-                       break;
-               tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i);
-               le16buf[i] = cpu_to_le16(tmp);
-               count += sizeof(tmp);
-               bufsize -= sizeof(tmp);
-       }
+       b43_tsf_read(dev, &tsf);
+       fappend("0x%08x%08x\n",
+               (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
+               (unsigned int)(tsf & 0xFFFFFFFFULL));
 
        return count;
 }
 
+/* wl->irq_lock is locked */
+static int tsf_write_file(struct b43_wldev *dev,
+                         const char *buf, size_t count)
+{
+       u64 tsf;
+
+       if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
+               return -EINVAL;
+       b43_tsf_write(dev, tsf);
+
+       return 0;
+}
+
 static ssize_t txstat_read_file(struct b43_wldev *dev,
                                char *buf, size_t bufsize)
 {
@@ -496,9 +753,15 @@ out_unlock:
                .take_irqlock   = _take_irqlock,                \
        }
 
+B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1);
+B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1);
+B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1);
+B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1);
+B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1);
+B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1);
+B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1);
+B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1);
 B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
-B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
-B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
 B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
 B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
 B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
@@ -538,6 +801,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev)
        add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
        add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
        add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
+       add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
 
 #undef add_dyn_dbg
 }
@@ -584,6 +848,13 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
                return;
        }
 
+       e->mmio16read_next = 0xFFFF; /* invalid address */
+       e->mmio32read_next = 0xFFFF; /* invalid address */
+       e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */
+       e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */
+       e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */
+       e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */
+
 #define ADD_FILE(name, mode)   \
        do {                                                    \
                struct dentry *d;                               \
@@ -596,9 +867,15 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
        } while (0)
 
 
+       ADD_FILE(shm16read, 0600);
+       ADD_FILE(shm16write, 0200);
+       ADD_FILE(shm32read, 0600);
+       ADD_FILE(shm32write, 0200);
+       ADD_FILE(mmio16read, 0600);
+       ADD_FILE(mmio16write, 0200);
+       ADD_FILE(mmio32read, 0600);
+       ADD_FILE(mmio32write, 0200);
        ADD_FILE(tsf, 0600);
-       ADD_FILE(ucode_regs, 0400);
-       ADD_FILE(shm, 0400);
        ADD_FILE(txstat, 0400);
        ADD_FILE(txpower_g, 0600);
        ADD_FILE(restart, 0200);
@@ -620,9 +897,15 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)
                return;
        b43_remove_dynamic_debug(dev);
 
+       debugfs_remove(e->file_shm16read.dentry);
+       debugfs_remove(e->file_shm16write.dentry);
+       debugfs_remove(e->file_shm32read.dentry);
+       debugfs_remove(e->file_shm32write.dentry);
+       debugfs_remove(e->file_mmio16read.dentry);
+       debugfs_remove(e->file_mmio16write.dentry);
+       debugfs_remove(e->file_mmio32read.dentry);
+       debugfs_remove(e->file_mmio32write.dentry);
        debugfs_remove(e->file_tsf.dentry);
-       debugfs_remove(e->file_ucode_regs.dentry);
-       debugfs_remove(e->file_shm.dentry);
        debugfs_remove(e->file_txstat.dentry);
        debugfs_remove(e->file_txpower_g.dentry);
        debugfs_remove(e->file_restart.dentry);
index c75cff4151d9a7609b05ffcbcf42262eaa3b654b..22ffd02ba554806a8625319b5c2fd2aeae1cdcba 100644 (file)
@@ -11,6 +11,7 @@ enum b43_dyndbg {             /* Dynamic debugging features */
        B43_DBG_PWORK_FAST,
        B43_DBG_PWORK_STOP,
        B43_DBG_LO,
+       B43_DBG_FIRMWARE,
        __B43_NR_DYNDBG,
 };
 
@@ -36,9 +37,15 @@ struct b43_dfsentry {
        struct b43_wldev *dev;
        struct dentry *subdir;
 
+       struct b43_dfs_file file_shm16read;
+       struct b43_dfs_file file_shm16write;
+       struct b43_dfs_file file_shm32read;
+       struct b43_dfs_file file_shm32write;
+       struct b43_dfs_file file_mmio16read;
+       struct b43_dfs_file file_mmio16write;
+       struct b43_dfs_file file_mmio32read;
+       struct b43_dfs_file file_mmio32write;
        struct b43_dfs_file file_tsf;
-       struct b43_dfs_file file_ucode_regs;
-       struct b43_dfs_file file_shm;
        struct b43_dfs_file file_txstat;
        struct b43_dfs_file file_txpower_g;
        struct b43_dfs_file file_restart;
@@ -46,6 +53,18 @@ struct b43_dfsentry {
 
        struct b43_txstatus_log txstatlog;
 
+       /* The cached address for the next mmio16read file read */
+       u16 mmio16read_next;
+       /* The cached address for the next mmio32read file read */
+       u16 mmio32read_next;
+
+       /* The cached address for the next shm16read file read */
+       u32 shm16read_routing_next;
+       u32 shm16read_addr_next;
+       /* The cached address for the next shm32read file read */
+       u32 shm32read_routing_next;
+       u32 shm32read_addr_next;
+
        /* Enabled/Disabled list for the dynamic debugging features. */
        u32 dyn_debug[__B43_NR_DYNDBG];
        /* Dentries for the dynamic debugging entries. */
index 8a09a1db08dbc4521f8645caf35c9d04825c8cc5..098f886976f658fe636c39aa8a9f3810d227e25f 100644 (file)
@@ -328,11 +328,11 @@ static inline
        dma_addr_t dmaaddr;
 
        if (tx) {
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
-                                        buf, len, DMA_TO_DEVICE);
+               dmaaddr = ssb_dma_map_single(ring->dev->dev,
+                                            buf, len, DMA_TO_DEVICE);
        } else {
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
-                                        buf, len, DMA_FROM_DEVICE);
+               dmaaddr = ssb_dma_map_single(ring->dev->dev,
+                                            buf, len, DMA_FROM_DEVICE);
        }
 
        return dmaaddr;
@@ -343,11 +343,11 @@ static inline
                          dma_addr_t addr, size_t len, int tx)
 {
        if (tx) {
-               dma_unmap_single(ring->dev->dev->dma_dev,
-                                addr, len, DMA_TO_DEVICE);
+               ssb_dma_unmap_single(ring->dev->dev,
+                                    addr, len, DMA_TO_DEVICE);
        } else {
-               dma_unmap_single(ring->dev->dev->dma_dev,
-                                addr, len, DMA_FROM_DEVICE);
+               ssb_dma_unmap_single(ring->dev->dev,
+                                    addr, len, DMA_FROM_DEVICE);
        }
 }
 
@@ -356,8 +356,8 @@ static inline
                                 dma_addr_t addr, size_t len)
 {
        B43_WARN_ON(ring->tx);
-       dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
-                               addr, len, DMA_FROM_DEVICE);
+       ssb_dma_sync_single_for_cpu(ring->dev->dev,
+                                   addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -365,8 +365,8 @@ static inline
                                    dma_addr_t addr, size_t len)
 {
        B43_WARN_ON(ring->tx);
-       dma_sync_single_for_device(ring->dev->dev->dma_dev,
-                                  addr, len, DMA_FROM_DEVICE);
+       ssb_dma_sync_single_for_device(ring->dev->dev,
+                                      addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -381,7 +381,6 @@ static inline
 
 static int alloc_ringmemory(struct b43_dmaring *ring)
 {
-       struct device *dma_dev = ring->dev->dev->dma_dev;
        gfp_t flags = GFP_KERNEL;
 
        /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
@@ -392,11 +391,14 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
         * For unknown reasons - possibly a hardware error - the BCM4311 rev
         * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
         * which accounts for the GFP_DMA flag below.
+        *
+        * The flags here must match the flags in free_ringmemory below!
         */
        if (ring->type == B43_DMA_64BIT)
                flags |= GFP_DMA;
-       ring->descbase = dma_alloc_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
-                                           &(ring->dmabase), flags);
+       ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
+                                                 B43_DMA_RINGMEMSIZE,
+                                                 &(ring->dmabase), flags);
        if (!ring->descbase) {
                b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
                return -ENOMEM;
@@ -408,10 +410,13 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
 
 static void free_ringmemory(struct b43_dmaring *ring)
 {
-       struct device *dma_dev = ring->dev->dev->dma_dev;
+       gfp_t flags = GFP_KERNEL;
+
+       if (ring->type == B43_DMA_64BIT)
+               flags |= GFP_DMA;
 
-       dma_free_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
-                         ring->descbase, ring->dmabase);
+       ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
+                               ring->descbase, ring->dmabase, flags);
 }
 
 /* Reset the RX DMA channel */
@@ -518,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
                                  dma_addr_t addr,
                                  size_t buffersize, bool dma_to_device)
 {
-       if (unlikely(dma_mapping_error(addr)))
+       if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
                return 1;
 
        switch (ring->type) {
@@ -844,10 +849,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        goto err_kfree_meta;
 
                /* test for ability to dma to txhdr_cache */
-               dma_test = dma_map_single(dev->dev->dma_dev,
-                                         ring->txhdr_cache,
-                                         b43_txhdr_size(dev),
-                                         DMA_TO_DEVICE);
+               dma_test = ssb_dma_map_single(dev->dev,
+                                             ring->txhdr_cache,
+                                             b43_txhdr_size(dev),
+                                             DMA_TO_DEVICE);
 
                if (b43_dma_mapping_error(ring, dma_test,
                                          b43_txhdr_size(dev), 1)) {
@@ -859,10 +864,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        if (!ring->txhdr_cache)
                                goto err_kfree_meta;
 
-                       dma_test = dma_map_single(dev->dev->dma_dev,
-                                                 ring->txhdr_cache,
-                                                 b43_txhdr_size(dev),
-                                                 DMA_TO_DEVICE);
+                       dma_test = ssb_dma_map_single(dev->dev,
+                                                     ring->txhdr_cache,
+                                                     b43_txhdr_size(dev),
+                                                     DMA_TO_DEVICE);
 
                        if (b43_dma_mapping_error(ring, dma_test,
                                                  b43_txhdr_size(dev), 1)) {
@@ -873,9 +878,9 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        }
                }
 
-               dma_unmap_single(dev->dev->dma_dev,
-                                dma_test, b43_txhdr_size(dev),
-                                DMA_TO_DEVICE);
+               ssb_dma_unmap_single(dev->dev,
+                                    dma_test, b43_txhdr_size(dev),
+                                    DMA_TO_DEVICE);
        }
 
        err = alloc_ringmemory(ring);
index 36a9c42df835c3fa77241533cf90f1eb6c14e9e4..76f4c7bad8b83e52b30000ccc62f86a77113e45b 100644 (file)
@@ -72,6 +72,9 @@ static void b43_led_brightness_set(struct led_classdev *led_dev,
        struct b43_wldev *dev = led->dev;
        bool radio_enabled;
 
+       if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED))
+               return;
+
        /* Checking the radio-enabled status here is slightly racy,
         * but we want to avoid the locking overhead and we don't care
         * whether the LED has the wrong state for a second. */
index 7bca8e9815129e158c5d4b13d834b92e57e72ea7..9d2eb273b726da910293bc9cac0ff811169a32a5 100644 (file)
@@ -373,13 +373,10 @@ static inline void b43_shm_control_word(struct b43_wldev *dev,
        b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
 }
 
-u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
+u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
 {
-       struct b43_wl *wl = dev->wl;
-       unsigned long flags;
        u32 ret;
 
-       spin_lock_irqsave(&wl->shm_lock, flags);
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
@@ -397,18 +394,26 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
        b43_shm_control_word(dev, routing, offset);
        ret = b43_read32(dev, B43_MMIO_SHM_DATA);
 out:
-       spin_unlock_irqrestore(&wl->shm_lock, flags);
-
        return ret;
 }
 
-u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
+u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
 {
        struct b43_wl *wl = dev->wl;
        unsigned long flags;
-       u16 ret;
+       u32 ret;
 
        spin_lock_irqsave(&wl->shm_lock, flags);
+       ret = __b43_shm_read32(dev, routing, offset);
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
+
+       return ret;
+}
+
+u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
+{
+       u16 ret;
+
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
@@ -423,17 +428,24 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
        b43_shm_control_word(dev, routing, offset);
        ret = b43_read16(dev, B43_MMIO_SHM_DATA);
 out:
-       spin_unlock_irqrestore(&wl->shm_lock, flags);
-
        return ret;
 }
 
-void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
+u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
 {
        struct b43_wl *wl = dev->wl;
        unsigned long flags;
+       u16 ret;
 
        spin_lock_irqsave(&wl->shm_lock, flags);
+       ret = __b43_shm_read16(dev, routing, offset);
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
+
+       return ret;
+}
+
+void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
+{
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
@@ -443,35 +455,47 @@ void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
                                    (value >> 16) & 0xffff);
                        b43_shm_control_word(dev, routing, (offset >> 2) + 1);
                        b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
-                       goto out;
+                       return;
                }
                offset >>= 2;
        }
        b43_shm_control_word(dev, routing, offset);
        b43_write32(dev, B43_MMIO_SHM_DATA, value);
-out:
-       spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
-void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
+void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
 {
        struct b43_wl *wl = dev->wl;
        unsigned long flags;
 
        spin_lock_irqsave(&wl->shm_lock, flags);
+       __b43_shm_write32(dev, routing, offset, value);
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
+}
+
+void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
+{
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
                        /* Unaligned access */
                        b43_shm_control_word(dev, routing, offset >> 2);
                        b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
-                       goto out;
+                       return;
                }
                offset >>= 2;
        }
        b43_shm_control_word(dev, routing, offset);
        b43_write16(dev, B43_MMIO_SHM_DATA, value);
-out:
+}
+
+void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
+{
+       struct b43_wl *wl = dev->wl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->shm_lock, flags);
+       __b43_shm_write16(dev, routing, offset, value);
        spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
@@ -2463,6 +2487,19 @@ static void b43_gpio_cleanup(struct b43_wldev *dev)
 /* http://bcm-specs.sipsolutions.net/EnableMac */
 void b43_mac_enable(struct b43_wldev *dev)
 {
+       if (b43_debug(dev, B43_DBG_FIRMWARE)) {
+               u16 fwstate;
+
+               fwstate = b43_shm_read16(dev, B43_SHM_SHARED,
+                                        B43_SHM_SH_UCODESTAT);
+               if ((fwstate != B43_SHM_SH_UCODESTAT_SUSP) &&
+                   (fwstate != B43_SHM_SH_UCODESTAT_SLEEP)) {
+                       b43err(dev->wl, "b43_mac_enable(): The firmware "
+                              "should be suspended, but current state is %u\n",
+                              fwstate);
+               }
+       }
+
        dev->mac_suspended--;
        B43_WARN_ON(dev->mac_suspended < 0);
        if (dev->mac_suspended == 0) {
@@ -2783,6 +2820,21 @@ static void b43_periodic_every30sec(struct b43_wldev *dev)
 static void b43_periodic_every15sec(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
+       u16 wdr;
+
+       if (dev->fw.opensource) {
+               /* Check if the firmware is still alive.
+                * It will reset the watchdog counter to 0 in its idle loop. */
+               wdr = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_WATCHDOG_REG);
+               if (unlikely(wdr)) {
+                       b43err(dev->wl, "Firmware watchdog: The firmware died!\n");
+                       b43_controller_restart(dev, "Firmware watchdog");
+                       return;
+               } else {
+                       b43_shm_write16(dev, B43_SHM_SCRATCH,
+                                       B43_WATCHDOG_REG, 1);
+               }
+       }
 
        if (phy->type == B43_PHYTYPE_G) {
                //TODO: update_aci_moving_average
@@ -2976,12 +3028,11 @@ static int b43_op_tx(struct ieee80211_hw *hw,
 
        if (unlikely(skb->len < 2 + 2 + 6)) {
                /* Too short, this can't be a valid frame. */
-               dev_kfree_skb_any(skb);
-               return NETDEV_TX_OK;
+               goto drop_packet;
        }
        B43_WARN_ON(skb_shinfo(skb)->nr_frags);
        if (unlikely(!dev))
-               return NETDEV_TX_BUSY;
+               goto drop_packet;
 
        /* Transmissions on seperate queues can run concurrently. */
        read_lock_irqsave(&wl->tx_lock, flags);
@@ -2997,7 +3048,12 @@ static int b43_op_tx(struct ieee80211_hw *hw,
        read_unlock_irqrestore(&wl->tx_lock, flags);
 
        if (unlikely(err))
-               return NETDEV_TX_BUSY;
+               goto drop_packet;
+       return NETDEV_TX_OK;
+
+drop_packet:
+       /* We can not transmit this packet. Drop it. */
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
index dad23c42b42278482db447938b15118588abc1ca..f871a252cb555f7c00ae767e73bde8d38f019f17 100644 (file)
@@ -95,9 +95,13 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
 void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
 
 u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
+u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
 u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
+u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
 void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
+void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
 void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
+void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
 
 u64 b43_hf_read(struct b43_wldev *dev);
 void b43_hf_write(struct b43_wldev *dev, u64 value);
index 8b1555d95f1c81654cafdbfc5fd3668203dd34a9..4015912675922f4a5e9f8e6249885f70d364c8b1 100644 (file)
@@ -586,7 +586,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
 
        spin_lock(&q->lock); /* IRQs are already disabled. */
 
-       info = (void *)pack->skb;
+       info = IEEE80211_SKB_CB(pack->skb);
        memset(&info->status, 0, sizeof(info->status));
 
        b43_fill_txstatus_report(info, status);
index 11f53cb1139ee58b3686dacf8e4f1ef24cc4d00c..4cca203992e83490444868ee0d18358e063036a4 100644 (file)
@@ -88,7 +88,7 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
                goto out_unlock;
        err = 0;
        switch (state) {
-       case RFKILL_STATE_ON:
+       case RFKILL_STATE_UNBLOCKED:
                if (!dev->radio_hw_enable) {
                        /* No luck. We can't toggle the hardware RF-kill
                         * button from software. */
@@ -98,10 +98,13 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
                if (!dev->phy.radio_on)
                        b43_radio_turn_on(dev);
                break;
-       case RFKILL_STATE_OFF:
+       case RFKILL_STATE_SOFT_BLOCKED:
                if (dev->phy.radio_on)
                        b43_radio_turn_off(dev, 0);
                break;
+       default:
+               b43warn(wl, "Received unexpected rfkill state %d.\n", state);
+               break;
        }
 out_unlock:
        mutex_unlock(&wl->mutex);
index f9e1cff2aecbec42752c3a4336288f86229c766d..bf6f6c1ed4cf5193117a88da50493a3e965b6426 100644 (file)
@@ -193,7 +193,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
        const struct ieee80211_hdr *wlhdr =
            (const struct ieee80211_hdr *)fragment_data;
        int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
-       u16 fctl = le16_to_cpu(wlhdr->frame_control);
+       __le16 fctl = wlhdr->frame_control;
        struct ieee80211_rate *fbrate;
        u8 rate, rate_fb;
        int rate_ofdm, rate_fb_ofdm;
@@ -259,7 +259,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                           B43_TXH_MAC_KEYIDX;
                mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
                           B43_TXH_MAC_KEYALG;
-               wlhdr_len = ieee80211_get_hdrlen(fctl);
+               wlhdr_len = ieee80211_hdrlen(fctl);
                iv_len = min((size_t) info->control.iv_len,
                             ARRAY_SIZE(txhdr->iv));
                memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
@@ -317,8 +317,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
        /* MAC control */
        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
                mac_ctl |= B43_TXH_MAC_ACK;
-       if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-             ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
+       if (!ieee80211_is_pspoll(fctl))
                mac_ctl |= B43_TXH_MAC_HWSEQ;
        if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
                mac_ctl |= B43_TXH_MAC_STMSDU;
@@ -509,7 +508,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
        struct b43_plcp_hdr6 *plcp;
        struct ieee80211_hdr *wlhdr;
        const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
-       u16 fctl;
+       __le16 fctl;
        u16 phystat0, phystat3, chanstat, mactime;
        u32 macstat;
        u16 chanid;
@@ -549,7 +548,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
                goto drop;
        }
        wlhdr = (struct ieee80211_hdr *)(skb->data);
-       fctl = le16_to_cpu(wlhdr->frame_control);
+       fctl = wlhdr->frame_control;
 
        if (macstat & B43_RX_MAC_DEC) {
                unsigned int keyidx;
@@ -564,7 +563,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
                B43_WARN_ON(keyidx >= dev->max_nr_keys);
 
                if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
-                       wlhdr_len = ieee80211_get_hdrlen(fctl);
+                       wlhdr_len = ieee80211_hdrlen(fctl);
                        if (unlikely(skb->len < (wlhdr_len + 3))) {
                                b43dbg(dev->wl,
                                       "RX: Packet size underrun (3)\n");
@@ -604,9 +603,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
         * of timestamp, i.e. about 65 milliseconds after the PHY received
         * the first symbol.
         */
-       if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
-           == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) ||
-           dev->wl->radiotap_enabled) {
+       if (ieee80211_is_beacon(fctl) || dev->wl->radiotap_enabled) {
                u16 low_mactime_now;
 
                b43_tsf_read(dev, &status.mactime);
index 33cc256c5baf5311a0f52b9d93ab3411ca95a316..eb0243a226917b060f56093d914c7aa460f32f4b 100644 (file)
@@ -393,13 +393,13 @@ dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
        dma_addr_t dmaaddr;
 
        if (tx)
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
-                                        buf, len,
-                                        DMA_TO_DEVICE);
+               dmaaddr = ssb_dma_map_single(ring->dev->dev,
+                                            buf, len,
+                                            DMA_TO_DEVICE);
        else
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
-                                        buf, len,
-                                        DMA_FROM_DEVICE);
+               dmaaddr = ssb_dma_map_single(ring->dev->dev,
+                                            buf, len,
+                                            DMA_FROM_DEVICE);
 
        return dmaaddr;
 }
@@ -411,13 +411,13 @@ void unmap_descbuffer(struct b43legacy_dmaring *ring,
                      int tx)
 {
        if (tx)
-               dma_unmap_single(ring->dev->dev->dma_dev,
-                                addr, len,
-                                DMA_TO_DEVICE);
+               ssb_dma_unmap_single(ring->dev->dev,
+                                    addr, len,
+                                    DMA_TO_DEVICE);
        else
-               dma_unmap_single(ring->dev->dev->dma_dev,
-                                addr, len,
-                                DMA_FROM_DEVICE);
+               ssb_dma_unmap_single(ring->dev->dev,
+                                    addr, len,
+                                    DMA_FROM_DEVICE);
 }
 
 static inline
@@ -427,8 +427,8 @@ void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
 {
        B43legacy_WARN_ON(ring->tx);
 
-       dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
-                               addr, len, DMA_FROM_DEVICE);
+       ssb_dma_sync_single_for_cpu(ring->dev->dev,
+                                   addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -438,8 +438,8 @@ void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
 {
        B43legacy_WARN_ON(ring->tx);
 
-       dma_sync_single_for_device(ring->dev->dev->dma_dev,
-                                  addr, len, DMA_FROM_DEVICE);
+       ssb_dma_sync_single_for_device(ring->dev->dev,
+                                      addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -458,10 +458,11 @@ void free_descriptor_buffer(struct b43legacy_dmaring *ring,
 
 static int alloc_ringmemory(struct b43legacy_dmaring *ring)
 {
-       struct device *dma_dev = ring->dev->dev->dma_dev;
-
-       ring->descbase = dma_alloc_coherent(dma_dev, B43legacy_DMA_RINGMEMSIZE,
-                                           &(ring->dmabase), GFP_KERNEL);
+       /* GFP flags must match the flags in free_ringmemory()! */
+       ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
+                                                 B43legacy_DMA_RINGMEMSIZE,
+                                                 &(ring->dmabase),
+                                                 GFP_KERNEL);
        if (!ring->descbase) {
                b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
                             " failed\n");
@@ -474,10 +475,8 @@ static int alloc_ringmemory(struct b43legacy_dmaring *ring)
 
 static void free_ringmemory(struct b43legacy_dmaring *ring)
 {
-       struct device *dma_dev = ring->dev->dev->dma_dev;
-
-       dma_free_coherent(dma_dev, B43legacy_DMA_RINGMEMSIZE,
-                         ring->descbase, ring->dmabase);
+       ssb_dma_free_consistent(ring->dev->dev, B43legacy_DMA_RINGMEMSIZE,
+                               ring->descbase, ring->dmabase, GFP_KERNEL);
 }
 
 /* Reset the RX DMA channel */
@@ -589,7 +588,7 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
                                         size_t buffersize,
                                         bool dma_to_device)
 {
-       if (unlikely(dma_mapping_error(addr)))
+       if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
                return 1;
 
        switch (ring->type) {
@@ -876,6 +875,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
        if (!ring)
                goto out;
        ring->type = type;
+       ring->dev = dev;
 
        nr_slots = B43legacy_RXRING_SLOTS;
        if (for_tx)
@@ -893,9 +893,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
                        goto err_kfree_meta;
 
                /* test for ability to dma to txhdr_cache */
-               dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache,
-                                         sizeof(struct b43legacy_txhdr_fw3),
-                                         DMA_TO_DEVICE);
+               dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache,
+                                             sizeof(struct b43legacy_txhdr_fw3),
+                                             DMA_TO_DEVICE);
 
                if (b43legacy_dma_mapping_error(ring, dma_test,
                                        sizeof(struct b43legacy_txhdr_fw3), 1)) {
@@ -907,7 +907,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
                        if (!ring->txhdr_cache)
                                goto err_kfree_meta;
 
-                       dma_test = dma_map_single(dev->dev->dma_dev,
+                               dma_test = ssb_dma_map_single(dev->dev,
                                        ring->txhdr_cache,
                                        sizeof(struct b43legacy_txhdr_fw3),
                                        DMA_TO_DEVICE);
@@ -917,12 +917,11 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
                                goto err_kfree_txhdr_cache;
                }
 
-               dma_unmap_single(dev->dev->dma_dev,
-                                dma_test, sizeof(struct b43legacy_txhdr_fw3),
-                                DMA_TO_DEVICE);
+               ssb_dma_unmap_single(dev->dev, dma_test,
+                                    sizeof(struct b43legacy_txhdr_fw3),
+                                    DMA_TO_DEVICE);
        }
 
-       ring->dev = dev;
        ring->nr_slots = nr_slots;
        ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index);
        ring->index = controller_index;
index 5f533b93ad5df4c042f7103a2c0b371879419a32..069157eea05cfd44f346326e587e569dee5fe720 100644 (file)
@@ -2377,8 +2377,10 @@ static int b43legacy_op_tx(struct ieee80211_hw *hw,
        } else
                err = b43legacy_dma_tx(dev, skb);
 out:
-       if (unlikely(err))
-               return NETDEV_TX_BUSY;
+       if (unlikely(err)) {
+               /* Drop the packet. */
+               dev_kfree_skb_any(skb);
+       }
        return NETDEV_TX_OK;
 }
 
index d178dfbb1c9f6e6abf03255223c41d7083a24a61..8935a302b22008b585a7b864f380c0904323c5d3 100644 (file)
@@ -90,7 +90,7 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
                goto out_unlock;
        err = 0;
        switch (state) {
-       case RFKILL_STATE_ON:
+       case RFKILL_STATE_UNBLOCKED:
                if (!dev->radio_hw_enable) {
                        /* No luck. We can't toggle the hardware RF-kill
                         * button from software. */
@@ -100,10 +100,14 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
                if (!dev->phy.radio_on)
                        b43legacy_radio_turn_on(dev);
                break;
-       case RFKILL_STATE_OFF:
+       case RFKILL_STATE_SOFT_BLOCKED:
                if (dev->phy.radio_on)
                        b43legacy_radio_turn_off(dev, 0);
                break;
+       default:
+               b43legacywarn(wl, "Received unexpected rfkill state %d.\n",
+                             state);
+               break;
        }
 
 out_unlock:
index 82dc04d59446979598a51f9d00a254ea5a3733f7..a3540787eb507bfe4809d58008dae28c738c6666 100644 (file)
@@ -442,7 +442,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
        struct b43legacy_plcp_hdr6 *plcp;
        struct ieee80211_hdr *wlhdr;
        const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr;
-       u16 fctl;
+       __le16 fctl;
        u16 phystat0;
        u16 phystat3;
        u16 chanstat;
@@ -480,7 +480,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
                goto drop;
        }
        wlhdr = (struct ieee80211_hdr *)(skb->data);
-       fctl = le16_to_cpu(wlhdr->frame_control);
+       fctl = wlhdr->frame_control;
 
        if ((macstat & B43legacy_RX_MAC_DEC) &&
            !(macstat & B43legacy_RX_MAC_DECERR)) {
@@ -499,11 +499,11 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
 
                if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) {
                        /* Remove PROTECTED flag to mark it as decrypted. */
-                       B43legacy_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED));
-                       fctl &= ~IEEE80211_FCTL_PROTECTED;
-                       wlhdr->frame_control = cpu_to_le16(fctl);
+                       B43legacy_WARN_ON(!ieee80211_has_protected(fctl));
+                       fctl &= ~cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+                       wlhdr->frame_control = fctl;
 
-                       wlhdr_len = ieee80211_get_hdrlen(fctl);
+                       wlhdr_len = ieee80211_hdrlen(fctl);
                        if (unlikely(skb->len < (wlhdr_len + 3))) {
                                b43legacydbg(dev->wl, "RX: Packet size"
                                             " underrun3\n");
@@ -556,9 +556,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
         * of timestamp, i.e. about 65 milliseconds after the PHY received
         * the first symbol.
         */
-       if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
-           == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) ||
-           dev->wl->radiotap_enabled) {
+       if (ieee80211_is_beacon(fctl) || dev->wl->radiotap_enabled) {
                u16 low_mactime_now;
 
                b43legacy_tsf_read(dev, &status.mactime);
index 547ba84dc797a3155138b0a6e853957ff7d0509c..3a386a636cca4a0f2aad3f24cf259908fa1729ef 100644 (file)
@@ -67,7 +67,8 @@ void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
 int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
                           struct iw_quality qual[], int buf_size,
                           int aplist);
-int prism2_ap_translate_scan(struct net_device *dev, char *buffer);
+int prism2_ap_translate_scan(struct net_device *dev,
+                            struct iw_request_info *info, char *buffer);
 int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param);
 
 
index 0acd9589c48c0f36277f6b1351a559bbb1988f14..06b23df8f69b630fba0ebe48554d6dbb9d1dbd05 100644 (file)
@@ -2420,7 +2420,8 @@ int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
 
 /* Translate our list of Access Points & Stations to a card independant
  * format that the Wireless Tools will understand - Jean II */
-int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
+int prism2_ap_translate_scan(struct net_device *dev,
+                            struct iw_request_info *info, char *buffer)
 {
        struct hostap_interface *iface;
        local_info_t *local;
@@ -2449,8 +2450,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
                iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
                memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN);
                iwe.len = IW_EV_ADDR_LEN;
-               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
-                                                 IW_EV_ADDR_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_ADDR_LEN);
 
                /* Use the mode to indicate if it's a station or
                 * an Access Point */
@@ -2461,8 +2462,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
                else
                        iwe.u.mode = IW_MODE_INFRA;
                iwe.len = IW_EV_UINT_LEN;
-               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
-                                                 IW_EV_UINT_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_UINT_LEN);
 
                /* Some quality */
                memset(&iwe, 0, sizeof(iwe));
@@ -2477,8 +2478,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
                iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
                iwe.u.qual.updated = sta->last_rx_updated;
                iwe.len = IW_EV_QUAL_LEN;
-               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
-                                                 IW_EV_QUAL_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_QUAL_LEN);
 
 #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
                if (sta->ap) {
@@ -2486,8 +2487,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
                        iwe.cmd = SIOCGIWESSID;
                        iwe.u.data.length = sta->u.ap.ssid_len;
                        iwe.u.data.flags = 1;
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
-                                                         &iwe,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf, &iwe,
                                                          sta->u.ap.ssid);
 
                        memset(&iwe, 0, sizeof(iwe));
@@ -2497,10 +2498,9 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
                                        IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
                        else
                                iwe.u.data.flags = IW_ENCODE_DISABLED;
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
-                                                         &iwe,
-                                                         sta->u.ap.ssid
-                                                         /* 0 byte memcpy */);
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf, &iwe,
+                                                         sta->u.ap.ssid);
 
                        if (sta->u.ap.channel > 0 &&
                            sta->u.ap.channel <= FREQ_COUNT) {
@@ -2510,7 +2510,7 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
                                        * 100000;
                                iwe.u.freq.e = 1;
                                current_ev = iwe_stream_add_event(
-                                       current_ev, end_buf, &iwe,
+                                       info, current_ev, end_buf, &iwe,
                                        IW_EV_FREQ_LEN);
                        }
 
@@ -2519,8 +2519,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
                        sprintf(buf, "beacon_interval=%d",
                                sta->listen_interval);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
-                                                         &iwe, buf);
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf, &iwe, buf);
                }
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
 
index 0ca0bfeb0ada33d44501ab4051d7d12b8007d53e..ed52d98317cd138cac3407be7eefcd2dd1090dd9 100644 (file)
@@ -1793,6 +1793,7 @@ static int prism2_ioctl_siwscan(struct net_device *dev,
 
 #ifndef PRISM2_NO_STATION_MODES
 static char * __prism2_translate_scan(local_info_t *local,
+                                     struct iw_request_info *info,
                                      struct hfa384x_hostscan_result *scan,
                                      struct hostap_bss_info *bss,
                                      char *current_ev, char *end_buf)
@@ -1823,7 +1824,7 @@ static char * __prism2_translate_scan(local_info_t *local,
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN);
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_ADDR_LEN);
 
        /* Other entries will be displayed in the order we give them */
@@ -1832,7 +1833,8 @@ static char * __prism2_translate_scan(local_info_t *local,
        iwe.cmd = SIOCGIWESSID;
        iwe.u.data.length = ssid_len;
        iwe.u.data.flags = 1;
-       current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid);
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, ssid);
 
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWMODE;
@@ -1847,8 +1849,8 @@ static char * __prism2_translate_scan(local_info_t *local,
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
-               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
-                                                 IW_EV_UINT_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_UINT_LEN);
        }
 
        memset(&iwe, 0, sizeof(iwe));
@@ -1864,8 +1866,8 @@ static char * __prism2_translate_scan(local_info_t *local,
        if (chan > 0) {
                iwe.u.freq.m = freq_list[chan - 1] * 100000;
                iwe.u.freq.e = 1;
-               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
-                                                 IW_EV_FREQ_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_FREQ_LEN);
        }
 
        if (scan) {
@@ -1884,8 +1886,8 @@ static char * __prism2_translate_scan(local_info_t *local,
                        | IW_QUAL_NOISE_UPDATED
                        | IW_QUAL_QUAL_INVALID
                        | IW_QUAL_DBM;
-               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
-                                                 IW_EV_QUAL_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_QUAL_LEN);
        }
 
        memset(&iwe, 0, sizeof(iwe));
@@ -1895,13 +1897,13 @@ static char * __prism2_translate_scan(local_info_t *local,
        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_stream_add_point(info, current_ev, end_buf, &iwe, "");
 
        /* TODO: add SuppRates into BSS table */
        if (scan) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = SIOCGIWRATE;
-               current_val = current_ev + IW_EV_LCP_LEN;
+               current_val = current_ev + iwe_stream_lcp_len(info);
                pos = scan->sup_rates;
                for (i = 0; i < sizeof(scan->sup_rates); i++) {
                        if (pos[i] == 0)
@@ -1909,11 +1911,11 @@ static char * __prism2_translate_scan(local_info_t *local,
                        /* Bit rate given in 500 kb/s units (+ 0x80) */
                        iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000);
                        current_val = iwe_stream_add_value(
-                               current_ev, current_val, end_buf, &iwe,
+                               info, current_ev, current_val, end_buf, &iwe,
                                IW_EV_PARAM_LEN);
                }
                /* Check if we added any event */
-               if ((current_val - current_ev) > IW_EV_LCP_LEN)
+               if ((current_val - current_ev) > iwe_stream_lcp_len(info))
                        current_ev = current_val;
        }
 
@@ -1924,15 +1926,15 @@ static char * __prism2_translate_scan(local_info_t *local,
                iwe.cmd = IWEVCUSTOM;
                sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval));
                iwe.u.data.length = strlen(buf);
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 buf);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, buf);
 
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVCUSTOM;
                sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate));
                iwe.u.data.length = strlen(buf);
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 buf);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, buf);
 
                if (local->last_scan_type == PRISM2_HOSTSCAN &&
                    (capabilities & WLAN_CAPABILITY_IBSS)) {
@@ -1940,8 +1942,8 @@ static char * __prism2_translate_scan(local_info_t *local,
                        iwe.cmd = IWEVCUSTOM;
                        sprintf(buf, "atim=%d", le16_to_cpu(scan->atim));
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
-                                                         &iwe, buf);
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf, &iwe, buf);
                }
        }
        kfree(buf);
@@ -1950,16 +1952,16 @@ static char * __prism2_translate_scan(local_info_t *local,
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->wpa_ie_len;
-               current_ev = iwe_stream_add_point(
-                       current_ev, end_buf, &iwe, bss->wpa_ie);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss->wpa_ie);
        }
 
        if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->rsn_ie_len;
-               current_ev = iwe_stream_add_point(
-                       current_ev, end_buf, &iwe, bss->rsn_ie);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss->rsn_ie);
        }
 
        return current_ev;
@@ -1969,6 +1971,7 @@ static char * __prism2_translate_scan(local_info_t *local,
 /* Translate scan data returned from the card to a card independant
  * format that the Wireless Tools will understand - Jean II */
 static inline int prism2_translate_scan(local_info_t *local,
+                                       struct iw_request_info *info,
                                        char *buffer, int buflen)
 {
        struct hfa384x_hostscan_result *scan;
@@ -1999,13 +2002,14 @@ static inline int prism2_translate_scan(local_info_t *local,
                        if (memcmp(bss->bssid, scan->bssid, ETH_ALEN) == 0) {
                                bss->included = 1;
                                current_ev = __prism2_translate_scan(
-                                       local, scan, bss, current_ev, end_buf);
+                                       local, info, scan, bss, current_ev,
+                                       end_buf);
                                found++;
                        }
                }
                if (!found) {
                        current_ev = __prism2_translate_scan(
-                               local, scan, NULL, current_ev, end_buf);
+                               local, info, scan, NULL, current_ev, end_buf);
                }
                /* Check if there is space for one more entry */
                if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
@@ -2023,7 +2027,7 @@ static inline int prism2_translate_scan(local_info_t *local,
                bss = list_entry(ptr, struct hostap_bss_info, list);
                if (bss->included)
                        continue;
-               current_ev = __prism2_translate_scan(local, NULL, bss,
+               current_ev = __prism2_translate_scan(local, info, NULL, bss,
                                                     current_ev, end_buf);
                /* Check if there is space for one more entry */
                if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
@@ -2070,7 +2074,7 @@ static inline int prism2_ioctl_giwscan_sta(struct net_device *dev,
        }
        local->scan_timestamp = 0;
 
-       res = prism2_translate_scan(local, extra, data->length);
+       res = prism2_translate_scan(local, info, extra, data->length);
 
        if (res >= 0) {
                data->length = res;
@@ -2103,7 +2107,7 @@ static int prism2_ioctl_giwscan(struct net_device *dev,
                 * Jean II */
 
                /* Translate to WE format */
-               res = prism2_ap_translate_scan(dev, extra);
+               res = prism2_ap_translate_scan(dev, info, extra);
                if (res >= 0) {
                        printk(KERN_DEBUG "Scan result translation succeeded "
                               "(length=%d)\n", res);
index a382c00789239e24eadc20679ac57b930455b221..d7ea32f39694c11612a8158efcd0356cef793db4 100644 (file)
@@ -8,7 +8,7 @@ config IWLCORE
        select MAC80211_LEDS if IWLWIFI_LEDS
        select LEDS_CLASS if IWLWIFI_LEDS
        select RFKILL if IWLWIFI_RFKILL
-       select RFKILL_INPUT if IWLWIFI_RFKILL
+       select RFKILL_INPUT if (IWLWIFI_RFKILL && INPUT)
 
 config IWLWIFI_LEDS
        bool
index 5f098747cf95cfc99a1e1bf877b08ffef0340d18..ffefbb487e121b62b287d0345804b64cd489a5df 100644 (file)
@@ -54,17 +54,20 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
        mutex_lock(&priv->mutex);
 
        switch (state) {
-       case RFKILL_STATE_ON:
+       case RFKILL_STATE_UNBLOCKED:
                iwl_radio_kill_sw_enable_radio(priv);
                /* if HW rf-kill is set dont allow ON state */
                if (iwl_is_rfkill(priv))
                        err = -EBUSY;
                break;
-       case RFKILL_STATE_OFF:
+       case RFKILL_STATE_SOFT_BLOCKED:
                iwl_radio_kill_sw_disable_radio(priv);
                if (!iwl_is_rfkill(priv))
                        err = -EBUSY;
                break;
+       default:
+               IWL_WARNING("we recieved unexpected RFKILL state %d\n", state);
+               break;
        }
        mutex_unlock(&priv->mutex);
 
@@ -95,6 +98,7 @@ int iwl_rfkill_init(struct iwl_priv *priv)
        priv->rfkill_mngr.rfkill->dev.class->suspend = NULL;
        priv->rfkill_mngr.rfkill->dev.class->resume = NULL;
 
+#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
        priv->rfkill_mngr.input_dev = input_allocate_device();
        if (!priv->rfkill_mngr.input_dev) {
                IWL_ERROR("Unable to allocate rfkill input device.\n");
@@ -109,6 +113,7 @@ int iwl_rfkill_init(struct iwl_priv *priv)
        priv->rfkill_mngr.input_dev->dev.parent = device;
        priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY);
        set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit);
+#endif
 
        ret = rfkill_register(priv->rfkill_mngr.rfkill);
        if (ret) {
@@ -116,11 +121,13 @@ int iwl_rfkill_init(struct iwl_priv *priv)
                goto free_input_dev;
        }
 
+#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
        ret = input_register_device(priv->rfkill_mngr.input_dev);
        if (ret) {
                IWL_ERROR("Unable to register rfkill input device: %d\n", ret);
                goto unregister_rfkill;
        }
+#endif
 
        IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
        return ret;
@@ -130,8 +137,10 @@ unregister_rfkill:
        priv->rfkill_mngr.rfkill = NULL;
 
 free_input_dev:
+#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
        input_free_device(priv->rfkill_mngr.input_dev);
        priv->rfkill_mngr.input_dev = NULL;
+#endif
 
 freed_rfkill:
        if (priv->rfkill_mngr.rfkill != NULL)
@@ -147,13 +156,16 @@ EXPORT_SYMBOL(iwl_rfkill_init);
 void iwl_rfkill_unregister(struct iwl_priv *priv)
 {
 
+#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
        if (priv->rfkill_mngr.input_dev)
                input_unregister_device(priv->rfkill_mngr.input_dev);
+       input_free_device(priv->rfkill_mngr.input_dev);
+       priv->rfkill_mngr.input_dev = NULL;
+#endif
 
        if (priv->rfkill_mngr.rfkill)
                rfkill_unregister(priv->rfkill_mngr.rfkill);
 
-       priv->rfkill_mngr.input_dev = NULL;
        priv->rfkill_mngr.rfkill = NULL;
 }
 EXPORT_SYMBOL(iwl_rfkill_unregister);
index 5ca181f7125dd81d55c16767ba766c59b4d0ab96..5b420b43af5cb8b067ed5354eec768e002b65b00 100644 (file)
@@ -276,13 +276,18 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
        cancel_delayed_work(&priv->scan_check);
 
        IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
-                      (priv->scan_bands == 2) ? "2.4" : "5.2",
+                      (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
+                                               "2.4" : "5.2",
                       jiffies_to_msecs(elapsed_jiffies
                                        (priv->scan_pass_start, jiffies)));
 
-       /* Remove this scanned band from the list
-        * of pending bands to scan */
-       priv->scan_bands--;
+       /* Remove this scanned band from the list of pending
+        * bands to scan, band G precedes A in order of scanning
+        * as seen in iwl_bg_request_scan */
+       if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
+               priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
+       else if (priv->scan_bands &  BIT(IEEE80211_BAND_5GHZ))
+               priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
 
        /* If a request to abort was given, or the scan did not succeed
         * then we reset the scan state machine and terminate,
@@ -292,7 +297,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                clear_bit(STATUS_SCAN_ABORTING, &priv->status);
        } else {
                /* If there are more bands on this scan pass reschedule */
-               if (priv->scan_bands > 0)
+               if (priv->scan_bands)
                        goto reschedule;
        }
 
@@ -389,7 +394,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
 
                ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
                if (!is_channel_valid(ch_info)) {
-                       IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+                       IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
                                       scan_ch->channel);
                        continue;
                }
@@ -465,7 +470,10 @@ int iwl_scan_initiate(struct iwl_priv *priv)
        }
 
        IWL_DEBUG_INFO("Starting scan...\n");
-       priv->scan_bands = 2;
+       if (priv->cfg->sku & IWL_SKU_G)
+               priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+       if (priv->cfg->sku & IWL_SKU_A)
+               priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
        set_bit(STATUS_SCANNING, &priv->status);
        priv->scan_start = jiffies;
        priv->scan_pass_start = priv->scan_start;
@@ -803,8 +811,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
 
-       switch (priv->scan_bands) {
-       case 2:
+       if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
                band = IEEE80211_BAND_2GHZ;
                scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
                tx_ant = iwl_scan_tx_ant(priv, band);
@@ -818,9 +825,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
                                                        tx_ant |
                                                        RATE_MCS_CCK_MSK);
                scan->good_CRC_th = 0;
-               break;
-
-       case 1:
+       } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
                band = IEEE80211_BAND_5GHZ;
                tx_ant = iwl_scan_tx_ant(priv, band);
                scan->tx_cmd.rate_n_flags =
@@ -833,9 +838,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
                 * MIMO is not used here, but value is required */
                if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
                        rx_chain = 0x6;
-
-               break;
-       default:
+       } else {
                IWL_WARNING("Invalid scan band count\n");
                goto done;
        }
index 47cf4b997f5096c1c49217e2d608d524f955deb8..92d1b2e312d4076af8ceaef762f75744585d6da0 100644 (file)
@@ -2217,7 +2217,10 @@ static int iwl3945_scan_initiate(struct iwl3945_priv *priv)
        }
 
        IWL_DEBUG_INFO("Starting scan...\n");
-       priv->scan_bands = 2;
+       if (priv->cfg->sku & IWL_SKU_G)
+               priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+       if (priv->cfg->sku & IWL_SKU_A)
+               priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
        set_bit(STATUS_SCANNING, &priv->status);
        priv->scan_start = jiffies;
        priv->scan_pass_start = priv->scan_start;
@@ -3342,13 +3345,18 @@ static void iwl3945_rx_scan_complete_notif(struct iwl3945_priv *priv,
        cancel_delayed_work(&priv->scan_check);
 
        IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
-                      (priv->scan_bands == 2) ? "2.4" : "5.2",
+                      (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
+                                                       "2.4" : "5.2",
                       jiffies_to_msecs(elapsed_jiffies
                                        (priv->scan_pass_start, jiffies)));
 
-       /* Remove this scanned band from the list
-        * of pending bands to scan */
-       priv->scan_bands--;
+       /* Remove this scanned band from the list of pending
+        * bands to scan, band G precedes A in order of scanning
+        * as seen in iwl3945_bg_request_scan */
+       if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
+               priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
+       else if (priv->scan_bands &  BIT(IEEE80211_BAND_5GHZ))
+               priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
 
        /* If a request to abort was given, or the scan did not succeed
         * then we reset the scan state machine and terminate,
@@ -4961,7 +4969,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
 
                ch_info = iwl3945_get_channel_info(priv, band, scan_ch->channel);
                if (!is_channel_valid(ch_info)) {
-                       IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+                       IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
                                       scan_ch->channel);
                        continue;
                }
@@ -6316,21 +6324,16 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
 
        /* flags + rate selection */
 
-       switch (priv->scan_bands) {
-       case 2:
+       if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
                scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
                scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
                scan->good_CRC_th = 0;
                band = IEEE80211_BAND_2GHZ;
-               break;
-
-       case 1:
+       } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
                scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
                scan->good_CRC_th = IWL_GOOD_CRC_TH;
                band = IEEE80211_BAND_5GHZ;
-               break;
-
-       default:
+       } else {
                IWL_WARNING("Invalid scan band count\n");
                goto done;
        }
@@ -6770,7 +6773,7 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
        ch_info = iwl3945_get_channel_info(priv, conf->channel->band,
                                           conf->channel->hw_value);
        if (!is_channel_valid(ch_info)) {
-               IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+               IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this band.\n",
                               conf->channel->hw_value, conf->channel->band);
                IWL_DEBUG_MAC80211("leave - invalid channel\n");
                spin_unlock_irqrestore(&priv->lock, flags);
index d448c9702a0f93528d66f7d5f2ee116a452a1604..343ed38f772d6a30d4f38526d381c34f7b6eae22 100644 (file)
@@ -776,8 +776,9 @@ out:
 #define MAX_CUSTOM_LEN 64
 
 static inline char *lbs_translate_scan(struct lbs_private *priv,
-                                      char *start, char *stop,
-                                      struct bss_descriptor *bss)
+                                           struct iw_request_info *info,
+                                           char *start, char *stop,
+                                           struct bss_descriptor *bss)
 {
        struct chan_freq_power *cfp;
        char *current_val;      /* For rates */
@@ -801,24 +802,24 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
-       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
+       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
 
        /* SSID */
        iwe.cmd = SIOCGIWESSID;
        iwe.u.data.flags = 1;
        iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE);
-       start = iwe_stream_add_point(start, stop, &iwe, bss->ssid);
+       start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
 
        /* Mode */
        iwe.cmd = SIOCGIWMODE;
        iwe.u.mode = bss->mode;
-       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
+       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
 
        /* Frequency */
        iwe.cmd = SIOCGIWFREQ;
        iwe.u.freq.m = (long)cfp->freq * 100000;
        iwe.u.freq.e = 1;
-       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
+       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
 
        /* Add quality statistics */
        iwe.cmd = IWEVQUAL;
@@ -852,7 +853,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
                nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
                iwe.u.qual.level = CAL_RSSI(snr, nf);
        }
-       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
+       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
 
        /* Add encryption capability */
        iwe.cmd = SIOCGIWENCODE;
@@ -862,9 +863,9 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
                iwe.u.data.flags = IW_ENCODE_DISABLED;
        }
        iwe.u.data.length = 0;
-       start = iwe_stream_add_point(start, stop, &iwe, bss->ssid);
+       start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
 
-       current_val = start + IW_EV_LCP_LEN;
+       current_val = start + iwe_stream_lcp_len(info);
 
        iwe.cmd = SIOCGIWRATE;
        iwe.u.bitrate.fixed = 0;
@@ -874,19 +875,19 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
        for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
                /* Bit rate given in 500 kb/s units */
                iwe.u.bitrate.value = bss->rates[j] * 500000;
-               current_val = iwe_stream_add_value(start, current_val,
-                                        stop, &iwe, IW_EV_PARAM_LEN);
+               current_val = iwe_stream_add_value(info, start, current_val,
+                                                  stop, &iwe, IW_EV_PARAM_LEN);
        }
        if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
            && !lbs_ssid_cmp(priv->curbssparams.ssid,
                             priv->curbssparams.ssid_len,
                             bss->ssid, bss->ssid_len)) {
                iwe.u.bitrate.value = 22 * 500000;
-               current_val = iwe_stream_add_value(start, current_val,
+               current_val = iwe_stream_add_value(info, start, current_val,
                                                   stop, &iwe, IW_EV_PARAM_LEN);
        }
        /* Check if we added any event */
-       if((current_val - start) > IW_EV_LCP_LEN)
+       if ((current_val - start) > iwe_stream_lcp_len(info))
                start = current_val;
 
        memset(&iwe, 0, sizeof(iwe));
@@ -895,7 +896,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
                memcpy(buf, bss->wpa_ie, bss->wpa_ie_len);
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->wpa_ie_len;
-               start = iwe_stream_add_point(start, stop, &iwe, buf);
+               start = iwe_stream_add_point(info, start, stop, &iwe, buf);
        }
 
        memset(&iwe, 0, sizeof(iwe));
@@ -904,7 +905,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
                memcpy(buf, bss->rsn_ie, bss->rsn_ie_len);
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->rsn_ie_len;
-               start = iwe_stream_add_point(start, stop, &iwe, buf);
+               start = iwe_stream_add_point(info, start, stop, &iwe, buf);
        }
 
        if (bss->mesh) {
@@ -915,7 +916,8 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
                p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");
                iwe.u.data.length = p - custom;
                if (iwe.u.data.length)
-                       start = iwe_stream_add_point(start, stop, &iwe, custom);
+                       start = iwe_stream_add_point(info, start, stop,
+                                                    &iwe, custom);
        }
 
 out:
@@ -1036,7 +1038,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
                }
 
                /* Translate to WE format this entry */
-               next_ev = lbs_translate_scan(priv, ev, stop, iter_bss);
+               next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss);
                if (next_ev == NULL)
                        continue;
                ev = next_ev;
index 8da352ae6825ad41934dcfe83de059e0cc8c9b2d..5d30c57e3969cfe4ed4d65da9d57d0f9728122ca 100644 (file)
@@ -430,15 +430,16 @@ static int __init init_mac80211_hwsim(void)
                hwsim_radios[i] = hw;
 
                data = hw->priv;
-               data->dev = device_create(hwsim_class, NULL, 0, "hwsim%d", i);
+               data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw,
+                                               "hwsim%d", i);
                if (IS_ERR(data->dev)) {
-                       printk(KERN_DEBUG "mac80211_hwsim: device_create "
+                       printk(KERN_DEBUG
+                              "mac80211_hwsim: device_create_drvdata "
                               "failed (%ld)\n", PTR_ERR(data->dev));
                        err = -ENOMEM;
                        goto failed;
                }
                data->dev->driver = &mac80211_hwsim_driver;
-               dev_set_drvdata(data->dev, hw);
 
                SET_IEEE80211_DEV(hw, data->dev);
                addr[3] = i >> 8;
index 6d13a0d15a0cba9818b21852e89da8dc0a0c22cf..b047306bf38681da30132a061c44b82de4efb029 100644 (file)
@@ -4046,6 +4046,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
  * format that the Wireless Tools will understand - Jean II
  * Return message length or -errno for fatal errors */
 static inline char *orinoco_translate_scan(struct net_device *dev,
+                                          struct iw_request_info *info,
                                           char *current_ev,
                                           char *end_buf,
                                           union hermes_scan_info *bss,
@@ -4062,7 +4063,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_ADDR_LEN);
 
        /* Other entries will be displayed in the order we give them */
 
@@ -4072,7 +4074,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
                iwe.u.data.length = 32;
        iwe.cmd = SIOCGIWESSID;
        iwe.u.data.flags = 1;
-       current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, bss->a.essid);
 
        /* Add mode */
        iwe.cmd = SIOCGIWMODE;
@@ -4082,7 +4085,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
-               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_UINT_LEN);
        }
 
        channel = bss->s.channel;
@@ -4091,7 +4095,7 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
                iwe.cmd = SIOCGIWFREQ;
                iwe.u.freq.m = channel_frequency[channel-1] * 100000;
                iwe.u.freq.e = 1;
-               current_ev = iwe_stream_add_event(current_ev, end_buf,
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
                                                  &iwe, IW_EV_FREQ_LEN);
        }
 
@@ -4106,7 +4110,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
                iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
        else
                iwe.u.qual.qual = 0;
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_QUAL_LEN);
 
        /* Add encryption capability */
        iwe.cmd = SIOCGIWENCODE;
@@ -4115,7 +4120,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
        else
                iwe.u.data.flags = IW_ENCODE_DISABLED;
        iwe.u.data.length = 0;
-       current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, bss->a.essid);
 
        /* Add EXTRA: Age to display seconds since last beacon/probe response
         * for given network. */
@@ -4126,11 +4132,12 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
                      jiffies_to_msecs(jiffies - last_scanned));
        iwe.u.data.length = p - custom;
        if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, custom);
 
        /* Bit rate is not available in Lucent/Agere firmwares */
        if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
-               char *current_val = current_ev + IW_EV_LCP_LEN;
+               char *current_val = current_ev + iwe_stream_lcp_len(info);
                int i;
                int step;
 
@@ -4149,12 +4156,13 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
                                break;
                        /* Bit rate given in 500 kb/s units (+ 0x80) */
                        iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000);
-                       current_val = iwe_stream_add_value(current_ev, current_val,
+                       current_val = iwe_stream_add_value(info, current_ev,
+                                                          current_val,
                                                           end_buf, &iwe,
                                                           IW_EV_PARAM_LEN);
                }
                /* Check if we added any event */
-               if ((current_val - current_ev) > IW_EV_LCP_LEN)
+               if ((current_val - current_ev) > iwe_stream_lcp_len(info))
                        current_ev = current_val;
        }
 
@@ -4190,7 +4198,7 @@ static int orinoco_ioctl_getscan(struct net_device *dev,
 
        list_for_each_entry(bss, &priv->bss_list, list) {
                /* Translate to WE format this entry */
-               current_ev = orinoco_translate_scan(dev, current_ev,
+               current_ev = orinoco_translate_scan(dev, info, current_ev,
                                                    extra + srq->length,
                                                    &bss->bss,
                                                    bss->last_scanned);
index 5b375b289036fe8d5f9ed2f5dd8fd73325831725..97fa14e0a47912c0c8513a23dd8053b3acb649bc 100644 (file)
@@ -571,8 +571,9 @@ prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
  */
 
 static char *
-prism54_translate_bss(struct net_device *ndev, char *current_ev,
-                     char *end_buf, struct obj_bss *bss, char noise)
+prism54_translate_bss(struct net_device *ndev, struct iw_request_info *info,
+                     char *current_ev, char *end_buf, struct obj_bss *bss,
+                     char noise)
 {
        struct iw_event iwe;    /* Temporary buffer */
        short cap;
@@ -584,8 +585,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
        memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        iwe.cmd = SIOCGIWAP;
-       current_ev =
-           iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_ADDR_LEN);
 
        /* The following entries will be displayed in the same order we give them */
 
@@ -593,7 +594,7 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
        iwe.u.data.length = bss->ssid.length;
        iwe.u.data.flags = 1;
        iwe.cmd = SIOCGIWESSID;
-       current_ev = iwe_stream_add_point(current_ev, end_buf,
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
                                          &iwe, bss->ssid.octets);
 
        /* Capabilities */
@@ -610,9 +611,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
                iwe.u.mode = IW_MODE_ADHOC;
        iwe.cmd = SIOCGIWMODE;
        if (iwe.u.mode)
-               current_ev =
-                   iwe_stream_add_event(current_ev, end_buf, &iwe,
-                                        IW_EV_UINT_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_UINT_LEN);
 
        /* Encryption capability */
        if (cap & CAP_CRYPT)
@@ -621,14 +621,15 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
                iwe.u.data.flags = IW_ENCODE_DISABLED;
        iwe.u.data.length = 0;
        iwe.cmd = SIOCGIWENCODE;
-       current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, NULL);
 
        /* Add frequency. (short) bss->channel is the frequency in MHz */
        iwe.u.freq.m = bss->channel;
        iwe.u.freq.e = 6;
        iwe.cmd = SIOCGIWFREQ;
-       current_ev =
-           iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_FREQ_LEN);
 
        /* Add quality statistics */
        iwe.u.qual.level = bss->rssi;
@@ -636,20 +637,20 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
        /* do a simple SNR for quality */
        iwe.u.qual.qual = bss->rssi - noise;
        iwe.cmd = IWEVQUAL;
-       current_ev =
-           iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_QUAL_LEN);
 
        /* Add WPA/RSN Information Element, if any */
        wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
        if (wpa_ie_len > 0) {
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
-               current_ev = iwe_stream_add_point(current_ev, end_buf,
-                               &iwe, wpa_ie);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, wpa_ie);
        }
        /* Do the bitrates */
        {
-               char *  current_val = current_ev + IW_EV_LCP_LEN;
+               char *current_val = current_ev + iwe_stream_lcp_len(info);
                int i;
                int mask;
 
@@ -662,14 +663,14 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
                for(i = 0; i < sizeof(scan_rate_list); i++) {
                        if(bss->rates & mask) {
                                iwe.u.bitrate.value = (scan_rate_list[i] * 500000);
-                               current_val = iwe_stream_add_value(current_ev, current_val,
-                                                                  end_buf, &iwe,
-                                                                  IW_EV_PARAM_LEN);
+                               current_val = iwe_stream_add_value(
+                                       info, current_ev, current_val,
+                                       end_buf, &iwe, IW_EV_PARAM_LEN);
                        }
                        mask <<= 1;
                }
                /* Check if we added any event */
-               if ((current_val - current_ev) > IW_EV_LCP_LEN)
+               if ((current_val - current_ev) > iwe_stream_lcp_len(info))
                        current_ev = current_val;
        }
 
@@ -710,7 +711,7 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
 
        /* ok now, scan the list and translate its info */
        for (i = 0; i < (int) bsslist->nr; i++) {
-               current_ev = prism54_translate_bss(ndev, current_ev,
+               current_ev = prism54_translate_bss(ndev, info, current_ev,
                                                   extra + dwrq->length,
                                                   &(bsslist->bsslist[i]),
                                                   noise);
@@ -2704,6 +2705,7 @@ prism2_ioctl_scan_req(struct net_device *ndev,
                      struct prism2_hostapd_param *param)
 {
        islpci_private *priv = netdev_priv(ndev);
+       struct iw_request_info info;
        int i, rvalue;
        struct obj_bsslist *bsslist;
        u32 noise = 0;
@@ -2727,9 +2729,12 @@ prism2_ioctl_scan_req(struct net_device *ndev,
        rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
        bsslist = r.ptr;
 
+       info.cmd = PRISM54_HOSTAPD;
+       info.flags = 0;
+
        /* ok now, scan the list and translate its info */
        for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
-               current_ev = prism54_translate_bss(ndev, current_ev,
+               current_ev = prism54_translate_bss(ndev, &info, current_ev,
                                                   extra + IW_SCAN_MAX_DATA,
                                                   &(bsslist->bsslist[i]),
                                                   noise);
index 762e85bef55dcef657ded932a53f911b051ae4b9..e43bae97ed8f66a6bc9ccb9eeb86a66a6db0302c 100644 (file)
@@ -290,7 +290,7 @@ islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb)
 
                avs->version = cpu_to_be32(P80211CAPTURE_VERSION);
                avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header));
-               avs->mactime = cpu_to_be64(le64_to_cpu(clock));
+               avs->mactime = cpu_to_be64(clock);
                avs->hosttime = cpu_to_be64(jiffies);
                avs->phytype = cpu_to_be32(6);  /*OFDM: 6 for (g), 8 for (a) */
                avs->channel = cpu_to_be32(channel_of_freq(freq));
index f001f2afd05e64d2ede968e833dd8dfbf43a8398..00e965b9da75b02345bf4df19b378c89b4bf88e4 100644 (file)
@@ -1648,7 +1648,9 @@ static int rndis_iw_set_scan(struct net_device *dev,
 
 
 static char *rndis_translate_scan(struct net_device *dev,
-    char *cev, char *end_buf, struct ndis_80211_bssid_ex *bssid)
+                                 struct iw_request_info *info, char *cev,
+                                 char *end_buf,
+                                 struct ndis_80211_bssid_ex *bssid)
 {
 #ifdef DEBUG
        struct usbnet *usbdev = dev->priv;
@@ -1667,14 +1669,14 @@ static char *rndis_translate_scan(struct net_device *dev,
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN);
-       cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN);
+       cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_ADDR_LEN);
 
        devdbg(usbdev, "SSID(%d) %s", le32_to_cpu(bssid->ssid.length),
                                                bssid->ssid.essid);
        iwe.cmd = SIOCGIWESSID;
        iwe.u.essid.length = le32_to_cpu(bssid->ssid.length);
        iwe.u.essid.flags = 1;
-       cev = iwe_stream_add_point(cev, end_buf, &iwe, bssid->ssid.essid);
+       cev = iwe_stream_add_point(info, cev, end_buf, &iwe, bssid->ssid.essid);
 
        devdbg(usbdev, "MODE %d", le32_to_cpu(bssid->net_infra));
        iwe.cmd = SIOCGIWMODE;
@@ -1690,12 +1692,12 @@ static char *rndis_translate_scan(struct net_device *dev,
                iwe.u.mode = IW_MODE_AUTO;
                break;
        }
-       cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN);
+       cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_UINT_LEN);
 
        devdbg(usbdev, "FREQ %d kHz", le32_to_cpu(bssid->config.ds_config));
        iwe.cmd = SIOCGIWFREQ;
        dsconfig_to_freq(le32_to_cpu(bssid->config.ds_config), &iwe.u.freq);
-       cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN);
+       cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_FREQ_LEN);
 
        devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->rssi));
        iwe.cmd = IWEVQUAL;
@@ -1704,7 +1706,7 @@ static char *rndis_translate_scan(struct net_device *dev,
        iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
                        | IW_QUAL_LEVEL_UPDATED
                        | IW_QUAL_NOISE_INVALID;
-       cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN);
+       cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_QUAL_LEN);
 
        devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->privacy));
        iwe.cmd = SIOCGIWENCODE;
@@ -1714,10 +1716,10 @@ static char *rndis_translate_scan(struct net_device *dev,
        else
                iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
 
-       cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL);
+       cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL);
 
        devdbg(usbdev, "RATES:");
-       current_val = cev + IW_EV_LCP_LEN;
+       current_val = cev + iwe_stream_lcp_len(info);
        iwe.cmd = SIOCGIWRATE;
        for (i = 0; i < sizeof(bssid->rates); i++) {
                if (bssid->rates[i] & 0x7f) {
@@ -1725,13 +1727,13 @@ static char *rndis_translate_scan(struct net_device *dev,
                                ((bssid->rates[i] & 0x7f) *
                                500000);
                        devdbg(usbdev, " %d", iwe.u.bitrate.value);
-                       current_val = iwe_stream_add_value(cev,
+                       current_val = iwe_stream_add_value(info, cev,
                                current_val, end_buf, &iwe,
                                IW_EV_PARAM_LEN);
                }
        }
 
-       if ((current_val - cev) > IW_EV_LCP_LEN)
+       if ((current_val - cev) > iwe_stream_lcp_len(info))
                cev = current_val;
 
        beacon = le32_to_cpu(bssid->config.beacon_period);
@@ -1739,14 +1741,14 @@ static char *rndis_translate_scan(struct net_device *dev,
        iwe.cmd = IWEVCUSTOM;
        snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon);
        iwe.u.data.length = strlen(sbuf);
-       cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf);
+       cev = iwe_stream_add_point(info, cev, end_buf, &iwe, sbuf);
 
        atim = le32_to_cpu(bssid->config.atim_window);
        devdbg(usbdev, "ATIM %d", atim);
        iwe.cmd = IWEVCUSTOM;
        snprintf(sbuf, sizeof(sbuf), "atim=%u", atim);
        iwe.u.data.length = strlen(sbuf);
-       cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf);
+       cev = iwe_stream_add_point(info, cev, end_buf, &iwe, sbuf);
 
        ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies));
        ie_len = min(bssid_len - (int)sizeof(*bssid),
@@ -1760,7 +1762,7 @@ static char *rndis_translate_scan(struct net_device *dev,
                                        (ie->id == MFIE_TYPE_RSN) ? 2 : 1);
                        iwe.cmd = IWEVGENIE;
                        iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN);
-                       cev = iwe_stream_add_point(cev, end_buf, &iwe,
+                       cev = iwe_stream_add_point(info, cev, end_buf, &iwe,
                                                                (u8 *)ie);
                }
 
@@ -1803,8 +1805,8 @@ static int rndis_iw_get_scan(struct net_device *dev,
        devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count);
 
        while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
-               cev = rndis_translate_scan(dev, cev, extra + IW_SCAN_MAX_DATA,
-                                                                       bssid);
+               cev = rndis_translate_scan(dev, info, cev,
+                                          extra + IW_SCAN_MAX_DATA, bssid);
                bssid = (void *)bssid + bssid_len;
                bssid_len = le32_to_cpu(bssid->length);
                count--;
index bb3d83560d02ae2e1ae6d4dfffa11c14dd185266..b3dffcfed835c9918f3433155dc7d9b54d9f893c 100644 (file)
@@ -632,15 +632,15 @@ static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
                                   struct queue_entry *entry)
 {
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        u32 word;
 
        rt2x00_desc_read(entry_priv->desc, 2, &word);
-       rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
-                          entry->queue->data_size);
+       rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len);
        rt2x00_desc_write(entry_priv->desc, 2, word);
 
        rt2x00_desc_read(entry_priv->desc, 1, &word);
-       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
 
        rt2x00_desc_read(entry_priv->desc, 0, &word);
@@ -1012,7 +1012,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         * Start writing the descriptor words.
         */
        rt2x00_desc_read(entry_priv->desc, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
@@ -1154,7 +1154,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
                }
                txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
 
-               rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
+               rt2x00lib_txdone(entry, &txdesc);
        }
 }
 
@@ -1366,7 +1366,7 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
                               IEEE80211_HW_SIGNAL_DBM;
        rt2x00dev->hw->extra_tx_headroom = 0;
 
-       SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+       SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
                                rt2x00_eeprom_addr(rt2x00dev,
                                                   EEPROM_MAC_ADDR_0));
@@ -1412,9 +1412,10 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        rt2400pci_probe_hw_mode(rt2x00dev);
 
        /*
-        * This device requires the atim queue
+        * This device requires the atim queue and DMA-mapped skbs.
         */
        __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
+       __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 
        /*
         * Set the rssi offset.
@@ -1526,7 +1527,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
         * Write entire beacon with descriptor to register,
         * and kick the beacon generator.
         */
-       memcpy(entry_priv->data, skb->data, skb->len);
+       rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
        rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
        rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 
index 3c956b91c4e3b8f75ee08c1725889e9cc7aeac08..0423c251c78e5c0b069bc247d14b310b03d8c951 100644 (file)
@@ -727,10 +727,11 @@ static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
                                   struct queue_entry *entry)
 {
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        u32 word;
 
        rt2x00_desc_read(entry_priv->desc, 1, &word);
-       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
 
        rt2x00_desc_read(entry_priv->desc, 0, &word);
@@ -1171,7 +1172,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         * Start writing the descriptor words.
         */
        rt2x00_desc_read(entry_priv->desc, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
@@ -1311,7 +1312,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
                }
                txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
 
-               rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
+               rt2x00lib_txdone(entry, &txdesc);
        }
 }
 
@@ -1688,7 +1689,7 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 
        rt2x00dev->hw->extra_tx_headroom = 0;
 
-       SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+       SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
                                rt2x00_eeprom_addr(rt2x00dev,
                                                   EEPROM_MAC_ADDR_0));
@@ -1752,9 +1753,10 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        rt2500pci_probe_hw_mode(rt2x00dev);
 
        /*
-        * This device requires the atim queue
+        * This device requires the atim queue and DMA-mapped skbs.
         */
        __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
+       __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 
        /*
         * Set the rssi offset.
@@ -1842,7 +1844,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
         * Write entire beacon with descriptor to register,
         * and kick the beacon generator.
         */
-       memcpy(entry_priv->data, skb->data, skb->len);
+       rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
        rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
        rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 
index 9851cefaabf3eadf315afba9a80b90ed193eb01d..0dd1cb537b92999d71ffb038b19bbe38902f66e4 100644 (file)
@@ -138,11 +138,8 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
         * Wait until the BBP becomes ready.
         */
        reg = rt2500usb_bbp_check(rt2x00dev);
-       if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
-               ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
-               mutex_unlock(&rt2x00dev->usb_cache_mutex);
-               return;
-       }
+       if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+               goto exit_fail;
 
        /*
         * Write the data into the BBP.
@@ -155,6 +152,13 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
        rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
 
        mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+       return;
+
+exit_fail:
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+       ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
 }
 
 static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -168,10 +172,8 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
         * Wait until the BBP becomes ready.
         */
        reg = rt2500usb_bbp_check(rt2x00dev);
-       if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
-               ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
-               return;
-       }
+       if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+               goto exit_fail;
 
        /*
         * Write the request into the BBP.
@@ -186,17 +188,21 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
         * Wait until the BBP becomes ready.
         */
        reg = rt2500usb_bbp_check(rt2x00dev);
-       if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
-               ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
-               *value = 0xff;
-               mutex_unlock(&rt2x00dev->usb_cache_mutex);
-               return;
-       }
+       if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+               goto exit_fail;
 
        rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
        *value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
 
        mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+       return;
+
+exit_fail:
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+       ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+       *value = 0xff;
 }
 
 static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
@@ -1588,7 +1594,7 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 
        rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
 
-       SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+       SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
                                rt2x00_eeprom_addr(rt2x00dev,
                                                   EEPROM_MAC_ADDR_0));
@@ -1672,7 +1678,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
+       struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
        struct queue_entry_priv_usb_bcn *bcn_priv;
index 0da8f972a1b22582b7faacb256d014afd4acef11..6842464dcf3e589fd5dfbde7bac9c7797898f4a9 100644 (file)
@@ -44,7 +44,7 @@
 /*
  * Module information.
  */
-#define DRV_VERSION    "2.1.7"
+#define DRV_VERSION    "2.1.8"
 #define DRV_PROJECT    "http://rt2x00.serialmonkey.com"
 
 /*
 #define SHORT_DIFS             ( SHORT_PIFS + SHORT_SLOT_TIME )
 #define EIFS                   ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) )
 
-/*
- * IEEE802.11 header defines
- */
-static inline int is_rts_frame(u16 fc)
-{
-       return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-               ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS));
-}
-
-static inline int is_cts_frame(u16 fc)
-{
-       return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-               ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS));
-}
-
-static inline int is_probe_resp(u16 fc)
-{
-       return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
-               ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP));
-}
-
-static inline int is_beacon(u16 fc)
-{
-       return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
-               ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON));
-}
-
 /*
  * Chipset identification
  * The chipset on the device is composed of a RT and RF chip.
@@ -628,6 +601,7 @@ enum rt2x00_flags {
        DRIVER_REQUIRE_BEACON_GUARD,
        DRIVER_REQUIRE_ATIM_QUEUE,
        DRIVER_REQUIRE_SCHEDULED,
+       DRIVER_REQUIRE_DMA,
 
        /*
         * Driver configuration
@@ -652,11 +626,7 @@ struct rt2x00_dev {
         * When accessing this variable, the rt2x00dev_{pci,usb}
         * macro's should be used for correct typecasting.
         */
-       void *dev;
-#define rt2x00dev_pci(__dev)   ( (struct pci_dev *)(__dev)->dev )
-#define rt2x00dev_usb(__dev)   ( (struct usb_interface *)(__dev)->dev )
-#define rt2x00dev_usb_dev(__dev)\
-       ( (struct usb_device *)interface_to_usbdev(rt2x00dev_usb(__dev)) )
+       struct device *dev;
 
        /*
         * Callback functions.
@@ -818,6 +788,7 @@ struct rt2x00_dev {
        /*
         * Scheduled work.
         */
+       struct workqueue_struct *workqueue;
        struct work_struct intf_work;
        struct work_struct filter_work;
 
@@ -930,10 +901,11 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
 }
 
 /**
- * rt2x00queue_alloc_rxskb - allocate a skb for RX purposes.
- * @queue: The queue for which the skb will be applicable.
+ * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to map.
  */
-struct sk_buff *rt2x00queue_alloc_rxskb(struct data_queue *queue);
+void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 
 /**
  * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
@@ -984,26 +956,14 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
 struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
                                          enum queue_index index);
 
-/**
- * rt2x00queue_index_inc - Index incrementation function
- * @queue: Queue (&struct data_queue) to perform the action on.
- * @index: Index type (&enum queue_index) to perform the action on.
- *
- * This function will increase the requested index on the queue,
- * it will grab the appropriate locks and handle queue overflow events by
- * resetting the index to the start of the queue.
- */
-void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
-
-
 /*
  * Interrupt context handlers.
  */
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
 void rt2x00lib_txdone(struct queue_entry *entry,
                      struct txdone_entry_desc *txdesc);
-void rt2x00lib_rxdone(struct queue_entry *entry,
-                     struct rxdone_entry_desc *rxdesc);
+void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
+                     struct queue_entry *entry);
 
 /*
  * mac80211 handlers.
index 9ea677320daa672e98b96e1945b261b199845433..ae8ab71fe474a462de1827214ca7dffa239d0282 100644 (file)
@@ -74,7 +74,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
 
        rt2x00lib_reset_link_tuner(rt2x00dev);
 
-       queue_delayed_work(rt2x00dev->hw->workqueue,
+       queue_delayed_work(rt2x00dev->workqueue,
                           &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
 }
 
@@ -137,14 +137,6 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
        if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
                return;
 
-       /*
-        * Stop all scheduled work.
-        */
-       if (work_pending(&rt2x00dev->intf_work))
-               cancel_work_sync(&rt2x00dev->intf_work);
-       if (work_pending(&rt2x00dev->filter_work))
-               cancel_work_sync(&rt2x00dev->filter_work);
-
        /*
         * Stop the TX queues.
         */
@@ -400,8 +392,8 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
         * Increase tuner counter, and reschedule the next link tuner run.
         */
        rt2x00dev->link.count++;
-       queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work,
-                          LINK_TUNE_INTERVAL);
+       queue_delayed_work(rt2x00dev->workqueue,
+                          &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
 }
 
 static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
@@ -434,6 +426,15 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 
        spin_unlock(&intf->lock);
 
+       /*
+        * It is possible the radio was disabled while the work had been
+        * scheduled. If that happens we should return here immediately,
+        * note that in the spinlock protected area above the delayed_flags
+        * have been cleared correctly.
+        */
+       if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+               return;
+
        if (delayed_flags & DELAYED_UPDATE_BEACON) {
                skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
                if (skb &&
@@ -442,7 +443,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
        }
 
        if (delayed_flags & DELAYED_CONFIG_ERP)
-               rt2x00lib_config_erp(rt2x00dev, intf, &intf->conf);
+               rt2x00lib_config_erp(rt2x00dev, intf, &conf);
 
        if (delayed_flags & DELAYED_LED_ASSOC)
                rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
@@ -468,12 +469,19 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
 static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
                                      struct ieee80211_vif *vif)
 {
+       struct rt2x00_dev *rt2x00dev = data;
        struct rt2x00_intf *intf = vif_to_intf(vif);
 
        if (vif->type != IEEE80211_IF_TYPE_AP &&
            vif->type != IEEE80211_IF_TYPE_IBSS)
                return;
 
+       /*
+        * Clean up the beacon skb.
+        */
+       rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
+       intf->beacon->skb = NULL;
+
        spin_lock(&intf->lock);
        intf->delayed_flags |= DELAYED_UPDATE_BEACON;
        spin_unlock(&intf->lock);
@@ -488,7 +496,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
                                                   rt2x00lib_beacondone_iter,
                                                   rt2x00dev);
 
-       queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+       queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
 
@@ -497,6 +505,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+       enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
+
+       /*
+        * Unmap the skb.
+        */
+       rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
 
        /*
         * Send frame to debugfs immediately, after this call is completed
@@ -545,39 +559,77 @@ void rt2x00lib_txdone(struct queue_entry *entry,
                ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
        else
                dev_kfree_skb_irq(entry->skb);
+
+       /*
+        * Make this entry available for reuse.
+        */
        entry->skb = NULL;
+       entry->flags = 0;
+
+       rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry);
+
+       __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+       rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
+
+       /*
+        * If the data queue was below the threshold before the txdone
+        * handler we must make sure the packet queue in the mac80211 stack
+        * is reenabled when the txdone handler has finished.
+        */
+       if (!rt2x00queue_threshold(entry->queue))
+               ieee80211_wake_queue(rt2x00dev->hw, qid);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
 
-void rt2x00lib_rxdone(struct queue_entry *entry,
-                     struct rxdone_entry_desc *rxdesc)
+void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
+                     struct queue_entry *entry)
 {
-       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct rxdone_entry_desc rxdesc;
+       struct sk_buff *skb;
        struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
-       unsigned int header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
        struct ieee80211_supported_band *sband;
        struct ieee80211_hdr *hdr;
        const struct rt2x00_rate *rate;
+       unsigned int header_size;
        unsigned int align;
        unsigned int i;
        int idx = -1;
-       u16 fc;
+
+       /*
+        * Allocate a new sk_buffer. If no new buffer available, drop the
+        * received frame and reuse the existing buffer.
+        */
+       skb = rt2x00queue_alloc_rxskb(rt2x00dev, entry);
+       if (!skb)
+               return;
+
+       /*
+        * Unmap the skb.
+        */
+       rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+
+       /*
+        * Extract the RXD details.
+        */
+       memset(&rxdesc, 0, sizeof(rxdesc));
+       rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
 
        /*
         * The data behind the ieee80211 header must be
         * aligned on a 4 byte boundary.
         */
+       header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
        align = ((unsigned long)(entry->skb->data + header_size)) & 3;
 
        if (align) {
                skb_push(entry->skb, align);
                /* Move entire frame in 1 command */
                memmove(entry->skb->data, entry->skb->data + align,
-                       rxdesc->size);
+                       rxdesc.size);
        }
 
        /* Update data pointers, trim buffer to correct size */
-       skb_trim(entry->skb, rxdesc->size);
+       skb_trim(entry->skb, rxdesc.size);
 
        /*
         * Update RX statistics.
@@ -586,10 +638,10 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
        for (i = 0; i < sband->n_bitrates; i++) {
                rate = rt2x00_get_rate(sband->bitrates[i].hw_value);
 
-               if (((rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) &&
-                    (rate->plcp == rxdesc->signal)) ||
-                   (!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) &&
-                     (rate->bitrate == rxdesc->signal))) {
+               if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
+                    (rate->plcp == rxdesc.signal)) ||
+                   (!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
+                     (rate->bitrate == rxdesc.signal))) {
                        idx = i;
                        break;
                }
@@ -597,8 +649,8 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
 
        if (idx < 0) {
                WARNING(rt2x00dev, "Frame received with unrecognized signal,"
-                       "signal=0x%.2x, plcp=%d.\n", rxdesc->signal,
-                       !!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP));
+                       "signal=0x%.2x, plcp=%d.\n", rxdesc.signal,
+                       !!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP));
                idx = 0;
        }
 
@@ -606,17 +658,17 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
         * Only update link status if this is a beacon frame carrying our bssid.
         */
        hdr = (struct ieee80211_hdr *)entry->skb->data;
-       fc = le16_to_cpu(hdr->frame_control);
-       if (is_beacon(fc) && (rxdesc->dev_flags & RXDONE_MY_BSS))
-               rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc->rssi);
+       if (ieee80211_is_beacon(hdr->frame_control) &&
+           (rxdesc.dev_flags & RXDONE_MY_BSS))
+               rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi);
 
        rt2x00dev->link.qual.rx_success++;
 
        rx_status->rate_idx = idx;
        rx_status->qual =
-           rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi);
-       rx_status->signal = rxdesc->rssi;
-       rx_status->flag = rxdesc->flags;
+           rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc.rssi);
+       rx_status->signal = rxdesc.rssi;
+       rx_status->flag = rxdesc.flags;
        rx_status->antenna = rt2x00dev->link.ant.active.rx;
 
        /*
@@ -625,7 +677,16 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
         */
        rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
        ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
-       entry->skb = NULL;
+
+       /*
+        * Replace the skb with the freshly allocated one.
+        */
+       entry->skb = skb;
+       entry->flags = 0;
+
+       rt2x00dev->ops->lib->init_rxentry(rt2x00dev, entry);
+
+       rt2x00queue_index_inc(entry->queue, Q_INDEX);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
 
@@ -1003,6 +1064,10 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
        /*
         * Initialize configuration work.
         */
+       rt2x00dev->workqueue = create_singlethread_workqueue("rt2x00lib");
+       if (!rt2x00dev->workqueue)
+               goto exit;
+
        INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
        INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
        INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
@@ -1062,6 +1127,13 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
        rt2x00rfkill_free(rt2x00dev);
        rt2x00leds_unregister(rt2x00dev);
 
+       /*
+        * Stop all queued work. Note that most tasks will already be halted
+        * during rt2x00lib_disable_radio() and rt2x00lib_uninitialize().
+        */
+       flush_workqueue(rt2x00dev->workqueue);
+       destroy_workqueue(rt2x00dev->workqueue);
+
        /*
         * Free ieee80211_hw memory.
         */
index 558f45bf27e33684825705d8dfd8489be80c9b25..1d1f0749375ed6e9698fcd2a5d57e4455a91e845 100644 (file)
@@ -98,10 +98,57 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
                      struct ieee80211_conf *conf, const int force_config);
 
-/*
- * Queue handlers.
+/**
+ * DOC: Queue handlers
+ */
+
+/**
+ * rt2x00queue_alloc_rxskb - allocate a skb for RX purposes.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @queue: The queue for which the skb will be applicable.
+ */
+struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
+                                       struct queue_entry *entry);
+
+/**
+ * rt2x00queue_unmap_skb - Unmap a skb from DMA.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to unmap.
+ */
+void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+
+/**
+ * rt2x00queue_free_skb - free a skb
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to free.
+ */
+void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+
+/**
+ * rt2x00queue_free_skb - free a skb
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to free.
+ */
+void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+
+/**
+ * rt2x00queue_write_tx_frame - Write TX frame to hardware
+ * @queue: Queue over which the frame should be send
+ * @skb: The skb to send
  */
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb);
+
+/**
+ * rt2x00queue_index_inc - Index incrementation function
+ * @queue: Queue (&struct data_queue) to perform the action on.
+ * @index: Index type (&enum queue_index) to perform the action on.
+ *
+ * This function will increase the requested index on the queue,
+ * it will grab the appropriate locks and handle queue overflow events by
+ * resetting the index to the start of the queue.
+ */
+void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
+
 void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev);
 void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev);
 int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);
index c90992f613fe1c54de36b9b8fce42e58baa3187b..1253da89295b71e49a60b2f29a88dd3e380a4d28 100644 (file)
@@ -431,7 +431,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
        if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
                rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
        else
-               queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+               queue_work(rt2x00dev->workqueue, &rt2x00dev->filter_work);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
 
@@ -512,7 +512,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
        memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
        if (delayed) {
                intf->delayed_flags |= delayed;
-               queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+               queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
        }
        spin_unlock(&intf->lock);
 }
index 8d6ad18d3890fd17ab6e70868aa276c178dd864a..adf2876ed8ab77de00d5c3676b781d4c62edeabf 100644 (file)
@@ -60,12 +60,8 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry)
         * Fill in skb descriptor
         */
        skbdesc = get_skb_frame_desc(entry->skb);
-       memset(skbdesc, 0, sizeof(*skbdesc));
        skbdesc->desc = entry_priv->desc;
        skbdesc->desc_len = entry->queue->desc_size;
-       skbdesc->entry = entry;
-
-       memcpy(entry_priv->data, entry->skb->data, entry->skb->len);
 
        return 0;
 }
@@ -80,7 +76,6 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
        struct queue_entry *entry;
        struct queue_entry_priv_pci *entry_priv;
        struct skb_frame_desc *skbdesc;
-       struct rxdone_entry_desc rxdesc;
        u32 word;
 
        while (1) {
@@ -91,110 +86,27 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
                if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
                        break;
 
-               memset(&rxdesc, 0, sizeof(rxdesc));
-               rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
-
                /*
-                * Allocate the sk_buffer and copy all data into it.
-                */
-               entry->skb = rt2x00queue_alloc_rxskb(queue);
-               if (!entry->skb)
-                       return;
-
-               memcpy(entry->skb->data, entry_priv->data, rxdesc.size);
-               skb_trim(entry->skb, rxdesc.size);
-
-               /*
-                * Fill in skb descriptor
+                * Fill in desc fields of the skb descriptor
                 */
                skbdesc = get_skb_frame_desc(entry->skb);
-               memset(skbdesc, 0, sizeof(*skbdesc));
                skbdesc->desc = entry_priv->desc;
-               skbdesc->desc_len = queue->desc_size;
-               skbdesc->entry = entry;
+               skbdesc->desc_len = entry->queue->desc_size;
 
                /*
                 * Send the frame to rt2x00lib for further processing.
                 */
-               rt2x00lib_rxdone(entry, &rxdesc);
-
-               if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) {
-                       rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
-                       rt2x00_desc_write(entry_priv->desc, 0, word);
-               }
-
-               rt2x00queue_index_inc(queue, Q_INDEX);
+               rt2x00lib_rxdone(rt2x00dev, entry);
        }
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
 
-void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
-                     struct txdone_entry_desc *txdesc)
-{
-       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
-       enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
-       u32 word;
-
-       rt2x00lib_txdone(entry, txdesc);
-
-       /*
-        * Make this entry available for reuse.
-        */
-       entry->flags = 0;
-
-       rt2x00_desc_read(entry_priv->desc, 0, &word);
-       rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0);
-       rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0);
-       rt2x00_desc_write(entry_priv->desc, 0, word);
-
-       __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-       rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
-
-       /*
-        * If the data queue was below the threshold before the txdone
-        * handler we must make sure the packet queue in the mac80211 stack
-        * is reenabled when the txdone handler has finished.
-        */
-       if (!rt2x00queue_threshold(entry->queue))
-               ieee80211_wake_queue(rt2x00dev->hw, qid);
-
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
-
 /*
  * Device initialization handlers.
  */
-#define desc_size(__queue)                     \
-({                                             \
-        ((__queue)->limit * (__queue)->desc_size);\
-})
-
-#define data_size(__queue)                     \
-({                                             \
-        ((__queue)->limit * (__queue)->data_size);\
-})
-
-#define dma_size(__queue)                      \
-({                                             \
-       data_size(__queue) + desc_size(__queue);\
-})
-
-#define desc_offset(__queue, __base, __i)      \
-({                                             \
-       (__base) + data_size(__queue) +         \
-           ((__i) * (__queue)->desc_size);     \
-})
-
-#define data_offset(__queue, __base, __i)      \
-({                                             \
-       (__base) +                              \
-           ((__i) * (__queue)->data_size);     \
-})
-
 static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
                                     struct data_queue *queue)
 {
-       struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
        struct queue_entry_priv_pci *entry_priv;
        void *addr;
        dma_addr_t dma;
@@ -203,21 +115,21 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
        /*
         * Allocate DMA memory for descriptor and buffer.
         */
-       addr = pci_alloc_consistent(pci_dev, dma_size(queue), &dma);
+       addr = dma_alloc_coherent(rt2x00dev->dev,
+                                 queue->limit * queue->desc_size,
+                                 &dma, GFP_KERNEL | GFP_DMA);
        if (!addr)
                return -ENOMEM;
 
-       memset(addr, 0, dma_size(queue));
+       memset(addr, 0, queue->limit * queue->desc_size);
 
        /*
         * Initialize all queue entries to contain valid addresses.
         */
        for (i = 0; i < queue->limit; i++) {
                entry_priv = queue->entries[i].priv_data;
-               entry_priv->desc = desc_offset(queue, addr, i);
-               entry_priv->desc_dma = desc_offset(queue, dma, i);
-               entry_priv->data = data_offset(queue, addr, i);
-               entry_priv->data_dma = data_offset(queue, dma, i);
+               entry_priv->desc = addr + i * queue->desc_size;
+               entry_priv->desc_dma = dma + i * queue->desc_size;
        }
 
        return 0;
@@ -226,19 +138,19 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
 static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
                                     struct data_queue *queue)
 {
-       struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
        struct queue_entry_priv_pci *entry_priv =
            queue->entries[0].priv_data;
 
-       if (entry_priv->data)
-               pci_free_consistent(pci_dev, dma_size(queue),
-                                   entry_priv->data, entry_priv->data_dma);
-       entry_priv->data = NULL;
+       if (entry_priv->desc)
+               dma_free_coherent(rt2x00dev->dev,
+                                 queue->limit * queue->desc_size,
+                                 entry_priv->desc, entry_priv->desc_dma);
+       entry_priv->desc = NULL;
 }
 
 int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
 {
-       struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+       struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
        struct data_queue *queue;
        int status;
 
@@ -279,7 +191,7 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
        /*
         * Free irq line.
         */
-       free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev);
+       free_irq(to_pci_dev(rt2x00dev->dev)->irq, rt2x00dev);
 
        /*
         * Free DMA
@@ -308,7 +220,7 @@ static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
 
 static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
 {
-       struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+       struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
 
        rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0),
                                      pci_resource_len(pci_dev, 0));
@@ -357,7 +269,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
        if (pci_set_mwi(pci_dev))
                ERROR_PROBE("MWI not available.\n");
 
-       if (pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
+       if (dma_set_mask(&pci_dev->dev, DMA_32BIT_MASK)) {
                ERROR_PROBE("PCI DMA not supported.\n");
                retval = -EIO;
                goto exit_disable_device;
@@ -373,7 +285,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
        pci_set_drvdata(pci_dev, hw);
 
        rt2x00dev = hw->priv;
-       rt2x00dev->dev = pci_dev;
+       rt2x00dev->dev = &pci_dev->dev;
        rt2x00dev->ops = ops;
        rt2x00dev->hw = hw;
 
index 87c4a0cd78db13c6e835d5ec2a23ef9cfcb7f47a..50c6df4f81db639ce67847e2bd2484d4362d1d8e 100644 (file)
@@ -107,9 +107,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry);
 struct queue_entry_priv_pci {
        __le32 *desc;
        dma_addr_t desc_dma;
-
-       void *data;
-       dma_addr_t data_dma;
 };
 
 /**
@@ -118,15 +115,6 @@ struct queue_entry_priv_pci {
  */
 void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
 
-/**
- * rt2x00pci_txdone - Handle TX done events
- * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
- * @entry: Entry which has completed the transmission of a frame.
- * @desc: TX done descriptor
- */
-void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
-                     struct txdone_entry_desc *desc);
-
 /*
  * Device initialization handlers.
  */
index 7b52039b01a60ab1823afb4f173de7434c2da380..8e86611791f03181a6cb659c44a82dc32677b523 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/dma-mapping.h>
 
 #include "rt2x00.h"
 #include "rt2x00lib.h"
 
-struct sk_buff *rt2x00queue_alloc_rxskb(struct data_queue *queue)
+struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
+                                       struct queue_entry *entry)
 {
-       struct sk_buff *skb;
        unsigned int frame_size;
        unsigned int reserved_size;
+       struct sk_buff *skb;
+       struct skb_frame_desc *skbdesc;
 
        /*
         * The frame size includes descriptor size, because the
         * hardware directly receive the frame into the skbuffer.
         */
-       frame_size = queue->data_size + queue->desc_size;
+       frame_size = entry->queue->data_size + entry->queue->desc_size;
 
        /*
-        * For the allocation we should keep a few things in mind:
-        * 1) 4byte alignment of 802.11 payload
-        *
-        * For (1) we need at most 4 bytes to guarentee the correct
-        * alignment. We are going to optimize the fact that the chance
-        * that the 802.11 header_size % 4 == 2 is much bigger then
-        * anything else. However since we need to move the frame up
-        * to 3 bytes to the front, which means we need to preallocate
-        * 6 bytes.
+        * Reserve a few bytes extra headroom to allow drivers some moving
+        * space (e.g. for alignment), while keeping the skb aligned.
         */
-       reserved_size = 6;
+       reserved_size = 8;
 
        /*
         * Allocate skbuffer.
@@ -64,9 +60,56 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct data_queue *queue)
        skb_reserve(skb, reserved_size);
        skb_put(skb, frame_size);
 
+       /*
+        * Populate skbdesc.
+        */
+       skbdesc = get_skb_frame_desc(skb);
+       memset(skbdesc, 0, sizeof(*skbdesc));
+       skbdesc->entry = entry;
+
+       if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) {
+               skbdesc->skb_dma = dma_map_single(rt2x00dev->dev,
+                                                 skb->data,
+                                                 skb->len,
+                                                 DMA_FROM_DEVICE);
+               skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
+       }
+
        return skb;
 }
-EXPORT_SYMBOL_GPL(rt2x00queue_alloc_rxskb);
+
+void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
+{
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+
+       skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len,
+                                         DMA_TO_DEVICE);
+       skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
+
+void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
+{
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+
+       if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) {
+               dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
+                                DMA_FROM_DEVICE);
+               skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX;
+       }
+
+       if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
+               dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
+                                DMA_TO_DEVICE);
+               skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
+       }
+}
+
+void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
+{
+       rt2x00queue_unmap_skb(rt2x00dev, skb);
+       dev_kfree_skb_any(skb);
+}
 
 void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
                                      struct txentry_desc *txdesc)
@@ -80,7 +123,6 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
        unsigned int data_length;
        unsigned int duration;
        unsigned int residual;
-       u16 frame_control;
 
        memset(txdesc, 0, sizeof(*txdesc));
 
@@ -95,11 +137,6 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
        /* Data length should be extended with 4 bytes for CRC */
        data_length = entry->skb->len + 4;
 
-       /*
-        * Read required fields from ieee80211 header.
-        */
-       frame_control = le16_to_cpu(hdr->frame_control);
-
        /*
         * Check whether this frame is to be acked.
         */
@@ -109,9 +146,10 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
        /*
         * Check if this is a RTS/CTS frame
         */
-       if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
+       if (ieee80211_is_rts(hdr->frame_control) ||
+           ieee80211_is_cts(hdr->frame_control)) {
                __set_bit(ENTRY_TXD_BURST, &txdesc->flags);
-               if (is_rts_frame(frame_control))
+               if (ieee80211_is_rts(hdr->frame_control))
                        __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags);
                else
                        __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags);
@@ -139,7 +177,8 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
         * Beacons and probe responses require the tsf timestamp
         * to be inserted into the frame.
         */
-       if (txdesc->queue == QID_BEACON || is_probe_resp(frame_control))
+       if (ieee80211_is_beacon(hdr->frame_control) ||
+           ieee80211_is_probe_resp(hdr->frame_control))
                __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
 
        /*
@@ -236,6 +275,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
 {
        struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
        struct txentry_desc txdesc;
+       struct skb_frame_desc *skbdesc;
 
        if (unlikely(rt2x00queue_full(queue)))
                return -EINVAL;
@@ -256,11 +296,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
        entry->skb = skb;
        rt2x00queue_create_tx_descriptor(entry, &txdesc);
 
+       /*
+        * skb->cb array is now ours and we are free to use it.
+        */
+       skbdesc = get_skb_frame_desc(entry->skb);
+       memset(skbdesc, 0, sizeof(*skbdesc));
+       skbdesc->entry = entry;
+
        if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
                __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
                return -EIO;
        }
 
+       if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
+               rt2x00queue_map_txskb(queue->rt2x00dev, skb);
+
        __set_bit(ENTRY_DATA_PENDING, &entry->flags);
 
        rt2x00queue_index_inc(queue, Q_INDEX);
@@ -336,7 +386,6 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
 
        spin_unlock_irqrestore(&queue->lock, irqflags);
 }
-EXPORT_SYMBOL_GPL(rt2x00queue_index_inc);
 
 static void rt2x00queue_reset(struct data_queue *queue)
 {
@@ -426,12 +475,41 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
        return 0;
 }
 
+static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev,
+                                 struct data_queue *queue)
+{
+       unsigned int i;
+
+       if (!queue->entries)
+               return;
+
+       for (i = 0; i < queue->limit; i++) {
+               if (queue->entries[i].skb)
+                       rt2x00queue_free_skb(rt2x00dev, queue->entries[i].skb);
+       }
+}
+
+static int rt2x00queue_alloc_rxskbs(struct rt2x00_dev *rt2x00dev,
+                                   struct data_queue *queue)
+{
+       unsigned int i;
+       struct sk_buff *skb;
+
+       for (i = 0; i < queue->limit; i++) {
+               skb = rt2x00queue_alloc_rxskb(rt2x00dev, &queue->entries[i]);
+               if (!skb)
+                       return -ENOMEM;
+               queue->entries[i].skb = skb;
+       }
+
+       return 0;
+}
+
 int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue;
        int status;
 
-
        status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx);
        if (status)
                goto exit;
@@ -446,11 +524,14 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
        if (status)
                goto exit;
 
-       if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
-               return 0;
+       if (test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) {
+               status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1],
+                                                  rt2x00dev->ops->atim);
+               if (status)
+                       goto exit;
+       }
 
-       status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1],
-                                          rt2x00dev->ops->atim);
+       status = rt2x00queue_alloc_rxskbs(rt2x00dev, rt2x00dev->rx);
        if (status)
                goto exit;
 
@@ -468,6 +549,8 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue;
 
+       rt2x00queue_free_skbs(rt2x00dev, rt2x00dev->rx);
+
        queue_for_each(rt2x00dev, queue) {
                kfree(queue->entries);
                queue->entries = NULL;
index fcf52520b016724070e32021776938a3a2f25168..5dd9cca3c62cf72a3cf0ce48ab9772dfa6f85ef6 100644 (file)
 /**
  * DOC: Number of entries per queue
  *
- * After research it was concluded that 12 entries in a RX and TX
- * queue would be sufficient. Although this is almost one third of
- * the amount the legacy driver allocated, the queues aren't getting
- * filled to the maximum even when working with the maximum rate.
+ * Under normal load without fragmentation 12 entries are sufficient
+ * without the queue being filled up to the maximum. When using fragmentation
+ * and the queue threshold code we need to add some additional margins to
+ * make sure the queue will never (or only under extreme load) fill up
+ * completely.
+ * Since we don't use preallocated DMA having a large number of queue entries
+ * will have only minimal impact on the memory requirements for the queue.
  */
-#define RX_ENTRIES     12
-#define TX_ENTRIES     12
+#define RX_ENTRIES     24
+#define TX_ENTRIES     24
 #define BEACON_ENTRIES 1
-#define ATIM_ENTRIES   1
+#define ATIM_ENTRIES   8
 
 /**
  * enum data_queue_qid: Queue identification
@@ -82,10 +85,13 @@ enum data_queue_qid {
 /**
  * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc
  *
+ * @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX
+ * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX
  */
-//enum skb_frame_desc_flags {
-//     TEMPORARILY EMPTY
-//};
+enum skb_frame_desc_flags {
+       SKBDESC_DMA_MAPPED_RX = (1 << 0),
+       SKBDESC_DMA_MAPPED_TX = (1 << 1),
+};
 
 /**
  * struct skb_frame_desc: Descriptor information for the skb buffer
@@ -94,19 +100,20 @@ enum data_queue_qid {
  * this structure should not exceed the size of that array (40 bytes).
  *
  * @flags: Frame flags, see &enum skb_frame_desc_flags.
- * @data: Pointer to data part of frame (Start of ieee80211 header).
+ * @desc_len: Length of the frame descriptor.
  * @desc: Pointer to descriptor part of the frame.
  *     Note that this pointer could point to something outside
  *     of the scope of the skb->data pointer.
- * @data_len: Length of the frame data.
- * @desc_len: Length of the frame descriptor.
+ * @skb_dma: (PCI-only) the DMA address associated with the sk buffer.
  * @entry: The entry to which this sk buffer belongs.
  */
 struct skb_frame_desc {
        unsigned int flags;
 
-       void *desc;
        unsigned int desc_len;
+       void *desc;
+
+       dma_addr_t skb_dma;
 
        struct queue_entry *entry;
 };
index fcef9885ab5eaf1c4c841184517dbf0b45b0f158..207281cfa8b7167faabe1412ce5abe04e2fbdef5 100644 (file)
@@ -45,14 +45,17 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
        if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
                return 0;
 
-       if (state == RFKILL_STATE_ON) {
+       if (state == RFKILL_STATE_UNBLOCKED) {
                INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
                __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
                retval = rt2x00lib_enable_radio(rt2x00dev);
-       } else if (state == RFKILL_STATE_OFF) {
+       } else if (state == RFKILL_STATE_SOFT_BLOCKED) {
                INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n");
                __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
                rt2x00lib_disable_radio(rt2x00dev);
+       } else {
+               WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n",
+                       state);
        }
 
        return retval;
index 3080969ae5b313933431124f2b0a8e100eb3908a..83862e7f7aec1f03b4de6ea221f1d90491e30277 100644 (file)
@@ -40,7 +40,7 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
                             void *buffer, const u16 buffer_length,
                             const int timeout)
 {
-       struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
+       struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        int status;
        unsigned int i;
        unsigned int pipe =
@@ -130,10 +130,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
        struct queue_entry *entry = (struct queue_entry *)urb->context;
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct txdone_entry_desc txdesc;
-       enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
 
        if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
-           !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+           !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
                return;
 
        /*
@@ -157,26 +156,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
        txdesc.retry = 0;
 
        rt2x00lib_txdone(entry, &txdesc);
-
-       /*
-        * Make this entry available for reuse.
-        */
-       entry->flags = 0;
-       rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
-
-       /*
-        * If the data queue was below the threshold before the txdone
-        * handler we must make sure the packet queue in the mac80211 stack
-        * is reenabled when the txdone handler has finished.
-        */
-       if (!rt2x00queue_threshold(entry->queue))
-               ieee80211_wake_queue(rt2x00dev->hw, qid);
 }
 
 int rt2x00usb_write_tx_data(struct queue_entry *entry)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
+       struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
        struct skb_frame_desc *skbdesc;
        u32 length;
@@ -191,10 +176,8 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
         * Fill in skb descriptor
         */
        skbdesc = get_skb_frame_desc(entry->skb);
-       memset(skbdesc, 0, sizeof(*skbdesc));
        skbdesc->desc = entry->skb->data;
        skbdesc->desc_len = entry->queue->desc_size;
-       skbdesc->entry = entry;
 
        /*
         * USB devices cannot blindly pass the skb->len as the
@@ -264,13 +247,11 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
 {
        struct queue_entry *entry = (struct queue_entry *)urb->context;
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct sk_buff *skb;
-       struct skb_frame_desc *skbdesc;
-       struct rxdone_entry_desc rxdesc;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        u8 rxd[32];
 
        if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
-           !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+           !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
                return;
 
        /*
@@ -278,50 +259,22 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
         * to be actually valid, or if the urb is signaling
         * a problem.
         */
-       if (urb->actual_length < entry->queue->desc_size || urb->status)
-               goto skip_entry;
+       if (urb->actual_length < entry->queue->desc_size || urb->status) {
+               __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+               usb_submit_urb(urb, GFP_ATOMIC);
+               return;
+       }
 
        /*
-        * Fill in skb descriptor
+        * Fill in desc fields of the skb descriptor
         */
-       skbdesc = get_skb_frame_desc(entry->skb);
-       memset(skbdesc, 0, sizeof(*skbdesc));
-       skbdesc->entry = entry;
        skbdesc->desc = rxd;
        skbdesc->desc_len = entry->queue->desc_size;
 
-       memset(&rxdesc, 0, sizeof(rxdesc));
-       rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
-
-       /*
-        * Allocate a new sk buffer to replace the current one.
-        * If allocation fails, we should drop the current frame
-        * so we can recycle the existing sk buffer for the new frame.
-        */
-       skb = rt2x00queue_alloc_rxskb(entry->queue);
-       if (!skb)
-               goto skip_entry;
-
        /*
         * Send the frame to rt2x00lib for further processing.
         */
-       rt2x00lib_rxdone(entry, &rxdesc);
-
-       /*
-        * Replace current entry's skb with the newly allocated one,
-        * and reinitialize the urb.
-        */
-       entry->skb = skb;
-       urb->transfer_buffer = entry->skb->data;
-       urb->transfer_buffer_length = entry->skb->len;
-
-skip_entry:
-       if (test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) {
-               __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-               usb_submit_urb(urb, GFP_ATOMIC);
-       }
-
-       rt2x00queue_index_inc(entry->queue, Q_INDEX);
+       rt2x00lib_rxdone(rt2x00dev, entry);
 }
 
 /*
@@ -331,6 +284,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
        struct queue_entry_priv_usb *entry_priv;
        struct queue_entry_priv_usb_bcn *bcn_priv;
+       struct data_queue *queue;
        unsigned int i;
 
        rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
@@ -339,9 +293,11 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
        /*
         * Cancel all queues.
         */
-       for (i = 0; i < rt2x00dev->rx->limit; i++) {
-               entry_priv = rt2x00dev->rx->entries[i].priv_data;
-               usb_kill_urb(entry_priv->urb);
+       queue_for_each(rt2x00dev, queue) {
+               for (i = 0; i < queue->limit; i++) {
+                       entry_priv = queue->entries[i].priv_data;
+                       usb_kill_urb(entry_priv->urb);
+               }
        }
 
        /*
@@ -364,7 +320,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
 void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
                            struct queue_entry *entry)
 {
-       struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
+       struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
 
        usb_fill_bulk_urb(entry_priv->urb, usb_dev,
@@ -431,8 +387,6 @@ static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
                entry_priv = queue->entries[i].priv_data;
                usb_kill_urb(entry_priv->urb);
                usb_free_urb(entry_priv->urb);
-               if (queue->entries[i].skb)
-                       kfree_skb(queue->entries[i].skb);
        }
 
        /*
@@ -454,10 +408,7 @@ static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
 int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue;
-       struct sk_buff *skb;
-       unsigned int entry_size;
-       unsigned int i;
-       int uninitialized_var(status);
+       int status;
 
        /*
         * Allocate DMA
@@ -468,18 +419,6 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
                        goto exit;
        }
 
-       /*
-        * For the RX queue, skb's should be allocated.
-        */
-       entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size;
-       for (i = 0; i < rt2x00dev->rx->limit; i++) {
-               skb = rt2x00queue_alloc_rxskb(rt2x00dev->rx);
-               if (!skb)
-                       goto exit;
-
-               rt2x00dev->rx->entries[i].skb = skb;
-       }
-
        return 0;
 
 exit:
@@ -558,7 +497,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
        usb_set_intfdata(usb_intf, hw);
 
        rt2x00dev = hw->priv;
-       rt2x00dev->dev = usb_intf;
+       rt2x00dev->dev = &usb_intf->dev;
        rt2x00dev->ops = ops;
        rt2x00dev->hw = hw;
        mutex_init(&rt2x00dev->usb_cache_mutex);
index b1187c812e7f9d145a9ad12626cedf4b075b2274..aad794adf52cc87632df22fe3c011f89391d6da8 100644 (file)
 #ifndef RT2X00USB_H
 #define RT2X00USB_H
 
+#define to_usb_device_intf(d) \
+({ \
+       struct usb_interface *intf = to_usb_interface(d); \
+       interface_to_usbdev(intf); \
+})
+
 /*
  * This variable should be used with the
  * usb_driver structure initialization.
index 5b7267ece1b9f94302eb5ea5933c16d5326ec941..bbf1048f6400e89b18da2c8b74d202a13b0c0e2f 100644 (file)
@@ -1030,11 +1030,12 @@ static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
                                 struct queue_entry *entry)
 {
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        u32 word;
 
        rt2x00_desc_read(entry_priv->desc, 5, &word);
        rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
-                          entry_priv->data_dma);
+                          skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 5, word);
 
        rt2x00_desc_read(entry_priv->desc, 0, &word);
@@ -1522,7 +1523,6 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
        __le32 *txd = skbdesc->desc;
        u32 word;
 
@@ -1557,7 +1557,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 
        rt2x00_desc_read(txd, 6, &word);
        rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
-                          entry_priv->data_dma);
+                          skbdesc->skb_dma);
        rt2x00_desc_write(txd, 6, word);
 
        if (skbdesc->desc_len > TXINFO_SIZE) {
@@ -1767,7 +1767,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                        __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
                        txdesc.retry = 0;
 
-                       rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc);
+                       rt2x00lib_txdone(entry_done, &txdesc);
                        entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
                }
 
@@ -1787,7 +1787,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                }
                txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
 
-               rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
+               rt2x00lib_txdone(entry, &txdesc);
        }
 }
 
@@ -1973,7 +1973,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
         * To determine the RT chip we have to read the
         * PCI header of the device.
         */
-       pci_read_config_word(rt2x00dev_pci(rt2x00dev),
+       pci_read_config_word(to_pci_dev(rt2x00dev->dev),
                             PCI_CONFIG_HEADER_DEVICE, &device);
        value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
        rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
@@ -2239,7 +2239,7 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
            IEEE80211_HW_SIGNAL_DBM;
        rt2x00dev->hw->extra_tx_headroom = 0;
 
-       SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+       SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
                                rt2x00_eeprom_addr(rt2x00dev,
                                                   EEPROM_MAC_ADDR_0));
@@ -2302,9 +2302,10 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        rt61pci_probe_hw_mode(rt2x00dev);
 
        /*
-        * This device requires firmware.
+        * This device requires firmware and DMA mapped skbs.
         */
        __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+       __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 
        /*
         * Set the rssi offset.
@@ -2402,6 +2403,12 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
                                      skb->data, skb->len);
        rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON);
 
+       /*
+        * Clean up beacon skb.
+        */
+       dev_kfree_skb_any(skb);
+       intf->beacon->skb = NULL;
+
        return 0;
 }
 
index fceefd730ab8e5ac796f81cdba50cd11ba748f81..3ef318e098e7a372895723b2c969a4493bbbf895 100644 (file)
@@ -134,11 +134,8 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
         * Wait until the BBP becomes ready.
         */
        reg = rt73usb_bbp_check(rt2x00dev);
-       if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-               ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
-               mutex_unlock(&rt2x00dev->usb_cache_mutex);
-               return;
-       }
+       if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+               goto exit_fail;
 
        /*
         * Write the data into the BBP.
@@ -151,6 +148,13 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 
        rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
        mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+       return;
+
+exit_fail:
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+       ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
 }
 
 static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -164,11 +168,8 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
         * Wait until the BBP becomes ready.
         */
        reg = rt73usb_bbp_check(rt2x00dev);
-       if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-               ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-               mutex_unlock(&rt2x00dev->usb_cache_mutex);
-               return;
-       }
+       if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+               goto exit_fail;
 
        /*
         * Write the request into the BBP.
@@ -184,14 +185,19 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
         * Wait until the BBP becomes ready.
         */
        reg = rt73usb_bbp_check(rt2x00dev);
-       if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-               ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-               *value = 0xff;
-               return;
-       }
+       if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+               goto exit_fail;
 
        *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
        mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+       return;
+
+exit_fail:
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+       ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+       *value = 0xff;
 }
 
 static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
@@ -1821,7 +1827,7 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
            IEEE80211_HW_SIGNAL_DBM;
        rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
 
-       SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+       SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
                                rt2x00_eeprom_addr(rt2x00dev,
                                                   EEPROM_MAC_ADDR_0));
@@ -2001,6 +2007,12 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
                                 REGISTER_TIMEOUT32(skb->len));
        rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON);
 
+       /*
+        * Clean up the beacon skb.
+        */
+       dev_kfree_skb(skb);
+       intf->beacon->skb = NULL;
+
        return 0;
 }
 
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
deleted file mode 100644 (file)
index 883af89..0000000
+++ /dev/null
@@ -1,2804 +0,0 @@
-/*
- * Copyright 1996 The Board of Trustees of The Leland Stanford
- * Junior University. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies.  Stanford University
- * makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without
- * express or implied warranty.
- *
- * strip.c     This module implements Starmode Radio IP (STRIP)
- *             for kernel-based devices like TTY.  It interfaces between a
- *             raw TTY, and the kernel's INET protocol layers (via DDI).
- *
- * Version:    @(#)strip.c     1.3     July 1997
- *
- * Author:     Stuart Cheshire <cheshire@cs.stanford.edu>
- *
- * Fixes:      v0.9 12th Feb 1996 (SC)
- *             New byte stuffing (2+6 run-length encoding)
- *             New watchdog timer task
- *             New Protocol key (SIP0)
- *             
- *             v0.9.1 3rd March 1996 (SC)
- *             Changed to dynamic device allocation -- no more compile
- *             time (or boot time) limit on the number of STRIP devices.
- *             
- *             v0.9.2 13th March 1996 (SC)
- *             Uses arp cache lookups (but doesn't send arp packets yet)
- *             
- *             v0.9.3 17th April 1996 (SC)
- *             Fixed bug where STR_ERROR flag was getting set unneccessarily
- *             (causing otherwise good packets to be unneccessarily dropped)
- *             
- *             v0.9.4 27th April 1996 (SC)
- *             First attempt at using "&COMMAND" Starmode AT commands
- *             
- *             v0.9.5 29th May 1996 (SC)
- *             First attempt at sending (unicast) ARP packets
- *             
- *             v0.9.6 5th June 1996 (Elliot)
- *             Put "message level" tags in every "printk" statement
- *             
- *             v0.9.7 13th June 1996 (laik)
- *             Added support for the /proc fs
- *
- *              v0.9.8 July 1996 (Mema)
- *              Added packet logging
- *
- *              v1.0 November 1996 (SC)
- *              Fixed (severe) memory leaks in the /proc fs code
- *              Fixed race conditions in the logging code
- *
- *              v1.1 January 1997 (SC)
- *              Deleted packet logging (use tcpdump instead)
- *              Added support for Metricom Firmware v204 features
- *              (like message checksums)
- *
- *              v1.2 January 1997 (SC)
- *              Put portables list back in
- *
- *              v1.3 July 1997 (SC)
- *              Made STRIP driver set the radio's baud rate automatically.
- *              It is no longer necessarily to manually set the radio's
- *              rate permanently to 115200 -- the driver handles setting
- *              the rate automatically.
- */
-
-#ifdef MODULE
-static const char StripVersion[] = "1.3A-STUART.CHESHIRE-MODULAR";
-#else
-static const char StripVersion[] = "1.3A-STUART.CHESHIRE";
-#endif
-
-#define TICKLE_TIMERS 0
-#define EXT_COUNTERS 1
-
-
-/************************************************************************/
-/* Header files                                                                */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-# include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/if_strip.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/rcupdate.h>
-#include <net/arp.h>
-#include <net/net_namespace.h>
-
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/time.h>
-#include <linux/jiffies.h>
-
-/************************************************************************/
-/* Useful structures and definitions                                   */
-
-/*
- * A MetricomKey identifies the protocol being carried inside a Metricom
- * Starmode packet.
- */
-
-typedef union {
-       __u8 c[4];
-       __u32 l;
-} MetricomKey;
-
-/*
- * An IP address can be viewed as four bytes in memory (which is what it is) or as
- * a single 32-bit long (which is convenient for assignment, equality testing etc.)
- */
-
-typedef union {
-       __u8 b[4];
-       __u32 l;
-} IPaddr;
-
-/*
- * A MetricomAddressString is used to hold a printable representation of
- * a Metricom address.
- */
-
-typedef struct {
-       __u8 c[24];
-} MetricomAddressString;
-
-/* Encapsulation can expand packet of size x to 65/64x + 1
- * Sent packet looks like "<CR>*<address>*<key><encaps payload><CR>"
- *                           1 1   1-18  1  4         ?         1
- * eg.                     <CR>*0000-1234*SIP0<encaps payload><CR>
- * We allow 31 bytes for the stars, the key, the address and the <CR>s
- */
-#define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L)
-
-/*
- * A STRIP_Header is never really sent over the radio, but making a dummy
- * header for internal use within the kernel that looks like an Ethernet
- * header makes certain other software happier. For example, tcpdump
- * already understands Ethernet headers.
- */
-
-typedef struct {
-       MetricomAddress dst_addr;       /* Destination address, e.g. "0000-1234"   */
-       MetricomAddress src_addr;       /* Source address, e.g. "0000-5678"        */
-       unsigned short protocol;        /* The protocol type, using Ethernet codes */
-} STRIP_Header;
-
-typedef struct {
-       char c[60];
-} MetricomNode;
-
-#define NODE_TABLE_SIZE 32
-typedef struct {
-       struct timeval timestamp;
-       int num_nodes;
-       MetricomNode node[NODE_TABLE_SIZE];
-} MetricomNodeTable;
-
-enum { FALSE = 0, TRUE = 1 };
-
-/*
- * Holds the radio's firmware version.
- */
-typedef struct {
-       char c[50];
-} FirmwareVersion;
-
-/*
- * Holds the radio's serial number.
- */
-typedef struct {
-       char c[18];
-} SerialNumber;
-
-/*
- * Holds the radio's battery voltage.
- */
-typedef struct {
-       char c[11];
-} BatteryVoltage;
-
-typedef struct {
-       char c[8];
-} char8;
-
-enum {
-       NoStructure = 0,        /* Really old firmware */
-       StructuredMessages = 1, /* Parsable AT response msgs */
-       ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */
-};
-
-struct strip {
-       int magic;
-       /*
-        * These are pointers to the malloc()ed frame buffers.
-        */
-
-       unsigned char *rx_buff; /* buffer for received IP packet */
-       unsigned char *sx_buff; /* buffer for received serial data */
-       int sx_count;           /* received serial data counter */
-       int sx_size;            /* Serial buffer size           */
-       unsigned char *tx_buff; /* transmitter buffer           */
-       unsigned char *tx_head; /* pointer to next byte to XMIT */
-       int tx_left;            /* bytes left in XMIT queue     */
-       int tx_size;            /* Serial buffer size           */
-
-       /*
-        * STRIP interface statistics.
-        */
-
-       unsigned long rx_packets;       /* inbound frames counter       */
-       unsigned long tx_packets;       /* outbound frames counter      */
-       unsigned long rx_errors;        /* Parity, etc. errors          */
-       unsigned long tx_errors;        /* Planned stuff                */
-       unsigned long rx_dropped;       /* No memory for skb            */
-       unsigned long tx_dropped;       /* When MTU change              */
-       unsigned long rx_over_errors;   /* Frame bigger then STRIP buf. */
-
-       unsigned long pps_timer;        /* Timer to determine pps       */
-       unsigned long rx_pps_count;     /* Counter to determine pps     */
-       unsigned long tx_pps_count;     /* Counter to determine pps     */
-       unsigned long sx_pps_count;     /* Counter to determine pps     */
-       unsigned long rx_average_pps;   /* rx packets per second * 8    */
-       unsigned long tx_average_pps;   /* tx packets per second * 8    */
-       unsigned long sx_average_pps;   /* sent packets per second * 8  */
-
-#ifdef EXT_COUNTERS
-       unsigned long rx_bytes;         /* total received bytes */
-       unsigned long tx_bytes;         /* total received bytes */
-       unsigned long rx_rbytes;        /* bytes thru radio i/f */
-       unsigned long tx_rbytes;        /* bytes thru radio i/f */
-       unsigned long rx_sbytes;        /* tot bytes thru serial i/f */
-       unsigned long tx_sbytes;        /* tot bytes thru serial i/f */
-       unsigned long rx_ebytes;        /* tot stat/err bytes */
-       unsigned long tx_ebytes;        /* tot stat/err bytes */
-#endif
-
-       /*
-        * Internal variables.
-        */
-
-       struct list_head  list;         /* Linked list of devices */
-
-       int discard;                    /* Set if serial error          */
-       int working;                    /* Is radio working correctly?  */
-       int firmware_level;             /* Message structuring level    */
-       int next_command;               /* Next periodic command        */
-       unsigned int user_baud;         /* The user-selected baud rate  */
-       int mtu;                        /* Our mtu (to spot changes!)   */
-       long watchdog_doprobe;          /* Next time to test the radio  */
-       long watchdog_doreset;          /* Time to do next reset        */
-       long gratuitous_arp;            /* Time to send next ARP refresh */
-       long arp_interval;              /* Next ARP interval            */
-       struct timer_list idle_timer;   /* For periodic wakeup calls    */
-       MetricomAddress true_dev_addr;  /* True address of radio        */
-       int manual_dev_addr;            /* Hack: See note below         */
-
-       FirmwareVersion firmware_version;       /* The radio's firmware version */
-       SerialNumber serial_number;     /* The radio's serial number    */
-       BatteryVoltage battery_voltage; /* The radio's battery voltage  */
-
-       /*
-        * Other useful structures.
-        */
-
-       struct tty_struct *tty;         /* ptr to TTY structure         */
-       struct net_device *dev;         /* Our device structure         */
-
-       /*
-        * Neighbour radio records
-        */
-
-       MetricomNodeTable portables;
-       MetricomNodeTable poletops;
-};
-
-/*
- * Note: manual_dev_addr hack
- * 
- * It is not possible to change the hardware address of a Metricom radio,
- * or to send packets with a user-specified hardware source address, thus
- * trying to manually set a hardware source address is a questionable
- * thing to do.  However, if the user *does* manually set the hardware
- * source address of a STRIP interface, then the kernel will believe it,
- * and use it in certain places. For example, the hardware address listed
- * by ifconfig will be the manual address, not the true one.
- * (Both addresses are listed in /proc/net/strip.)
- * Also, ARP packets will be sent out giving the user-specified address as
- * the source address, not the real address. This is dangerous, because
- * it means you won't receive any replies -- the ARP replies will go to
- * the specified address, which will be some other radio. The case where
- * this is useful is when that other radio is also connected to the same
- * machine. This allows you to connect a pair of radios to one machine,
- * and to use one exclusively for inbound traffic, and the other
- * exclusively for outbound traffic. Pretty neat, huh?
- * 
- * Here's the full procedure to set this up:
- * 
- * 1. "slattach" two interfaces, e.g. st0 for outgoing packets,
- *    and st1 for incoming packets
- * 
- * 2. "ifconfig" st0 (outbound radio) to have the hardware address
- *    which is the real hardware address of st1 (inbound radio).
- *    Now when it sends out packets, it will masquerade as st1, and
- *    replies will be sent to that radio, which is exactly what we want.
- * 
- * 3. Set the route table entry ("route add default ..." or
- *    "route add -net ...", as appropriate) to send packets via the st0
- *    interface (outbound radio). Do not add any route which sends packets
- *    out via the st1 interface -- that radio is for inbound traffic only.
- * 
- * 4. "ifconfig" st1 (inbound radio) to have hardware address zero.
- *    This tells the STRIP driver to "shut down" that interface and not
- *    send any packets through it. In particular, it stops sending the
- *    periodic gratuitous ARP packets that a STRIP interface normally sends.
- *    Also, when packets arrive on that interface, it will search the
- *    interface list to see if there is another interface who's manual
- *    hardware address matches its own real address (i.e. st0 in this
- *    example) and if so it will transfer ownership of the skbuff to
- *    that interface, so that it looks to the kernel as if the packet
- *    arrived on that interface. This is necessary because when the
- *    kernel sends an ARP packet on st0, it expects to get a reply on
- *    st0, and if it sees the reply come from st1 then it will ignore
- *    it (to be accurate, it puts the entry in the ARP table, but
- *    labelled in such a way that st0 can't use it).
- * 
- * Thanks to Petros Maniatis for coming up with the idea of splitting
- * inbound and outbound traffic between two interfaces, which turned
- * out to be really easy to implement, even if it is a bit of a hack.
- * 
- * Having set a manual address on an interface, you can restore it
- * to automatic operation (where the address is automatically kept
- * consistent with the real address of the radio) by setting a manual
- * address of all ones, e.g. "ifconfig st0 hw strip FFFFFFFFFFFF"
- * This 'turns off' manual override mode for the device address.
- * 
- * Note: The IEEE 802 headers reported in tcpdump will show the *real*
- * radio addresses the packets were sent and received from, so that you
- * can see what is really going on with packets, and which interfaces
- * they are really going through.
- */
-
-
-/************************************************************************/
-/* Constants                                                           */
-
-/*
- * CommandString1 works on all radios
- * Other CommandStrings are only used with firmware that provides structured responses.
- * 
- * ats319=1 Enables Info message for node additions and deletions
- * ats319=2 Enables Info message for a new best node
- * ats319=4 Enables checksums
- * ats319=8 Enables ACK messages
- */
-
-static const int MaxCommandStringLength = 32;
-static const int CompatibilityCommand = 1;
-
-static const char CommandString0[] = "*&COMMAND*ATS319=7";     /* Turn on checksums & info messages */
-static const char CommandString1[] = "*&COMMAND*ATS305?";      /* Query radio name */
-static const char CommandString2[] = "*&COMMAND*ATS325?";      /* Query battery voltage */
-static const char CommandString3[] = "*&COMMAND*ATS300?";      /* Query version information */
-static const char CommandString4[] = "*&COMMAND*ATS311?";      /* Query poletop list */
-static const char CommandString5[] = "*&COMMAND*AT~LA";                /* Query portables list */
-typedef struct {
-       const char *string;
-       long length;
-} StringDescriptor;
-
-static const StringDescriptor CommandString[] = {
-       {CommandString0, sizeof(CommandString0) - 1},
-       {CommandString1, sizeof(CommandString1) - 1},
-       {CommandString2, sizeof(CommandString2) - 1},
-       {CommandString3, sizeof(CommandString3) - 1},
-       {CommandString4, sizeof(CommandString4) - 1},
-       {CommandString5, sizeof(CommandString5) - 1}
-};
-
-#define GOT_ALL_RADIO_INFO(S)      \
-    ((S)->firmware_version.c[0] && \
-     (S)->battery_voltage.c[0]  && \
-     memcmp(&(S)->true_dev_addr, zero_address.c, sizeof(zero_address)))
-
-static const char hextable[16] = "0123456789ABCDEF";
-
-static const MetricomAddress zero_address;
-static const MetricomAddress broadcast_address =
-    { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} };
-
-static const MetricomKey SIP0Key = { "SIP0" };
-static const MetricomKey ARP0Key = { "ARP0" };
-static const MetricomKey ATR_Key = { "ATR " };
-static const MetricomKey ACK_Key = { "ACK_" };
-static const MetricomKey INF_Key = { "INF_" };
-static const MetricomKey ERR_Key = { "ERR_" };
-
-static const long MaxARPInterval = 60 * HZ;    /* One minute */
-
-/*
- * Maximum Starmode packet length is 1183 bytes. Allowing 4 bytes for
- * protocol key, 4 bytes for checksum, one byte for CR, and 65/64 expansion
- * for STRIP encoding, that translates to a maximum payload MTU of 1155.
- * Note: A standard NFS 1K data packet is a total of 0x480 (1152) bytes
- * long, including IP header, UDP header, and NFS header. Setting the STRIP
- * MTU to 1152 allows us to send default sized NFS packets without fragmentation.
- */
-static const unsigned short MAX_SEND_MTU = 1152;
-static const unsigned short MAX_RECV_MTU = 1500;       /* Hoping for Ethernet sized packets in the future! */
-static const unsigned short DEFAULT_STRIP_MTU = 1152;
-static const int STRIP_MAGIC = 0x5303;
-static const long LongTime = 0x7FFFFFFF;
-
-/************************************************************************/
-/* Global variables                                                    */
-
-static LIST_HEAD(strip_list);
-static DEFINE_SPINLOCK(strip_lock);
-
-/************************************************************************/
-/* Macros                                                              */
-
-/* Returns TRUE if text T begins with prefix P */
-#define has_prefix(T,L,P) (((L) >= sizeof(P)-1) && !strncmp((T), (P), sizeof(P)-1))
-
-/* Returns TRUE if text T of length L is equal to string S */
-#define text_equal(T,L,S) (((L) == sizeof(S)-1) && !strncmp((T), (S), sizeof(S)-1))
-
-#define READHEX(X) ((X)>='0' && (X)<='9' ? (X)-'0' :      \
-                    (X)>='a' && (X)<='f' ? (X)-'a'+10 :   \
-                    (X)>='A' && (X)<='F' ? (X)-'A'+10 : 0 )
-
-#define READHEX16(X) ((__u16)(READHEX(X)))
-
-#define READDEC(X) ((X)>='0' && (X)<='9' ? (X)-'0' : 0)
-
-#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
-
-#define JIFFIE_TO_SEC(X) ((X) / HZ)
-
-
-/************************************************************************/
-/* Utility routines                                                    */
-
-static int arp_query(unsigned char *haddr, u32 paddr,
-                    struct net_device *dev)
-{
-       struct neighbour *neighbor_entry;
-       int ret = 0;
-
-       neighbor_entry = neigh_lookup(&arp_tbl, &paddr, dev);
-
-       if (neighbor_entry != NULL) {
-               neighbor_entry->used = jiffies;
-               if (neighbor_entry->nud_state & NUD_VALID) {
-                       memcpy(haddr, neighbor_entry->ha, dev->addr_len);
-                       ret = 1;
-               }
-               neigh_release(neighbor_entry);
-       }
-       return ret;
-}
-
-static void DumpData(char *msg, struct strip *strip_info, __u8 * ptr,
-                    __u8 * end)
-{
-       static const int MAX_DumpData = 80;
-       __u8 pkt_text[MAX_DumpData], *p = pkt_text;
-
-       *p++ = '\"';
-
-       while (ptr < end && p < &pkt_text[MAX_DumpData - 4]) {
-               if (*ptr == '\\') {
-                       *p++ = '\\';
-                       *p++ = '\\';
-               } else {
-                       if (*ptr >= 32 && *ptr <= 126) {
-                               *p++ = *ptr;
-                       } else {
-                               sprintf(p, "\\%02X", *ptr);
-                               p += 3;
-                       }
-               }
-               ptr++;
-       }
-
-       if (ptr == end)
-               *p++ = '\"';
-       *p++ = 0;
-
-       printk(KERN_INFO "%s: %-13s%s\n", strip_info->dev->name, msg, pkt_text);
-}
-
-
-/************************************************************************/
-/* Byte stuffing/unstuffing routines                                   */
-
-/* Stuffing scheme:
- * 00    Unused (reserved character)
- * 01-3F Run of 2-64 different characters
- * 40-7F Run of 1-64 different characters plus a single zero at the end
- * 80-BF Run of 1-64 of the same character
- * C0-FF Run of 1-64 zeroes (ASCII 0)
- */
-
-typedef enum {
-       Stuff_Diff = 0x00,
-       Stuff_DiffZero = 0x40,
-       Stuff_Same = 0x80,
-       Stuff_Zero = 0xC0,
-       Stuff_NoCode = 0xFF,    /* Special code, meaning no code selected */
-
-       Stuff_CodeMask = 0xC0,
-       Stuff_CountMask = 0x3F,
-       Stuff_MaxCount = 0x3F,
-       Stuff_Magic = 0x0D      /* The value we are eliminating */
-} StuffingCode;
-
-/* StuffData encodes the data starting at "src" for "length" bytes.
- * It writes it to the buffer pointed to by "dst" (which must be at least
- * as long as 1 + 65/64 of the input length). The output may be up to 1.6%
- * larger than the input for pathological input, but will usually be smaller.
- * StuffData returns the new value of the dst pointer as its result.
- * "code_ptr_ptr" points to a "__u8 *" which is used to hold encoding state
- * between calls, allowing an encoded packet to be incrementally built up
- * from small parts. On the first call, the "__u8 *" pointed to should be
- * initialized to NULL; between subsequent calls the calling routine should
- * leave the value alone and simply pass it back unchanged so that the
- * encoder can recover its current state.
- */
-
-#define StuffData_FinishBlock(X) \
-(*code_ptr = (X) ^ Stuff_Magic, code = Stuff_NoCode)
-
-static __u8 *StuffData(__u8 * src, __u32 length, __u8 * dst,
-                      __u8 ** code_ptr_ptr)
-{
-       __u8 *end = src + length;
-       __u8 *code_ptr = *code_ptr_ptr;
-       __u8 code = Stuff_NoCode, count = 0;
-
-       if (!length)
-               return (dst);
-
-       if (code_ptr) {
-               /*
-                * Recover state from last call, if applicable
-                */
-               code = (*code_ptr ^ Stuff_Magic) & Stuff_CodeMask;
-               count = (*code_ptr ^ Stuff_Magic) & Stuff_CountMask;
-       }
-
-       while (src < end) {
-               switch (code) {
-                       /* Stuff_NoCode: If no current code, select one */
-               case Stuff_NoCode:
-                       /* Record where we're going to put this code */
-                       code_ptr = dst++;
-                       count = 0;      /* Reset the count (zero means one instance) */
-                       /* Tentatively start a new block */
-                       if (*src == 0) {
-                               code = Stuff_Zero;
-                               src++;
-                       } else {
-                               code = Stuff_Same;
-                               *dst++ = *src++ ^ Stuff_Magic;
-                       }
-                       /* Note: We optimistically assume run of same -- */
-                       /* which will be fixed later in Stuff_Same */
-                       /* if it turns out not to be true. */
-                       break;
-
-                       /* Stuff_Zero: We already have at least one zero encoded */
-               case Stuff_Zero:
-                       /* If another zero, count it, else finish this code block */
-                       if (*src == 0) {
-                               count++;
-                               src++;
-                       } else {
-                               StuffData_FinishBlock(Stuff_Zero + count);
-                       }
-                       break;
-
-                       /* Stuff_Same: We already have at least one byte encoded */
-               case Stuff_Same:
-                       /* If another one the same, count it */
-                       if ((*src ^ Stuff_Magic) == code_ptr[1]) {
-                               count++;
-                               src++;
-                               break;
-                       }
-                       /* else, this byte does not match this block. */
-                       /* If we already have two or more bytes encoded, finish this code block */
-                       if (count) {
-                               StuffData_FinishBlock(Stuff_Same + count);
-                               break;
-                       }
-                       /* else, we only have one so far, so switch to Stuff_Diff code */
-                       code = Stuff_Diff;
-                       /* and fall through to Stuff_Diff case below
-                        * Note cunning cleverness here: case Stuff_Diff compares 
-                        * the current character with the previous two to see if it
-                        * has a run of three the same. Won't this be an error if
-                        * there aren't two previous characters stored to compare with?
-                        * No. Because we know the current character is *not* the same
-                        * as the previous one, the first test below will necessarily
-                        * fail and the send half of the "if" won't be executed.
-                        */
-
-                       /* Stuff_Diff: We have at least two *different* bytes encoded */
-               case Stuff_Diff:
-                       /* If this is a zero, must encode a Stuff_DiffZero, and begin a new block */
-                       if (*src == 0) {
-                               StuffData_FinishBlock(Stuff_DiffZero +
-                                                     count);
-                       }
-                       /* else, if we have three in a row, it is worth starting a Stuff_Same block */
-                       else if ((*src ^ Stuff_Magic) == dst[-1]
-                                && dst[-1] == dst[-2]) {
-                               /* Back off the last two characters we encoded */
-                               code += count - 2;
-                               /* Note: "Stuff_Diff + 0" is an illegal code */
-                               if (code == Stuff_Diff + 0) {
-                                       code = Stuff_Same + 0;
-                               }
-                               StuffData_FinishBlock(code);
-                               code_ptr = dst - 2;
-                               /* dst[-1] already holds the correct value */
-                               count = 2;      /* 2 means three bytes encoded */
-                               code = Stuff_Same;
-                       }
-                       /* else, another different byte, so add it to the block */
-                       else {
-                               *dst++ = *src ^ Stuff_Magic;
-                               count++;
-                       }
-                       src++;  /* Consume the byte */
-                       break;
-               }
-               if (count == Stuff_MaxCount) {
-                       StuffData_FinishBlock(code + count);
-               }
-       }
-       if (code == Stuff_NoCode) {
-               *code_ptr_ptr = NULL;
-       } else {
-               *code_ptr_ptr = code_ptr;
-               StuffData_FinishBlock(code + count);
-       }
-       return (dst);
-}
-
-/*
- * UnStuffData decodes the data at "src", up to (but not including) "end".
- * It writes the decoded data into the buffer pointed to by "dst", up to a
- * maximum of "dst_length", and returns the new value of "src" so that a
- * follow-on call can read more data, continuing from where the first left off.
- * 
- * There are three types of results:
- * 1. The source data runs out before extracting "dst_length" bytes:
- *    UnStuffData returns NULL to indicate failure.
- * 2. The source data produces exactly "dst_length" bytes:
- *    UnStuffData returns new_src = end to indicate that all bytes were consumed.
- * 3. "dst_length" bytes are extracted, with more remaining.
- *    UnStuffData returns new_src < end to indicate that there are more bytes
- *    to be read.
- * 
- * Note: The decoding may be destructive, in that it may alter the source
- * data in the process of decoding it (this is necessary to allow a follow-on
- * call to resume correctly).
- */
-
-static __u8 *UnStuffData(__u8 * src, __u8 * end, __u8 * dst,
-                        __u32 dst_length)
-{
-       __u8 *dst_end = dst + dst_length;
-       /* Sanity check */
-       if (!src || !end || !dst || !dst_length)
-               return (NULL);
-       while (src < end && dst < dst_end) {
-               int count = (*src ^ Stuff_Magic) & Stuff_CountMask;
-               switch ((*src ^ Stuff_Magic) & Stuff_CodeMask) {
-               case Stuff_Diff:
-                       if (src + 1 + count >= end)
-                               return (NULL);
-                       do {
-                               *dst++ = *++src ^ Stuff_Magic;
-                       }
-                       while (--count >= 0 && dst < dst_end);
-                       if (count < 0)
-                               src += 1;
-                       else {
-                               if (count == 0)
-                                       *src = Stuff_Same ^ Stuff_Magic;
-                               else
-                                       *src =
-                                           (Stuff_Diff +
-                                            count) ^ Stuff_Magic;
-                       }
-                       break;
-               case Stuff_DiffZero:
-                       if (src + 1 + count >= end)
-                               return (NULL);
-                       do {
-                               *dst++ = *++src ^ Stuff_Magic;
-                       }
-                       while (--count >= 0 && dst < dst_end);
-                       if (count < 0)
-                               *src = Stuff_Zero ^ Stuff_Magic;
-                       else
-                               *src =
-                                   (Stuff_DiffZero + count) ^ Stuff_Magic;
-                       break;
-               case Stuff_Same:
-                       if (src + 1 >= end)
-                               return (NULL);
-                       do {
-                               *dst++ = src[1] ^ Stuff_Magic;
-                       }
-                       while (--count >= 0 && dst < dst_end);
-                       if (count < 0)
-                               src += 2;
-                       else
-                               *src = (Stuff_Same + count) ^ Stuff_Magic;
-                       break;
-               case Stuff_Zero:
-                       do {
-                               *dst++ = 0;
-                       }
-                       while (--count >= 0 && dst < dst_end);
-                       if (count < 0)
-                               src += 1;
-                       else
-                               *src = (Stuff_Zero + count) ^ Stuff_Magic;
-                       break;
-               }
-       }
-       if (dst < dst_end)
-               return (NULL);
-       else
-               return (src);
-}
-
-
-/************************************************************************/
-/* General routines for STRIP                                          */
-
-/*
- * set_baud sets the baud rate to the rate defined by baudcode
- */
-static void set_baud(struct tty_struct *tty, speed_t baudrate)
-{
-       struct ktermios old_termios;
-
-       mutex_lock(&tty->termios_mutex);
-       old_termios =*(tty->termios);
-       tty_encode_baud_rate(tty, baudrate, baudrate);
-       tty->ops->set_termios(tty, &old_termios);
-       mutex_unlock(&tty->termios_mutex);
-}
-
-/*
- * Convert a string to a Metricom Address.
- */
-
-#define IS_RADIO_ADDRESS(p) (                                                 \
-  isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \
-  (p)[4] == '-' &&                                                            \
-  isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8])    )
-
-static int string_to_radio_address(MetricomAddress * addr, __u8 * p)
-{
-       if (!IS_RADIO_ADDRESS(p))
-               return (1);
-       addr->c[0] = 0;
-       addr->c[1] = 0;
-       addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]);
-       addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]);
-       addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]);
-       addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]);
-       return (0);
-}
-
-/*
- * Convert a Metricom Address to a string.
- */
-
-static __u8 *radio_address_to_string(const MetricomAddress * addr,
-                                    MetricomAddressString * p)
-{
-       sprintf(p->c, "%02X%02X-%02X%02X", addr->c[2], addr->c[3],
-               addr->c[4], addr->c[5]);
-       return (p->c);
-}
-
-/*
- * Note: Must make sure sx_size is big enough to receive a stuffed
- * MAX_RECV_MTU packet. Additionally, we also want to ensure that it's
- * big enough to receive a large radio neighbour list (currently 4K).
- */
-
-static int allocate_buffers(struct strip *strip_info, int mtu)
-{
-       struct net_device *dev = strip_info->dev;
-       int sx_size = max_t(int, STRIP_ENCAP_SIZE(MAX_RECV_MTU), 4096);
-       int tx_size = STRIP_ENCAP_SIZE(mtu) + MaxCommandStringLength;
-       __u8 *r = kmalloc(MAX_RECV_MTU, GFP_ATOMIC);
-       __u8 *s = kmalloc(sx_size, GFP_ATOMIC);
-       __u8 *t = kmalloc(tx_size, GFP_ATOMIC);
-       if (r && s && t) {
-               strip_info->rx_buff = r;
-               strip_info->sx_buff = s;
-               strip_info->tx_buff = t;
-               strip_info->sx_size = sx_size;
-               strip_info->tx_size = tx_size;
-               strip_info->mtu = dev->mtu = mtu;
-               return (1);
-       }
-       kfree(r);
-       kfree(s);
-       kfree(t);
-       return (0);
-}
-
-/*
- * MTU has been changed by the IP layer. 
- * We could be in
- * an upcall from the tty driver, or in an ip packet queue.
- */
-static int strip_change_mtu(struct net_device *dev, int new_mtu)
-{
-       struct strip *strip_info = netdev_priv(dev);
-       int old_mtu = strip_info->mtu;
-       unsigned char *orbuff = strip_info->rx_buff;
-       unsigned char *osbuff = strip_info->sx_buff;
-       unsigned char *otbuff = strip_info->tx_buff;
-
-       if (new_mtu > MAX_SEND_MTU) {
-               printk(KERN_ERR
-                      "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n",
-                      strip_info->dev->name, MAX_SEND_MTU);
-               return -EINVAL;
-       }
-
-       spin_lock_bh(&strip_lock);
-       if (!allocate_buffers(strip_info, new_mtu)) {
-               printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n",
-                      strip_info->dev->name);
-               spin_unlock_bh(&strip_lock);
-               return -ENOMEM;
-       }
-
-       if (strip_info->sx_count) {
-               if (strip_info->sx_count <= strip_info->sx_size)
-                       memcpy(strip_info->sx_buff, osbuff,
-                              strip_info->sx_count);
-               else {
-                       strip_info->discard = strip_info->sx_count;
-                       strip_info->rx_over_errors++;
-               }
-       }
-
-       if (strip_info->tx_left) {
-               if (strip_info->tx_left <= strip_info->tx_size)
-                       memcpy(strip_info->tx_buff, strip_info->tx_head,
-                              strip_info->tx_left);
-               else {
-                       strip_info->tx_left = 0;
-                       strip_info->tx_dropped++;
-               }
-       }
-       strip_info->tx_head = strip_info->tx_buff;
-       spin_unlock_bh(&strip_lock);
-
-       printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n",
-              strip_info->dev->name, old_mtu, strip_info->mtu);
-
-       kfree(orbuff);
-       kfree(osbuff);
-       kfree(otbuff);
-       return 0;
-}
-
-static void strip_unlock(struct strip *strip_info)
-{
-       /*
-        * Set the timer to go off in one second.
-        */
-       strip_info->idle_timer.expires = jiffies + 1 * HZ;
-       add_timer(&strip_info->idle_timer);
-       netif_wake_queue(strip_info->dev);
-}
-
-
-
-/*
- * If the time is in the near future, time_delta prints the number of
- * seconds to go into the buffer and returns the address of the buffer.
- * If the time is not in the near future, it returns the address of the
- * string "Not scheduled" The buffer must be long enough to contain the
- * ascii representation of the number plus 9 charactes for the " seconds"
- * and the null character.
- */
-#ifdef CONFIG_PROC_FS
-static char *time_delta(char buffer[], long time)
-{
-       time -= jiffies;
-       if (time > LongTime / 2)
-               return ("Not scheduled");
-       if (time < 0)
-               time = 0;       /* Don't print negative times */
-       sprintf(buffer, "%ld seconds", time / HZ);
-       return (buffer);
-}
-
-/* get Nth element of the linked list */
-static struct strip *strip_get_idx(loff_t pos) 
-{
-       struct strip *str;
-       int i = 0;
-
-       list_for_each_entry_rcu(str, &strip_list, list) {
-               if (pos == i)
-                       return str;
-               ++i;
-       }
-       return NULL;
-}
-
-static void *strip_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       rcu_read_lock();
-       return *pos ? strip_get_idx(*pos - 1) : SEQ_START_TOKEN;
-}
-
-static void *strip_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       struct list_head *l;
-       struct strip *s;
-
-       ++*pos;
-       if (v == SEQ_START_TOKEN)
-               return strip_get_idx(1);
-
-       s = v;
-       l = &s->list;
-       list_for_each_continue_rcu(l, &strip_list) {
-               return list_entry(l, struct strip, list);
-       }
-       return NULL;
-}
-
-static void strip_seq_stop(struct seq_file *seq, void *v)
-{
-       rcu_read_unlock();
-}
-
-static void strip_seq_neighbours(struct seq_file *seq,
-                          const MetricomNodeTable * table,
-                          const char *title)
-{
-       /* We wrap this in a do/while loop, so if the table changes */
-       /* while we're reading it, we just go around and try again. */
-       struct timeval t;
-
-       do {
-               int i;
-               t = table->timestamp;
-               if (table->num_nodes)
-                       seq_printf(seq, "\n %s\n", title);
-               for (i = 0; i < table->num_nodes; i++) {
-                       MetricomNode node;
-
-                       spin_lock_bh(&strip_lock);
-                       node = table->node[i];
-                       spin_unlock_bh(&strip_lock);
-                       seq_printf(seq, "  %s\n", node.c);
-               }
-       } while (table->timestamp.tv_sec != t.tv_sec
-                || table->timestamp.tv_usec != t.tv_usec);
-}
-
-/*
- * This function prints radio status information via the seq_file
- * interface.  The interface takes care of buffer size and over
- * run issues. 
- *
- * The buffer in seq_file is PAGESIZE (4K) 
- * so this routine should never print more or it will get truncated.
- * With the maximum of 32 portables and 32 poletops
- * reported, the routine outputs 3107 bytes into the buffer.
- */
-static void strip_seq_status_info(struct seq_file *seq, 
-                                 const struct strip *strip_info)
-{
-       char temp[32];
-       MetricomAddressString addr_string;
-
-       /* First, we must copy all of our data to a safe place, */
-       /* in case a serial interrupt comes in and changes it.  */
-       int tx_left = strip_info->tx_left;
-       unsigned long rx_average_pps = strip_info->rx_average_pps;
-       unsigned long tx_average_pps = strip_info->tx_average_pps;
-       unsigned long sx_average_pps = strip_info->sx_average_pps;
-       int working = strip_info->working;
-       int firmware_level = strip_info->firmware_level;
-       long watchdog_doprobe = strip_info->watchdog_doprobe;
-       long watchdog_doreset = strip_info->watchdog_doreset;
-       long gratuitous_arp = strip_info->gratuitous_arp;
-       long arp_interval = strip_info->arp_interval;
-       FirmwareVersion firmware_version = strip_info->firmware_version;
-       SerialNumber serial_number = strip_info->serial_number;
-       BatteryVoltage battery_voltage = strip_info->battery_voltage;
-       char *if_name = strip_info->dev->name;
-       MetricomAddress true_dev_addr = strip_info->true_dev_addr;
-       MetricomAddress dev_dev_addr =
-           *(MetricomAddress *) strip_info->dev->dev_addr;
-       int manual_dev_addr = strip_info->manual_dev_addr;
-#ifdef EXT_COUNTERS
-       unsigned long rx_bytes = strip_info->rx_bytes;
-       unsigned long tx_bytes = strip_info->tx_bytes;
-       unsigned long rx_rbytes = strip_info->rx_rbytes;
-       unsigned long tx_rbytes = strip_info->tx_rbytes;
-       unsigned long rx_sbytes = strip_info->rx_sbytes;
-       unsigned long tx_sbytes = strip_info->tx_sbytes;
-       unsigned long rx_ebytes = strip_info->rx_ebytes;
-       unsigned long tx_ebytes = strip_info->tx_ebytes;
-#endif
-
-       seq_printf(seq, "\nInterface name\t\t%s\n", if_name);
-       seq_printf(seq, " Radio working:\t\t%s\n", working ? "Yes" : "No");
-       radio_address_to_string(&true_dev_addr, &addr_string);
-       seq_printf(seq, " Radio address:\t\t%s\n", addr_string.c);
-       if (manual_dev_addr) {
-               radio_address_to_string(&dev_dev_addr, &addr_string);
-               seq_printf(seq, " Device address:\t%s\n", addr_string.c);
-       }
-       seq_printf(seq, " Firmware version:\t%s", !working ? "Unknown" :
-                    !firmware_level ? "Should be upgraded" :
-                    firmware_version.c);
-       if (firmware_level >= ChecksummedMessages)
-               seq_printf(seq, " (Checksums Enabled)");
-       seq_printf(seq, "\n");
-       seq_printf(seq, " Serial number:\t\t%s\n", serial_number.c);
-       seq_printf(seq, " Battery voltage:\t%s\n", battery_voltage.c);
-       seq_printf(seq, " Transmit queue (bytes):%d\n", tx_left);
-       seq_printf(seq, " Receive packet rate:   %ld packets per second\n",
-                    rx_average_pps / 8);
-       seq_printf(seq, " Transmit packet rate:  %ld packets per second\n",
-                    tx_average_pps / 8);
-       seq_printf(seq, " Sent packet rate:      %ld packets per second\n",
-                    sx_average_pps / 8);
-       seq_printf(seq, " Next watchdog probe:\t%s\n",
-                    time_delta(temp, watchdog_doprobe));
-       seq_printf(seq, " Next watchdog reset:\t%s\n",
-                    time_delta(temp, watchdog_doreset));
-       seq_printf(seq, " Next gratuitous ARP:\t");
-
-       if (!memcmp
-           (strip_info->dev->dev_addr, zero_address.c,
-            sizeof(zero_address)))
-               seq_printf(seq, "Disabled\n");
-       else {
-               seq_printf(seq, "%s\n", time_delta(temp, gratuitous_arp));
-               seq_printf(seq, " Next ARP interval:\t%ld seconds\n",
-                            JIFFIE_TO_SEC(arp_interval));
-       }
-
-       if (working) {
-#ifdef EXT_COUNTERS
-               seq_printf(seq, "\n");
-               seq_printf(seq,
-                            " Total bytes:         \trx:\t%lu\ttx:\t%lu\n",
-                            rx_bytes, tx_bytes);
-               seq_printf(seq,
-                            "  thru radio:         \trx:\t%lu\ttx:\t%lu\n",
-                            rx_rbytes, tx_rbytes);
-               seq_printf(seq,
-                            "  thru serial port:   \trx:\t%lu\ttx:\t%lu\n",
-                            rx_sbytes, tx_sbytes);
-               seq_printf(seq,
-                            " Total stat/err bytes:\trx:\t%lu\ttx:\t%lu\n",
-                            rx_ebytes, tx_ebytes);
-#endif
-               strip_seq_neighbours(seq, &strip_info->poletops,
-                                       "Poletops:");
-               strip_seq_neighbours(seq, &strip_info->portables,
-                                       "Portables:");
-       }
-}
-
-/*
- * This function is exports status information from the STRIP driver through
- * the /proc file system.
- */
-static int strip_seq_show(struct seq_file *seq, void *v)
-{
-       if (v == SEQ_START_TOKEN)
-               seq_printf(seq, "strip_version: %s\n", StripVersion);
-       else
-               strip_seq_status_info(seq, (const struct strip *)v);
-       return 0;
-}
-
-
-static struct seq_operations strip_seq_ops = {
-       .start = strip_seq_start,
-       .next  = strip_seq_next,
-       .stop  = strip_seq_stop,
-       .show  = strip_seq_show,
-};
-
-static int strip_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &strip_seq_ops);
-}
-
-static const struct file_operations strip_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = strip_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-#endif
-
-
-
-/************************************************************************/
-/* Sending routines                                                    */
-
-static void ResetRadio(struct strip *strip_info)
-{
-       struct tty_struct *tty = strip_info->tty;
-       static const char init[] = "ate0q1dt**starmode\r**";
-       StringDescriptor s = { init, sizeof(init) - 1 };
-
-       /* 
-        * If the radio isn't working anymore,
-        * we should clear the old status information.
-        */
-       if (strip_info->working) {
-               printk(KERN_INFO "%s: No response: Resetting radio.\n",
-                      strip_info->dev->name);
-               strip_info->firmware_version.c[0] = '\0';
-               strip_info->serial_number.c[0] = '\0';
-               strip_info->battery_voltage.c[0] = '\0';
-               strip_info->portables.num_nodes = 0;
-               do_gettimeofday(&strip_info->portables.timestamp);
-               strip_info->poletops.num_nodes = 0;
-               do_gettimeofday(&strip_info->poletops.timestamp);
-       }
-
-       strip_info->pps_timer = jiffies;
-       strip_info->rx_pps_count = 0;
-       strip_info->tx_pps_count = 0;
-       strip_info->sx_pps_count = 0;
-       strip_info->rx_average_pps = 0;
-       strip_info->tx_average_pps = 0;
-       strip_info->sx_average_pps = 0;
-
-       /* Mark radio address as unknown */
-       *(MetricomAddress *) & strip_info->true_dev_addr = zero_address;
-       if (!strip_info->manual_dev_addr)
-               *(MetricomAddress *) strip_info->dev->dev_addr =
-                   zero_address;
-       strip_info->working = FALSE;
-       strip_info->firmware_level = NoStructure;
-       strip_info->next_command = CompatibilityCommand;
-       strip_info->watchdog_doprobe = jiffies + 10 * HZ;
-       strip_info->watchdog_doreset = jiffies + 1 * HZ;
-
-       /* If the user has selected a baud rate above 38.4 see what magic we have to do */
-       if (strip_info->user_baud > 38400) {
-               /*
-                * Subtle stuff: Pay attention :-)
-                * If the serial port is currently at the user's selected (>38.4) rate,
-                * then we temporarily switch to 19.2 and issue the ATS304 command
-                * to tell the radio to switch to the user's selected rate.
-                * If the serial port is not currently at that rate, that means we just
-                * issued the ATS304 command last time through, so this time we restore
-                * the user's selected rate and issue the normal starmode reset string.
-                */
-               if (strip_info->user_baud == tty_get_baud_rate(tty)) {
-                       static const char b0[] = "ate0q1s304=57600\r";
-                       static const char b1[] = "ate0q1s304=115200\r";
-                       static const StringDescriptor baudstring[2] =
-                           { {b0, sizeof(b0) - 1}
-                       , {b1, sizeof(b1) - 1}
-                       };
-                       set_baud(tty, 19200);
-                       if (strip_info->user_baud == 57600)
-                               s = baudstring[0];
-                       else if (strip_info->user_baud == 115200)
-                               s = baudstring[1];
-                       else
-                               s = baudstring[1];      /* For now */
-               } else
-                       set_baud(tty, strip_info->user_baud);
-       }
-
-       tty->ops->write(tty, s.string, s.length);
-#ifdef EXT_COUNTERS
-       strip_info->tx_ebytes += s.length;
-#endif
-}
-
-/*
- * Called by the driver when there's room for more data.  If we have
- * more packets to send, we send them here.
- */
-
-static void strip_write_some_more(struct tty_struct *tty)
-{
-       struct strip *strip_info = (struct strip *) tty->disc_data;
-
-       /* First make sure we're connected. */
-       if (!strip_info || strip_info->magic != STRIP_MAGIC ||
-           !netif_running(strip_info->dev))
-               return;
-
-       if (strip_info->tx_left > 0) {
-               int num_written =
-                   tty->ops->write(tty, strip_info->tx_head,
-                                     strip_info->tx_left);
-               strip_info->tx_left -= num_written;
-               strip_info->tx_head += num_written;
-#ifdef EXT_COUNTERS
-               strip_info->tx_sbytes += num_written;
-#endif
-       } else {                /* Else start transmission of another packet */
-
-               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-               strip_unlock(strip_info);
-       }
-}
-
-static __u8 *add_checksum(__u8 * buffer, __u8 * end)
-{
-       __u16 sum = 0;
-       __u8 *p = buffer;
-       while (p < end)
-               sum += *p++;
-       end[3] = hextable[sum & 0xF];
-       sum >>= 4;
-       end[2] = hextable[sum & 0xF];
-       sum >>= 4;
-       end[1] = hextable[sum & 0xF];
-       sum >>= 4;
-       end[0] = hextable[sum & 0xF];
-       return (end + 4);
-}
-
-static unsigned char *strip_make_packet(unsigned char *buffer,
-                                       struct strip *strip_info,
-                                       struct sk_buff *skb)
-{
-       __u8 *ptr = buffer;
-       __u8 *stuffstate = NULL;
-       STRIP_Header *header = (STRIP_Header *) skb->data;
-       MetricomAddress haddr = header->dst_addr;
-       int len = skb->len - sizeof(STRIP_Header);
-       MetricomKey key;
-
-       /*HexDump("strip_make_packet", strip_info, skb->data, skb->data + skb->len); */
-
-       if (header->protocol == htons(ETH_P_IP))
-               key = SIP0Key;
-       else if (header->protocol == htons(ETH_P_ARP))
-               key = ARP0Key;
-       else {
-               printk(KERN_ERR
-                      "%s: strip_make_packet: Unknown packet type 0x%04X\n",
-                      strip_info->dev->name, ntohs(header->protocol));
-               return (NULL);
-       }
-
-       if (len > strip_info->mtu) {
-               printk(KERN_ERR
-                      "%s: Dropping oversized transmit packet: %d bytes\n",
-                      strip_info->dev->name, len);
-               return (NULL);
-       }
-
-       /*
-        * If we're sending to ourselves, discard the packet.
-        * (Metricom radios choke if they try to send a packet to their own address.)
-        */
-       if (!memcmp(haddr.c, strip_info->true_dev_addr.c, sizeof(haddr))) {
-               printk(KERN_ERR "%s: Dropping packet addressed to self\n",
-                      strip_info->dev->name);
-               return (NULL);
-       }
-
-       /*
-        * If this is a broadcast packet, send it to our designated Metricom
-        * 'broadcast hub' radio (First byte of address being 0xFF means broadcast)
-        */
-       if (haddr.c[0] == 0xFF) {
-               __be32 brd = 0;
-               struct in_device *in_dev;
-
-               rcu_read_lock();
-               in_dev = __in_dev_get_rcu(strip_info->dev);
-               if (in_dev == NULL) {
-                       rcu_read_unlock();
-                       return NULL;
-               }
-               if (in_dev->ifa_list)
-                       brd = in_dev->ifa_list->ifa_broadcast;
-               rcu_read_unlock();
-
-               /* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */
-               if (!arp_query(haddr.c, brd, strip_info->dev)) {
-                       printk(KERN_ERR
-                              "%s: Unable to send packet (no broadcast hub configured)\n",
-                              strip_info->dev->name);
-                       return (NULL);
-               }
-               /*
-                * If we are the broadcast hub, don't bother sending to ourselves.
-                * (Metricom radios choke if they try to send a packet to their own address.)
-                */
-               if (!memcmp
-                   (haddr.c, strip_info->true_dev_addr.c, sizeof(haddr)))
-                       return (NULL);
-       }
-
-       *ptr++ = 0x0D;
-       *ptr++ = '*';
-       *ptr++ = hextable[haddr.c[2] >> 4];
-       *ptr++ = hextable[haddr.c[2] & 0xF];
-       *ptr++ = hextable[haddr.c[3] >> 4];
-       *ptr++ = hextable[haddr.c[3] & 0xF];
-       *ptr++ = '-';
-       *ptr++ = hextable[haddr.c[4] >> 4];
-       *ptr++ = hextable[haddr.c[4] & 0xF];
-       *ptr++ = hextable[haddr.c[5] >> 4];
-       *ptr++ = hextable[haddr.c[5] & 0xF];
-       *ptr++ = '*';
-       *ptr++ = key.c[0];
-       *ptr++ = key.c[1];
-       *ptr++ = key.c[2];
-       *ptr++ = key.c[3];
-
-       ptr =
-           StuffData(skb->data + sizeof(STRIP_Header), len, ptr,
-                     &stuffstate);
-
-       if (strip_info->firmware_level >= ChecksummedMessages)
-               ptr = add_checksum(buffer + 1, ptr);
-
-       *ptr++ = 0x0D;
-       return (ptr);
-}
-
-static void strip_send(struct strip *strip_info, struct sk_buff *skb)
-{
-       MetricomAddress haddr;
-       unsigned char *ptr = strip_info->tx_buff;
-       int doreset = (long) jiffies - strip_info->watchdog_doreset >= 0;
-       int doprobe = (long) jiffies - strip_info->watchdog_doprobe >= 0
-           && !doreset;
-       __be32 addr, brd;
-
-       /*
-        * 1. If we have a packet, encapsulate it and put it in the buffer
-        */
-       if (skb) {
-               char *newptr = strip_make_packet(ptr, strip_info, skb);
-               strip_info->tx_pps_count++;
-               if (!newptr)
-                       strip_info->tx_dropped++;
-               else {
-                       ptr = newptr;
-                       strip_info->sx_pps_count++;
-                       strip_info->tx_packets++;       /* Count another successful packet */
-#ifdef EXT_COUNTERS
-                       strip_info->tx_bytes += skb->len;
-                       strip_info->tx_rbytes += ptr - strip_info->tx_buff;
-#endif
-                       /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr); */
-                       /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr); */
-               }
-       }
-
-       /*
-        * 2. If it is time for another tickle, tack it on, after the packet
-        */
-       if (doprobe) {
-               StringDescriptor ts = CommandString[strip_info->next_command];
-#if TICKLE_TIMERS
-               {
-                       struct timeval tv;
-                       do_gettimeofday(&tv);
-                       printk(KERN_INFO "**** Sending tickle string %d      at %02d.%06d\n",
-                              strip_info->next_command, tv.tv_sec % 100,
-                              tv.tv_usec);
-               }
-#endif
-               if (ptr == strip_info->tx_buff)
-                       *ptr++ = 0x0D;
-
-               *ptr++ = '*';   /* First send "**" to provoke an error message */
-               *ptr++ = '*';
-
-               /* Then add the command */
-               memcpy(ptr, ts.string, ts.length);
-
-               /* Add a checksum ? */
-               if (strip_info->firmware_level < ChecksummedMessages)
-                       ptr += ts.length;
-               else
-                       ptr = add_checksum(ptr, ptr + ts.length);
-
-               *ptr++ = 0x0D;  /* Terminate the command with a <CR> */
-
-               /* Cycle to next periodic command? */
-               if (strip_info->firmware_level >= StructuredMessages)
-                       if (++strip_info->next_command >=
-                           ARRAY_SIZE(CommandString))
-                               strip_info->next_command = 0;
-#ifdef EXT_COUNTERS
-               strip_info->tx_ebytes += ts.length;
-#endif
-               strip_info->watchdog_doprobe = jiffies + 10 * HZ;
-               strip_info->watchdog_doreset = jiffies + 1 * HZ;
-               /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev->name); */
-       }
-
-       /*
-        * 3. Set up the strip_info ready to send the data (if any).
-        */
-       strip_info->tx_head = strip_info->tx_buff;
-       strip_info->tx_left = ptr - strip_info->tx_buff;
-       strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-
-       /*
-        * 4. Debugging check to make sure we're not overflowing the buffer.
-        */
-       if (strip_info->tx_size - strip_info->tx_left < 20)
-               printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n",
-                      strip_info->dev->name, strip_info->tx_left,
-                      strip_info->tx_size - strip_info->tx_left);
-
-       /*
-        * 5. If watchdog has expired, reset the radio. Note: if there's data waiting in
-        * the buffer, strip_write_some_more will send it after the reset has finished
-        */
-       if (doreset) {
-               ResetRadio(strip_info);
-               return;
-       }
-
-       if (1) {
-               struct in_device *in_dev;
-
-               brd = addr = 0;
-               rcu_read_lock();
-               in_dev = __in_dev_get_rcu(strip_info->dev);
-               if (in_dev) {
-                       if (in_dev->ifa_list) {
-                               brd = in_dev->ifa_list->ifa_broadcast;
-                               addr = in_dev->ifa_list->ifa_local;
-                       }
-               }
-               rcu_read_unlock();
-       }
-
-
-       /*
-        * 6. If it is time for a periodic ARP, queue one up to be sent.
-        * We only do this if:
-        *  1. The radio is working
-        *  2. It's time to send another periodic ARP
-        *  3. We really know what our address is (and it is not manually set to zero)
-        *  4. We have a designated broadcast address configured
-        * If we queue up an ARP packet when we don't have a designated broadcast
-        * address configured, then the packet will just have to be discarded in
-        * strip_make_packet. This is not fatal, but it causes misleading information
-        * to be displayed in tcpdump. tcpdump will report that periodic APRs are
-        * being sent, when in fact they are not, because they are all being dropped
-        * in the strip_make_packet routine.
-        */
-       if (strip_info->working
-           && (long) jiffies - strip_info->gratuitous_arp >= 0
-           && memcmp(strip_info->dev->dev_addr, zero_address.c,
-                     sizeof(zero_address))
-           && arp_query(haddr.c, brd, strip_info->dev)) {
-               /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n",
-                  strip_info->dev->name, strip_info->arp_interval / HZ); */
-               strip_info->gratuitous_arp =
-                   jiffies + strip_info->arp_interval;
-               strip_info->arp_interval *= 2;
-               if (strip_info->arp_interval > MaxARPInterval)
-                       strip_info->arp_interval = MaxARPInterval;
-               if (addr)
-                       arp_send(ARPOP_REPLY, ETH_P_ARP, addr,  /* Target address of ARP packet is our address */
-                                strip_info->dev,       /* Device to send packet on */
-                                addr,  /* Source IP address this ARP packet comes from */
-                                NULL,  /* Destination HW address is NULL (broadcast it) */
-                                strip_info->dev->dev_addr,     /* Source HW address is our HW address */
-                                strip_info->dev->dev_addr);    /* Target HW address is our HW address (redundant) */
-       }
-
-       /*
-        * 7. All ready. Start the transmission
-        */
-       strip_write_some_more(strip_info->tty);
-}
-
-/* Encapsulate a datagram and kick it into a TTY queue. */
-static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct strip *strip_info = netdev_priv(dev);
-
-       if (!netif_running(dev)) {
-               printk(KERN_ERR "%s: xmit call when iface is down\n",
-                      dev->name);
-               return (1);
-       }
-
-       netif_stop_queue(dev);
-
-       del_timer(&strip_info->idle_timer);
-
-
-       if (time_after(jiffies, strip_info->pps_timer + HZ)) {
-               unsigned long t = jiffies - strip_info->pps_timer;
-               unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t / 2) / t;
-               unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t / 2) / t;
-               unsigned long sx_pps_count = (strip_info->sx_pps_count * HZ * 8 + t / 2) / t;
-
-               strip_info->pps_timer = jiffies;
-               strip_info->rx_pps_count = 0;
-               strip_info->tx_pps_count = 0;
-               strip_info->sx_pps_count = 0;
-
-               strip_info->rx_average_pps = (strip_info->rx_average_pps + rx_pps_count + 1) / 2;
-               strip_info->tx_average_pps = (strip_info->tx_average_pps + tx_pps_count + 1) / 2;
-               strip_info->sx_average_pps = (strip_info->sx_average_pps + sx_pps_count + 1) / 2;
-
-               if (rx_pps_count / 8 >= 10)
-                       printk(KERN_INFO "%s: WARNING: Receiving %ld packets per second.\n",
-                              strip_info->dev->name, rx_pps_count / 8);
-               if (tx_pps_count / 8 >= 10)
-                       printk(KERN_INFO "%s: WARNING: Tx        %ld packets per second.\n",
-                              strip_info->dev->name, tx_pps_count / 8);
-               if (sx_pps_count / 8 >= 10)
-                       printk(KERN_INFO "%s: WARNING: Sending   %ld packets per second.\n",
-                              strip_info->dev->name, sx_pps_count / 8);
-       }
-
-       spin_lock_bh(&strip_lock);
-
-       strip_send(strip_info, skb);
-
-       spin_unlock_bh(&strip_lock);
-
-       if (skb)
-               dev_kfree_skb(skb);
-       return 0;
-}
-
-/*
- * IdleTask periodically calls strip_xmit, so even when we have no IP packets
- * to send for an extended period of time, the watchdog processing still gets
- * done to ensure that the radio stays in Starmode
- */
-
-static void strip_IdleTask(unsigned long parameter)
-{
-       strip_xmit(NULL, (struct net_device *) parameter);
-}
-
-/*
- * Create the MAC header for an arbitrary protocol layer
- *
- * saddr!=NULL        means use this specific address (n/a for Metricom)
- * saddr==NULL        means use default device source address
- * daddr!=NULL        means use this destination address
- * daddr==NULL        means leave destination address alone
- *                 (e.g. unresolved arp -- kernel will call
- *                 rebuild_header later to fill in the address)
- */
-
-static int strip_header(struct sk_buff *skb, struct net_device *dev,
-                       unsigned short type, const void *daddr,
-                       const void *saddr, unsigned len)
-{
-       struct strip *strip_info = netdev_priv(dev);
-       STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header));
-
-       /*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type,
-          type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : ""); */
-
-       header->src_addr = strip_info->true_dev_addr;
-       header->protocol = htons(type);
-
-       /*HexDump("strip_header", netdev_priv(dev), skb->data, skb->data + skb->len); */
-
-       if (!daddr)
-               return (-dev->hard_header_len);
-
-       header->dst_addr = *(MetricomAddress *) daddr;
-       return (dev->hard_header_len);
-}
-
-/*
- * Rebuild the MAC header. This is called after an ARP
- * (or in future other address resolution) has completed on this
- * sk_buff. We now let ARP fill in the other fields.
- * I think this should return zero if packet is ready to send,
- * or non-zero if it needs more time to do an address lookup
- */
-
-static int strip_rebuild_header(struct sk_buff *skb)
-{
-#ifdef CONFIG_INET
-       STRIP_Header *header = (STRIP_Header *) skb->data;
-
-       /* Arp find returns zero if if knows the address, */
-       /* or if it doesn't know the address it sends an ARP packet and returns non-zero */
-       return arp_find(header->dst_addr.c, skb) ? 1 : 0;
-#else
-       return 0;
-#endif
-}
-
-
-/************************************************************************/
-/* Receiving routines                                                  */
-
-/*
- * This function parses the response to the ATS300? command,
- * extracting the radio version and serial number.
- */
-static void get_radio_version(struct strip *strip_info, __u8 * ptr, __u8 * end)
-{
-       __u8 *p, *value_begin, *value_end;
-       int len;
-
-       /* Determine the beginning of the second line of the payload */
-       p = ptr;
-       while (p < end && *p != 10)
-               p++;
-       if (p >= end)
-               return;
-       p++;
-       value_begin = p;
-
-       /* Determine the end of line */
-       while (p < end && *p != 10)
-               p++;
-       if (p >= end)
-               return;
-       value_end = p;
-       p++;
-
-       len = value_end - value_begin;
-       len = min_t(int, len, sizeof(FirmwareVersion) - 1);
-       if (strip_info->firmware_version.c[0] == 0)
-               printk(KERN_INFO "%s: Radio Firmware: %.*s\n",
-                      strip_info->dev->name, len, value_begin);
-       sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin);
-
-       /* Look for the first colon */
-       while (p < end && *p != ':')
-               p++;
-       if (p >= end)
-               return;
-       /* Skip over the space */
-       p += 2;
-       len = sizeof(SerialNumber) - 1;
-       if (p + len <= end) {
-               sprintf(strip_info->serial_number.c, "%.*s", len, p);
-       } else {
-               printk(KERN_DEBUG
-                      "STRIP: radio serial number shorter (%zd) than expected (%d)\n",
-                      end - p, len);
-       }
-}
-
-/*
- * This function parses the response to the ATS325? command,
- * extracting the radio battery voltage.
- */
-static void get_radio_voltage(struct strip *strip_info, __u8 * ptr, __u8 * end)
-{
-       int len;
-
-       len = sizeof(BatteryVoltage) - 1;
-       if (ptr + len <= end) {
-               sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr);
-       } else {
-               printk(KERN_DEBUG
-                      "STRIP: radio voltage string shorter (%zd) than expected (%d)\n",
-                      end - ptr, len);
-       }
-}
-
-/*
- * This function parses the responses to the AT~LA and ATS311 commands,
- * which list the radio's neighbours.
- */
-static void get_radio_neighbours(MetricomNodeTable * table, __u8 * ptr, __u8 * end)
-{
-       table->num_nodes = 0;
-       while (ptr < end && table->num_nodes < NODE_TABLE_SIZE) {
-               MetricomNode *node = &table->node[table->num_nodes++];
-               char *dst = node->c, *limit = dst + sizeof(*node) - 1;
-               while (ptr < end && *ptr <= 32)
-                       ptr++;
-               while (ptr < end && dst < limit && *ptr != 10)
-                       *dst++ = *ptr++;
-               *dst++ = 0;
-               while (ptr < end && ptr[-1] != 10)
-                       ptr++;
-       }
-       do_gettimeofday(&table->timestamp);
-}
-
-static int get_radio_address(struct strip *strip_info, __u8 * p)
-{
-       MetricomAddress addr;
-
-       if (string_to_radio_address(&addr, p))
-               return (1);
-
-       /* See if our radio address has changed */
-       if (memcmp(strip_info->true_dev_addr.c, addr.c, sizeof(addr))) {
-               MetricomAddressString addr_string;
-               radio_address_to_string(&addr, &addr_string);
-               printk(KERN_INFO "%s: Radio address = %s\n",
-                      strip_info->dev->name, addr_string.c);
-               strip_info->true_dev_addr = addr;
-               if (!strip_info->manual_dev_addr)
-                       *(MetricomAddress *) strip_info->dev->dev_addr =
-                           addr;
-               /* Give the radio a few seconds to get its head straight, then send an arp */
-               strip_info->gratuitous_arp = jiffies + 15 * HZ;
-               strip_info->arp_interval = 1 * HZ;
-       }
-       return (0);
-}
-
-static int verify_checksum(struct strip *strip_info)
-{
-       __u8 *p = strip_info->sx_buff;
-       __u8 *end = strip_info->sx_buff + strip_info->sx_count - 4;
-       u_short sum =
-           (READHEX16(end[0]) << 12) | (READHEX16(end[1]) << 8) |
-           (READHEX16(end[2]) << 4) | (READHEX16(end[3]));
-       while (p < end)
-               sum -= *p++;
-       if (sum == 0 && strip_info->firmware_level == StructuredMessages) {
-               strip_info->firmware_level = ChecksummedMessages;
-               printk(KERN_INFO "%s: Radio provides message checksums\n",
-                      strip_info->dev->name);
-       }
-       return (sum == 0);
-}
-
-static void RecvErr(char *msg, struct strip *strip_info)
-{
-       __u8 *ptr = strip_info->sx_buff;
-       __u8 *end = strip_info->sx_buff + strip_info->sx_count;
-       DumpData(msg, strip_info, ptr, end);
-       strip_info->rx_errors++;
-}
-
-static void RecvErr_Message(struct strip *strip_info, __u8 * sendername,
-                           const __u8 * msg, u_long len)
-{
-       if (has_prefix(msg, len, "001")) {      /* Not in StarMode! */
-               RecvErr("Error Msg:", strip_info);
-               printk(KERN_INFO "%s: Radio %s is not in StarMode\n",
-                      strip_info->dev->name, sendername);
-       }
-
-       else if (has_prefix(msg, len, "002")) { /* Remap handle */
-               /* We ignore "Remap handle" messages for now */
-       }
-
-       else if (has_prefix(msg, len, "003")) { /* Can't resolve name */
-               RecvErr("Error Msg:", strip_info);
-               printk(KERN_INFO "%s: Destination radio name is unknown\n",
-                      strip_info->dev->name);
-       }
-
-       else if (has_prefix(msg, len, "004")) { /* Name too small or missing */
-               strip_info->watchdog_doreset = jiffies + LongTime;
-#if TICKLE_TIMERS
-               {
-                       struct timeval tv;
-                       do_gettimeofday(&tv);
-                       printk(KERN_INFO
-                              "**** Got ERR_004 response         at %02d.%06d\n",
-                              tv.tv_sec % 100, tv.tv_usec);
-               }
-#endif
-               if (!strip_info->working) {
-                       strip_info->working = TRUE;
-                       printk(KERN_INFO "%s: Radio now in starmode\n",
-                              strip_info->dev->name);
-                       /*
-                        * If the radio has just entered a working state, we should do our first
-                        * probe ASAP, so that we find out our radio address etc. without delay.
-                        */
-                       strip_info->watchdog_doprobe = jiffies;
-               }
-               if (strip_info->firmware_level == NoStructure && sendername) {
-                       strip_info->firmware_level = StructuredMessages;
-                       strip_info->next_command = 0;   /* Try to enable checksums ASAP */
-                       printk(KERN_INFO
-                              "%s: Radio provides structured messages\n",
-                              strip_info->dev->name);
-               }
-               if (strip_info->firmware_level >= StructuredMessages) {
-                       /*
-                        * If this message has a valid checksum on the end, then the call to verify_checksum
-                        * will elevate the firmware_level to ChecksummedMessages for us. (The actual return
-                        * code from verify_checksum is ignored here.)
-                        */
-                       verify_checksum(strip_info);
-                       /*
-                        * If the radio has structured messages but we don't yet have all our information about it,
-                        * we should do probes without delay, until we have gathered all the information
-                        */
-                       if (!GOT_ALL_RADIO_INFO(strip_info))
-                               strip_info->watchdog_doprobe = jiffies;
-               }
-       }
-
-       else if (has_prefix(msg, len, "005"))   /* Bad count specification */
-               RecvErr("Error Msg:", strip_info);
-
-       else if (has_prefix(msg, len, "006"))   /* Header too big */
-               RecvErr("Error Msg:", strip_info);
-
-       else if (has_prefix(msg, len, "007")) { /* Body too big */
-               RecvErr("Error Msg:", strip_info);
-               printk(KERN_ERR
-                      "%s: Error! Packet size too big for radio.\n",
-                      strip_info->dev->name);
-       }
-
-       else if (has_prefix(msg, len, "008")) { /* Bad character in name */
-               RecvErr("Error Msg:", strip_info);
-               printk(KERN_ERR
-                      "%s: Radio name contains illegal character\n",
-                      strip_info->dev->name);
-       }
-
-       else if (has_prefix(msg, len, "009"))   /* No count or line terminator */
-               RecvErr("Error Msg:", strip_info);
-
-       else if (has_prefix(msg, len, "010"))   /* Invalid checksum */
-               RecvErr("Error Msg:", strip_info);
-
-       else if (has_prefix(msg, len, "011"))   /* Checksum didn't match */
-               RecvErr("Error Msg:", strip_info);
-
-       else if (has_prefix(msg, len, "012"))   /* Failed to transmit packet */
-               RecvErr("Error Msg:", strip_info);
-
-       else
-               RecvErr("Error Msg:", strip_info);
-}
-
-static void process_AT_response(struct strip *strip_info, __u8 * ptr,
-                               __u8 * end)
-{
-       u_long len;
-       __u8 *p = ptr;
-       while (p < end && p[-1] != 10)
-               p++;            /* Skip past first newline character */
-       /* Now ptr points to the AT command, and p points to the text of the response. */
-       len = p - ptr;
-
-#if TICKLE_TIMERS
-       {
-               struct timeval tv;
-               do_gettimeofday(&tv);
-               printk(KERN_INFO "**** Got AT response %.7s      at %02d.%06d\n",
-                      ptr, tv.tv_sec % 100, tv.tv_usec);
-       }
-#endif
-
-       if (has_prefix(ptr, len, "ATS300?"))
-               get_radio_version(strip_info, p, end);
-       else if (has_prefix(ptr, len, "ATS305?"))
-               get_radio_address(strip_info, p);
-       else if (has_prefix(ptr, len, "ATS311?"))
-               get_radio_neighbours(&strip_info->poletops, p, end);
-       else if (has_prefix(ptr, len, "ATS319=7"))
-               verify_checksum(strip_info);
-       else if (has_prefix(ptr, len, "ATS325?"))
-               get_radio_voltage(strip_info, p, end);
-       else if (has_prefix(ptr, len, "AT~LA"))
-               get_radio_neighbours(&strip_info->portables, p, end);
-       else
-               RecvErr("Unknown AT Response:", strip_info);
-}
-
-static void process_ACK(struct strip *strip_info, __u8 * ptr, __u8 * end)
-{
-       /* Currently we don't do anything with ACKs from the radio */
-}
-
-static void process_Info(struct strip *strip_info, __u8 * ptr, __u8 * end)
-{
-       if (ptr + 16 > end)
-               RecvErr("Bad Info Msg:", strip_info);
-}
-
-static struct net_device *get_strip_dev(struct strip *strip_info)
-{
-       /* If our hardware address is *manually set* to zero, and we know our */
-       /* real radio hardware address, try to find another strip device that has been */
-       /* manually set to that address that we can 'transfer ownership' of this packet to  */
-       if (strip_info->manual_dev_addr &&
-           !memcmp(strip_info->dev->dev_addr, zero_address.c,
-                   sizeof(zero_address))
-           && memcmp(&strip_info->true_dev_addr, zero_address.c,
-                     sizeof(zero_address))) {
-               struct net_device *dev;
-               read_lock_bh(&dev_base_lock);
-               for_each_netdev(&init_net, dev) {
-                       if (dev->type == strip_info->dev->type &&
-                           !memcmp(dev->dev_addr,
-                                   &strip_info->true_dev_addr,
-                                   sizeof(MetricomAddress))) {
-                               printk(KERN_INFO
-                                      "%s: Transferred packet ownership to %s.\n",
-                                      strip_info->dev->name, dev->name);
-                               read_unlock_bh(&dev_base_lock);
-                               return (dev);
-                       }
-               }
-               read_unlock_bh(&dev_base_lock);
-       }
-       return (strip_info->dev);
-}
-
-/*
- * Send one completely decapsulated datagram to the next layer.
- */
-
-static void deliver_packet(struct strip *strip_info, STRIP_Header * header,
-                          __u16 packetlen)
-{
-       struct sk_buff *skb = dev_alloc_skb(sizeof(STRIP_Header) + packetlen);
-       if (!skb) {
-               printk(KERN_ERR "%s: memory squeeze, dropping packet.\n",
-                      strip_info->dev->name);
-               strip_info->rx_dropped++;
-       } else {
-               memcpy(skb_put(skb, sizeof(STRIP_Header)), header,
-                      sizeof(STRIP_Header));
-               memcpy(skb_put(skb, packetlen), strip_info->rx_buff,
-                      packetlen);
-               skb->dev = get_strip_dev(strip_info);
-               skb->protocol = header->protocol;
-               skb_reset_mac_header(skb);
-
-               /* Having put a fake header on the front of the sk_buff for the */
-               /* benefit of tools like tcpdump, skb_pull now 'consumes' that  */
-               /* fake header before we hand the packet up to the next layer.  */
-               skb_pull(skb, sizeof(STRIP_Header));
-
-               /* Finally, hand the packet up to the next layer (e.g. IP or ARP, etc.) */
-               strip_info->rx_packets++;
-               strip_info->rx_pps_count++;
-#ifdef EXT_COUNTERS
-               strip_info->rx_bytes += packetlen;
-#endif
-               skb->dev->last_rx = jiffies;
-               netif_rx(skb);
-       }
-}
-
-static void process_IP_packet(struct strip *strip_info,
-                             STRIP_Header * header, __u8 * ptr,
-                             __u8 * end)
-{
-       __u16 packetlen;
-
-       /* Decode start of the IP packet header */
-       ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4);
-       if (!ptr) {
-               RecvErr("IP Packet too short", strip_info);
-               return;
-       }
-
-       packetlen = ((__u16) strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3];
-
-       if (packetlen > MAX_RECV_MTU) {
-               printk(KERN_INFO "%s: Dropping oversized received IP packet: %d bytes\n",
-                      strip_info->dev->name, packetlen);
-               strip_info->rx_dropped++;
-               return;
-       }
-
-       /*printk(KERN_INFO "%s: Got %d byte IP packet\n", strip_info->dev->name, packetlen); */
-
-       /* Decode remainder of the IP packet */
-       ptr =
-           UnStuffData(ptr, end, strip_info->rx_buff + 4, packetlen - 4);
-       if (!ptr) {
-               RecvErr("IP Packet too short", strip_info);
-               return;
-       }
-
-       if (ptr < end) {
-               RecvErr("IP Packet too long", strip_info);
-               return;
-       }
-
-       header->protocol = htons(ETH_P_IP);
-
-       deliver_packet(strip_info, header, packetlen);
-}
-
-static void process_ARP_packet(struct strip *strip_info,
-                              STRIP_Header * header, __u8 * ptr,
-                              __u8 * end)
-{
-       __u16 packetlen;
-       struct arphdr *arphdr = (struct arphdr *) strip_info->rx_buff;
-
-       /* Decode start of the ARP packet */
-       ptr = UnStuffData(ptr, end, strip_info->rx_buff, 8);
-       if (!ptr) {
-               RecvErr("ARP Packet too short", strip_info);
-               return;
-       }
-
-       packetlen = 8 + (arphdr->ar_hln + arphdr->ar_pln) * 2;
-
-       if (packetlen > MAX_RECV_MTU) {
-               printk(KERN_INFO
-                      "%s: Dropping oversized received ARP packet: %d bytes\n",
-                      strip_info->dev->name, packetlen);
-               strip_info->rx_dropped++;
-               return;
-       }
-
-       /*printk(KERN_INFO "%s: Got %d byte ARP %s\n",
-          strip_info->dev->name, packetlen,
-          ntohs(arphdr->ar_op) == ARPOP_REQUEST ? "request" : "reply"); */
-
-       /* Decode remainder of the ARP packet */
-       ptr =
-           UnStuffData(ptr, end, strip_info->rx_buff + 8, packetlen - 8);
-       if (!ptr) {
-               RecvErr("ARP Packet too short", strip_info);
-               return;
-       }
-
-       if (ptr < end) {
-               RecvErr("ARP Packet too long", strip_info);
-               return;
-       }
-
-       header->protocol = htons(ETH_P_ARP);
-
-       deliver_packet(strip_info, header, packetlen);
-}
-
-/*
- * process_text_message processes a <CR>-terminated block of data received
- * from the radio that doesn't begin with a '*' character. All normal
- * Starmode communication messages with the radio begin with a '*',
- * so any text that does not indicates a serial port error, a radio that
- * is in Hayes command mode instead of Starmode, or a radio with really
- * old firmware that doesn't frame its Starmode responses properly.
- */
-static void process_text_message(struct strip *strip_info)
-{
-       __u8 *msg = strip_info->sx_buff;
-       int len = strip_info->sx_count;
-
-       /* Check for anything that looks like it might be our radio name */
-       /* (This is here for backwards compatibility with old firmware)  */
-       if (len == 9 && get_radio_address(strip_info, msg) == 0)
-               return;
-
-       if (text_equal(msg, len, "OK"))
-               return;         /* Ignore 'OK' responses from prior commands */
-       if (text_equal(msg, len, "ERROR"))
-               return;         /* Ignore 'ERROR' messages */
-       if (has_prefix(msg, len, "ate0q1"))
-               return;         /* Ignore character echo back from the radio */
-
-       /* Catch other error messages */
-       /* (This is here for backwards compatibility with old firmware) */
-       if (has_prefix(msg, len, "ERR_")) {
-               RecvErr_Message(strip_info, NULL, &msg[4], len - 4);
-               return;
-       }
-
-       RecvErr("No initial *", strip_info);
-}
-
-/*
- * process_message processes a <CR>-terminated block of data received
- * from the radio. If the radio is not in Starmode or has old firmware,
- * it may be a line of text in response to an AT command. Ideally, with
- * a current radio that's properly in Starmode, all data received should
- * be properly framed and checksummed radio message blocks, containing
- * either a starmode packet, or a other communication from the radio
- * firmware, like "INF_" Info messages and &COMMAND responses.
- */
-static void process_message(struct strip *strip_info)
-{
-       STRIP_Header header = { zero_address, zero_address, 0 };
-       __u8 *ptr = strip_info->sx_buff;
-       __u8 *end = strip_info->sx_buff + strip_info->sx_count;
-       __u8 sendername[32], *sptr = sendername;
-       MetricomKey key;
-
-       /*HexDump("Receiving", strip_info, ptr, end); */
-
-       /* Check for start of address marker, and then skip over it */
-       if (*ptr == '*')
-               ptr++;
-       else {
-               process_text_message(strip_info);
-               return;
-       }
-
-       /* Copy out the return address */
-       while (ptr < end && *ptr != '*'
-              && sptr < ARRAY_END(sendername) - 1)
-               *sptr++ = *ptr++;
-       *sptr = 0;              /* Null terminate the sender name */
-
-       /* Check for end of address marker, and skip over it */
-       if (ptr >= end || *ptr != '*') {
-               RecvErr("No second *", strip_info);
-               return;
-       }
-       ptr++;                  /* Skip the second '*' */
-
-       /* If the sender name is "&COMMAND", ignore this 'packet'       */
-       /* (This is here for backwards compatibility with old firmware) */
-       if (!strcmp(sendername, "&COMMAND")) {
-               strip_info->firmware_level = NoStructure;
-               strip_info->next_command = CompatibilityCommand;
-               return;
-       }
-
-       if (ptr + 4 > end) {
-               RecvErr("No proto key", strip_info);
-               return;
-       }
-
-       /* Get the protocol key out of the buffer */
-       key.c[0] = *ptr++;
-       key.c[1] = *ptr++;
-       key.c[2] = *ptr++;
-       key.c[3] = *ptr++;
-
-       /* If we're using checksums, verify the checksum at the end of the packet */
-       if (strip_info->firmware_level >= ChecksummedMessages) {
-               end -= 4;       /* Chop the last four bytes off the packet (they're the checksum) */
-               if (ptr > end) {
-                       RecvErr("Missing Checksum", strip_info);
-                       return;
-               }
-               if (!verify_checksum(strip_info)) {
-                       RecvErr("Bad Checksum", strip_info);
-                       return;
-               }
-       }
-
-       /*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev->name, sendername); */
-
-       /*
-        * Fill in (pseudo) source and destination addresses in the packet.
-        * We assume that the destination address was our address (the radio does not
-        * tell us this). If the radio supplies a source address, then we use it.
-        */
-       header.dst_addr = strip_info->true_dev_addr;
-       string_to_radio_address(&header.src_addr, sendername);
-
-#ifdef EXT_COUNTERS
-       if (key.l == SIP0Key.l) {
-               strip_info->rx_rbytes += (end - ptr);
-               process_IP_packet(strip_info, &header, ptr, end);
-       } else if (key.l == ARP0Key.l) {
-               strip_info->rx_rbytes += (end - ptr);
-               process_ARP_packet(strip_info, &header, ptr, end);
-       } else if (key.l == ATR_Key.l) {
-               strip_info->rx_ebytes += (end - ptr);
-               process_AT_response(strip_info, ptr, end);
-       } else if (key.l == ACK_Key.l) {
-               strip_info->rx_ebytes += (end - ptr);
-               process_ACK(strip_info, ptr, end);
-       } else if (key.l == INF_Key.l) {
-               strip_info->rx_ebytes += (end - ptr);
-               process_Info(strip_info, ptr, end);
-       } else if (key.l == ERR_Key.l) {
-               strip_info->rx_ebytes += (end - ptr);
-               RecvErr_Message(strip_info, sendername, ptr, end - ptr);
-       } else
-               RecvErr("Unrecognized protocol key", strip_info);
-#else
-       if (key.l == SIP0Key.l)
-               process_IP_packet(strip_info, &header, ptr, end);
-       else if (key.l == ARP0Key.l)
-               process_ARP_packet(strip_info, &header, ptr, end);
-       else if (key.l == ATR_Key.l)
-               process_AT_response(strip_info, ptr, end);
-       else if (key.l == ACK_Key.l)
-               process_ACK(strip_info, ptr, end);
-       else if (key.l == INF_Key.l)
-               process_Info(strip_info, ptr, end);
-       else if (key.l == ERR_Key.l)
-               RecvErr_Message(strip_info, sendername, ptr, end - ptr);
-       else
-               RecvErr("Unrecognized protocol key", strip_info);
-#endif
-}
-
-#define TTYERROR(X) ((X) == TTY_BREAK   ? "Break"            : \
-                     (X) == TTY_FRAME   ? "Framing Error"    : \
-                     (X) == TTY_PARITY  ? "Parity Error"     : \
-                     (X) == TTY_OVERRUN ? "Hardware Overrun" : "Unknown Error")
-
-/*
- * Handle the 'receiver data ready' interrupt.
- * This function is called by the 'tty_io' module in the kernel when
- * a block of STRIP data has been received, which can now be decapsulated
- * and sent on to some IP layer for further processing.
- */
-
-static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                 char *fp, int count)
-{
-       struct strip *strip_info = (struct strip *) tty->disc_data;
-       const unsigned char *end = cp + count;
-
-       if (!strip_info || strip_info->magic != STRIP_MAGIC
-           || !netif_running(strip_info->dev))
-               return;
-
-       spin_lock_bh(&strip_lock);
-#if 0
-       {
-               struct timeval tv;
-               do_gettimeofday(&tv);
-               printk(KERN_INFO
-                      "**** strip_receive_buf: %3d bytes at %02d.%06d\n",
-                      count, tv.tv_sec % 100, tv.tv_usec);
-       }
-#endif
-
-#ifdef EXT_COUNTERS
-       strip_info->rx_sbytes += count;
-#endif
-
-       /* Read the characters out of the buffer */
-       while (cp < end) {
-               if (fp && *fp)
-                       printk(KERN_INFO "%s: %s on serial port\n",
-                              strip_info->dev->name, TTYERROR(*fp));
-               if (fp && *fp++ && !strip_info->discard) {      /* If there's a serial error, record it */
-                       /* If we have some characters in the buffer, discard them */
-                       strip_info->discard = strip_info->sx_count;
-                       strip_info->rx_errors++;
-               }
-
-               /* Leading control characters (CR, NL, Tab, etc.) are ignored */
-               if (strip_info->sx_count > 0 || *cp >= ' ') {
-                       if (*cp == 0x0D) {      /* If end of packet, decide what to do with it */
-                               if (strip_info->sx_count > 3000)
-                                       printk(KERN_INFO
-                                              "%s: Cut a %d byte packet (%zd bytes remaining)%s\n",
-                                              strip_info->dev->name,
-                                              strip_info->sx_count,
-                                              end - cp - 1,
-                                              strip_info->
-                                              discard ? " (discarded)" :
-                                              "");
-                               if (strip_info->sx_count >
-                                   strip_info->sx_size) {
-                                       strip_info->rx_over_errors++;
-                                       printk(KERN_INFO
-                                              "%s: sx_buff overflow (%d bytes total)\n",
-                                              strip_info->dev->name,
-                                              strip_info->sx_count);
-                               } else if (strip_info->discard)
-                                       printk(KERN_INFO
-                                              "%s: Discarding bad packet (%d/%d)\n",
-                                              strip_info->dev->name,
-                                              strip_info->discard,
-                                              strip_info->sx_count);
-                               else
-                                       process_message(strip_info);
-                               strip_info->discard = 0;
-                               strip_info->sx_count = 0;
-                       } else {
-                               /* Make sure we have space in the buffer */
-                               if (strip_info->sx_count <
-                                   strip_info->sx_size)
-                                       strip_info->sx_buff[strip_info->
-                                                           sx_count] =
-                                           *cp;
-                               strip_info->sx_count++;
-                       }
-               }
-               cp++;
-       }
-       spin_unlock_bh(&strip_lock);
-}
-
-
-/************************************************************************/
-/* General control routines                                            */
-
-static int set_mac_address(struct strip *strip_info,
-                          MetricomAddress * addr)
-{
-       /*
-        * We're using a manually specified address if the address is set
-        * to anything other than all ones. Setting the address to all ones
-        * disables manual mode and goes back to automatic address determination
-        * (tracking the true address that the radio has).
-        */
-       strip_info->manual_dev_addr =
-           memcmp(addr->c, broadcast_address.c,
-                  sizeof(broadcast_address));
-       if (strip_info->manual_dev_addr)
-               *(MetricomAddress *) strip_info->dev->dev_addr = *addr;
-       else
-               *(MetricomAddress *) strip_info->dev->dev_addr =
-                   strip_info->true_dev_addr;
-       return 0;
-}
-
-static int strip_set_mac_address(struct net_device *dev, void *addr)
-{
-       struct strip *strip_info = netdev_priv(dev);
-       struct sockaddr *sa = addr;
-       printk(KERN_INFO "%s: strip_set_dev_mac_address called\n", dev->name);
-       set_mac_address(strip_info, (MetricomAddress *) sa->sa_data);
-       return 0;
-}
-
-static struct net_device_stats *strip_get_stats(struct net_device *dev)
-{
-       struct strip *strip_info = netdev_priv(dev);
-       static struct net_device_stats stats;
-
-       memset(&stats, 0, sizeof(struct net_device_stats));
-
-       stats.rx_packets = strip_info->rx_packets;
-       stats.tx_packets = strip_info->tx_packets;
-       stats.rx_dropped = strip_info->rx_dropped;
-       stats.tx_dropped = strip_info->tx_dropped;
-       stats.tx_errors = strip_info->tx_errors;
-       stats.rx_errors = strip_info->rx_errors;
-       stats.rx_over_errors = strip_info->rx_over_errors;
-       return (&stats);
-}
-
-
-/************************************************************************/
-/* Opening and closing                                                 */
-
-/*
- * Here's the order things happen:
- * When the user runs "slattach -p strip ..."
- *  1. The TTY module calls strip_open;;
- *  2. strip_open calls strip_alloc
- *  3.                  strip_alloc calls register_netdev
- *  4.                  register_netdev calls strip_dev_init
- *  5. then strip_open finishes setting up the strip_info
- *
- * When the user runs "ifconfig st<x> up address netmask ..."
- *  6. strip_open_low gets called
- *
- * When the user runs "ifconfig st<x> down"
- *  7. strip_close_low gets called
- *
- * When the user kills the slattach process
- *  8. strip_close gets called
- *  9. strip_close calls dev_close
- * 10. if the device is still up, then dev_close calls strip_close_low
- * 11. strip_close calls strip_free
- */
-
-/* Open the low-level part of the STRIP channel. Easy! */
-
-static int strip_open_low(struct net_device *dev)
-{
-       struct strip *strip_info = netdev_priv(dev);
-
-       if (strip_info->tty == NULL)
-               return (-ENODEV);
-
-       if (!allocate_buffers(strip_info, dev->mtu))
-               return (-ENOMEM);
-
-       strip_info->sx_count = 0;
-       strip_info->tx_left = 0;
-
-       strip_info->discard = 0;
-       strip_info->working = FALSE;
-       strip_info->firmware_level = NoStructure;
-       strip_info->next_command = CompatibilityCommand;
-       strip_info->user_baud = tty_get_baud_rate(strip_info->tty);
-
-       printk(KERN_INFO "%s: Initializing Radio.\n",
-              strip_info->dev->name);
-       ResetRadio(strip_info);
-       strip_info->idle_timer.expires = jiffies + 1 * HZ;
-       add_timer(&strip_info->idle_timer);
-       netif_wake_queue(dev);
-       return (0);
-}
-
-
-/*
- * Close the low-level part of the STRIP channel. Easy!
- */
-
-static int strip_close_low(struct net_device *dev)
-{
-       struct strip *strip_info = netdev_priv(dev);
-
-       if (strip_info->tty == NULL)
-               return -EBUSY;
-       strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-
-       netif_stop_queue(dev);
-
-       /*
-        * Free all STRIP frame buffers.
-        */
-       kfree(strip_info->rx_buff);
-       strip_info->rx_buff = NULL;
-       kfree(strip_info->sx_buff);
-       strip_info->sx_buff = NULL;
-       kfree(strip_info->tx_buff);
-       strip_info->tx_buff = NULL;
-
-       del_timer(&strip_info->idle_timer);
-       return 0;
-}
-
-static const struct header_ops strip_header_ops = {
-       .create = strip_header,
-       .rebuild = strip_rebuild_header,
-};
-
-/*
- * This routine is called by DDI when the
- * (dynamically assigned) device is registered
- */
-
-static void strip_dev_setup(struct net_device *dev)
-{
-       /*
-        * Finish setting up the DEVICE info.
-        */
-
-       dev->trans_start = 0;
-       dev->last_rx = 0;
-       dev->tx_queue_len = 30; /* Drop after 30 frames queued */
-
-       dev->flags = 0;
-       dev->mtu = DEFAULT_STRIP_MTU;
-       dev->type = ARPHRD_METRICOM;    /* dtang */
-       dev->hard_header_len = sizeof(STRIP_Header);
-       /*
-        *  dev->priv             Already holds a pointer to our struct strip
-        */
-
-       *(MetricomAddress *) & dev->broadcast = broadcast_address;
-       dev->dev_addr[0] = 0;
-       dev->addr_len = sizeof(MetricomAddress);
-
-       /*
-        * Pointers to interface service routines.
-        */
-
-       dev->open = strip_open_low;
-       dev->stop = strip_close_low;
-       dev->hard_start_xmit = strip_xmit;
-       dev->header_ops = &strip_header_ops;
-
-       dev->set_mac_address = strip_set_mac_address;
-       dev->get_stats = strip_get_stats;
-       dev->change_mtu = strip_change_mtu;
-}
-
-/*
- * Free a STRIP channel.
- */
-
-static void strip_free(struct strip *strip_info)
-{
-       spin_lock_bh(&strip_lock);
-       list_del_rcu(&strip_info->list);
-       spin_unlock_bh(&strip_lock);
-
-       strip_info->magic = 0;
-
-       free_netdev(strip_info->dev);
-}
-
-
-/*
- * Allocate a new free STRIP channel
- */
-static struct strip *strip_alloc(void)
-{
-       struct list_head *n;
-       struct net_device *dev;
-       struct strip *strip_info;
-
-       dev = alloc_netdev(sizeof(struct strip), "st%d",
-                          strip_dev_setup);
-
-       if (!dev)
-               return NULL;    /* If no more memory, return */
-
-
-       strip_info = netdev_priv(dev);
-       strip_info->dev = dev;
-
-       strip_info->magic = STRIP_MAGIC;
-       strip_info->tty = NULL;
-
-       strip_info->gratuitous_arp = jiffies + LongTime;
-       strip_info->arp_interval = 0;
-       init_timer(&strip_info->idle_timer);
-       strip_info->idle_timer.data = (long) dev;
-       strip_info->idle_timer.function = strip_IdleTask;
-
-
-       spin_lock_bh(&strip_lock);
- rescan:
-       /*
-        * Search the list to find where to put our new entry
-        * (and in the process decide what channel number it is
-        * going to be)
-        */
-       list_for_each(n, &strip_list) {
-               struct strip *s = hlist_entry(n, struct strip, list);
-
-               if (s->dev->base_addr == dev->base_addr) {
-                       ++dev->base_addr;
-                       goto rescan;
-               }
-       }
-
-       sprintf(dev->name, "st%ld", dev->base_addr);
-
-       list_add_tail_rcu(&strip_info->list, &strip_list);
-       spin_unlock_bh(&strip_lock);
-
-       return strip_info;
-}
-
-/*
- * Open the high-level part of the STRIP channel.
- * This function is called by the TTY module when the
- * STRIP line discipline is called for.  Because we are
- * sure the tty line exists, we only have to link it to
- * a free STRIP channel...
- */
-
-static int strip_open(struct tty_struct *tty)
-{
-       struct strip *strip_info = (struct strip *) tty->disc_data;
-
-       /*
-        * First make sure we're not already connected.
-        */
-
-       if (strip_info && strip_info->magic == STRIP_MAGIC)
-               return -EEXIST;
-
-       /*
-        * We need a write method.
-        */
-
-       if (tty->ops->write == NULL || tty->ops->set_termios == NULL)
-               return -EOPNOTSUPP;
-
-       /*
-        * OK.  Find a free STRIP channel to use.
-        */
-       if ((strip_info = strip_alloc()) == NULL)
-               return -ENFILE;
-
-       /*
-        * Register our newly created device so it can be ifconfig'd
-        * strip_dev_init() will be called as a side-effect
-        */
-
-       if (register_netdev(strip_info->dev) != 0) {
-               printk(KERN_ERR "strip: register_netdev() failed.\n");
-               strip_free(strip_info);
-               return -ENFILE;
-       }
-
-       strip_info->tty = tty;
-       tty->disc_data = strip_info;
-       tty->receive_room = 65536;
-
-       tty_driver_flush_buffer(tty);
-
-       /*
-        * Restore default settings
-        */
-
-       strip_info->dev->type = ARPHRD_METRICOM;        /* dtang */
-
-       /*
-        * Set tty options
-        */
-
-       tty->termios->c_iflag |= IGNBRK | IGNPAR;       /* Ignore breaks and parity errors. */
-       tty->termios->c_cflag |= CLOCAL;        /* Ignore modem control signals. */
-       tty->termios->c_cflag &= ~HUPCL;        /* Don't close on hup */
-
-       printk(KERN_INFO "STRIP: device \"%s\" activated\n",
-              strip_info->dev->name);
-
-       /*
-        * Done.  We have linked the TTY line to a channel.
-        */
-       return (strip_info->dev->base_addr);
-}
-
-/*
- * Close down a STRIP channel.
- * This means flushing out any pending queues, and then restoring the
- * TTY line discipline to what it was before it got hooked to STRIP
- * (which usually is TTY again).
- */
-
-static void strip_close(struct tty_struct *tty)
-{
-       struct strip *strip_info = (struct strip *) tty->disc_data;
-
-       /*
-        * First make sure we're connected.
-        */
-
-       if (!strip_info || strip_info->magic != STRIP_MAGIC)
-               return;
-
-       unregister_netdev(strip_info->dev);
-
-       tty->disc_data = NULL;
-       strip_info->tty = NULL;
-       printk(KERN_INFO "STRIP: device \"%s\" closed down\n",
-              strip_info->dev->name);
-       strip_free(strip_info);
-       tty->disc_data = NULL;
-}
-
-
-/************************************************************************/
-/* Perform I/O control calls on an active STRIP channel.               */
-
-static int strip_ioctl(struct tty_struct *tty, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       struct strip *strip_info = (struct strip *) tty->disc_data;
-
-       /*
-        * First make sure we're connected.
-        */
-
-       if (!strip_info || strip_info->magic != STRIP_MAGIC)
-               return -EINVAL;
-
-       switch (cmd) {
-       case SIOCGIFNAME:
-               if(copy_to_user((void __user *) arg, strip_info->dev->name, strlen(strip_info->dev->name) + 1))
-                       return -EFAULT;
-               break;
-       case SIOCSIFHWADDR:
-       {
-               MetricomAddress addr;
-               //printk(KERN_INFO "%s: SIOCSIFHWADDR\n", strip_info->dev->name);
-               if(copy_from_user(&addr, (void __user *) arg, sizeof(MetricomAddress)))
-                       return -EFAULT;
-               return set_mac_address(strip_info, &addr);
-       }
-       default:
-               return tty_mode_ioctl(tty, file, cmd, arg);
-               break;
-       }
-       return 0;
-}
-
-
-/************************************************************************/
-/* Initialization                                                      */
-
-static struct tty_ldisc strip_ldisc = {
-       .magic = TTY_LDISC_MAGIC,
-       .name = "strip",
-       .owner = THIS_MODULE,
-       .open = strip_open,
-       .close = strip_close,
-       .ioctl = strip_ioctl,
-       .receive_buf = strip_receive_buf,
-       .write_wakeup = strip_write_some_more,
-};
-
-/*
- * Initialize the STRIP driver.
- * This routine is called at boot time, to bootstrap the multi-channel
- * STRIP driver
- */
-
-static char signon[] __initdata =
-    KERN_INFO "STRIP: Version %s (unlimited channels)\n";
-
-static int __init strip_init_driver(void)
-{
-       int status;
-
-       printk(signon, StripVersion);
-
-       
-       /*
-        * Fill in our line protocol discipline, and register it
-        */
-       if ((status = tty_register_ldisc(N_STRIP, &strip_ldisc)))
-               printk(KERN_ERR "STRIP: can't register line discipline (err = %d)\n",
-                      status);
-
-       /*
-        * Register the status file with /proc
-        */
-       proc_net_fops_create(&init_net, "strip", S_IFREG | S_IRUGO, &strip_seq_fops);
-
-       return status;
-}
-
-module_init(strip_init_driver);
-
-static const char signoff[] __exitdata =
-    KERN_INFO "STRIP: Module Unloaded\n";
-
-static void __exit strip_exit_driver(void)
-{
-       int i;
-       struct list_head *p,*n;
-
-       /* module ref count rules assure that all entries are unregistered */
-       list_for_each_safe(p, n, &strip_list) {
-               struct strip *s = list_entry(p, struct strip, list);
-               strip_free(s);
-       }
-
-       /* Unregister with the /proc/net file here. */
-       proc_net_remove(&init_net, "strip");
-
-       if ((i = tty_unregister_ldisc(N_STRIP)))
-               printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i);
-
-       printk(signoff);
-}
-
-module_exit(strip_exit_driver);
-
-MODULE_AUTHOR("Stuart Cheshire <cheshire@cs.stanford.edu>");
-MODULE_DESCRIPTION("Starmode Radio IP (STRIP) Device Driver");
-MODULE_LICENSE("Dual BSD/GPL");
-
-MODULE_SUPPORTED_DEVICE("Starmode Radio IP (STRIP) modem");
index 42a36b3f3ff78789feb1510dbfca4c4bc13b8fe3..377141995e36ca70132ecbe7e6ff857d7fe262a1 100644 (file)
@@ -1624,25 +1624,25 @@ static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
                iwe.cmd                 = SIOCGIWAP;
                iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
                memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].bssid, ETH_ALEN);
-               current_ev = iwe_stream_add_event(current_ev,
+               current_ev = iwe_stream_add_event(info, current_ev,
                                                  extra + IW_SCAN_MAX_DATA,
                                                  &iwe, IW_EV_ADDR_LEN);
                iwe.cmd           = SIOCGIWESSID;
                iwe.u.data.flags  = 1;
                iwe.u.data.length = this->bss_set[i].ssid.el.len;
-               current_ev = iwe_stream_add_point(current_ev,
+               current_ev = iwe_stream_add_point(info, current_ev,
                                                  extra + IW_SCAN_MAX_DATA,
                                                  &iwe,
                                                  this->bss_set[i].ssid.essid);
                iwe.cmd    = SIOCGIWMODE;
                iwe.u.mode = this->bss_set[i].bss_type;
-               current_ev = iwe_stream_add_event(current_ev,
+               current_ev = iwe_stream_add_event(info, current_ev,
                                                  extra + IW_SCAN_MAX_DATA,
                                                  &iwe, IW_EV_UINT_LEN);
                iwe.cmd = SIOCGIWFREQ;
                iwe.u.freq.m = this->bss_set[i].ds_pset.chan;
                iwe.u.freq.e = 0;
-               current_ev = iwe_stream_add_event(current_ev,
+               current_ev = iwe_stream_add_event(info, current_ev,
                                                  extra + IW_SCAN_MAX_DATA,
                                                  &iwe, IW_EV_FREQ_LEN);
                iwe.cmd = SIOCGIWENCODE;
@@ -1651,7 +1651,7 @@ static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
                else
                        iwe.u.data.flags = IW_ENCODE_DISABLED;
                iwe.u.data.length = 0;
-               current_ev = iwe_stream_add_point(current_ev,
+               current_ev = iwe_stream_add_point(info, current_ev,
                                                  extra + IW_SCAN_MAX_DATA,
                                                  &iwe, NULL);
        }
index d5c0c66188cad3d146e32e3b0c6ccf0012e3066a..07e4d1f732078d28f96d9fd49c5f7732bdf814db 100644 (file)
@@ -1152,32 +1152,36 @@ static int zd1201_get_scan(struct net_device *dev,
                iwe.cmd = SIOCGIWAP;
                iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
                memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6);
-               cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN);
+               cev = iwe_stream_add_event(info, cev, end_buf,
+                                          &iwe, IW_EV_ADDR_LEN);
 
                iwe.cmd = SIOCGIWESSID;
                iwe.u.data.length = zd->rxdata[i+16];
                iwe.u.data.flags = 1;
-               cev = iwe_stream_add_point(cev, end_buf, &iwe, zd->rxdata+i+18);
+               cev = iwe_stream_add_point(info, cev, end_buf,
+                                          &iwe, zd->rxdata+i+18);
 
                iwe.cmd = SIOCGIWMODE;
                if (zd->rxdata[i+14]&0x01)
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
-               cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN);
+               cev = iwe_stream_add_event(info, cev, end_buf,
+                                          &iwe, IW_EV_UINT_LEN);
                
                iwe.cmd = SIOCGIWFREQ;
                iwe.u.freq.m = zd->rxdata[i+0];
                iwe.u.freq.e = 0;
-               cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN);
+               cev = iwe_stream_add_event(info, cev, end_buf,
+                                          &iwe, IW_EV_FREQ_LEN);
                
                iwe.cmd = SIOCGIWRATE;
                iwe.u.bitrate.fixed = 0;
                iwe.u.bitrate.disabled = 0;
                for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) {
                        iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000;
-                       cev=iwe_stream_add_event(cev, end_buf, &iwe,
-                           IW_EV_PARAM_LEN);
+                       cev = iwe_stream_add_event(info, cev, end_buf,
+                                                  &iwe, IW_EV_PARAM_LEN);
                }
                
                iwe.cmd = SIOCGIWENCODE;
@@ -1186,14 +1190,15 @@ static int zd1201_get_scan(struct net_device *dev,
                        iwe.u.data.flags = IW_ENCODE_ENABLED;
                else
                        iwe.u.data.flags = IW_ENCODE_DISABLED;
-               cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL);
+               cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL);
                
                iwe.cmd = IWEVQUAL;
                iwe.u.qual.qual = zd->rxdata[i+4];
                iwe.u.qual.noise= zd->rxdata[i+2]/10-100;
                iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100;
                iwe.u.qual.updated = 7;
-               cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN);
+               cev = iwe_stream_add_event(info, cev, end_buf,
+                                          &iwe, IW_EV_QUAL_LEN);
        }
 
        if (!enabled_save)
index 6d86b365f15078b2f8ae0eb338777ccfed76259a..317c5e24f80c9e9f2b19d94d236a7245971e5b70 100644 (file)
@@ -376,8 +376,6 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
 static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
                           struct ieee80211_hdr *header, u32 flags)
 {
-       u16 fctl = le16_to_cpu(header->frame_control);
-
        /*
         * CONTROL TODO:
         * - if backoff needed, enable bit 0
@@ -395,8 +393,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
                cs->control |= ZD_CS_MULTICAST;
 
        /* PS-POLL */
-       if ((fctl & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) ==
-           (IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL))
+       if (ieee80211_is_pspoll(header->frame_control))
                cs->control |= ZD_CS_PS_POLL_FRAME;
 
        if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
@@ -550,13 +547,11 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
                      struct ieee80211_rx_status *stats)
 {
-       u16 fc = le16_to_cpu(rx_hdr->frame_control);
        struct sk_buff *skb;
        struct sk_buff_head *q;
        unsigned long flags;
 
-       if ((fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) !=
-           (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK))
+       if (!ieee80211_is_ack(rx_hdr->frame_control))
                return 0;
 
        q = &zd_hw_mac(hw)->ack_wait_queue;
@@ -584,8 +579,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
        const struct rx_status *status;
        struct sk_buff *skb;
        int bad_frame = 0;
-       u16 fc;
-       bool is_qos, is_4addr, need_padding;
+       __le16 fc;
+       int need_padding;
        int i;
        u8 rate;
 
@@ -644,13 +639,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
                        && !mac->pass_ctrl)
                return 0;
 
-       fc = le16_to_cpu(*((__le16 *) buffer));
-
-       is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
-                (fc & IEEE80211_STYPE_QOS_DATA);
-       is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
-                  (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
-       need_padding = is_qos ^ is_4addr;
+       fc = *(__le16 *)buffer;
+       need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc);
 
        skb = dev_alloc_skb(length + (need_padding ? 2 : 0));
        if (skb == NULL)
index cd845b8acd17b006ac4021120f0aee8bec85f045..307b1f62d949c42c49940d9ca7dd206943076e67 100644 (file)
@@ -2,7 +2,7 @@ menu "Sonics Silicon Backplane"
 
 config SSB_POSSIBLE
        bool
-       depends on HAS_IOMEM
+       depends on HAS_IOMEM && HAS_DMA
        default y
 
 config SSB
index d184f2aea78d1f0a4b2e2df05c5d79bf8d4a75d9..d831a2beff393079d9a20686494bf022be1f7651 100644 (file)
@@ -462,18 +462,15 @@ static int ssb_devices_register(struct ssb_bus *bus)
 #ifdef CONFIG_SSB_PCIHOST
                        sdev->irq = bus->host_pci->irq;
                        dev->parent = &bus->host_pci->dev;
-                       sdev->dma_dev = &bus->host_pci->dev;
 #endif
                        break;
                case SSB_BUSTYPE_PCMCIA:
 #ifdef CONFIG_SSB_PCMCIAHOST
                        sdev->irq = bus->host_pcmcia->irq.AssignedIRQ;
                        dev->parent = &bus->host_pcmcia->dev;
-                       sdev->dma_dev = &bus->host_pcmcia->dev;
 #endif
                        break;
                case SSB_BUSTYPE_SSB:
-                       sdev->dma_dev = dev;
                        break;
                }
 
@@ -1156,36 +1153,82 @@ u32 ssb_dma_translation(struct ssb_device *dev)
 {
        switch (dev->bus->bustype) {
        case SSB_BUSTYPE_SSB:
-       case SSB_BUSTYPE_PCMCIA:
                return 0;
        case SSB_BUSTYPE_PCI:
                return SSB_PCI_DMA;
+       default:
+               __ssb_dma_not_implemented(dev);
        }
        return 0;
 }
 EXPORT_SYMBOL(ssb_dma_translation);
 
-int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)
+int ssb_dma_set_mask(struct ssb_device *dev, u64 mask)
 {
-       struct device *dma_dev = ssb_dev->dma_dev;
-       int err = 0;
+       int err;
 
-#ifdef CONFIG_SSB_PCIHOST
-       if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI) {
-               err = pci_set_dma_mask(ssb_dev->bus->host_pci, mask);
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               err = pci_set_dma_mask(dev->bus->host_pci, mask);
                if (err)
                        return err;
-               err = pci_set_consistent_dma_mask(ssb_dev->bus->host_pci, mask);
+               err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask);
                return err;
+       case SSB_BUSTYPE_SSB:
+               return dma_set_mask(dev->dev, mask);
+       default:
+               __ssb_dma_not_implemented(dev);
        }
-#endif
-       dma_dev->coherent_dma_mask = mask;
-       dma_dev->dma_mask = &dma_dev->coherent_dma_mask;
-
-       return err;
+       return -ENOSYS;
 }
 EXPORT_SYMBOL(ssb_dma_set_mask);
 
+void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
+                               dma_addr_t *dma_handle, gfp_t gfp_flags)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               if (gfp_flags & GFP_DMA) {
+                       /* Workaround: The PCI API does not support passing
+                        * a GFP flag. */
+                       return dma_alloc_coherent(&dev->bus->host_pci->dev,
+                                                 size, dma_handle, gfp_flags);
+               }
+               return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle);
+       case SSB_BUSTYPE_SSB:
+               return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags);
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(ssb_dma_alloc_consistent);
+
+void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
+                            void *vaddr, dma_addr_t dma_handle,
+                            gfp_t gfp_flags)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               if (gfp_flags & GFP_DMA) {
+                       /* Workaround: The PCI API does not support passing
+                        * a GFP flag. */
+                       dma_free_coherent(&dev->bus->host_pci->dev,
+                                         size, vaddr, dma_handle);
+                       return;
+               }
+               pci_free_consistent(dev->bus->host_pci, size,
+                                   vaddr, dma_handle);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_free_coherent(dev->dev, size, vaddr, dma_handle);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
+EXPORT_SYMBOL(ssb_dma_free_consistent);
+
 int ssb_bus_may_powerdown(struct ssb_bus *bus)
 {
        struct ssb_chipcommon *cc;
index 97dba0d92348d27692c4f9c10bc6e99c25333cd8..05ec7eef8690601e332c3517baf11002159485b4 100644 (file)
@@ -58,7 +58,6 @@
 #include <linux/syscalls.h>
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
-#include <linux/wireless.h>
 #include <linux/atalk.h>
 #include <linux/loop.h>
 
@@ -1757,64 +1756,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a
        return sys_ioctl(fd, cmd, (unsigned long)tdata);
 }
 
-struct compat_iw_point {
-       compat_caddr_t pointer;
-       __u16 length;
-       __u16 flags;
-};
-
-static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-       struct iwreq __user *iwr;
-       struct iwreq __user *iwr_u;
-       struct iw_point __user *iwp;
-       struct compat_iw_point __user *iwp_u;
-       compat_caddr_t pointer_u;
-       void __user *pointer;
-       __u16 length, flags;
-       int ret;
-
-       iwr_u = compat_ptr(arg);
-       iwp_u = (struct compat_iw_point __user *) &iwr_u->u.data;
-       iwr = compat_alloc_user_space(sizeof(*iwr));
-       if (iwr == NULL)
-               return -ENOMEM;
-
-       iwp = &iwr->u.data;
-
-       if (!access_ok(VERIFY_WRITE, iwr, sizeof(*iwr)))
-               return -EFAULT;
-
-       if (__copy_in_user(&iwr->ifr_ifrn.ifrn_name[0],
-                          &iwr_u->ifr_ifrn.ifrn_name[0],
-                          sizeof(iwr->ifr_ifrn.ifrn_name)))
-               return -EFAULT;
-
-       if (__get_user(pointer_u, &iwp_u->pointer) ||
-           __get_user(length, &iwp_u->length) ||
-           __get_user(flags, &iwp_u->flags))
-               return -EFAULT;
-
-       if (__put_user(compat_ptr(pointer_u), &iwp->pointer) ||
-           __put_user(length, &iwp->length) ||
-           __put_user(flags, &iwp->flags))
-               return -EFAULT;
-
-       ret = sys_ioctl(fd, cmd, (unsigned long) iwr);
-
-       if (__get_user(pointer, &iwp->pointer) ||
-           __get_user(length, &iwp->length) ||
-           __get_user(flags, &iwp->flags))
-               return -EFAULT;
-
-       if (__put_user(ptr_to_compat(pointer), &iwp_u->pointer) ||
-           __put_user(length, &iwp_u->length) ||
-           __put_user(flags, &iwp_u->flags))
-               return -EFAULT;
-
-       return ret;
-}
-
 /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
  * for some operations; this forces use of the newer bridge-utils that
  * use compatiable ioctls
@@ -2495,36 +2436,6 @@ COMPATIBLE_IOCTL(I2C_TENBIT)
 COMPATIBLE_IOCTL(I2C_PEC)
 COMPATIBLE_IOCTL(I2C_RETRIES)
 COMPATIBLE_IOCTL(I2C_TIMEOUT)
-/* wireless */
-COMPATIBLE_IOCTL(SIOCSIWCOMMIT)
-COMPATIBLE_IOCTL(SIOCGIWNAME)
-COMPATIBLE_IOCTL(SIOCSIWNWID)
-COMPATIBLE_IOCTL(SIOCGIWNWID)
-COMPATIBLE_IOCTL(SIOCSIWFREQ)
-COMPATIBLE_IOCTL(SIOCGIWFREQ)
-COMPATIBLE_IOCTL(SIOCSIWMODE)
-COMPATIBLE_IOCTL(SIOCGIWMODE)
-COMPATIBLE_IOCTL(SIOCSIWSENS)
-COMPATIBLE_IOCTL(SIOCGIWSENS)
-COMPATIBLE_IOCTL(SIOCSIWRANGE)
-COMPATIBLE_IOCTL(SIOCSIWPRIV)
-COMPATIBLE_IOCTL(SIOCSIWSTATS)
-COMPATIBLE_IOCTL(SIOCSIWAP)
-COMPATIBLE_IOCTL(SIOCGIWAP)
-COMPATIBLE_IOCTL(SIOCSIWRATE)
-COMPATIBLE_IOCTL(SIOCGIWRATE)
-COMPATIBLE_IOCTL(SIOCSIWRTS)
-COMPATIBLE_IOCTL(SIOCGIWRTS)
-COMPATIBLE_IOCTL(SIOCSIWFRAG)
-COMPATIBLE_IOCTL(SIOCGIWFRAG)
-COMPATIBLE_IOCTL(SIOCSIWTXPOW)
-COMPATIBLE_IOCTL(SIOCGIWTXPOW)
-COMPATIBLE_IOCTL(SIOCSIWRETRY)
-COMPATIBLE_IOCTL(SIOCGIWRETRY)
-COMPATIBLE_IOCTL(SIOCSIWPOWER)
-COMPATIBLE_IOCTL(SIOCGIWPOWER)
-COMPATIBLE_IOCTL(SIOCSIWAUTH)
-COMPATIBLE_IOCTL(SIOCGIWAUTH)
 /* hiddev */
 COMPATIBLE_IOCTL(HIDIOCGVERSION)
 COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
@@ -2755,29 +2666,7 @@ COMPATIBLE_IOCTL(USBDEVFS_IOCTL32)
 HANDLE_IOCTL(I2C_FUNCS, w_long)
 HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
 HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl)
-/* wireless */
-HANDLE_IOCTL(SIOCGIWRANGE, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWPRIV, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWSTATS, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWSPY, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWSPY, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWTHRSPY, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWTHRSPY, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWMLME, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWAPLIST, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWSCAN, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWSCAN, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWESSID, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWESSID, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWNICKN, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWNICKN, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWENCODE, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWENCODE, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWGENIE, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWGENIE, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWENCODEEXT, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWENCODEEXT, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWPMKSA, do_wireless_ioctl)
+/* bridge */
 HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl)
 HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
 /* Not implemented in the native kernel */
index c8d216357865dda3e22bd503df478055b3d888b9..8bb5e87df365ef69cdb4bbbd7de4af05a3d42236 100644 (file)
@@ -272,6 +272,12 @@ enum ethtool_flags {
        ETH_FLAG_LRO            = (1 << 15),    /* LRO is enabled */
 };
 
+struct ethtool_rxnfc {
+       __u32           cmd;
+       __u32           flow_type;
+       __u64           data;
+};
+
 #ifdef __KERNEL__
 
 struct net_device;
@@ -396,6 +402,8 @@ struct ethtool_ops {
        /* the following hooks are obsolete */
        int     (*self_test_count)(struct net_device *);/* use get_sset_count */
        int     (*get_stats_count)(struct net_device *);/* use get_sset_count */
+       int     (*get_rxhash)(struct net_device *, struct ethtool_rxnfc *);
+       int     (*set_rxhash)(struct net_device *, struct ethtool_rxnfc *);
 };
 #endif /* __KERNEL__ */
 
@@ -442,6 +450,9 @@ struct ethtool_ops {
 #define ETHTOOL_GPFLAGS                0x00000027 /* Get driver-private flags bitmap */
 #define ETHTOOL_SPFLAGS                0x00000028 /* Set driver-private flags bitmap */
 
+#define        ETHTOOL_GRXFH           0x00000029 /* Get RX flow hash configuration */
+#define        ETHTOOL_SRXFH           0x0000002a /* Set RX flow hash configuration */
+
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
 #define SPARC_ETH_SSET         ETHTOOL_SSET
@@ -528,4 +539,26 @@ struct ethtool_ops {
 #define WAKE_MAGIC             (1 << 5)
 #define WAKE_MAGICSECURE       (1 << 6) /* only meaningful if WAKE_MAGIC */
 
+/* L3-L4 network traffic flow types */
+#define        TCP_V4_FLOW     0x01
+#define        UDP_V4_FLOW     0x02
+#define        SCTP_V4_FLOW    0x03
+#define        AH_ESP_V4_FLOW  0x04
+#define        TCP_V6_FLOW     0x05
+#define        UDP_V6_FLOW     0x06
+#define        SCTP_V6_FLOW    0x07
+#define        AH_ESP_V6_FLOW  0x08
+
+/* L3-L4 network traffic flow hash options */
+#define        RXH_DEV_PORT    (1 << 0)
+#define        RXH_L2DA        (1 << 1)
+#define        RXH_VLAN        (1 << 2)
+#define        RXH_L3_PROTO    (1 << 3)
+#define        RXH_IP_SRC      (1 << 4)
+#define        RXH_IP_DST      (1 << 5)
+#define        RXH_L4_B_0_1    (1 << 6) /* src port in case of TCP/UDP/SCTP */
+#define        RXH_L4_B_2_3    (1 << 7) /* dst port in case of TCP/UDP/SCTP */
+#define        RXH_DISCARD     (1 << 31)
+
+
 #endif /* _LINUX_ETHTOOL_H */
index 2998e3b5f166bd245132d44578708ea3dd42c518..cffd6d0094f9c00b2a93d735d7c07f15fd13c8c6 100644 (file)
@@ -469,6 +469,40 @@ struct ieee80211s_hdr {
        u8 eaddr3[6];
 } __attribute__ ((packed));
 
+/**
+ * struct ieee80211_quiet_ie
+ *
+ * This structure refers to "Quiet information element"
+ */
+struct ieee80211_quiet_ie {
+       u8 count;
+       u8 period;
+       __le16 duration;
+       __le16 offset;
+} __attribute__ ((packed));
+
+/**
+ * struct ieee80211_msrment_ie
+ *
+ * This structure refers to "Measurement Request/Report information element"
+ */
+struct ieee80211_msrment_ie {
+       u8 token;
+       u8 mode;
+       u8 type;
+       u8 request[0];
+} __attribute__ ((packed));
+
+/**
+ * struct ieee80211_channel_sw_ie
+ *
+ * This structure refers to "Channel Switch Announcement information element"
+ */
+struct ieee80211_channel_sw_ie {
+       u8 mode;
+       u8 new_ch_num;
+       u8 count;
+} __attribute__ ((packed));
 
 struct ieee80211_mgmt {
        __le16 frame_control;
@@ -544,10 +578,15 @@ struct ieee80211_mgmt {
                                        u8 action_code;
                                        u8 element_id;
                                        u8 length;
-                                       u8 switch_mode;
-                                       u8 new_chan;
-                                       u8 switch_count;
+                                       struct ieee80211_channel_sw_ie sw_elem;
                                } __attribute__((packed)) chan_switch;
+                               struct{
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       u8 element_id;
+                                       u8 length;
+                                       struct ieee80211_msrment_ie msr_elem;
+                               } __attribute__((packed)) measurement;
                                struct{
                                        u8 action_code;
                                        u8 dialog_token;
@@ -700,11 +739,21 @@ struct ieee80211_ht_addt_info {
 #define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
 #define WLAN_CAPABILITY_PBCC           (1<<6)
 #define WLAN_CAPABILITY_CHANNEL_AGILITY        (1<<7)
+
 /* 802.11h */
 #define WLAN_CAPABILITY_SPECTRUM_MGMT  (1<<8)
 #define WLAN_CAPABILITY_QOS            (1<<9)
 #define WLAN_CAPABILITY_SHORT_SLOT_TIME        (1<<10)
 #define WLAN_CAPABILITY_DSSS_OFDM      (1<<13)
+/* measurement */
+#define IEEE80211_SPCT_MSR_RPRT_MODE_LATE      (1<<0)
+#define IEEE80211_SPCT_MSR_RPRT_MODE_INCAPABLE (1<<1)
+#define IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED   (1<<2)
+
+#define IEEE80211_SPCT_MSR_RPRT_TYPE_BASIC     0
+#define IEEE80211_SPCT_MSR_RPRT_TYPE_CCA       1
+#define IEEE80211_SPCT_MSR_RPRT_TYPE_RPI       2
+
 
 /* 802.11g ERP information element */
 #define WLAN_ERP_NON_ERP_PRESENT (1<<0)
@@ -875,6 +924,15 @@ enum ieee80211_category {
        WLAN_CATEGORY_WMM = 17,
 };
 
+/* SPECTRUM_MGMT action code */
+enum ieee80211_spectrum_mgmt_actioncode {
+       WLAN_ACTION_SPCT_MSR_REQ = 0,
+       WLAN_ACTION_SPCT_MSR_RPRT = 1,
+       WLAN_ACTION_SPCT_TPC_REQ = 2,
+       WLAN_ACTION_SPCT_TPC_RPRT = 3,
+       WLAN_ACTION_SPCT_CHL_SWITCH = 4,
+};
+
 /* BACK action code */
 enum ieee80211_back_actioncode {
        WLAN_ACTION_ADDBA_REQ = 0,
index f5a1a0db2e8ecb5d79c25d1483610c93e29546ac..7bb3c095c15b4fb33d0ffd227ac9d39f86b9d297 100644 (file)
@@ -228,7 +228,6 @@ extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
 extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
                struct group_filter __user *optval, int __user *optlen);
 extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif);
-extern void ip_mr_init(void);
 extern void ip_mc_init_dev(struct in_device *);
 extern void ip_mc_destroy_dev(struct in_device *);
 extern void ip_mc_up(struct in_device *);
index 80335b7d77c5bea2d9f64320c46fb19dfcb60cc2..c4335faebb63eba7eb9771dc8f937b1fa82103ac 100644 (file)
@@ -84,7 +84,11 @@ struct net_lro_mgr {
                                    from received packets and eth protocol
                                    is still ETH_P_8021Q */
 
-       u32 ip_summed;      /* Set in non generated SKBs in page mode */
+       /*
+        * Set for generated SKBs that are not added to
+        * the frag list in fragmented mode
+        */
+       u32 ip_summed;
        u32 ip_summed_aggr; /* Set in aggregated SKBs: CHECKSUM_UNNECESSARY
                             * or CHECKSUM_NONE */
 
index cde056e0818172aeb7a5ae8d69998fb83d41796e..391ad0843a46af6b4af10abc5b7b552a26d95c0e 100644 (file)
@@ -163,6 +163,8 @@ struct ipv6_devconf {
 #ifdef CONFIG_IPV6_MROUTE
        __s32           mc_forwarding;
 #endif
+       __s32           disable_ipv6;
+       __s32           accept_dad;
        void            *sysctl;
 };
 
@@ -194,6 +196,8 @@ enum {
        DEVCONF_OPTIMISTIC_DAD,
        DEVCONF_ACCEPT_SOURCE_ROUTE,
        DEVCONF_MC_FORWARDING,
+       DEVCONF_DISABLE_IPV6,
+       DEVCONF_ACCEPT_DAD,
        DEVCONF_MAX
 };
 
index de4decfa1bfc7a9ef0f0f3399055b34f33fd73f7..07112ee9293a5aa25b8186db6e19c990c7863f11 100644 (file)
@@ -144,11 +144,37 @@ static inline int ip_mroute_opt(int opt)
 }
 #endif
 
+#ifdef CONFIG_IP_MROUTE
 extern int ip_mroute_setsockopt(struct sock *, int, char __user *, int);
 extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
 extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);
-extern void ip_mr_init(void);
+extern int ip_mr_init(void);
+#else
+static inline
+int ip_mroute_setsockopt(struct sock *sock,
+                        int optname, char __user *optval, int optlen)
+{
+       return -ENOPROTOOPT;
+}
+
+static inline
+int ip_mroute_getsockopt(struct sock *sock,
+                        int optname, char __user *optval, int __user *optlen)
+{
+       return -ENOPROTOOPT;
+}
 
+static inline
+int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static inline int ip_mr_init(void)
+{
+       return 0;
+}
+#endif
 
 struct vif_device
 {
index e7989593142be626d5c73ecc18be5baf0497cd51..5cf50473a10f0f6877263bb822a59c865b66163f 100644 (file)
@@ -131,11 +131,44 @@ static inline int ip6_mroute_opt(int opt)
 
 struct sock;
 
+#ifdef CONFIG_IPV6_MROUTE
 extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int);
 extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
 extern int ip6_mr_input(struct sk_buff *skb);
 extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg);
-extern void ip6_mr_init(void);
+extern int ip6_mr_init(void);
+extern void ip6_mr_cleanup(void);
+#else
+static inline
+int ip6_mroute_setsockopt(struct sock *sock,
+                         int optname, char __user *optval, int optlen)
+{
+       return -ENOPROTOOPT;
+}
+
+static inline
+int ip6_mroute_getsockopt(struct sock *sock,
+                         int optname, char __user *optval, int __user *optlen)
+{
+       return -ENOPROTOOPT;
+}
+
+static inline
+int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static inline int ip6_mr_init(void)
+{
+       return 0;
+}
+
+static inline void ip6_mr_cleanup(void)
+{
+       return;
+}
+#endif
 
 struct mif_device
 {
index 1304ad2d71052a7e5d37b34eb9865170fa6cedac..56dadb528f6737fcd5f111c100f875288f6b4f0c 100644 (file)
@@ -88,6 +88,8 @@ struct wireless_dev;
 #define NETDEV_TX_BUSY 1       /* driver tx path was busy*/
 #define NETDEV_TX_LOCKED -1    /* driver tx lock was already taken */
 
+#ifdef  __KERNEL__
+
 /*
  *     Compute the worst case header length according to the protocols
  *     used.
@@ -114,6 +116,8 @@ struct wireless_dev;
 #define MAX_HEADER (LL_MAX_HEADER + 48)
 #endif
 
+#endif  /*  __KERNEL__  */
+
 struct net_device_subqueue
 {
        /* Give a control state for each queue.  This struct may contain
index aa8411e2a1606fc9fbf2f8869e5f233885d3e56a..2be7c63bc0f2591386b24db123c1aa280b15e382 100644 (file)
@@ -241,7 +241,10 @@ enum nl80211_attrs {
        NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
 };
 
-#define NL80211_MAX_SUPP_RATES 32
+#define NL80211_MAX_SUPP_RATES                 32
+#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY      0
+#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY    16
+#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY    24
 
 /**
  * enum nl80211_iftype - (virtual) interface types
index e3ab21d7fc7f1973ec9483885012d83e800e1eb9..c5f6e54ec6ae6dd42106b340823e85f84250ec04 100644 (file)
  * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
  * RFKILL_TYPE_UWB: switch is on a ultra wideband device.
  * RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
+ * RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
  */
 enum rfkill_type {
        RFKILL_TYPE_WLAN ,
        RFKILL_TYPE_BLUETOOTH,
        RFKILL_TYPE_UWB,
        RFKILL_TYPE_WIMAX,
+       RFKILL_TYPE_WWAN,
        RFKILL_TYPE_MAX,
 };
 
 enum rfkill_state {
-       RFKILL_STATE_OFF        = 0,
-       RFKILL_STATE_ON         = 1,
+       RFKILL_STATE_SOFT_BLOCKED = 0,  /* Radio output blocked */
+       RFKILL_STATE_UNBLOCKED    = 1,  /* Radio output allowed */
+       RFKILL_STATE_HARD_BLOCKED = 2,  /* Output blocked, non-overrideable */
 };
 
+/*
+ * These are DEPRECATED, drivers using them should be verified to
+ * comply with the rfkill usage guidelines in Documentation/rfkill.txt
+ * and then converted to use the new names for rfkill_state
+ */
+#define RFKILL_STATE_OFF RFKILL_STATE_SOFT_BLOCKED
+#define RFKILL_STATE_ON  RFKILL_STATE_UNBLOCKED
+
 /**
  * struct rfkill - rfkill control structure.
  * @name: Name of the switch.
  * @type: Radio type which the button controls, the value stored
  *     here should be a value from enum rfkill_type.
- * @state: State of the switch (on/off).
+ * @state: State of the switch, "UNBLOCKED" means radio can operate.
  * @user_claim_unsupported: Whether the hardware supports exclusive
  *     RF-kill control by userspace. Set this before registering.
  * @user_claim: Set when the switch is controlled exlusively by userspace.
@@ -61,6 +72,12 @@ enum rfkill_state {
  * @data: Pointer to the RF button drivers private data which will be
  *     passed along when toggling radio state.
  * @toggle_radio(): Mandatory handler to control state of the radio.
+ *     only RFKILL_STATE_SOFT_BLOCKED and RFKILL_STATE_UNBLOCKED are
+ *     valid parameters.
+ * @get_state(): handler to read current radio state from hardware,
+ *      may be called from atomic context, should return 0 on success.
+ *      Either this handler OR judicious use of rfkill_force_state() is
+ *      MANDATORY for any driver capable of RFKILL_STATE_HARD_BLOCKED.
  * @led_trigger: A LED trigger for this button's LED.
  * @dev: Device structure integrating the switch into device tree.
  * @node: Used to place switch into list of all switches known to the
@@ -80,6 +97,7 @@ struct rfkill {
 
        void *data;
        int (*toggle_radio)(void *data, enum rfkill_state state);
+       int (*get_state)(void *data, enum rfkill_state *state);
 
 #ifdef CONFIG_RFKILL_LEDS
        struct led_trigger led_trigger;
@@ -95,6 +113,21 @@ void rfkill_free(struct rfkill *rfkill);
 int rfkill_register(struct rfkill *rfkill);
 void rfkill_unregister(struct rfkill *rfkill);
 
+int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state);
+
+/**
+ * rfkill_state_complement - return complementar state
+ * @state: state to return the complement of
+ *
+ * Returns RFKILL_STATE_SOFT_BLOCKED if @state is RFKILL_STATE_UNBLOCKED,
+ * returns RFKILL_STATE_UNBLOCKED otherwise.
+ */
+static inline enum rfkill_state rfkill_state_complement(enum rfkill_state state)
+{
+       return (state == RFKILL_STATE_UNBLOCKED) ?
+               RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED;
+}
+
 /**
  * rfkill_get_led_name - Get the LED trigger name for the button's LED.
  * This function might return a NULL pointer if registering of the
@@ -110,4 +143,11 @@ static inline char *rfkill_get_led_name(struct rfkill *rfkill)
 #endif
 }
 
+/* rfkill notification chain */
+#define RFKILL_STATE_CHANGED           0x0001  /* state of a normal rfkill
+                                                  switch has changed */
+
+int register_rfkill_notifier(struct notifier_block *nb);
+int unregister_rfkill_notifier(struct notifier_block *nb);
+
 #endif /* RFKILL_H */
index 50dfd0dc4093c6137c70c7ae6a50e1379ec08508..0fe5a0ded3eac17f4075d2cbdfcfb88153031238 100644 (file)
@@ -137,9 +137,6 @@ struct ssb_device {
        const struct ssb_bus_ops *ops;
 
        struct device *dev;
-       /* Pointer to the device that has to be used for
-        * any DMA related operation. */
-       struct device *dma_dev;
 
        struct ssb_bus *bus;
        struct ssb_device_id id;
@@ -399,13 +396,151 @@ static inline void ssb_block_write(struct ssb_device *dev, const void *buffer,
 #endif /* CONFIG_SSB_BLOCKIO */
 
 
+/* The SSB DMA API. Use this API for any DMA operation on the device.
+ * This API basically is a wrapper that calls the correct DMA API for
+ * the host device type the SSB device is attached to. */
+
 /* Translation (routing) bits that need to be ORed to DMA
  * addresses before they are given to a device. */
 extern u32 ssb_dma_translation(struct ssb_device *dev);
 #define SSB_DMA_TRANSLATION_MASK       0xC0000000
 #define SSB_DMA_TRANSLATION_SHIFT      30
 
-extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask);
+extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask);
+
+extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
+                                      dma_addr_t *dma_handle, gfp_t gfp_flags);
+extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
+                                   void *vaddr, dma_addr_t dma_handle,
+                                   gfp_t gfp_flags);
+
+static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
+{
+#ifdef CONFIG_SSB_DEBUG
+       printk(KERN_ERR "SSB: BUG! Calling DMA API for "
+              "unsupported bustype %d\n", dev->bus->bustype);
+#endif /* DEBUG */
+}
+
+static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               return pci_dma_mapping_error(addr);
+       case SSB_BUSTYPE_SSB:
+               return dma_mapping_error(addr);
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+       return -ENOSYS;
+}
+
+static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p,
+                                           size_t size, enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               return pci_map_single(dev->bus->host_pci, p, size, dir);
+       case SSB_BUSTYPE_SSB:
+               return dma_map_single(dev->dev, p, size, dir);
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+       return 0;
+}
+
+static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr,
+                                       size_t size, enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_unmap_single(dev->dev, dma_addr, size, dir);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
+
+static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev,
+                                              dma_addr_t dma_addr,
+                                              size_t size,
+                                              enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
+                                           size, dir);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
+
+static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev,
+                                                 dma_addr_t dma_addr,
+                                                 size_t size,
+                                                 enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
+                                              size, dir);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_sync_single_for_device(dev->dev, dma_addr, size, dir);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
+
+static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev,
+                                                    dma_addr_t dma_addr,
+                                                    unsigned long offset,
+                                                    size_t size,
+                                                    enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               /* Just sync everything. That's all the PCI API can do. */
+               pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
+                                           offset + size, dir);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset,
+                                             size, dir);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
+
+static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev,
+                                                       dma_addr_t dma_addr,
+                                                       unsigned long offset,
+                                                       size_t size,
+                                                       enum dma_data_direction dir)
+{
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_PCI:
+               /* Just sync everything. That's all the PCI API can do. */
+               pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
+                                              offset + size, dir);
+               return;
+       case SSB_BUSTYPE_SSB:
+               dma_sync_single_range_for_device(dev->dev, dma_addr, offset,
+                                                size, dir);
+               return;
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+}
 
 
 #ifdef CONFIG_SSB_PCIHOST
index 4a95a0e5eeca20753246406664254b67d949d7ad..d7958f9b52cba59e15dfb8a26e4ce5b04ea1309a 100644 (file)
@@ -677,6 +677,19 @@ struct     iw_point
   __u16                flags;          /* Optional params */
 };
 
+#ifdef __KERNEL__
+#ifdef CONFIG_COMPAT
+
+#include <linux/compat.h>
+
+struct compat_iw_point {
+       compat_caddr_t pointer;
+       __u16 length;
+       __u16 flags;
+};
+#endif
+#endif
+
 /*
  *     A frequency
  *     For numbers lower than 10^9, we encode the number in 'm' and
@@ -1100,6 +1113,21 @@ struct iw_event
 #define IW_EV_POINT_LEN        (IW_EV_LCP_LEN + sizeof(struct iw_point) - \
                         IW_EV_POINT_OFF)
 
+#ifdef __KERNEL__
+#ifdef CONFIG_COMPAT
+struct __compat_iw_event {
+       __u16           len;                    /* Real length of this stuff */
+       __u16           cmd;                    /* Wireless IOCTL */
+       compat_caddr_t  pointer;
+};
+#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer)
+#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length)
+#define IW_EV_COMPAT_POINT_LEN \
+       (IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \
+        IW_EV_COMPAT_POINT_OFF)
+#endif
+#endif
+
 /* Size of the Event prefix when packed in stream */
 #define IW_EV_LCP_PK_LEN       (4)
 /* Size of the various events when packed in stream */
index 7f7db8d579347d5804ebf0e7f8c33fd771981e86..c2222ee74d66281e04119bcde109a645a49e0ef8 100644 (file)
@@ -365,6 +365,12 @@ static inline int ipv6_addr_any(const struct in6_addr *a)
                 a->s6_addr32[2] | a->s6_addr32[3] ) == 0); 
 }
 
+static inline int ipv6_addr_loopback(const struct in6_addr *a)
+{
+       return ((a->s6_addr32[0] | a->s6_addr32[1] |
+                a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0);
+}
+
 static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
 {
        return ((a->s6_addr32[0] | a->s6_addr32[1] |
index 369d50e08b99619874ad8d4b6588228871728c53..51b9a37de991198999c48a8bf45d8b05a49bf3ec 100644 (file)
 #define EIWCOMMIT      EINPROGRESS
 
 /* Flags available in struct iw_request_info */
-#define IW_REQUEST_FLAG_NONE   0x0000  /* No flag so far */
+#define IW_REQUEST_FLAG_COMPAT 0x0001  /* Compat ioctl call */
 
 /* Type of headers we know about (basically union iwreq_data) */
 #define IW_HEADER_TYPE_NULL    0       /* Not available */
@@ -478,105 +478,58 @@ extern void wireless_spy_update(struct net_device *      dev,
  * Function that are so simple that it's more efficient inlining them
  */
 
-/*------------------------------------------------------------------*/
-/*
- * Wrapper to add an Wireless Event to a stream of events.
- */
-static inline char *
-iwe_stream_add_event(char *    stream,         /* Stream of events */
-                    char *     ends,           /* End of stream */
-                    struct iw_event *iwe,      /* Payload */
-                    int        event_len)      /* Real size of payload */
+static inline int iwe_stream_lcp_len(struct iw_request_info *info)
 {
-       /* Check if it's possible */
-       if(likely((stream + event_len) < ends)) {
-               iwe->len = event_len;
-               /* Beware of alignement issues on 64 bits */
-               memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
-               memcpy(stream + IW_EV_LCP_LEN,
-                      ((char *) iwe) + IW_EV_LCP_LEN,
-                      event_len - IW_EV_LCP_LEN);
-               stream += event_len;
-       }
-       return stream;
+#ifdef CONFIG_COMPAT
+       if (info->flags & IW_REQUEST_FLAG_COMPAT)
+               return IW_EV_COMPAT_LCP_LEN;
+#endif
+       return IW_EV_LCP_LEN;
 }
 
-/*------------------------------------------------------------------*/
-/*
- * Wrapper to add an short Wireless Event containing a pointer to a
- * stream of events.
- */
-static inline char *
-iwe_stream_add_point(char *    stream,         /* Stream of events */
-                    char *     ends,           /* End of stream */
-                    struct iw_event *iwe,      /* Payload length + flags */
-                    char *     extra)          /* More payload */
+static inline int iwe_stream_point_len(struct iw_request_info *info)
 {
-       int     event_len = IW_EV_POINT_LEN + iwe->u.data.length;
-       /* Check if it's possible */
-       if(likely((stream + event_len) < ends)) {
-               iwe->len = event_len;
-               memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
-               memcpy(stream + IW_EV_LCP_LEN,
-                      ((char *) iwe) + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
-                      IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
-               memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
-               stream += event_len;
-       }
-       return stream;
+#ifdef CONFIG_COMPAT
+       if (info->flags & IW_REQUEST_FLAG_COMPAT)
+               return IW_EV_COMPAT_POINT_LEN;
+#endif
+       return IW_EV_POINT_LEN;
 }
 
-/*------------------------------------------------------------------*/
-/*
- * Wrapper to add a value to a Wireless Event in a stream of events.
- * Be careful, this one is tricky to use properly :
- * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
- */
-static inline char *
-iwe_stream_add_value(char *    event,          /* Event in the stream */
-                    char *     value,          /* Value in event */
-                    char *     ends,           /* End of stream */
-                    struct iw_event *iwe,      /* Payload */
-                    int        event_len)      /* Real size of payload */
+static inline int iwe_stream_event_len_adjust(struct iw_request_info *info,
+                                             int event_len)
 {
-       /* Don't duplicate LCP */
-       event_len -= IW_EV_LCP_LEN;
-
-       /* Check if it's possible */
-       if(likely((value + event_len) < ends)) {
-               /* Add new value */
-               memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
-               value += event_len;
-               /* Patch LCP */
-               iwe->len = value - event;
-               memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
+#ifdef CONFIG_COMPAT
+       if (info->flags & IW_REQUEST_FLAG_COMPAT) {
+               event_len -= IW_EV_LCP_LEN;
+               event_len += IW_EV_COMPAT_LCP_LEN;
        }
-       return value;
+#endif
+
+       return event_len;
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Wrapper to add an Wireless Event to a stream of events.
- * Same as above, with explicit error check...
  */
 static inline char *
-iwe_stream_check_add_event(char *      stream,         /* Stream of events */
-                          char *       ends,           /* End of stream */
-                          struct iw_event *iwe,        /* Payload */
-                          int          event_len,      /* Size of payload */
-                          int *        perr)           /* Error report */
+iwe_stream_add_event(struct iw_request_info *info, char *stream, char *ends,
+                    struct iw_event *iwe, int event_len)
 {
-       /* Check if it's possible, set error if not */
+       int lcp_len = iwe_stream_lcp_len(info);
+
+       event_len = iwe_stream_event_len_adjust(info, event_len);
+
+       /* Check if it's possible */
        if(likely((stream + event_len) < ends)) {
                iwe->len = event_len;
                /* Beware of alignement issues on 64 bits */
                memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
-               memcpy(stream + IW_EV_LCP_LEN,
-                      ((char *) iwe) + IW_EV_LCP_LEN,
-                      event_len - IW_EV_LCP_LEN);
+               memcpy(stream + lcp_len, &iwe->u,
+                      event_len - lcp_len);
                stream += event_len;
-       } else
-               *perr = -E2BIG;
+       }
        return stream;
 }
 
@@ -584,27 +537,25 @@ iwe_stream_check_add_event(char * stream,         /* Stream of events */
 /*
  * Wrapper to add an short Wireless Event containing a pointer to a
  * stream of events.
- * Same as above, with explicit error check...
  */
 static inline char *
-iwe_stream_check_add_point(char *      stream,         /* Stream of events */
-                          char *       ends,           /* End of stream */
-                          struct iw_event *iwe,        /* Payload length + flags */
-                          char *       extra,          /* More payload */
-                          int *        perr)           /* Error report */
+iwe_stream_add_point(struct iw_request_info *info, char *stream, char *ends,
+                    struct iw_event *iwe, char *extra)
 {
-       int     event_len = IW_EV_POINT_LEN + iwe->u.data.length;
+       int event_len = iwe_stream_point_len(info) + iwe->u.data.length;
+       int point_len = iwe_stream_point_len(info);
+       int lcp_len   = iwe_stream_lcp_len(info);
+
        /* Check if it's possible */
        if(likely((stream + event_len) < ends)) {
                iwe->len = event_len;
                memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
-               memcpy(stream + IW_EV_LCP_LEN,
-                      ((char *) iwe) + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
+               memcpy(stream + lcp_len,
+                      ((char *) &iwe->u) + IW_EV_POINT_OFF,
                       IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
-               memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
+               memcpy(stream + point_len, extra, iwe->u.data.length);
                stream += event_len;
-       } else
-               *perr = -E2BIG;
+       }
        return stream;
 }
 
@@ -613,29 +564,25 @@ iwe_stream_check_add_point(char * stream,         /* Stream of events */
  * Wrapper to add a value to a Wireless Event in a stream of events.
  * Be careful, this one is tricky to use properly :
  * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
- * Same as above, with explicit error check...
  */
 static inline char *
-iwe_stream_check_add_value(char *      event,          /* Event in the stream */
-                          char *       value,          /* Value in event */
-                          char *       ends,           /* End of stream */
-                          struct iw_event *iwe,        /* Payload */
-                          int          event_len,      /* Size of payload */
-                          int *        perr)           /* Error report */
+iwe_stream_add_value(struct iw_request_info *info, char *event, char *value,
+                    char *ends, struct iw_event *iwe, int event_len)
 {
+       int lcp_len = iwe_stream_lcp_len(info);
+
        /* Don't duplicate LCP */
        event_len -= IW_EV_LCP_LEN;
 
        /* Check if it's possible */
        if(likely((value + event_len) < ends)) {
                /* Add new value */
-               memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
+               memcpy(value, &iwe->u, event_len);
                value += event_len;
                /* Patch LCP */
                iwe->len = value - event;
-               memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
-       } else
-               *perr = -E2BIG;
+               memcpy(event, (char *) iwe, lcp_len);
+       }
        return value;
 }
 
index 7ab4ff6159a24f063ae599a82033b0bcb7c12a42..02c79e6b309e69e007ce57859cde1a51432e1830 100644 (file)
@@ -595,7 +595,12 @@ enum ieee80211_key_flags {
  * @flags: key flags, see &enum ieee80211_key_flags.
  * @keyidx: the key index (0-3)
  * @keylen: key material length
- * @key: key material
+ * @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte)
+ *     data block:
+ *     - Temporal Encryption Key (128 bits)
+ *     - Temporal Authenticator Tx MIC Key (64 bits)
+ *     - Temporal Authenticator Rx MIC Key (64 bits)
+ *
  */
 struct ieee80211_key_conf {
        enum ieee80211_key_alg alg;
@@ -733,8 +738,11 @@ enum ieee80211_hw_flags {
  * @conf: &struct ieee80211_conf, device configuration, don't use.
  *
  * @workqueue: single threaded workqueue available for driver use,
- *     allocated by mac80211 on registration and flushed on
- *     unregistration.
+ *     allocated by mac80211 on registration and flushed when an
+ *     interface is removed.
+ *     NOTICE: All work performed on this workqueue should NEVER
+ *     acquire the RTNL lock (i.e. Don't use the function
+ *     ieee80211_iterate_active_interfaces())
  *
  * @priv: pointer to private area that was allocated for driver use
  *     along with this structure.
index 8df751b3be55bc2c5b15719f55be5188e1045738..f90443045c70467cbfd854845806b78d69e872e5 100644 (file)
@@ -95,6 +95,11 @@ extern struct list_head net_namespace_list;
 #ifdef CONFIG_NET_NS
 extern void __put_net(struct net *net);
 
+static inline int net_alive(struct net *net)
+{
+       return net && atomic_read(&net->count);
+}
+
 static inline struct net *get_net(struct net *net)
 {
        atomic_inc(&net->count);
@@ -125,6 +130,12 @@ int net_eq(const struct net *net1, const struct net *net2)
        return net1 == net2;
 }
 #else
+
+static inline int net_alive(struct net *net)
+{
+       return 1;
+}
+
 static inline struct net *get_net(struct net *net)
 {
        return net;
index 80b31d826b7a8a3f3765bf0dc6fc569eefc930da..6d76a39a9c5b4cdf08842fd6e46c482afbfe72f3 100644 (file)
@@ -12,6 +12,8 @@ extern int wext_proc_init(struct net *net);
 extern void wext_proc_exit(struct net *net);
 extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
                             void __user *arg);
+extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
+                                   unsigned long arg);
 #else
 static inline int wext_proc_init(struct net *net)
 {
@@ -26,6 +28,11 @@ static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned
 {
        return -EINVAL;
 }
+static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
+                                          unsigned long arg)
+{
+       return -EINVAL;
+}
 #endif
 
 #endif /* __NET_WEXT_H */
index f6944ecd5b2ec000e28e6ac5c558706918d05afd..472676dd550e9693dd91131b7a1b17bad3dd06f5 100644 (file)
@@ -2107,6 +2107,10 @@ int netif_receive_skb(struct sk_buff *skb)
 
        rcu_read_lock();
 
+       /* Don't receive packets in an exiting network namespace */
+       if (!net_alive(dev_net(skb->dev)))
+               goto out;
+
 #ifdef CONFIG_NET_CLS_ACT
        if (skb->tc_verd & TC_NCLS) {
                skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
@@ -3034,7 +3038,7 @@ EXPORT_SYMBOL(dev_unicast_delete);
 /**
  *     dev_unicast_add         - add a secondary unicast address
  *     @dev: device
- *     @addr: address to delete
+ *     @addr: address to add
  *     @alen: length of @addr
  *
  *     Add a secondary unicast address to the device or increase
index 0133b5ebd545287be9a2ee19d8fbf75db8e9ca59..14ada537f895c10f86006b63b4ba4f312eb610d3 100644 (file)
@@ -209,6 +209,36 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
        return 0;
 }
 
+static int ethtool_set_rxhash(struct net_device *dev, void __user *useraddr)
+{
+       struct ethtool_rxnfc cmd;
+
+       if (!dev->ethtool_ops->set_rxhash)
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+               return -EFAULT;
+
+       return dev->ethtool_ops->set_rxhash(dev, &cmd);
+}
+
+static int ethtool_get_rxhash(struct net_device *dev, void __user *useraddr)
+{
+       struct ethtool_rxnfc info;
+
+       if (!dev->ethtool_ops->get_rxhash)
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&info, useraddr, sizeof(info)))
+               return -EFAULT;
+
+       dev->ethtool_ops->get_rxhash(dev, &info);
+
+       if (copy_to_user(useraddr, &info, sizeof(info)))
+               return -EFAULT;
+       return 0;
+}
+
 static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
 {
        struct ethtool_regs regs;
@@ -826,6 +856,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GGSO:
        case ETHTOOL_GFLAGS:
        case ETHTOOL_GPFLAGS:
+       case ETHTOOL_GRXFH:
                break;
        default:
                if (!capable(CAP_NET_ADMIN))
@@ -977,6 +1008,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
                rc = ethtool_set_value(dev, useraddr,
                                       dev->ethtool_ops->set_priv_flags);
                break;
+       case ETHTOOL_GRXFH:
+               rc = ethtool_get_rxhash(dev, useraddr);
+               break;
+       case ETHTOOL_SRXFH:
+               rc = ethtool_set_rxhash(dev, useraddr);
+               break;
        default:
                rc = -EOPNOTSUPP;
        }
index 72b4c184dd84a4d583a20ef0ed5dbd06618f5757..7c52fe277b62441966f758b25fad9acef18a10d0 100644 (file)
@@ -140,6 +140,9 @@ static void cleanup_net(struct work_struct *work)
        struct pernet_operations *ops;
        struct net *net;
 
+       /* Be very certain incoming network packets will not find us */
+       rcu_barrier();
+
        net = container_of(work, struct net, work);
 
        mutex_lock(&net_mutex);
index 2df012be973d4f580f2f6733c297e6cc6f5ad9cb..7c571560e9d2f411726590a9ab0f9586464306fd 100644 (file)
@@ -1290,12 +1290,14 @@ static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
 {
        unsigned int nr_pages = spd->nr_pages;
        unsigned int poff, plen, len, toff, tlen;
-       int headlen, seg;
+       int headlen, seg, error = 0;
 
        toff = *offset;
        tlen = *total_len;
-       if (!tlen)
+       if (!tlen) {
+               error = 1;
                goto err;
+       }
 
        /*
         * if the offset is greater than the linear part, go directly to
@@ -1337,7 +1339,8 @@ static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
                 * just jump directly to update and return, no point
                 * in going over fragments when the output is full.
                 */
-               if (spd_fill_page(spd, virt_to_page(p), plen, poff, skb))
+               error = spd_fill_page(spd, virt_to_page(p), plen, poff, skb);
+               if (error)
                        goto done;
 
                tlen -= plen;
@@ -1367,7 +1370,8 @@ map_frag:
                if (!plen)
                        break;
 
-               if (spd_fill_page(spd, f->page, plen, poff, skb))
+               error = spd_fill_page(spd, f->page, plen, poff, skb);
+               if (error)
                        break;
 
                tlen -= plen;
@@ -1380,7 +1384,10 @@ done:
                return 0;
        }
 err:
-       return 1;
+       /* update the offset to reflect the linear part skip, if any */
+       if (!error)
+               *offset = toff;
+       return error;
 }
 
 /*
index 822606b615cae8851955f03011646478f9658fbb..973832dd7faf6a56c189290f89a1d33e87184871 100644 (file)
@@ -43,8 +43,9 @@ static const char *ieee80211_modes[] = {
 
 #define MAX_CUSTOM_LEN 64
 static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
-                                          char *start, char *stop,
-                                          struct ieee80211_network *network)
+                                     char *start, char *stop,
+                                     struct ieee80211_network *network,
+                                     struct iw_request_info *info)
 {
        char custom[MAX_CUSTOM_LEN];
        char *p;
@@ -57,7 +58,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
-       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
+       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
 
        /* Remaining entries will be displayed in the order we provide them */
 
@@ -66,17 +67,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
        iwe.u.data.flags = 1;
        if (network->flags & NETWORK_EMPTY_ESSID) {
                iwe.u.data.length = sizeof("<hidden>");
-               start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
+               start = iwe_stream_add_point(info, start, stop,
+                                            &iwe, "<hidden>");
        } else {
                iwe.u.data.length = min(network->ssid_len, (u8) 32);
-               start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
+               start = iwe_stream_add_point(info, start, stop,
+                                            &iwe, network->ssid);
        }
 
        /* Add the protocol name */
        iwe.cmd = SIOCGIWNAME;
        snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
                 ieee80211_modes[network->mode]);
-       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
+       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
 
        /* Add mode */
        iwe.cmd = SIOCGIWMODE;
@@ -86,7 +89,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
                else
                        iwe.u.mode = IW_MODE_ADHOC;
 
-               start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
+               start = iwe_stream_add_event(info, start, stop,
+                                            &iwe, IW_EV_UINT_LEN);
        }
 
        /* Add channel and frequency */
@@ -95,7 +99,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
        iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
        iwe.u.freq.e = 6;
        iwe.u.freq.i = 0;
-       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
+       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
 
        /* Add encryption capability */
        iwe.cmd = SIOCGIWENCODE;
@@ -104,12 +108,13 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
        else
                iwe.u.data.flags = IW_ENCODE_DISABLED;
        iwe.u.data.length = 0;
-       start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
+       start = iwe_stream_add_point(info, start, stop,
+                                    &iwe, network->ssid);
 
        /* Add basic and extended rates */
        /* Rate : stuffing multiple values in a single event require a bit
         * more of magic - Jean II */
-       current_val = start + IW_EV_LCP_LEN;
+       current_val = start + iwe_stream_lcp_len(info);
        iwe.cmd = SIOCGIWRATE;
        /* Those two flags are ignored... */
        iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
@@ -124,17 +129,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
                /* Bit rate given in 500 kb/s units (+ 0x80) */
                iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
                /* Add new value to event */
-               current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
+               current_val = iwe_stream_add_value(info, start, current_val,
+                                                  stop, &iwe, IW_EV_PARAM_LEN);
        }
        for (; j < network->rates_ex_len; j++) {
                rate = network->rates_ex[j] & 0x7F;
                /* Bit rate given in 500 kb/s units (+ 0x80) */
                iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
                /* Add new value to event */
-               current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
+               current_val = iwe_stream_add_value(info, start, current_val,
+                                                  stop, &iwe, IW_EV_PARAM_LEN);
        }
        /* Check if we added any rate */
-       if((current_val - start) > IW_EV_LCP_LEN)
+       if ((current_val - start) > iwe_stream_lcp_len(info))
                start = current_val;
 
        /* Add quality statistics */
@@ -181,14 +188,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
                iwe.u.qual.level = network->stats.signal;
        }
 
-       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
+       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
 
        iwe.cmd = IWEVCUSTOM;
        p = custom;
 
        iwe.u.data.length = p - custom;
        if (iwe.u.data.length)
-               start = iwe_stream_add_point(start, stop, &iwe, custom);
+               start = iwe_stream_add_point(info, start, stop, &iwe, custom);
 
        memset(&iwe, 0, sizeof(iwe));
        if (network->wpa_ie_len) {
@@ -196,7 +203,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
                memcpy(buf, network->wpa_ie, network->wpa_ie_len);
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = network->wpa_ie_len;
-               start = iwe_stream_add_point(start, stop, &iwe, buf);
+               start = iwe_stream_add_point(info, start, stop, &iwe, buf);
        }
 
        memset(&iwe, 0, sizeof(iwe));
@@ -205,7 +212,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
                memcpy(buf, network->rsn_ie, network->rsn_ie_len);
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = network->rsn_ie_len;
-               start = iwe_stream_add_point(start, stop, &iwe, buf);
+               start = iwe_stream_add_point(info, start, stop, &iwe, buf);
        }
 
        /* Add EXTRA: Age to display seconds since last beacon/probe response
@@ -217,7 +224,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
                      jiffies_to_msecs(jiffies - network->last_scanned));
        iwe.u.data.length = p - custom;
        if (iwe.u.data.length)
-               start = iwe_stream_add_point(start, stop, &iwe, custom);
+               start = iwe_stream_add_point(info, start, stop, &iwe, custom);
 
        /* Add spectrum management information */
        iwe.cmd = -1;
@@ -238,7 +245,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
 
        if (iwe.cmd == IWEVCUSTOM) {
                iwe.u.data.length = p - custom;
-               start = iwe_stream_add_point(start, stop, &iwe, custom);
+               start = iwe_stream_add_point(info, start, stop, &iwe, custom);
        }
 
        return start;
@@ -272,7 +279,8 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
 
                if (ieee->scan_age == 0 ||
                    time_after(network->last_scanned + ieee->scan_age, jiffies))
-                       ev = ieee80211_translate_scan(ieee, ev, stop, network);
+                       ev = ieee80211_translate_scan(ieee, ev, stop, network,
+                                                     info);
                else
                        IEEE80211_DEBUG_SCAN("Not showing network '%s ("
                                             "%s)' due to age (%dms).\n",
index 42bd24b64b57b9ce84701de040c3686c2db950b5..dc411335c14fdb876e0576df3919ad33e25e7615 100644 (file)
@@ -1479,14 +1479,15 @@ static int __init inet_init(void)
         *      Initialise the multicast router
         */
 #if defined(CONFIG_IP_MROUTE)
-       ip_mr_init();
+       if (ip_mr_init())
+               printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n");
 #endif
        /*
         *      Initialise per-cpu ipv4 mibs
         */
 
        if (init_ipv4_mibs())
-               printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ;
+               printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n");
 
        ipv4_proc_init();
 
index 4ed429bd5951542401130f16e3a4f0341ded3920..0546a0bc97ea37bdc1b9bef0c22d6b82ec190abf 100644 (file)
@@ -192,14 +192,21 @@ EXPORT_SYMBOL(inet_frag_evictor);
 
 static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
                struct inet_frag_queue *qp_in, struct inet_frags *f,
-               unsigned int hash, void *arg)
+               void *arg)
 {
        struct inet_frag_queue *qp;
 #ifdef CONFIG_SMP
        struct hlist_node *n;
 #endif
+       unsigned int hash;
 
        write_lock(&f->lock);
+       /*
+        * While we stayed w/o the lock other CPU could update
+        * the rnd seed, so we need to re-calculate the hash
+        * chain. Fortunatelly the qp_in can be used to get one.
+        */
+       hash = f->hashfn(qp_in);
 #ifdef CONFIG_SMP
        /* With SMP race we have to recheck hash table, because
         * such entry could be created on other cpu, while we
@@ -247,7 +254,7 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf,
 }
 
 static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf,
-               struct inet_frags *f, void *arg, unsigned int hash)
+               struct inet_frags *f, void *arg)
 {
        struct inet_frag_queue *q;
 
@@ -255,7 +262,7 @@ static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf,
        if (q == NULL)
                return NULL;
 
-       return inet_frag_intern(nf, q, f, hash, arg);
+       return inet_frag_intern(nf, q, f, arg);
 }
 
 struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
@@ -264,7 +271,6 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
        struct inet_frag_queue *q;
        struct hlist_node *n;
 
-       read_lock(&f->lock);
        hlist_for_each_entry(q, n, &f->hash[hash], list) {
                if (q->net == nf && f->match(q, key)) {
                        atomic_inc(&q->refcnt);
@@ -274,6 +280,6 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
        }
        read_unlock(&f->lock);
 
-       return inet_frag_create(nf, f, key, hash);
+       return inet_frag_create(nf, f, key);
 }
 EXPORT_SYMBOL(inet_frag_find);
index 4a4d49fca1f2518a12eebbfbae02211eace06a19..cfd034a2b96ed7926f5139aeb161a58ba1820b2f 100644 (file)
@@ -383,8 +383,7 @@ static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb,
 out2: /* send aggregated SKBs to stack */
        lro_flush(lro_mgr, lro_desc);
 
-out:  /* Original SKB has to be posted to stack */
-       skb->ip_summed = lro_mgr->ip_summed;
+out:
        return 1;
 }
 
index 91e3214073130596a2242d6ffd471c199cfde360..fbd5804b5d83a56d93fde16d898dd2880a7e6da1 100644 (file)
@@ -227,6 +227,8 @@ static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user)
 
        arg.iph = iph;
        arg.user = user;
+
+       read_lock(&ip4_frags.lock);
        hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
 
        q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash);
index 300ab0c2919e846d2cb1b148d64b02d43c7d38bc..438fab9c62a052cbdadc49d159b7d68a03b4815b 100644 (file)
@@ -1878,16 +1878,36 @@ static struct net_protocol pim_protocol = {
  *     Setup for IP multicast routing
  */
 
-void __init ip_mr_init(void)
+int __init ip_mr_init(void)
 {
+       int err;
+
        mrt_cachep = kmem_cache_create("ip_mrt_cache",
                                       sizeof(struct mfc_cache),
                                       0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
                                       NULL);
+       if (!mrt_cachep)
+               return -ENOMEM;
+
        setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
-       register_netdevice_notifier(&ip_mr_notifier);
+       err = register_netdevice_notifier(&ip_mr_notifier);
+       if (err)
+               goto reg_notif_fail;
 #ifdef CONFIG_PROC_FS
-       proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops);
-       proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops);
+       err = -ENOMEM;
+       if (!proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops))
+               goto proc_vif_fail;
+       if (!proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops))
+               goto proc_cache_fail;
 #endif
+       return 0;
+reg_notif_fail:
+       kmem_cache_destroy(mrt_cachep);
+#ifdef CONFIG_PROC_FS
+proc_vif_fail:
+       unregister_netdevice_notifier(&ip_mr_notifier);
+proc_cache_fail:
+       proc_net_remove(&init_net, "ip_mr_vif");
+#endif
+       return err;
 }
index 9016070032054f9fa6d5aa30c08ff1c3f91dc9ee..14ef202a2254f21a57e4c7e5dfdd666e8ef65e63 100644 (file)
@@ -793,7 +793,8 @@ static struct ctl_table ipv4_net_table[] = {
                .data           = &init_net.ipv4.sysctl_icmp_ratelimit,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec
+               .proc_handler   = &proc_dointvec_ms_jiffies,
+               .strategy       = &sysctl_ms_jiffies
        },
        {
                .ctl_name       = NET_IPV4_ICMP_RATEMASK,
index cf0850c068f5488856a642e9bc588c3b8900c536..c66ac83316e8fd1a596a0063211b69b13d25314b 100644 (file)
 #include <linux/socket.h>
 #include <linux/random.h>
 #include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/swap.h>
 #include <linux/cache.h>
 #include <linux/err.h>
 #include <linux/crypto.h>
@@ -2688,7 +2690,7 @@ __setup("thash_entries=", set_thash_entries);
 void __init tcp_init(void)
 {
        struct sk_buff *skb = NULL;
-       unsigned long limit;
+       unsigned long nr_pages, limit;
        int order, i, max_share;
 
        BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));
@@ -2757,8 +2759,9 @@ void __init tcp_init(void)
         * is up to 1/2 at 256 MB, decreasing toward zero with the amount of
         * memory, with a floor of 128 pages.
         */
-       limit = min(nr_all_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
-       limit = (limit * (nr_all_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
+       nr_pages = totalram_pages - totalhigh_pages;
+       limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
+       limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
        limit = max(limit, 128UL);
        sysctl_tcp_mem[0] = limit / 4 * 3;
        sysctl_tcp_mem[1] = limit;
index de30e70ff256335b8cbc8ec531e1a8c3433a76e5..d6ea970a15135da3e2ce5041ca7a0569b1effa31 100644 (file)
@@ -947,17 +947,21 @@ static void tcp_update_reordering(struct sock *sk, const int metric,
 {
        struct tcp_sock *tp = tcp_sk(sk);
        if (metric > tp->reordering) {
+               int mib_idx;
+
                tp->reordering = min(TCP_MAX_REORDERING, metric);
 
                /* This exciting event is worth to be remembered. 8) */
                if (ts)
-                       NET_INC_STATS_BH(LINUX_MIB_TCPTSREORDER);
+                       mib_idx = LINUX_MIB_TCPTSREORDER;
                else if (tcp_is_reno(tp))
-                       NET_INC_STATS_BH(LINUX_MIB_TCPRENOREORDER);
+                       mib_idx = LINUX_MIB_TCPRENOREORDER;
                else if (tcp_is_fack(tp))
-                       NET_INC_STATS_BH(LINUX_MIB_TCPFACKREORDER);
+                       mib_idx = LINUX_MIB_TCPFACKREORDER;
                else
-                       NET_INC_STATS_BH(LINUX_MIB_TCPSACKREORDER);
+                       mib_idx = LINUX_MIB_TCPSACKREORDER;
+
+               NET_INC_STATS_BH(mib_idx);
 #if FASTRETRANS_DEBUG > 1
                printk(KERN_DEBUG "Disorder%d %d %u f%u s%u rr%d\n",
                       tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state,
@@ -1456,18 +1460,22 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb,
                if (!tcp_is_sackblock_valid(tp, dup_sack,
                                            sp[used_sacks].start_seq,
                                            sp[used_sacks].end_seq)) {
+                       int mib_idx;
+
                        if (dup_sack) {
                                if (!tp->undo_marker)
-                                       NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO);
+                                       mib_idx = LINUX_MIB_TCPDSACKIGNOREDNOUNDO;
                                else
-                                       NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD);
+                                       mib_idx = LINUX_MIB_TCPDSACKIGNOREDOLD;
                        } else {
                                /* Don't count olds caused by ACK reordering */
                                if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) &&
                                    !after(sp[used_sacks].end_seq, tp->snd_una))
                                        continue;
-                               NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD);
+                               mib_idx = LINUX_MIB_TCPSACKDISCARD;
                        }
+
+                       NET_INC_STATS_BH(mib_idx);
                        if (i == 0)
                                first_sack_index = -1;
                        continue;
@@ -2380,15 +2388,19 @@ static int tcp_try_undo_recovery(struct sock *sk)
        struct tcp_sock *tp = tcp_sk(sk);
 
        if (tcp_may_undo(tp)) {
+               int mib_idx;
+
                /* Happy end! We did not retransmit anything
                 * or our original transmission succeeded.
                 */
                DBGUNDO(sk, inet_csk(sk)->icsk_ca_state == TCP_CA_Loss ? "loss" : "retrans");
                tcp_undo_cwr(sk, 1);
                if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss)
-                       NET_INC_STATS_BH(LINUX_MIB_TCPLOSSUNDO);
+                       mib_idx = LINUX_MIB_TCPLOSSUNDO;
                else
-                       NET_INC_STATS_BH(LINUX_MIB_TCPFULLUNDO);
+                       mib_idx = LINUX_MIB_TCPFULLUNDO;
+
+               NET_INC_STATS_BH(mib_idx);
                tp->undo_marker = 0;
        }
        if (tp->snd_una == tp->high_seq && tcp_is_reno(tp)) {
@@ -2560,7 +2572,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
        int is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
        int do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) &&
                                    (tcp_fackets_out(tp) > tp->reordering));
-       int fast_rexmit = 0;
+       int fast_rexmit = 0, mib_idx;
 
        if (WARN_ON(!tp->packets_out && tp->sacked_out))
                tp->sacked_out = 0;
@@ -2683,9 +2695,11 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
                /* Otherwise enter Recovery state */
 
                if (tcp_is_reno(tp))
-                       NET_INC_STATS_BH(LINUX_MIB_TCPRENORECOVERY);
+                       mib_idx = LINUX_MIB_TCPRENORECOVERY;
                else
-                       NET_INC_STATS_BH(LINUX_MIB_TCPSACKRECOVERY);
+                       mib_idx = LINUX_MIB_TCPSACKRECOVERY;
+
+               NET_INC_STATS_BH(mib_idx);
 
                tp->high_seq = tp->snd_nxt;
                tp->prior_ssthresh = 0;
@@ -3700,10 +3714,14 @@ static inline int tcp_sack_extend(struct tcp_sack_block *sp, u32 seq,
 static void tcp_dsack_set(struct tcp_sock *tp, u32 seq, u32 end_seq)
 {
        if (tcp_is_sack(tp) && sysctl_tcp_dsack) {
+               int mib_idx;
+
                if (before(seq, tp->rcv_nxt))
-                       NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOLDSENT);
+                       mib_idx = LINUX_MIB_TCPDSACKOLDSENT;
                else
-                       NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFOSENT);
+                       mib_idx = LINUX_MIB_TCPDSACKOFOSENT;
+
+               NET_INC_STATS_BH(mib_idx);
 
                tp->rx_opt.dsack = 1;
                tp->duplicate_sack[0].start_seq = seq;
index 0db9b75c1fa23701f0602dd58bc172bade0c07a7..4300bcf2ceafb8f3397ff44c8804ee520c9d2f0f 100644 (file)
@@ -2189,7 +2189,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
        }
 
        seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
-                       "%08X %5d %8d %lu %d %p %u %u %u %u %d%n",
+                       "%08X %5d %8d %lu %d %p %lu %lu %u %u %d%n",
                i, src, srcp, dest, destp, sk->sk_state,
                tp->write_seq - tp->snd_una,
                sk->sk_state == TCP_LISTEN ? sk->sk_ack_backlog :
@@ -2201,8 +2201,8 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
                icsk->icsk_probes_out,
                sock_i_ino(sk),
                atomic_read(&sk->sk_refcnt), sk,
-               icsk->icsk_rto,
-               icsk->icsk_ack.ato,
+               jiffies_to_clock_t(icsk->icsk_rto),
+               jiffies_to_clock_t(icsk->icsk_ack.ato),
                (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
                tp->snd_cwnd,
                tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh,
index 8f83ab4327052979138d1466028d42332bd2d832..edef2afe905e14ebccf5b5e7b98eaf84363775ba 100644 (file)
@@ -1985,14 +1985,17 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
 
                        if (sacked & TCPCB_LOST) {
                                if (!(sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))) {
+                                       int mib_idx;
+
                                        if (tcp_retransmit_skb(sk, skb)) {
                                                tp->retransmit_skb_hint = NULL;
                                                return;
                                        }
                                        if (icsk->icsk_ca_state != TCP_CA_Loss)
-                                               NET_INC_STATS_BH(LINUX_MIB_TCPFASTRETRANS);
+                                               mib_idx = LINUX_MIB_TCPFASTRETRANS;
                                        else
-                                               NET_INC_STATS_BH(LINUX_MIB_TCPSLOWSTARTRETRANS);
+                                               mib_idx = LINUX_MIB_TCPSLOWSTARTRETRANS;
+                                       NET_INC_STATS_BH(mib_idx);
 
                                        if (skb == tcp_write_queue_head(sk))
                                                inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
index 3e358cbb1247c89fa9c81b3c560245bc21da16e6..6a480d1fd8f657bbaf4da9c9de138945bc5420f6 100644 (file)
@@ -326,24 +326,27 @@ static void tcp_retransmit_timer(struct sock *sk)
                goto out;
 
        if (icsk->icsk_retransmits == 0) {
+               int mib_idx;
+
                if (icsk->icsk_ca_state == TCP_CA_Disorder ||
                    icsk->icsk_ca_state == TCP_CA_Recovery) {
                        if (tcp_is_sack(tp)) {
                                if (icsk->icsk_ca_state == TCP_CA_Recovery)
-                                       NET_INC_STATS_BH(LINUX_MIB_TCPSACKRECOVERYFAIL);
+                                       mib_idx = LINUX_MIB_TCPSACKRECOVERYFAIL;
                                else
-                                       NET_INC_STATS_BH(LINUX_MIB_TCPSACKFAILURES);
+                                       mib_idx = LINUX_MIB_TCPSACKFAILURES;
                        } else {
                                if (icsk->icsk_ca_state == TCP_CA_Recovery)
-                                       NET_INC_STATS_BH(LINUX_MIB_TCPRENORECOVERYFAIL);
+                                       mib_idx = LINUX_MIB_TCPRENORECOVERYFAIL;
                                else
-                                       NET_INC_STATS_BH(LINUX_MIB_TCPRENOFAILURES);
+                                       mib_idx = LINUX_MIB_TCPRENOFAILURES;
                        }
                } else if (icsk->icsk_ca_state == TCP_CA_Loss) {
-                       NET_INC_STATS_BH(LINUX_MIB_TCPLOSSFAILURES);
+                       mib_idx = LINUX_MIB_TCPLOSSFAILURES;
                } else {
-                       NET_INC_STATS_BH(LINUX_MIB_TCPTIMEOUTS);
+                       mib_idx = LINUX_MIB_TCPTIMEOUTS;
                }
+               NET_INC_STATS_BH(mib_idx);
        }
 
        if (tcp_use_frto(sk)) {
index 84127d854cfcba1d2007d1149bfa96ef49363e83..2ec73e62202c18b741adc862168c7e0da854be3a 100644 (file)
@@ -119,6 +119,7 @@ static void ipv6_regen_rndid(unsigned long data);
 static int desync_factor = MAX_DESYNC_FACTOR * HZ;
 #endif
 
+static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
 static int ipv6_count_addresses(struct inet6_dev *idev);
 
 /*
@@ -183,6 +184,8 @@ struct ipv6_devconf ipv6_devconf __read_mostly = {
 #endif
        .proxy_ndp              = 0,
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
+       .disable_ipv6           = 0,
+       .accept_dad             = 1,
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -215,6 +218,8 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 #endif
        .proxy_ndp              = 0,
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
+       .disable_ipv6           = 0,
+       .accept_dad             = 1,
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -378,6 +383,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
         */
        in6_dev_hold(ndev);
 
+       if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
+               ndev->cnf.accept_dad = -1;
+
 #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
        if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {
                printk(KERN_INFO
@@ -578,6 +586,13 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        struct rt6_info *rt;
        int hash;
        int err = 0;
+       int addr_type = ipv6_addr_type(addr);
+
+       if (addr_type == IPV6_ADDR_ANY ||
+           addr_type & IPV6_ADDR_MULTICAST ||
+           (!(idev->dev->flags & IFF_LOOPBACK) &&
+            addr_type & IPV6_ADDR_LOOPBACK))
+               return ERR_PTR(-EADDRNOTAVAIL);
 
        rcu_read_lock_bh();
        if (idev->dead) {
@@ -1412,6 +1427,20 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
 
 void addrconf_dad_failure(struct inet6_ifaddr *ifp)
 {
+       struct inet6_dev *idev = ifp->idev;
+       if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
+               struct in6_addr addr;
+
+               addr.s6_addr32[0] = htonl(0xfe800000);
+               addr.s6_addr32[1] = 0;
+
+               if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) &&
+                   ipv6_addr_equal(&ifp->addr, &addr)) {
+                       /* DAD failed for link-local based on MAC address */
+                       idev->cnf.disable_ipv6 = 1;
+               }
+       }
+
        if (net_ratelimit())
                printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
        addrconf_dad_stop(ifp);
@@ -2744,6 +2773,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
        spin_lock_bh(&ifp->lock);
 
        if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
+           idev->cnf.accept_dad < 1 ||
            !(ifp->flags&IFA_F_TENTATIVE) ||
            ifp->flags & IFA_F_NODAD) {
                ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
@@ -2791,6 +2821,11 @@ static void addrconf_dad_timer(unsigned long data)
                read_unlock_bh(&idev->lock);
                goto out;
        }
+       if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
+               read_unlock_bh(&idev->lock);
+               addrconf_dad_failure(ifp);
+               return;
+       }
        spin_lock_bh(&ifp->lock);
        if (ifp->probes == 0) {
                /*
@@ -3650,6 +3685,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
 #ifdef CONFIG_IPV6_MROUTE
        array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
 #endif
+       array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
+       array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
 }
 
 static inline size_t inet6_if_nlmsg_size(void)
@@ -4208,6 +4245,22 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       &proc_dointvec,
                },
 #endif
+               {
+                       .ctl_name       =       CTL_UNNUMBERED,
+                       .procname       =       "disable_ipv6",
+                       .data           =       &ipv6_devconf.disable_ipv6,
+                       .maxlen         =       sizeof(int),
+                       .mode           =       0644,
+                       .proc_handler   =       &proc_dointvec,
+               },
+               {
+                       .ctl_name       =       CTL_UNNUMBERED,
+                       .procname       =       "accept_dad",
+                       .data           =       &ipv6_devconf.accept_dad,
+                       .maxlen         =       sizeof(int),
+                       .mode           =       0644,
+                       .proc_handler   =       &proc_dointvec,
+               },
                {
                        .ctl_name       =       0,      /* sentinel */
                }
index 3ce8d2f318c6e385b349d4ae1171f8edc0b4c6ed..3d828bc4b1cf97cbfcbd1df9e76c5b357b37a9c4 100644 (file)
@@ -59,9 +59,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#ifdef CONFIG_IPV6_MROUTE
 #include <linux/mroute6.h>
-#endif
 
 MODULE_AUTHOR("Cast of dozens");
 MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
@@ -952,9 +950,9 @@ static int __init inet6_init(void)
        err = icmpv6_init();
        if (err)
                goto icmp_fail;
-#ifdef CONFIG_IPV6_MROUTE
-       ip6_mr_init();
-#endif
+       err = ip6_mr_init();
+       if (err)
+               goto ipmr_fail;
        err = ndisc_init();
        if (err)
                goto ndisc_fail;
@@ -1057,6 +1055,8 @@ netfilter_fail:
 igmp_fail:
        ndisc_cleanup();
 ndisc_fail:
+       ip6_mr_cleanup();
+ipmr_fail:
        icmpv6_cleanup();
 icmp_fail:
        unregister_pernet_subsys(&inet6_net_ops);
@@ -1111,6 +1111,7 @@ static void __exit inet6_exit(void)
        ipv6_netfilter_fini();
        igmp6_cleanup();
        ndisc_cleanup();
+       ip6_mr_cleanup();
        icmpv6_cleanup();
        rawv6_exit();
 
index 399d41f65437952c3ce7cc9f1259b49400164574..abedf95fdf2dd0ca5f8cfa25cdfe0f6504395592 100644 (file)
@@ -954,7 +954,8 @@ ctl_table ipv6_icmp_table_template[] = {
                .data           = &init_net.ipv6.sysctl.icmpv6_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec
+               .proc_handler   = &proc_dointvec_ms_jiffies,
+               .strategy       = &sysctl_ms_jiffies
        },
        { .ctl_name = 0 },
 };
index f77a6011c302cc57b67d7e86eef4b782f021c947..ea81c614dde2be1cf70c42f955ab96af3489b29e 100644 (file)
@@ -71,7 +71,8 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
 
        IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES);
 
-       if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+       if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
+           !idev || unlikely(idev->cnf.disable_ipv6)) {
                IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
                rcu_read_unlock();
                goto out;
@@ -100,6 +101,15 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
        if (hdr->version != 6)
                goto err;
 
+       /*
+        * RFC4291 2.5.3
+        * A packet received on an interface with a destination address
+        * of loopback must be dropped.
+        */
+       if (!(dev->flags & IFF_LOOPBACK) &&
+           ipv6_addr_loopback(&hdr->daddr))
+               goto err;
+
        skb->transport_header = skb->network_header + sizeof(*hdr);
        IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
 
index fd7cd1bfe1510e4e71fcd000b02087a8c4280d97..0981c1ef305797322ab0b703a4aba609efcbbfc2 100644 (file)
@@ -173,6 +173,13 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
 
 int ip6_output(struct sk_buff *skb)
 {
+       struct inet6_dev *idev = ip6_dst_idev(skb->dst);
+       if (unlikely(idev->cnf.disable_ipv6)) {
+               IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+               kfree_skb(skb);
+               return 0;
+       }
+
        if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
                                dst_allfrag(skb->dst))
                return ip6_fragment(skb, ip6_output2);
@@ -498,7 +505,8 @@ int ip6_forward(struct sk_buff *skb)
                int addrtype = ipv6_addr_type(&hdr->saddr);
 
                /* This check is security critical. */
-               if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK))
+               if (addrtype == IPV6_ADDR_ANY ||
+                   addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK))
                        goto error;
                if (addrtype & IPV6_ADDR_LINKLOCAL) {
                        icmpv6_send(skb, ICMPV6_DEST_UNREACH,
index 90e763073dc5fdebf09b4fd538594118c8215ec7..cfac26d674ede45d76fb199ce154297c7cf59609 100644 (file)
@@ -948,23 +948,51 @@ static struct notifier_block ip6_mr_notifier = {
  *     Setup for IP multicast routing
  */
 
-void __init ip6_mr_init(void)
+int __init ip6_mr_init(void)
 {
+       int err;
+
        mrt_cachep = kmem_cache_create("ip6_mrt_cache",
                                       sizeof(struct mfc6_cache),
                                       0, SLAB_HWCACHE_ALIGN,
                                       NULL);
        if (!mrt_cachep)
-               panic("cannot allocate ip6_mrt_cache");
+               return -ENOMEM;
 
        setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
-       register_netdevice_notifier(&ip6_mr_notifier);
+       err = register_netdevice_notifier(&ip6_mr_notifier);
+       if (err)
+               goto reg_notif_fail;
+#ifdef CONFIG_PROC_FS
+       err = -ENOMEM;
+       if (!proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops))
+               goto proc_vif_fail;
+       if (!proc_net_fops_create(&init_net, "ip6_mr_cache",
+                                    0, &ip6mr_mfc_fops))
+               goto proc_cache_fail;
+#endif
+       return 0;
+reg_notif_fail:
+       kmem_cache_destroy(mrt_cachep);
 #ifdef CONFIG_PROC_FS
-       proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops);
-       proc_net_fops_create(&init_net, "ip6_mr_cache", 0, &ip6mr_mfc_fops);
+proc_vif_fail:
+       unregister_netdevice_notifier(&ip6_mr_notifier);
+proc_cache_fail:
+       proc_net_remove(&init_net, "ip6_mr_vif");
 #endif
+       return err;
 }
 
+void ip6_mr_cleanup(void)
+{
+#ifdef CONFIG_PROC_FS
+       proc_net_remove(&init_net, "ip6_mr_cache");
+       proc_net_remove(&init_net, "ip6_mr_vif");
+#endif
+       unregister_netdevice_notifier(&ip6_mr_notifier);
+       del_timer(&ipmr_expire_timer);
+       kmem_cache_destroy(mrt_cachep);
+}
 
 static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock)
 {
index a9988841172af06fbd6ec6f4e754bbc51cda30f9..030c0c956f9db6d9aa1411c825d07bab00b32c0f 100644 (file)
@@ -343,18 +343,21 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
        case IPV6_DSTOPTS:
        {
                struct ipv6_txoptions *opt;
+
+               /* remove any sticky options header with a zero option
+                * length, per RFC3542.
+                */
                if (optlen == 0)
                        optval = NULL;
+               else if (optlen < sizeof(struct ipv6_opt_hdr) ||
+                        optlen & 0x7 || optlen > 8 * 255)
+                       goto e_inval;
 
                /* hop-by-hop / destination options are privileged option */
                retv = -EPERM;
                if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
                        break;
 
-               if (optlen < sizeof(struct ipv6_opt_hdr) ||
-                   optlen & 0x7 || optlen > 8 * 255)
-                       goto e_inval;
-
                opt = ipv6_renew_options(sk, np->opt, optname,
                                         (struct ipv6_opt_hdr __user *)optval,
                                         optlen);
index 27a5e8b48d93a27fababd4d79fb998903d039422..f405cea21a8b89687558c83deb094d7c1940631e 100644 (file)
@@ -129,7 +129,7 @@ static struct nf_hook_ops ip6t_ops[] __read_mostly = {
                .priority       = NF_IP6_PRI_MANGLE,
        },
        {
-               .hook           = ip6t_local_hook,
+               .hook           = ip6t_route_hook,
                .owner          = THIS_MODULE,
                .pf             = PF_INET6,
                .hooknum        = NF_INET_LOCAL_IN,
index e65e26e210ee3a66873f6d472fdca708559fb0a2..cf20bc4fd60db346eab94b35ec3b84ee255dd265 100644 (file)
@@ -207,9 +207,10 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst)
        arg.id = id;
        arg.src = src;
        arg.dst = dst;
+
+       read_lock_bh(&nf_frags.lock);
        hash = ip6qhashfn(id, src, dst);
 
-       local_bh_disable();
        q = inet_frag_find(&nf_init_frags, &nf_frags, &arg, hash);
        local_bh_enable();
        if (q == NULL)
index 13509f906d890f4e1733b894f253f9bb7f146ad2..6ab957ec2dd6d4a64bee43cc20d754e7e85ca579 100644 (file)
@@ -245,6 +245,8 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst,
        arg.id = id;
        arg.src = src;
        arg.dst = dst;
+
+       read_lock(&ip6_frags.lock);
        hash = ip6qhashfn(id, src, dst);
 
        q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash);
index efe036aa3dd1bbb02384d893b185768720c67695..5d6c166dfbb6e087e0f634d69d305d1f1912fdda 100644 (file)
@@ -228,7 +228,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt)
 static inline int rt6_need_strict(struct in6_addr *daddr)
 {
        return (ipv6_addr_type(daddr) &
-               (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
+               (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK));
 }
 
 /*
@@ -237,21 +237,26 @@ static inline int rt6_need_strict(struct in6_addr *daddr)
 
 static inline struct rt6_info *rt6_device_match(struct net *net,
                                                    struct rt6_info *rt,
+                                                   struct in6_addr *saddr,
                                                    int oif,
-                                                   int strict)
+                                                   int flags)
 {
        struct rt6_info *local = NULL;
        struct rt6_info *sprt;
 
-       if (oif) {
-               for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) {
-                       struct net_device *dev = sprt->rt6i_dev;
+       if (!oif && ipv6_addr_any(saddr))
+               goto out;
+
+       for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) {
+               struct net_device *dev = sprt->rt6i_dev;
+
+               if (oif) {
                        if (dev->ifindex == oif)
                                return sprt;
                        if (dev->flags & IFF_LOOPBACK) {
                                if (sprt->rt6i_idev == NULL ||
                                    sprt->rt6i_idev->dev->ifindex != oif) {
-                                       if (strict && oif)
+                                       if (flags & RT6_LOOKUP_F_IFACE && oif)
                                                continue;
                                        if (local && (!oif ||
                                                      local->rt6i_idev->dev->ifindex == oif))
@@ -259,14 +264,21 @@ static inline struct rt6_info *rt6_device_match(struct net *net,
                                }
                                local = sprt;
                        }
+               } else {
+                       if (ipv6_chk_addr(net, saddr, dev,
+                                         flags & RT6_LOOKUP_F_IFACE))
+                               return sprt;
                }
+       }
 
+       if (oif) {
                if (local)
                        return local;
 
-               if (strict)
+               if (flags & RT6_LOOKUP_F_IFACE)
                        return net->ipv6.ip6_null_entry;
        }
+out:
        return rt;
 }
 
@@ -539,7 +551,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
        fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
 restart:
        rt = fn->leaf;
-       rt = rt6_device_match(net, rt, fl->oif, flags);
+       rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags);
        BACKTRACK(net, &fl->fl6_src);
 out:
        dst_use(&rt->u.dst, jiffies);
index 09be09cc1aa62166eb58f1d487040b6f480e671d..30dbab7cc3ccafbeb5d17a98ab5c3d13495bba36 100644 (file)
@@ -1946,7 +1946,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
 
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
@@ -1962,8 +1962,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
                   icsk->icsk_probes_out,
                   sock_i_ino(sp),
                   atomic_read(&sp->sk_refcnt), sp,
-                  icsk->icsk_rto,
-                  icsk->icsk_ack.ato,
+                  jiffies_to_clock_t(icsk->icsk_rto),
+                  jiffies_to_clock_t(icsk->icsk_ack.ato),
                   (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
                   tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
                   );
index 590e00b2766c8dbee2600dd33fd6d2b485d7bc46..0d3661d9b6a050256ee5b78034ba349d94d00dee 100644 (file)
@@ -150,7 +150,7 @@ config MAC80211_LOWTX_FRAME_DUMP
          If unsure, say N and insert the debugging code
          you require into the driver you are debugging.
 
-config TKIP_DEBUG
+config MAC80211_TKIP_DEBUG
        bool "TKIP debugging"
        depends on MAC80211_DEBUG
 
index 14fccf16b80f0f1a8f6924c07eeb0ae259357768..af352c05c983bc363e37ee1ed35ef0203dab6e6b 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/spinlock.h>
 #include <linux/etherdevice.h>
 #include <net/wireless.h>
+#include <net/iw_handler.h>
 #include "key.h"
 #include "sta_info.h"
 
@@ -790,6 +791,10 @@ struct ieee802_11_elems {
        u8 *preq;
        u8 *prep;
        u8 *perr;
+       u8 *ch_switch_elem;
+       u8 *country_elem;
+       u8 *pwr_constr_elem;
+       u8 *quiet_elem;         /* first quite element */
 
        /* length of them, respectively */
        u8 ssid_len;
@@ -814,6 +819,11 @@ struct ieee802_11_elems {
        u8 preq_len;
        u8 prep_len;
        u8 perr_len;
+       u8 ch_switch_elem_len;
+       u8 country_elem_len;
+       u8 pwr_constr_elem_len;
+       u8 quiet_elem_len;
+       u8 num_of_quiet_elem;   /* can be more the one */
 };
 
 static inline struct ieee80211_local *hw_to_local(
@@ -867,7 +877,9 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid);
 int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
 void ieee80211_sta_req_auth(struct net_device *dev,
                            struct ieee80211_if_sta *ifsta);
-int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
+int ieee80211_sta_scan_results(struct net_device *dev,
+                              struct iw_request_info *info,
+                              char *buf, size_t len);
 ieee80211_rx_result ieee80211_sta_rx_scan(
        struct net_device *dev, struct sk_buff *skb,
        struct ieee80211_rx_status *rx_status);
index d4893bd177548a33c3cbbfd0fd54bab6d5a933e4..6597c779e35a946147c510b5f0659afb4b40bce7 100644 (file)
@@ -387,6 +387,15 @@ void ieee80211_key_free(struct ieee80211_key *key)
        if (!key)
                return;
 
+       if (!key->sdata) {
+               /* The key has not been linked yet, simply free it
+                * and don't Oops */
+               if (key->conf.alg == ALG_CCMP)
+                       ieee80211_aes_key_free(key->u.ccmp.tfm);
+               kfree(key);
+               return;
+       }
+
        spin_lock_irqsave(&key->sdata->local->key_lock, flags);
        __ieee80211_key_free(key);
        spin_unlock_irqrestore(&key->sdata->local->key_lock, flags);
index a0f774aafa455709f3184cb017a105c54d35ede3..425816e0996cb27d292b759915f91eb4ce2d3e4e 100644 (file)
 #include <linux/rcupdate.h>
 #include <net/mac80211.h>
 
-/* ALG_TKIP
- * struct ieee80211_key::key is encoded as a 256-bit (32 byte) data block:
- * Temporal Encryption Key (128 bits)
- * Temporal Authenticator Tx MIC Key (64 bits)
- * Temporal Authenticator Rx MIC Key (64 bits)
- */
-
-#define WEP_IV_LEN 4
-#define WEP_ICV_LEN 4
-
-#define ALG_TKIP_KEY_LEN 32
-/* Starting offsets for each key */
-#define ALG_TKIP_TEMP_ENCR_KEY 0
-#define ALG_TKIP_TEMP_AUTH_TX_MIC_KEY 16
-#define ALG_TKIP_TEMP_AUTH_RX_MIC_KEY 24
-#define TKIP_IV_LEN 8
-#define TKIP_ICV_LEN 4
-
-#define ALG_CCMP_KEY_LEN 16
-#define CCMP_HDR_LEN 8
-#define CCMP_MIC_LEN 8
-#define CCMP_TK_LEN 16
-#define CCMP_PN_LEN 6
-
-#define NUM_RX_DATA_QUEUES 17
+#define WEP_IV_LEN             4
+#define WEP_ICV_LEN            4
+#define ALG_TKIP_KEY_LEN       32
+#define ALG_CCMP_KEY_LEN       16
+#define CCMP_HDR_LEN           8
+#define CCMP_MIC_LEN           8
+#define CCMP_TK_LEN            16
+#define CCMP_PN_LEN            6
+#define TKIP_IV_LEN            8
+#define TKIP_ICV_LEN           4
+
+#define NUM_RX_DATA_QUEUES     17
 
 struct ieee80211_local;
 struct ieee80211_sub_if_data;
index 5c5396edad3233f730be3852c2a7f8955a03f287..b661ee5bb8246534c42dee2ab2dba87a50d2b346 100644 (file)
@@ -1691,7 +1691,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        list_add_tail(&sdata->list, &local->interfaces);
 
        name = wiphy_dev(local->hw.wiphy)->driver->name;
-       local->hw.workqueue = create_singlethread_workqueue(name);
+       local->hw.workqueue = create_freezeable_workqueue(name);
        if (!local->hw.workqueue) {
                result = -ENOMEM;
                goto fail_workqueue;
index 55659a730dc1409a1274dcd938b567b20fc01b89..7b4d4d46843b4eebaa9bd98af6a8f363d88620bf 100644 (file)
@@ -204,6 +204,25 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
                        elems->perr = pos;
                        elems->perr_len = elen;
                        break;
+               case WLAN_EID_CHANNEL_SWITCH:
+                       elems->ch_switch_elem = pos;
+                       elems->ch_switch_elem_len = elen;
+                       break;
+               case WLAN_EID_QUIET:
+                       if (!elems->quiet_elem) {
+                               elems->quiet_elem = pos;
+                               elems->quiet_elem_len = elen;
+                       }
+                       elems->num_of_quiet_elem++;
+                       break;
+               case WLAN_EID_COUNTRY:
+                       elems->country_elem = pos;
+                       elems->country_elem_len = elen;
+                       break;
+               case WLAN_EID_PWR_CONSTRAINT:
+                       elems->pwr_constr_elem = pos;
+                       elems->pwr_constr_elem_len = elen;
+                       break;
                default:
                        break;
                }
@@ -1701,6 +1720,71 @@ void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr)
        }
 }
 
+static void ieee80211_send_refuse_measurement_request(struct net_device *dev,
+                                       struct ieee80211_msrment_ie *request_ie,
+                                       const u8 *da, const u8 *bssid,
+                                       u8 dialog_token)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *msr_report;
+
+       skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
+                               sizeof(struct ieee80211_msrment_ie));
+
+       if (!skb) {
+               printk(KERN_ERR "%s: failed to allocate buffer for "
+                               "measurement report frame\n", dev->name);
+               return;
+       }
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+       msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
+       memset(msr_report, 0, 24);
+       memcpy(msr_report->da, da, ETH_ALEN);
+       memcpy(msr_report->sa, dev->dev_addr, ETH_ALEN);
+       memcpy(msr_report->bssid, bssid, ETH_ALEN);
+       msr_report->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+                                               IEEE80211_STYPE_ACTION);
+
+       skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement));
+       msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
+       msr_report->u.action.u.measurement.action_code =
+                               WLAN_ACTION_SPCT_MSR_RPRT;
+       msr_report->u.action.u.measurement.dialog_token = dialog_token;
+
+       msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT;
+       msr_report->u.action.u.measurement.length =
+                       sizeof(struct ieee80211_msrment_ie);
+
+       memset(&msr_report->u.action.u.measurement.msr_elem, 0,
+               sizeof(struct ieee80211_msrment_ie));
+       msr_report->u.action.u.measurement.msr_elem.token = request_ie->token;
+       msr_report->u.action.u.measurement.msr_elem.mode |=
+                       IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
+       msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
+
+       ieee80211_sta_tx(dev, skb, 0);
+}
+
+static void ieee80211_sta_process_measurement_req(struct net_device *dev,
+                                               struct ieee80211_mgmt *mgmt,
+                                               size_t len)
+{
+       /*
+        * Ignoring measurement request is spec violation.
+        * Mandatory measurements must be reported optional
+        * measurements might be refused or reported incapable
+        * For now just refuse
+        * TODO: Answer basic measurement as unmeasured
+        */
+       ieee80211_send_refuse_measurement_request(dev,
+                       &mgmt->u.action.u.measurement.msr_elem,
+                       mgmt->sa, mgmt->bssid,
+                       mgmt->u.action.u.measurement.dialog_token);
+}
+
+
 static void ieee80211_rx_mgmt_auth(struct net_device *dev,
                                   struct ieee80211_if_sta *ifsta,
                                   struct ieee80211_mgmt *mgmt,
@@ -1753,11 +1837,12 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
               auth_transaction, status_code);
 
        if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
-               /* IEEE 802.11 standard does not require authentication in IBSS
+               /*
+                * IEEE 802.11 standard does not require authentication in IBSS
                 * networks and most implementations do not seem to use it.
                 * However, try to reply to authentication attempts if someone
                 * has actually implemented this.
-                * TODO: Could implement shared key authentication. */
+                */
                if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
                        printk(KERN_DEBUG "%s: unexpected IBSS authentication "
                               "frame (alg=%d transaction=%d)\n",
@@ -3025,11 +3110,24 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev,
                                     struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
        if (len < IEEE80211_MIN_ACTION_SIZE)
                return;
 
        switch (mgmt->u.action.category) {
+       case WLAN_CATEGORY_SPECTRUM_MGMT:
+               if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
+                       break;
+               switch (mgmt->u.action.u.chan_switch.action_code) {
+               case WLAN_ACTION_SPCT_MSR_REQ:
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.measurement)))
+                               break;
+                       ieee80211_sta_process_measurement_req(dev, mgmt, len);
+                       break;
+               }
+               break;
        case WLAN_CATEGORY_BACK:
                switch (mgmt->u.action.u.addba_req.action_code) {
                case WLAN_ACTION_ADDBA_REQ:
@@ -3173,33 +3271,32 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
                      struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_mgmt *mgmt;
-       u16 fc;
+       __le16 fc;
 
        if (skb->len < 2)
                return RX_DROP_UNUSABLE;
 
        mgmt = (struct ieee80211_mgmt *) skb->data;
-       fc = le16_to_cpu(mgmt->frame_control);
+       fc = mgmt->frame_control;
 
-       if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
+       if (ieee80211_is_ctl(fc))
                return RX_CONTINUE;
 
        if (skb->len < 24)
                return RX_DROP_MONITOR;
 
-       if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
-               if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
-                       ieee80211_rx_mgmt_probe_resp(dev, mgmt,
-                                                    skb->len, rx_status);
-                       dev_kfree_skb(skb);
-                       return RX_QUEUED;
-               } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
-                       ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
-                                                rx_status);
-                       dev_kfree_skb(skb);
-                       return RX_QUEUED;
-               }
+       if (ieee80211_is_probe_resp(fc)) {
+               ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status);
+               dev_kfree_skb(skb);
+               return RX_QUEUED;
        }
+
+       if (ieee80211_is_beacon(fc)) {
+               ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
+               dev_kfree_skb(skb);
+               return RX_QUEUED;
+       }
+
        return RX_CONTINUE;
 }
 
@@ -3777,7 +3874,7 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
 {
        struct sk_buff *skb;
        struct ieee80211_hdr *nullfunc;
-       u16 fc;
+       __le16 fc;
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
        if (!skb) {
@@ -3789,11 +3886,11 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
 
        nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
        memset(nullfunc, 0, 24);
-       fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
-            IEEE80211_FCTL_TODS;
+       fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+                        IEEE80211_FCTL_TODS);
        if (powersave)
-               fc |= IEEE80211_FCTL_PM;
-       nullfunc->frame_control = cpu_to_le16(fc);
+               fc |= cpu_to_le16(IEEE80211_FCTL_PM);
+       nullfunc->frame_control = fc;
        memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
        memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
        memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
@@ -4087,6 +4184,7 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
 
 static char *
 ieee80211_sta_scan_result(struct net_device *dev,
+                         struct iw_request_info *info,
                          struct ieee80211_sta_bss *bss,
                          char *current_ev, char *end_buf)
 {
@@ -4101,7 +4199,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_ADDR_LEN);
 
        memset(&iwe, 0, sizeof(iwe));
@@ -4109,13 +4207,13 @@ ieee80211_sta_scan_result(struct net_device *dev,
        if (bss_mesh_cfg(bss)) {
                iwe.u.data.length = bss_mesh_id_len(bss);
                iwe.u.data.flags = 1;
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 bss_mesh_id(bss));
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss_mesh_id(bss));
        } else {
                iwe.u.data.length = bss->ssid_len;
                iwe.u.data.flags = 1;
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 bss->ssid);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss->ssid);
        }
 
        if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
@@ -4128,22 +4226,22 @@ ieee80211_sta_scan_result(struct net_device *dev,
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
-               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
-                                                 IW_EV_UINT_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_UINT_LEN);
        }
 
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
        iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
        iwe.u.freq.e = 0;
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
 
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
        iwe.u.freq.m = bss->freq;
        iwe.u.freq.e = 6;
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = IWEVQUAL;
@@ -4151,7 +4249,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
        iwe.u.qual.level = bss->signal;
        iwe.u.qual.noise = bss->noise;
        iwe.u.qual.updated = local->wstats_flags;
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_QUAL_LEN);
 
        memset(&iwe, 0, sizeof(iwe));
@@ -4161,35 +4259,36 @@ ieee80211_sta_scan_result(struct net_device *dev,
        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_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, "");
 
        if (bss && bss->wpa_ie) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->wpa_ie_len;
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 bss->wpa_ie);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss->wpa_ie);
        }
 
        if (bss && bss->rsn_ie) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->rsn_ie_len;
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 bss->rsn_ie);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss->rsn_ie);
        }
 
        if (bss && bss->ht_ie) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->ht_ie_len;
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 bss->ht_ie);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss->ht_ie);
        }
 
        if (bss && bss->supp_rates_len > 0) {
                /* display all supported rates in readable format */
-               char *p = current_ev + IW_EV_LCP_LEN;
+               char *p = current_ev + iwe_stream_lcp_len(info);
                int i;
 
                memset(&iwe, 0, sizeof(iwe));
@@ -4200,7 +4299,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
                for (i = 0; i < bss->supp_rates_len; i++) {
                        iwe.u.bitrate.value = ((bss->supp_rates[i] &
                                                        0x7f) * 500000);
-                       p = iwe_stream_add_value(current_ev, p,
+                       p = iwe_stream_add_value(info, current_ev, p,
                                        end_buf, &iwe, IW_EV_PARAM_LEN);
                }
                current_ev = p;
@@ -4214,7 +4313,8 @@ ieee80211_sta_scan_result(struct net_device *dev,
                        iwe.cmd = IWEVCUSTOM;
                        sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        kfree(buf);
                }
@@ -4229,31 +4329,36 @@ ieee80211_sta_scan_result(struct net_device *dev,
                        iwe.cmd = IWEVCUSTOM;
                        sprintf(buf, "Mesh network (version %d)", cfg[0]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Path Selection Protocol ID: "
                                "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
                                                        cfg[4]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Path Selection Metric ID: "
                                "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
                                                        cfg[8]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Congestion Control Mode ID: "
                                "0x%02X%02X%02X%02X", cfg[9], cfg[10],
                                                        cfg[11], cfg[12]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Channel Precedence: "
                                "0x%02X%02X%02X%02X", cfg[13], cfg[14],
                                                        cfg[15], cfg[16]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        kfree(buf);
                }
@@ -4263,7 +4368,9 @@ ieee80211_sta_scan_result(struct net_device *dev,
 }
 
 
-int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
+int ieee80211_sta_scan_results(struct net_device *dev,
+                              struct iw_request_info *info,
+                              char *buf, size_t len)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        char *current_ev = buf;
@@ -4276,8 +4383,8 @@ int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
                        spin_unlock_bh(&local->sta_bss_lock);
                        return -E2BIG;
                }
-               current_ev = ieee80211_sta_scan_result(dev, bss, current_ev,
-                                                      end_buf);
+               current_ev = ieee80211_sta_scan_result(dev, info, bss,
+                                                      current_ev, end_buf);
        }
        spin_unlock_bh(&local->sta_bss_lock);
        return current_ev - buf;
index c32a0bcd53b71a344b084e30d417bfefa3491ce1..8962d1355f04b0b7bfc030bef0b7f9b7c9edbf9e 100644 (file)
@@ -61,7 +61,7 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
                                    int present_fcs_len,
                                    int radiotap_len)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
        if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
                return 1;
@@ -2123,7 +2123,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
        struct tid_ampdu_rx *tid_agg_rx;
        u16 sc;
        u16 mpdu_seq_num;
-       u8 ret = 0, *qc;
+       u8 ret = 0;
        int tid;
 
        sta = sta_info_get(local, hdr->addr2);
@@ -2135,8 +2135,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
        if (!ieee80211_is_data_qos(hdr->frame_control))
                goto end_reorder;
 
-       qc = ieee80211_get_qos_ctl(hdr);
-       tid = qc[0] & QOS_CONTROL_TID_MASK;
+       tid = *ieee80211_get_qos_ctl(hdr) & QOS_CONTROL_TID_MASK;
 
        if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
                goto end_reorder;
index c24770cb02c5d696f160136c497f2a9544747128..b3c733162fc1ecbb464842a1b2ef5387ac5fe84e 100644 (file)
@@ -235,6 +235,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                return NULL;
 
        spin_lock_init(&sta->lock);
+       spin_lock_init(&sta->flaglock);
 
        memcpy(sta->addr, addr, ETH_ALEN);
        sta->local = local;
index 95753f860acf311efc7bf28868ff08c633800db4..fd228c198e318ab320e734cbc3f144d17fff4987 100644 (file)
@@ -164,6 +164,7 @@ struct sta_ampdu_mlme {
  * @aid: STA's unique AID (1..2007, 0 = not assigned yet),
  *     only used in AP (and IBSS?) mode
  * @flags: STA flags, see &enum ieee80211_sta_info_flags
+ * @flaglock: spinlock for flags accesses
  * @ps_tx_buf: buffer of frames to transmit to this station
  *     when it leaves power saving state
  * @tx_filtered: buffer of frames we already tried to transmit
@@ -186,6 +187,7 @@ struct sta_info {
        struct rate_control_ref *rate_ctrl;
        void *rate_ctrl_priv;
        spinlock_t lock;
+       spinlock_t flaglock;
        struct ieee80211_ht_info ht_info;
        u64 supp_rates[IEEE80211_NUM_BANDS];
        u8 addr[ETH_ALEN];
@@ -198,7 +200,10 @@ struct sta_info {
         */
        u8 pin_status;
 
-       /* frequently updated information, locked with lock spinlock */
+       /*
+        * frequently updated, locked with own spinlock (flaglock),
+        * use the accessors defined below
+        */
        u32 flags;
 
        /*
@@ -293,34 +298,41 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta)
 
 static inline void set_sta_flags(struct sta_info *sta, const u32 flags)
 {
-       spin_lock_bh(&sta->lock);
+       unsigned long irqfl;
+
+       spin_lock_irqsave(&sta->flaglock, irqfl);
        sta->flags |= flags;
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_irqrestore(&sta->flaglock, irqfl);
 }
 
 static inline void clear_sta_flags(struct sta_info *sta, const u32 flags)
 {
-       spin_lock_bh(&sta->lock);
+       unsigned long irqfl;
+
+       spin_lock_irqsave(&sta->flaglock, irqfl);
        sta->flags &= ~flags;
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_irqrestore(&sta->flaglock, irqfl);
 }
 
 static inline void set_and_clear_sta_flags(struct sta_info *sta,
                                           const u32 set, const u32 clear)
 {
-       spin_lock_bh(&sta->lock);
+       unsigned long irqfl;
+
+       spin_lock_irqsave(&sta->flaglock, irqfl);
        sta->flags |= set;
        sta->flags &= ~clear;
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_irqrestore(&sta->flaglock, irqfl);
 }
 
 static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags)
 {
        u32 ret;
+       unsigned long irqfl;
 
-       spin_lock_bh(&sta->lock);
+       spin_lock_irqsave(&sta->flaglock, irqfl);
        ret = sta->flags & flags;
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_irqrestore(&sta->flaglock, irqfl);
 
        return ret;
 }
@@ -329,11 +341,12 @@ static inline u32 test_and_clear_sta_flags(struct sta_info *sta,
                                           const u32 flags)
 {
        u32 ret;
+       unsigned long irqfl;
 
-       spin_lock_bh(&sta->lock);
+       spin_lock_irqsave(&sta->flaglock, irqfl);
        ret = sta->flags & flags;
        sta->flags &= ~flags;
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_irqrestore(&sta->flaglock, irqfl);
 
        return ret;
 }
@@ -341,10 +354,11 @@ static inline u32 test_and_clear_sta_flags(struct sta_info *sta,
 static inline u32 get_sta_flags(struct sta_info *sta)
 {
        u32 ret;
+       unsigned long irqfl;
 
-       spin_lock_bh(&sta->lock);
+       spin_lock_irqsave(&sta->flaglock, irqfl);
        ret = sta->flags;
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_irqrestore(&sta->flaglock, irqfl);
 
        return ret;
 }
index e710243d82e291e303d315cdea4d8a57dc86bf27..995f7af3d25e71cf2fc83473e1468dbd143a2fb1 100644 (file)
@@ -164,10 +164,10 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
        iv16 = data[2] | (data[0] << 8);
        iv32 = get_unaligned_le32(&data[4]);
 
-       tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
+       tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
        ctx = &key->u.tkip.tx;
 
-#ifdef CONFIG_TKIP_DEBUG
+#ifdef CONFIG_MAC80211_TKIP_DEBUG
        printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
                        iv16, iv32);
 
@@ -177,7 +177,7 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
                printk(KERN_DEBUG "Wrap around of iv16 in the middle of a "
                        "fragmented packet\n");
        }
-#endif /* CONFIG_TKIP_DEBUG */
+#endif
 
        /* Update the p1k only when the iv16 in the packet wraps around, this
         * might occur after the wrap around of iv16 in the key in case of
@@ -205,7 +205,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
 {
        u8 rc4key[16];
        struct tkip_ctx *ctx = &key->u.tkip.tx;
-       const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
+       const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
 
        /* Calculate per-packet key */
        if (ctx->iv16 == 0 || !ctx->initialized)
@@ -231,7 +231,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
        u32 iv16;
        u8 rc4key[16], keyid, *pos = payload;
        int res;
-       const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
+       const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
 
        if (payload_len < 12)
                return -1;
@@ -240,7 +240,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
        keyid = pos[3];
        iv32 = get_unaligned_le32(pos + 4);
        pos += 8;
-#ifdef CONFIG_TKIP_DEBUG
+#ifdef CONFIG_MAC80211_TKIP_DEBUG
        {
                int i;
                printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len);
@@ -250,7 +250,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
                printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n",
                       iv16, iv32);
        }
-#endif /* CONFIG_TKIP_DEBUG */
+#endif
 
        if (!(keyid & (1 << 5)))
                return TKIP_DECRYPT_NO_EXT_IV;
@@ -262,14 +262,14 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
            (iv32 < key->u.tkip.rx[queue].iv32 ||
             (iv32 == key->u.tkip.rx[queue].iv32 &&
              iv16 <= key->u.tkip.rx[queue].iv16))) {
-#ifdef CONFIG_TKIP_DEBUG
+#ifdef CONFIG_MAC80211_TKIP_DEBUG
                DECLARE_MAC_BUF(mac);
                printk(KERN_DEBUG "TKIP replay detected for RX frame from "
                       "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
                       print_mac(mac, ta),
                       iv32, iv16, key->u.tkip.rx[queue].iv32,
                       key->u.tkip.rx[queue].iv16);
-#endif /* CONFIG_TKIP_DEBUG */
+#endif
                return TKIP_DECRYPT_REPLAY;
        }
 
@@ -283,23 +283,23 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
            key->u.tkip.rx[queue].iv32 != iv32) {
                /* IV16 wrapped around - perform TKIP phase 1 */
                tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
-#ifdef CONFIG_TKIP_DEBUG
+#ifdef CONFIG_MAC80211_TKIP_DEBUG
                {
                        int i;
+                       u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY;
                        DECLARE_MAC_BUF(mac);
                        printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s"
                               " TK=", print_mac(mac, ta));
                        for (i = 0; i < 16; i++)
                                printk("%02x ",
-                                      key->conf.key[
-                                               ALG_TKIP_TEMP_ENCR_KEY + i]);
+                                      key->conf.key[key_offset + i]);
                        printk("\n");
                        printk(KERN_DEBUG "TKIP decrypt: P1K=");
                        for (i = 0; i < 5; i++)
                                printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
                        printk("\n");
                }
-#endif /* CONFIG_TKIP_DEBUG */
+#endif
                if (key->local->ops->update_tkip_key &&
                        key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
                        u8 bcast[ETH_ALEN] =
@@ -316,7 +316,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
        }
 
        tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
-#ifdef CONFIG_TKIP_DEBUG
+#ifdef CONFIG_MAC80211_TKIP_DEBUG
        {
                int i;
                printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key=");
@@ -324,7 +324,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
                        printk("%02x ", rc4key[i]);
                printk("\n");
        }
-#endif /* CONFIG_TKIP_DEBUG */
+#endif
 
        res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
  done:
index ce06e791bf43a7a11b5814be0bc4ef455b6d3c00..52ab85c4341ba419522dafa597f5a561acb8f46f 100644 (file)
@@ -52,9 +52,8 @@ static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdat
 static void ieee80211_dump_frame(const char *ifname, const char *title,
                                 const struct sk_buff *skb)
 {
-       const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u16 fc;
-       int hdrlen;
+       const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       unsigned int hdrlen;
        DECLARE_MAC_BUF(mac);
 
        printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
@@ -63,13 +62,12 @@ static void ieee80211_dump_frame(const char *ifname, const char *title,
                return;
        }
 
-       fc = le16_to_cpu(hdr->frame_control);
-       hdrlen = ieee80211_get_hdrlen(fc);
+       hdrlen = ieee80211_hdrlen(hdr->frame_control);
        if (hdrlen > skb->len)
                hdrlen = skb->len;
        if (hdrlen >= 4)
                printk(" FC=0x%04x DUR=0x%04x",
-                      fc, le16_to_cpu(hdr->duration_id));
+                   le16_to_cpu(hdr->frame_control), le16_to_cpu(hdr->duration_id));
        if (hdrlen >= 10)
                printk(" A1=%s", print_mac(mac, hdr->addr1));
        if (hdrlen >= 16)
@@ -87,8 +85,8 @@ static inline void ieee80211_dump_frame(const char *ifname, const char *title,
 }
 #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
 
-static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
-                             int next_frag_len)
+static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
+                                int next_frag_len)
 {
        int rate, mrate, erp, dur, i;
        struct ieee80211_rate *txrate;
@@ -140,7 +138,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
 
        /* data/mgmt */
        if (0 /* FIX: data/mgmt during CFP */)
-               return 32768;
+               return cpu_to_le16(32768);
 
        if (group_addr) /* Group address as the destination - no ACK */
                return 0;
@@ -210,7 +208,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
                                tx->sdata->bss_conf.use_short_preamble);
        }
 
-       return dur;
+       return cpu_to_le16(dur);
 }
 
 static int inline is_ieee80211_device(struct net_device *dev,
@@ -281,7 +279,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 
-       if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
+       if (ieee80211_hdrlen(hdr->frame_control) >= 24)
                ieee80211_include_sequence(tx->sdata, hdr);
 
        return TX_CONTINUE;
@@ -542,9 +540,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 static ieee80211_tx_result
 ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-       u16 fc = le16_to_cpu(hdr->frame_control);
-       u16 dur;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        struct ieee80211_supported_band *sband;
 
@@ -595,21 +591,13 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
        /* Transmit data frames using short preambles if the driver supports
         * short preambles at the selected rate and short preambles are
         * available on the network at the current point in time. */
-       if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+       if (ieee80211_is_data(hdr->frame_control) &&
            (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
            tx->sdata->bss_conf.use_short_preamble &&
            (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
                info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
        }
 
-       /* Setup duration field for the first fragment of the frame. Duration
-        * for remaining fragments will be updated when they are being sent
-        * to low-level driver in ieee80211_tx(). */
-       dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
-                                (tx->flags & IEEE80211_TX_FRAGMENTED) ?
-                                tx->extra_frag[0]->len : 0);
-       hdr->duration_id = cpu_to_le16(dur);
-
        if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
            (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
                struct ieee80211_rate *rate;
@@ -647,7 +635,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
 static ieee80211_tx_result
 ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        size_t hdrlen, per_fragm, num_fragm, payload_len, left;
        struct sk_buff **frags, *first, *frag;
        int i;
@@ -670,7 +658,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 
        first = tx->skb;
 
-       hdrlen = ieee80211_get_hdrlen(tx->fc);
+       hdrlen = ieee80211_hdrlen(hdr->frame_control);
        payload_len = first->len - hdrlen;
        per_fragm = frag_threshold - hdrlen - FCS_LEN;
        num_fragm = DIV_ROUND_UP(payload_len, per_fragm);
@@ -711,6 +699,8 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
                fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
                copylen = left > per_fragm ? per_fragm : left;
                memcpy(skb_put(frag, copylen), pos, copylen);
+               memcpy(frag->cb, first->cb, sizeof(frag->cb));
+               skb_copy_queue_mapping(frag, first);
 
                pos += copylen;
                left -= copylen;
@@ -754,6 +744,36 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
        return TX_DROP;
 }
 
+static ieee80211_tx_result
+ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+       int next_len, i;
+       int group_addr = is_multicast_ether_addr(hdr->addr1);
+
+       if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) {
+               hdr->duration_id = ieee80211_duration(tx, group_addr, 0);
+               return TX_CONTINUE;
+       }
+
+       hdr->duration_id = ieee80211_duration(tx, group_addr,
+                                             tx->extra_frag[0]->len);
+
+       for (i = 0; i < tx->num_extra_frag; i++) {
+               if (i + 1 < tx->num_extra_frag) {
+                       next_len = tx->extra_frag[i + 1]->len;
+               } else {
+                       next_len = 0;
+                       tx->rate_idx = tx->last_frag_rate_idx;
+               }
+
+               hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data;
+               hdr->duration_id = ieee80211_duration(tx, 0, next_len);
+       }
+
+       return TX_CONTINUE;
+}
+
 static ieee80211_tx_result
 ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
 {
@@ -788,6 +808,7 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] =
        ieee80211_tx_h_fragment,
        /* handlers after fragment must be aware of tx info fragmentation! */
        ieee80211_tx_h_encrypt,
+       ieee80211_tx_h_calculate_duration,
        ieee80211_tx_h_stats,
        NULL
 };
@@ -1083,13 +1104,46 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
        return IEEE80211_TX_OK;
 }
 
+/*
+ * Invoke TX handlers, return 0 on success and non-zero if the
+ * frame was dropped or queued.
+ */
+static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
+{
+       struct ieee80211_local *local = tx->local;
+       struct sk_buff *skb = tx->skb;
+       ieee80211_tx_handler *handler;
+       ieee80211_tx_result res = TX_DROP;
+       int i;
+
+       for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
+               res = (*handler)(tx);
+               if (res != TX_CONTINUE)
+                       break;
+       }
+
+       if (unlikely(res == TX_DROP)) {
+               I802_DEBUG_INC(local->tx_handlers_drop);
+               dev_kfree_skb(skb);
+               for (i = 0; i < tx->num_extra_frag; i++)
+                       if (tx->extra_frag[i])
+                               dev_kfree_skb(tx->extra_frag[i]);
+               kfree(tx->extra_frag);
+               return -1;
+       } else if (unlikely(res == TX_QUEUED)) {
+               I802_DEBUG_INC(local->tx_handlers_queued);
+               return -1;
+       }
+
+       return 0;
+}
+
 static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct sta_info *sta;
-       ieee80211_tx_handler *handler;
        struct ieee80211_tx_data tx;
-       ieee80211_tx_result res = TX_DROP, res_prepare;
+       ieee80211_tx_result res_prepare;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int ret, i;
        u16 queue;
@@ -1118,44 +1172,8 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
        tx.channel = local->hw.conf.channel;
        info->band = tx.channel->band;
 
-       for (handler = ieee80211_tx_handlers; *handler != NULL;
-            handler++) {
-               res = (*handler)(&tx);
-               if (res != TX_CONTINUE)
-                       break;
-       }
-
-       if (WARN_ON(tx.skb != skb))
-               goto drop;
-
-       if (unlikely(res == TX_DROP)) {
-               I802_DEBUG_INC(local->tx_handlers_drop);
-               goto drop;
-       }
-
-       if (unlikely(res == TX_QUEUED)) {
-               I802_DEBUG_INC(local->tx_handlers_queued);
-               rcu_read_unlock();
-               return 0;
-       }
-
-       if (tx.extra_frag) {
-               for (i = 0; i < tx.num_extra_frag; i++) {
-                       int next_len, dur;
-                       struct ieee80211_hdr *hdr =
-                               (struct ieee80211_hdr *)
-                               tx.extra_frag[i]->data;
-
-                       if (i + 1 < tx.num_extra_frag) {
-                               next_len = tx.extra_frag[i + 1]->len;
-                       } else {
-                               next_len = 0;
-                               tx.rate_idx = tx.last_frag_rate_idx;
-                       }
-                       dur = ieee80211_duration(&tx, 0, next_len);
-                       hdr->duration_id = cpu_to_le16(dur);
-               }
-       }
+       if (invoke_tx_handlers(&tx))
+               goto out;
 
 retry:
        ret = __ieee80211_tx(local, skb, &tx);
@@ -1198,6 +1216,7 @@ retry:
                store->last_frag_rate_ctrl_probe =
                        !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
        }
+ out:
        rcu_read_unlock();
        return 0;
 
@@ -1379,7 +1398,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        struct ieee80211_tx_info *info;
        struct ieee80211_sub_if_data *sdata;
        int ret = 1, head_need;
-       u16 ethertype, hdrlen,  meshhdrlen = 0, fc;
+       u16 ethertype, hdrlen,  meshhdrlen = 0;
+       __le16 fc;
        struct ieee80211_hdr hdr;
        struct ieee80211s_hdr mesh_hdr;
        const u8 *encaps_data;
@@ -1402,12 +1422,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        /* convert Ethernet header to proper 802.11 header (based on
         * operation mode) */
        ethertype = (skb->data[12] << 8) | skb->data[13];
-       fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
+       fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
 
        switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_AP:
        case IEEE80211_IF_TYPE_VLAN:
-               fc |= IEEE80211_FCTL_FROMDS;
+               fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
                /* DA BSSID SA */
                memcpy(hdr.addr1, skb->data, ETH_ALEN);
                memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
@@ -1415,7 +1435,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                hdrlen = 24;
                break;
        case IEEE80211_IF_TYPE_WDS:
-               fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+               fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                /* RA TA DA SA */
                memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
                memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
@@ -1425,7 +1445,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                break;
 #ifdef CONFIG_MAC80211_MESH
        case IEEE80211_IF_TYPE_MESH_POINT:
-               fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+               fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                /* RA TA DA SA */
                if (is_multicast_ether_addr(skb->data))
                        memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -1455,7 +1475,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                break;
 #endif
        case IEEE80211_IF_TYPE_STA:
-               fc |= IEEE80211_FCTL_TODS;
+               fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
                /* BSSID SA DA */
                memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
                memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
@@ -1490,7 +1510,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        /* receiver and we are QoS enabled, use a QoS type frame */
        if (sta_flags & WLAN_STA_WME &&
            ieee80211_num_regular_queues(&local->hw) >= 4) {
-               fc |= IEEE80211_STYPE_QOS_DATA;
+               fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
                hdrlen += 2;
        }
 
@@ -1518,7 +1538,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                goto fail;
        }
 
-       hdr.frame_control = cpu_to_le16(fc);
+       hdr.frame_control = fc;
        hdr.duration_id = 0;
        hdr.seq_ctrl = 0;
 
@@ -1587,7 +1607,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                h_pos += meshhdrlen;
        }
 
-       if (fc & IEEE80211_STYPE_QOS_DATA) {
+       if (ieee80211_is_data_qos(fc)) {
                __le16 *qos_control;
 
                qos_control = (__le16*) skb_push(skb, 2);
@@ -1845,8 +1865,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                mgmt = (struct ieee80211_mgmt *)
                        skb_put(skb, 24 + sizeof(mgmt->u.beacon));
                memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
-               mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                                  IEEE80211_STYPE_BEACON);
+               mgmt->frame_control =
+                   cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
                memset(mgmt->da, 0xff, ETH_ALEN);
                memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
                /* BSSID is left zeroed, wildcard value */
@@ -1914,10 +1934,9 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       struct ieee80211_rts *rts)
 {
        const struct ieee80211_hdr *hdr = frame;
-       u16 fctl;
 
-       fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
-       rts->frame_control = cpu_to_le16(fctl);
+       rts->frame_control =
+           cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
        rts->duration = ieee80211_rts_duration(hw, vif, frame_len,
                                               frame_txctl);
        memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
@@ -1931,10 +1950,9 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                             struct ieee80211_cts *cts)
 {
        const struct ieee80211_hdr *hdr = frame;
-       u16 fctl;
 
-       fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;
-       cts->frame_control = cpu_to_le16(fctl);
+       cts->frame_control =
+           cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
        cts->duration = ieee80211_ctstoself_duration(hw, vif,
                                                     frame_len, frame_txctl);
        memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
@@ -1948,9 +1966,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
        struct ieee80211_local *local = hw_to_local(hw);
        struct sk_buff *skb = NULL;
        struct sta_info *sta;
-       ieee80211_tx_handler *handler;
        struct ieee80211_tx_data tx;
-       ieee80211_tx_result res = TX_DROP;
        struct net_device *bdev;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_if_ap *bss = NULL;
@@ -2001,25 +2017,9 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
        tx.channel = local->hw.conf.channel;
        info->band = tx.channel->band;
 
-       for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
-               res = (*handler)(&tx);
-               if (res == TX_DROP || res == TX_QUEUED)
-                       break;
-       }
-
-       if (WARN_ON(tx.skb != skb))
-               res = TX_DROP;
-
-       if (res == TX_DROP) {
-               I802_DEBUG_INC(local->tx_handlers_drop);
-               dev_kfree_skb(skb);
+       if (invoke_tx_handlers(&tx))
                skb = NULL;
-       } else if (res == TX_QUEUED) {
-               I802_DEBUG_INC(local->tx_handlers_queued);
-               skb = NULL;
-       }
-
-out:
+ out:
        rcu_read_unlock();
 
        return skb;
index e7b6344c900a6f15005748b1f1650ab03eb5a1ec..35b664d00e239e2e65b80c5504900b5290a329d2 100644 (file)
@@ -84,20 +84,17 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
                                struct sk_buff *skb,
                                struct ieee80211_key *key)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u16 fc;
-       int hdrlen;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       unsigned int hdrlen;
        u8 *newhdr;
 
-       fc = le16_to_cpu(hdr->frame_control);
-       fc |= IEEE80211_FCTL_PROTECTED;
-       hdr->frame_control = cpu_to_le16(fc);
+       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 
        if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN ||
                    skb_headroom(skb) < WEP_IV_LEN))
                return NULL;
 
-       hdrlen = ieee80211_get_hdrlen(fc);
+       hdrlen = ieee80211_hdrlen(hdr->frame_control);
        newhdr = skb_push(skb, WEP_IV_LEN);
        memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
        ieee80211_wep_get_iv(local, key, newhdr + hdrlen);
@@ -109,12 +106,10 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local,
                                    struct sk_buff *skb,
                                    struct ieee80211_key *key)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u16 fc;
-       int hdrlen;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       unsigned int hdrlen;
 
-       fc = le16_to_cpu(hdr->frame_control);
-       hdrlen = ieee80211_get_hdrlen(fc);
+       hdrlen = ieee80211_hdrlen(hdr->frame_control);
        memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen);
        skb_pull(skb, WEP_IV_LEN);
 }
@@ -224,17 +219,15 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
        u32 klen;
        u8 *rc4key;
        u8 keyidx;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u16 fc;
-       int hdrlen;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       unsigned int hdrlen;
        size_t len;
        int ret = 0;
 
-       fc = le16_to_cpu(hdr->frame_control);
-       if (!(fc & IEEE80211_FCTL_PROTECTED))
+       if (!ieee80211_has_protected(hdr->frame_control))
                return -1;
 
-       hdrlen = ieee80211_get_hdrlen(fc);
+       hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
        if (skb->len < 8 + hdrlen)
                return -1;
@@ -281,17 +274,15 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
 
 u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u16 fc;
-       int hdrlen;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       unsigned int hdrlen;
        u8 *ivpos;
        u32 iv;
 
-       fc = le16_to_cpu(hdr->frame_control);
-       if (!(fc & IEEE80211_FCTL_PROTECTED))
+       if (!ieee80211_has_protected(hdr->frame_control))
                return NULL;
 
-       hdrlen = ieee80211_get_hdrlen(fc);
+       hdrlen = ieee80211_hdrlen(hdr->frame_control);
        ivpos = skb->data + hdrlen;
        iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
 
index 5af3862e7191e8a991c1d60262f7292222f571ec..df0531c28141e99fcfb33f0f9362295e9eb22f6a 100644 (file)
@@ -135,7 +135,39 @@ static int ieee80211_ioctl_giwname(struct net_device *dev,
                                   struct iw_request_info *info,
                                   char *name, char *extra)
 {
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_supported_band *sband;
+       u8 is_ht = 0, is_a = 0, is_b = 0, is_g = 0;
+
+
+       sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ];
+       if (sband) {
+               is_a = 1;
+               is_ht |= sband->ht_info.ht_supported;
+       }
+
+       sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ];
+       if (sband) {
+               int i;
+               /* Check for mandatory rates */
+               for (i = 0; i < sband->n_bitrates; i++) {
+                       if (sband->bitrates[i].bitrate == 10)
+                               is_b = 1;
+                       if (sband->bitrates[i].bitrate == 60)
+                               is_g = 1;
+               }
+               is_ht |= sband->ht_info.ht_supported;
+       }
+
        strcpy(name, "IEEE 802.11");
+       if (is_a)
+               strcat(name, "a");
+       if (is_b)
+               strcat(name, "b");
+       if (is_g)
+               strcat(name, "g");
+       if (is_ht)
+               strcat(name, "n");
 
        return 0;
 }
@@ -567,7 +599,7 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
        if (local->sta_sw_scanning || local->sta_hw_scanning)
                return -EAGAIN;
 
-       res = ieee80211_sta_scan_results(dev, extra, data->length);
+       res = ieee80211_sta_scan_results(dev, info, extra, data->length);
        if (res >= 0) {
                data->length = res;
                return 0;
@@ -721,6 +753,9 @@ static int ieee80211_ioctl_siwrts(struct net_device *dev,
 
        if (rts->disabled)
                local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+       else if (!rts->fixed)
+               /* if the rts value is not fixed, then take default */
+               local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
        else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
                return -EINVAL;
        else
@@ -949,6 +984,19 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
        erq->length = sdata->keys[idx]->conf.keylen;
        erq->flags |= IW_ENCODE_ENABLED;
 
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
+               struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+               switch (ifsta->auth_alg) {
+               case WLAN_AUTH_OPEN:
+               case WLAN_AUTH_LEAP:
+                       erq->flags |= IW_ENCODE_OPEN;
+                       break;
+               case WLAN_AUTH_SHARED_KEY:
+                       erq->flags |= IW_ENCODE_RESTRICTED;
+                       break;
+               }
+       }
+
        return 0;
 }
 
index 345e10e9b313c3a88bceaa1cfb05bac08a2eda58..f809761fbfb50c8f3ed41a5af2a8b786cc5ee23f 100644 (file)
@@ -49,7 +49,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
 ieee80211_tx_result
 ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
 {
-       u8 *data, *sa, *da, *key, *mic, qos_tid;
+       u8 *data, *sa, *da, *key, *mic, qos_tid, key_offset;
        size_t data_len;
        u16 fc;
        struct sk_buff *skb = tx->skb;
@@ -88,8 +88,12 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
 #else
        authenticator = 1;
 #endif
-       key = &tx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY :
-                                ALG_TKIP_TEMP_AUTH_RX_MIC_KEY];
+       /* At this point we know we're using ALG_TKIP. To get the MIC key
+        * we now will rely on the offset from the ieee80211_key_conf::key */
+       key_offset = authenticator ?
+               NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY :
+               NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
+       key = &tx->key->conf.key[key_offset];
        mic = skb_put(skb, MICHAEL_MIC_LEN);
        michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
 
@@ -100,7 +104,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
 ieee80211_rx_result
 ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
 {
-       u8 *data, *sa, *da, *key = NULL, qos_tid;
+       u8 *data, *sa, *da, *key = NULL, qos_tid, key_offset;
        size_t data_len;
        u16 fc;
        u8 mic[MICHAEL_MIC_LEN];
@@ -131,8 +135,12 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
 #else
        authenticator = 1;
 #endif
-       key = &rx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY :
-                                ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
+       /* At this point we know we're using ALG_TKIP. To get the MIC key
+        * we now will rely on the offset from the ieee80211_key_conf::key */
+       key_offset = authenticator ?
+               NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY :
+               NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
+       key = &rx->key->conf.key[key_offset];
        michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
        if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
                if (!(rx->flags & IEEE80211_RX_RA_MATCH))
index 0099da5b2591e5295429b7578688fa6949db3db1..52b2611a6eb6625f8d1d329bea03d03e7ad460ac 100644 (file)
@@ -1534,7 +1534,7 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
                }
        }
        list_for_each_entry_rcu(addr6, &iface->addr6_list, list) {
-               if (addr6->valid || iter_addr6++ < skip_addr6)
+               if (!addr6->valid || iter_addr6++ < skip_addr6)
                        continue;
                if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
                                           iface,
index 47bbf45ae5d7905e05487955d77832e03915f215..2d106cfe1d276bf5e234195753eb091cba7b7f1e 100644 (file)
@@ -132,6 +132,7 @@ errout:
  * @maxtype: maximum attribute type to be expected
  * @head: head of attribute stream
  * @len: length of attribute stream
+ * @policy: validation policy
  *
  * Parses a stream of attributes and stores a pointer to each attribute in
  * the tb array accessable via the attribute type. Attributes with a type
@@ -194,7 +195,7 @@ struct nlattr *nla_find(struct nlattr *head, int len, int attrtype)
 /**
  * nla_strlcpy - Copy string attribute payload into a sized buffer
  * @dst: where to copy the string to
- * @src: attribute to copy the string from
+ * @nla: attribute to copy the string from
  * @dstsize: size of destination buffer
  *
  * Copies at most dstsize - 1 bytes into the destination buffer.
@@ -340,9 +341,9 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
 }
 
 /**
- * nla_reserve - reserve room for attribute without header
+ * nla_reserve_nohdr - reserve room for attribute without header
  * @skb: socket buffer to reserve room on
- * @len: length of attribute payload
+ * @attrlen: length of attribute payload
  *
  * Reserves room for attribute payload without a header.
  *
index e4b051dbed612bc45726328f73a18c65ad81f87b..8aa82273014516a14a8184bd44cdcdff70f972af 100644 (file)
@@ -30,39 +30,62 @@ struct rfkill_task {
        spinlock_t lock; /* for accessing last and desired state */
        unsigned long last; /* last schedule */
        enum rfkill_state desired_state; /* on/off */
-       enum rfkill_state current_state; /* on/off */
 };
 
 static void rfkill_task_handler(struct work_struct *work)
 {
        struct rfkill_task *task = container_of(work, struct rfkill_task, work);
-       enum rfkill_state state;
 
        mutex_lock(&task->mutex);
 
-       /*
-        * Use temp variable to fetch desired state to keep it
-        * consistent even if rfkill_schedule_toggle() runs in
-        * another thread or interrupts us.
-        */
-       state = task->desired_state;
+       rfkill_switch_all(task->type, task->desired_state);
 
-       if (state != task->current_state) {
-               rfkill_switch_all(task->type, state);
-               task->current_state = state;
+       mutex_unlock(&task->mutex);
+}
+
+static void rfkill_task_epo_handler(struct work_struct *work)
+{
+       rfkill_epo();
+}
+
+static DECLARE_WORK(epo_work, rfkill_task_epo_handler);
+
+static void rfkill_schedule_epo(void)
+{
+       schedule_work(&epo_work);
+}
+
+static void rfkill_schedule_set(struct rfkill_task *task,
+                               enum rfkill_state desired_state)
+{
+       unsigned long flags;
+
+       if (unlikely(work_pending(&epo_work)))
+               return;
+
+       spin_lock_irqsave(&task->lock, flags);
+
+       if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
+               task->desired_state = desired_state;
+               task->last = jiffies;
+               schedule_work(&task->work);
        }
 
-       mutex_unlock(&task->mutex);
+       spin_unlock_irqrestore(&task->lock, flags);
 }
 
 static void rfkill_schedule_toggle(struct rfkill_task *task)
 {
        unsigned long flags;
 
+       if (unlikely(work_pending(&epo_work)))
+               return;
+
        spin_lock_irqsave(&task->lock, flags);
 
        if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
-               task->desired_state = !task->desired_state;
+               task->desired_state =
+                               rfkill_state_complement(task->desired_state);
                task->last = jiffies;
                schedule_work(&task->work);
        }
@@ -70,26 +93,26 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
        spin_unlock_irqrestore(&task->lock, flags);
 }
 
-#define DEFINE_RFKILL_TASK(n, t)                       \
-       struct rfkill_task n = {                        \
-               .work = __WORK_INITIALIZER(n.work,      \
-                               rfkill_task_handler),   \
-               .type = t,                              \
-               .mutex = __MUTEX_INITIALIZER(n.mutex),  \
-               .lock = __SPIN_LOCK_UNLOCKED(n.lock),   \
-               .desired_state = RFKILL_STATE_ON,       \
-               .current_state = RFKILL_STATE_ON,       \
+#define DEFINE_RFKILL_TASK(n, t)                               \
+       struct rfkill_task n = {                                \
+               .work = __WORK_INITIALIZER(n.work,              \
+                               rfkill_task_handler),           \
+               .type = t,                                      \
+               .mutex = __MUTEX_INITIALIZER(n.mutex),          \
+               .lock = __SPIN_LOCK_UNLOCKED(n.lock),           \
+               .desired_state = RFKILL_STATE_UNBLOCKED,        \
        }
 
 static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
 static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
 static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
 static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
+static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
 
 static void rfkill_event(struct input_handle *handle, unsigned int type,
-                       unsigned int code, int down)
+                       unsigned int code, int data)
 {
-       if (type == EV_KEY && down == 1) {
+       if (type == EV_KEY && data == 1) {
                switch (code) {
                case KEY_WLAN:
                        rfkill_schedule_toggle(&rfkill_wlan);
@@ -106,6 +129,28 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
                default:
                        break;
                }
+       } else if (type == EV_SW) {
+               switch (code) {
+               case SW_RFKILL_ALL:
+                       /* EVERY radio type. data != 0 means radios ON */
+                       /* handle EPO (emergency power off) through shortcut */
+                       if (data) {
+                               rfkill_schedule_set(&rfkill_wwan,
+                                                   RFKILL_STATE_UNBLOCKED);
+                               rfkill_schedule_set(&rfkill_wimax,
+                                                   RFKILL_STATE_UNBLOCKED);
+                               rfkill_schedule_set(&rfkill_uwb,
+                                                   RFKILL_STATE_UNBLOCKED);
+                               rfkill_schedule_set(&rfkill_bt,
+                                                   RFKILL_STATE_UNBLOCKED);
+                               rfkill_schedule_set(&rfkill_wlan,
+                                                   RFKILL_STATE_UNBLOCKED);
+                       } else
+                               rfkill_schedule_epo();
+                       break;
+               default:
+                       break;
+               }
        }
 }
 
@@ -168,6 +213,11 @@ static const struct input_device_id rfkill_ids[] = {
                .evbit = { BIT_MASK(EV_KEY) },
                .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
        },
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT,
+               .evbit = { BIT(EV_SW) },
+               .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) },
+       },
        { }
 };
 
index 4dae5006fc776639764158b2a11e1f3c9b080885..f63d05045685a6d36b02bd494b6d14d96a737ac3 100644 (file)
@@ -12,5 +12,6 @@
 #define __RFKILL_INPUT_H
 
 void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
+void rfkill_epo(void);
 
 #endif /* __RFKILL_INPUT_H */
index 4e10a95de8321acfd3ea3aa37885d1519f2a0ecf..ce0e23148cdde2bf6cb714da88f528255d9f6b08 100644 (file)
@@ -39,8 +39,56 @@ MODULE_LICENSE("GPL");
 static LIST_HEAD(rfkill_list); /* list of registered rf switches */
 static DEFINE_MUTEX(rfkill_mutex);
 
+static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED;
+module_param_named(default_state, rfkill_default_state, uint, 0444);
+MODULE_PARM_DESC(default_state,
+                "Default initial state for all radio types, 0 = radio off");
+
 static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX];
 
+static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list);
+
+
+/**
+ * register_rfkill_notifier - Add notifier to rfkill notifier chain
+ * @nb: pointer to the new entry to add to the chain
+ *
+ * See blocking_notifier_chain_register() for return value and further
+ * observations.
+ *
+ * Adds a notifier to the rfkill notifier chain.  The chain will be
+ * called with a pointer to the relevant rfkill structure as a parameter,
+ * refer to include/linux/rfkill.h for the possible events.
+ *
+ * Notifiers added to this chain are to always return NOTIFY_DONE.  This
+ * chain is a blocking notifier chain: notifiers can sleep.
+ *
+ * Calls to this chain may have been done through a workqueue.  One must
+ * assume unordered asynchronous behaviour, there is no way to know if
+ * actions related to the event that generated the notification have been
+ * carried out already.
+ */
+int register_rfkill_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&rfkill_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_rfkill_notifier);
+
+/**
+ * unregister_rfkill_notifier - remove notifier from rfkill notifier chain
+ * @nb: pointer to the entry to remove from the chain
+ *
+ * See blocking_notifier_chain_unregister() for return value and further
+ * observations.
+ *
+ * Removes a notifier from the rfkill notifier chain.
+ */
+int unregister_rfkill_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_rfkill_notifier);
+
 
 static void rfkill_led_trigger(struct rfkill *rfkill,
                               enum rfkill_state state)
@@ -50,24 +98,99 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
 
        if (!led->name)
                return;
-       if (state == RFKILL_STATE_OFF)
+       if (state != RFKILL_STATE_UNBLOCKED)
                led_trigger_event(led, LED_OFF);
        else
                led_trigger_event(led, LED_FULL);
 #endif /* CONFIG_RFKILL_LEDS */
 }
 
+static void notify_rfkill_state_change(struct rfkill *rfkill)
+{
+       blocking_notifier_call_chain(&rfkill_notifier_list,
+                       RFKILL_STATE_CHANGED,
+                       rfkill);
+}
+
+static void update_rfkill_state(struct rfkill *rfkill)
+{
+       enum rfkill_state newstate, oldstate;
+
+       if (rfkill->get_state) {
+               mutex_lock(&rfkill->mutex);
+               if (!rfkill->get_state(rfkill->data, &newstate)) {
+                       oldstate = rfkill->state;
+                       rfkill->state = newstate;
+                       if (oldstate != newstate)
+                               notify_rfkill_state_change(rfkill);
+               }
+               mutex_unlock(&rfkill->mutex);
+       }
+}
+
+/**
+ * rfkill_toggle_radio - wrapper for toggle_radio hook
+ * calls toggle_radio taking into account a lot of "small"
+ * details.
+ * @rfkill: the rfkill struct to use
+ * @force: calls toggle_radio even if cache says it is not needed,
+ *     and also makes sure notifications of the state will be
+ *     sent even if it didn't change
+ * @state: the new state to call toggle_radio() with
+ *
+ * This wrappen protects and enforces the API for toggle_radio
+ * calls.  Note that @force cannot override a (possibly cached)
+ * state of RFKILL_STATE_HARD_BLOCKED.  Any device making use of
+ * RFKILL_STATE_HARD_BLOCKED implements either get_state() or
+ * rfkill_force_state(), so the cache either is bypassed or valid.
+ *
+ * Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED
+ * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to
+ * give the driver a hint that it should double-BLOCK the transmitter.
+ *
+ * Caller must have aquired rfkill_mutex.
+ */
 static int rfkill_toggle_radio(struct rfkill *rfkill,
-                               enum rfkill_state state)
+                               enum rfkill_state state,
+                               int force)
 {
        int retval = 0;
+       enum rfkill_state oldstate, newstate;
+
+       oldstate = rfkill->state;
 
-       if (state != rfkill->state) {
+       if (rfkill->get_state && !force &&
+           !rfkill->get_state(rfkill->data, &newstate))
+               rfkill->state = newstate;
+
+       switch (state) {
+       case RFKILL_STATE_HARD_BLOCKED:
+               /* typically happens when refreshing hardware state,
+                * such as on resume */
+               state = RFKILL_STATE_SOFT_BLOCKED;
+               break;
+       case RFKILL_STATE_UNBLOCKED:
+               /* force can't override this, only rfkill_force_state() can */
+               if (rfkill->state == RFKILL_STATE_HARD_BLOCKED)
+                       return -EPERM;
+               break;
+       case RFKILL_STATE_SOFT_BLOCKED:
+               /* nothing to do, we want to give drivers the hint to double
+                * BLOCK even a transmitter that is already in state
+                * RFKILL_STATE_HARD_BLOCKED */
+               break;
+       }
+
+       if (force || state != rfkill->state) {
                retval = rfkill->toggle_radio(rfkill->data, state);
-               if (!retval) {
+               /* never allow a HARD->SOFT downgrade! */
+               if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED)
                        rfkill->state = state;
-                       rfkill_led_trigger(rfkill, state);
-               }
+       }
+
+       if (force || rfkill->state != oldstate) {
+               rfkill_led_trigger(rfkill, rfkill->state);
+               notify_rfkill_state_change(rfkill);
        }
 
        return retval;
@@ -82,7 +205,6 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
  * a specific switch is claimed by userspace in which case it is
  * left alone.
  */
-
 void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
 {
        struct rfkill *rfkill;
@@ -93,13 +215,66 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
 
        list_for_each_entry(rfkill, &rfkill_list, node) {
                if ((!rfkill->user_claim) && (rfkill->type == type))
-                       rfkill_toggle_radio(rfkill, state);
+                       rfkill_toggle_radio(rfkill, state, 0);
        }
 
        mutex_unlock(&rfkill_mutex);
 }
 EXPORT_SYMBOL(rfkill_switch_all);
 
+/**
+ * rfkill_epo - emergency power off all transmitters
+ *
+ * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring
+ * everything in its path but rfkill_mutex.
+ */
+void rfkill_epo(void)
+{
+       struct rfkill *rfkill;
+
+       mutex_lock(&rfkill_mutex);
+       list_for_each_entry(rfkill, &rfkill_list, node) {
+               rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
+       }
+       mutex_unlock(&rfkill_mutex);
+}
+EXPORT_SYMBOL_GPL(rfkill_epo);
+
+/**
+ * rfkill_force_state - Force the internal rfkill radio state
+ * @rfkill: pointer to the rfkill class to modify.
+ * @state: the current radio state the class should be forced to.
+ *
+ * This function updates the internal state of the radio cached
+ * by the rfkill class.  It should be used when the driver gets
+ * a notification by the firmware/hardware of the current *real*
+ * state of the radio rfkill switch.
+ *
+ * It may not be called from an atomic context.
+ */
+int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
+{
+       enum rfkill_state oldstate;
+
+       if (state != RFKILL_STATE_SOFT_BLOCKED &&
+           state != RFKILL_STATE_UNBLOCKED &&
+           state != RFKILL_STATE_HARD_BLOCKED)
+               return -EINVAL;
+
+       mutex_lock(&rfkill->mutex);
+
+       oldstate = rfkill->state;
+       rfkill->state = state;
+
+       if (state != oldstate)
+               notify_rfkill_state_change(rfkill);
+
+       mutex_unlock(&rfkill->mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(rfkill_force_state);
+
 static ssize_t rfkill_name_show(struct device *dev,
                                struct device_attribute *attr,
                                char *buf)
@@ -109,31 +284,31 @@ static ssize_t rfkill_name_show(struct device *dev,
        return sprintf(buf, "%s\n", rfkill->name);
 }
 
-static ssize_t rfkill_type_show(struct device *dev,
-                               struct device_attribute *attr,
-                               char *buf)
+static const char *rfkill_get_type_str(enum rfkill_type type)
 {
-       struct rfkill *rfkill = to_rfkill(dev);
-       const char *type;
-
-       switch (rfkill->type) {
+       switch (type) {
        case RFKILL_TYPE_WLAN:
-               type = "wlan";
-               break;
+               return "wlan";
        case RFKILL_TYPE_BLUETOOTH:
-               type = "bluetooth";
-               break;
+               return "bluetooth";
        case RFKILL_TYPE_UWB:
-               type = "ultrawideband";
-               break;
+               return "ultrawideband";
        case RFKILL_TYPE_WIMAX:
-               type = "wimax";
-               break;
+               return "wimax";
+       case RFKILL_TYPE_WWAN:
+               return "wwan";
        default:
                BUG();
        }
+}
+
+static ssize_t rfkill_type_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
 
-       return sprintf(buf, "%s\n", type);
+       return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type));
 }
 
 static ssize_t rfkill_state_show(struct device *dev,
@@ -142,6 +317,7 @@ static ssize_t rfkill_state_show(struct device *dev,
 {
        struct rfkill *rfkill = to_rfkill(dev);
 
+       update_rfkill_state(rfkill);
        return sprintf(buf, "%d\n", rfkill->state);
 }
 
@@ -156,10 +332,14 @@ static ssize_t rfkill_state_store(struct device *dev,
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
+       /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
+       if (state != RFKILL_STATE_UNBLOCKED &&
+           state != RFKILL_STATE_SOFT_BLOCKED)
+               return -EINVAL;
+
        if (mutex_lock_interruptible(&rfkill->mutex))
                return -ERESTARTSYS;
-       error = rfkill_toggle_radio(rfkill,
-                       state ? RFKILL_STATE_ON : RFKILL_STATE_OFF);
+       error = rfkill_toggle_radio(rfkill, state, 0);
        mutex_unlock(&rfkill->mutex);
 
        return error ? error : count;
@@ -200,7 +380,8 @@ static ssize_t rfkill_claim_store(struct device *dev,
        if (rfkill->user_claim != claim) {
                if (!claim)
                        rfkill_toggle_radio(rfkill,
-                                           rfkill_states[rfkill->type]);
+                                           rfkill_states[rfkill->type],
+                                           0);
                rfkill->user_claim = claim;
        }
 
@@ -233,12 +414,12 @@ static int rfkill_suspend(struct device *dev, pm_message_t state)
 
        if (dev->power.power_state.event != state.event) {
                if (state.event & PM_EVENT_SLEEP) {
-                       mutex_lock(&rfkill->mutex);
-
-                       if (rfkill->state == RFKILL_STATE_ON)
-                               rfkill->toggle_radio(rfkill->data,
-                                                    RFKILL_STATE_OFF);
+                       /* Stop transmitter, keep state, no notifies */
+                       update_rfkill_state(rfkill);
 
+                       mutex_lock(&rfkill->mutex);
+                       rfkill->toggle_radio(rfkill->data,
+                                               RFKILL_STATE_SOFT_BLOCKED);
                        mutex_unlock(&rfkill->mutex);
                }
 
@@ -255,8 +436,8 @@ static int rfkill_resume(struct device *dev)
        if (dev->power.power_state.event != PM_EVENT_ON) {
                mutex_lock(&rfkill->mutex);
 
-               if (rfkill->state == RFKILL_STATE_ON)
-                       rfkill->toggle_radio(rfkill->data, RFKILL_STATE_ON);
+               /* restore radio state AND notify everybody */
+               rfkill_toggle_radio(rfkill, rfkill->state, 1);
 
                mutex_unlock(&rfkill->mutex);
        }
@@ -269,12 +450,51 @@ static int rfkill_resume(struct device *dev)
 #define rfkill_resume NULL
 #endif
 
+static int rfkill_blocking_uevent_notifier(struct notifier_block *nb,
+                                       unsigned long eventid,
+                                       void *data)
+{
+       struct rfkill *rfkill = (struct rfkill *)data;
+
+       switch (eventid) {
+       case RFKILL_STATE_CHANGED:
+               kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
+               break;
+       default:
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block rfkill_blocking_uevent_nb = {
+       .notifier_call  = rfkill_blocking_uevent_notifier,
+       .priority       = 0,
+};
+
+static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+       int error;
+
+       error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name);
+       if (error)
+               return error;
+       error = add_uevent_var(env, "RFKILL_TYPE=%s",
+                               rfkill_get_type_str(rfkill->type));
+       if (error)
+               return error;
+       error = add_uevent_var(env, "RFKILL_STATE=%d", rfkill->state);
+       return error;
+}
+
 static struct class rfkill_class = {
        .name           = "rfkill",
        .dev_release    = rfkill_release,
        .dev_attrs      = rfkill_dev_attrs,
        .suspend        = rfkill_suspend,
        .resume         = rfkill_resume,
+       .dev_uevent     = rfkill_dev_uevent,
 };
 
 static int rfkill_add_switch(struct rfkill *rfkill)
@@ -283,7 +503,7 @@ static int rfkill_add_switch(struct rfkill *rfkill)
 
        mutex_lock(&rfkill_mutex);
 
-       error = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type]);
+       error = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type], 0);
        if (!error)
                list_add_tail(&rfkill->node, &rfkill_list);
 
@@ -296,7 +516,7 @@ static void rfkill_remove_switch(struct rfkill *rfkill)
 {
        mutex_lock(&rfkill_mutex);
        list_del_init(&rfkill->node);
-       rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF);
+       rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
        mutex_unlock(&rfkill_mutex);
 }
 
@@ -412,7 +632,7 @@ int rfkill_register(struct rfkill *rfkill)
 EXPORT_SYMBOL(rfkill_register);
 
 /**
- * rfkill_unregister - Uegister a rfkill structure.
+ * rfkill_unregister - Unregister a rfkill structure.
  * @rfkill: rfkill structure to be unregistered
  *
  * This function should be called by the network driver during device
@@ -436,8 +656,13 @@ static int __init rfkill_init(void)
        int error;
        int i;
 
+       /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
+       if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED &&
+           rfkill_default_state != RFKILL_STATE_UNBLOCKED)
+               return -EINVAL;
+
        for (i = 0; i < ARRAY_SIZE(rfkill_states); i++)
-               rfkill_states[i] = RFKILL_STATE_ON;
+               rfkill_states[i] = rfkill_default_state;
 
        error = class_register(&rfkill_class);
        if (error) {
@@ -445,11 +670,14 @@ static int __init rfkill_init(void)
                return error;
        }
 
+       register_rfkill_notifier(&rfkill_blocking_uevent_nb);
+
        return 0;
 }
 
 static void __exit rfkill_exit(void)
 {
+       unregister_rfkill_notifier(&rfkill_blocking_uevent_nb);
        class_unregister(&rfkill_class);
 }
 
index 82adfe6447d7db004c7108731e0ad4c7b87f8657..9437b27ff84de101b88b3cbe08675f002e562238 100644 (file)
@@ -106,17 +106,6 @@ config NET_SCH_PRIO
          To compile this code as a module, choose M here: the
          module will be called sch_prio.
 
-config NET_SCH_RR
-       tristate "Multi Band Round Robin Queuing (RR)"
-       select NET_SCH_PRIO
-       ---help---
-         Say Y here if you want to use an n-band round robin packet
-         scheduler.
-
-         The module uses sch_prio for its framework and is aliased as
-         sch_rr, so it will load sch_prio, although it is referred
-         to using sch_rr.
-
 config NET_SCH_RED
        tristate "Random Early Detection (RED)"
        ---help---
index d355e5e47fe3a71aca1d151db1ce72429a069297..13afa7214392a74998ebbad3576ae4bb7a6d4638 100644 (file)
@@ -468,7 +468,7 @@ struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops)
 
        return sch;
 errout:
-       return ERR_PTR(-err);
+       return ERR_PTR(err);
 }
 
 struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops,
index f98650cc48d8bf0f3e0806177305b9013cb05312..df5572c39f0c0b68b4e1d2119610ed542d3bec07 100644 (file)
@@ -4223,6 +4223,8 @@ static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len,
        if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
                return -EFAULT;
 
+       printk(KERN_WARNING "SCTP: Use of SCTP_GET_PEER_ADDRS_NUM_OLD "
+                           "socket option deprecated\n");
        /* For UDP-style sockets, id specifies the association to query.  */
        asoc = sctp_id2assoc(sk, id);
        if (!asoc)
@@ -4262,6 +4264,9 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len,
 
        if (getaddrs.addr_num <= 0) return -EINVAL;
 
+       printk(KERN_WARNING "SCTP: Use of SCTP_GET_PEER_ADDRS_OLD "
+                           "socket option deprecated\n");
+
        /* For UDP-style sockets, id specifies the association to query.  */
        asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
        if (!asoc)
@@ -4355,6 +4360,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
        if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
                return -EFAULT;
 
+       printk(KERN_WARNING "SCTP: Use of SCTP_GET_LOCAL_ADDRS_NUM_OLD "
+                           "socket option deprecated\n");
+
        /*
         *  For UDP-style sockets, id specifies the association to query.
         *  If the id field is set to the value '0' then the locally bound
@@ -4512,7 +4520,13 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
        if (copy_from_user(&getaddrs, optval, len))
                return -EFAULT;
 
-       if (getaddrs.addr_num <= 0) return -EINVAL;
+       if (getaddrs.addr_num <= 0 ||
+           getaddrs.addr_num >= (INT_MAX / sizeof(union sctp_addr)))
+               return -EINVAL;
+
+       printk(KERN_WARNING "SCTP: Use of SCTP_GET_LOCAL_ADDRS_OLD "
+                           "socket option deprecated\n");
+
        /*
         *  For UDP-style sockets, id specifies the association to query.
         *  If the id field is set to the value '0' then the locally bound
index 66c4a8cf6db9d2d2886e013cf3904d5527c7438d..81fe82513046eae8110eeaccfebe5c3f49d7701d 100644 (file)
@@ -90,6 +90,7 @@
 #include <asm/unistd.h>
 
 #include <net/compat.h>
+#include <net/wext.h>
 
 #include <net/sock.h>
 #include <linux/netfilter.h>
@@ -2210,10 +2211,19 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd,
 {
        struct socket *sock = file->private_data;
        int ret = -ENOIOCTLCMD;
+       struct sock *sk;
+       struct net *net;
+
+       sk = sock->sk;
+       net = sock_net(sk);
 
        if (sock->ops->compat_ioctl)
                ret = sock->ops->compat_ioctl(sock, cmd, arg);
 
+       if (ret == -ENOIOCTLCMD &&
+           (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST))
+               ret = compat_wext_handle_ioctl(net, cmd, arg);
+
        return ret;
 }
 #endif
index b4280490cf6e5abe850763e581002abee1304fb9..70ceb1604ad83278359dc30b313dd43b5ac481c4 100644 (file)
@@ -485,8 +485,8 @@ static int unix_socketpair(struct socket *, struct socket *);
 static int unix_accept(struct socket *, struct socket *, int);
 static int unix_getname(struct socket *, struct sockaddr *, int *, int);
 static unsigned int unix_poll(struct file *, struct socket *, poll_table *);
-static unsigned int unix_datagram_poll(struct file *, struct socket *,
-                                      poll_table *);
+static unsigned int unix_dgram_poll(struct file *, struct socket *,
+                                   poll_table *);
 static int unix_ioctl(struct socket *, unsigned int, unsigned long);
 static int unix_shutdown(struct socket *, int);
 static int unix_stream_sendmsg(struct kiocb *, struct socket *,
@@ -532,7 +532,7 @@ static const struct proto_ops unix_dgram_ops = {
        .socketpair =   unix_socketpair,
        .accept =       sock_no_accept,
        .getname =      unix_getname,
-       .poll =         unix_datagram_poll,
+       .poll =         unix_dgram_poll,
        .ioctl =        unix_ioctl,
        .listen =       sock_no_listen,
        .shutdown =     unix_shutdown,
@@ -553,7 +553,7 @@ static const struct proto_ops unix_seqpacket_ops = {
        .socketpair =   unix_socketpair,
        .accept =       unix_accept,
        .getname =      unix_getname,
-       .poll =         unix_datagram_poll,
+       .poll =         unix_dgram_poll,
        .ioctl =        unix_ioctl,
        .listen =       unix_listen,
        .shutdown =     unix_shutdown,
@@ -1992,29 +1992,13 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl
        return mask;
 }
 
-static unsigned int unix_datagram_poll(struct file *file, struct socket *sock,
-                                      poll_table *wait)
+static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
+                                   poll_table *wait)
 {
-       struct sock *sk = sock->sk, *peer;
-       unsigned int mask;
+       struct sock *sk = sock->sk, *other;
+       unsigned int mask, writable;
 
        poll_wait(file, sk->sk_sleep, wait);
-
-       peer = unix_peer_get(sk);
-       if (peer) {
-               if (peer != sk) {
-                       /*
-                        * Writability of a connected socket additionally
-                        * depends on the state of the receive queue of the
-                        * peer.
-                        */
-                       poll_wait(file, &unix_sk(peer)->peer_wait, wait);
-               } else {
-                       sock_put(peer);
-                       peer = NULL;
-               }
-       }
-
        mask = 0;
 
        /* exceptional events? */
@@ -2040,14 +2024,26 @@ static unsigned int unix_datagram_poll(struct file *file, struct socket *sock,
        }
 
        /* writable? */
-       if (unix_writable(sk) && !(peer && unix_recvq_full(peer)))
+       writable = unix_writable(sk);
+       if (writable) {
+               other = unix_peer_get(sk);
+               if (other) {
+                       if (unix_peer(other) != sk) {
+                               poll_wait(file, &unix_sk(other)->peer_wait,
+                                         wait);
+                               if (unix_recvq_full(other))
+                                       writable = 0;
+                       }
+
+                       sock_put(other);
+               }
+       }
+
+       if (writable)
                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
        else
                set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
 
-       if (peer)
-               sock_put(peer);
-
        return mask;
 }
 
index 947188a5b937ed96d71afbf81997211102bae071..273a843599983ed308c1aa59a0055069e5f83cc9 100644 (file)
@@ -500,7 +500,7 @@ static int call_commit_handler(struct net_device *dev)
 /*
  * Calculate size of private arguments
  */
-static inline int get_priv_size(__u16  args)
+static int get_priv_size(__u16 args)
 {
        int     num = args & IW_PRIV_SIZE_MASK;
        int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
@@ -512,10 +512,9 @@ static inline int get_priv_size(__u16      args)
 /*
  * Re-calculate the size of private arguments
  */
-static inline int adjust_priv_size(__u16               args,
-                                  union iwreq_data *   wrqu)
+static int adjust_priv_size(__u16 args, struct iw_point *iwp)
 {
-       int     num = wrqu->data.length;
+       int     num = iwp->length;
        int     max = args & IW_PRIV_SIZE_MASK;
        int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
 
@@ -695,19 +694,150 @@ void wext_proc_exit(struct net *net)
  */
 
 /* ---------------------------------------------------------------- */
+static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
+                                  const struct iw_ioctl_description *descr,
+                                  iw_handler handler, struct net_device *dev,
+                                  struct iw_request_info *info)
+{
+       int err, extra_size, user_length = 0, essid_compat = 0;
+       char *extra;
+
+       /* Calculate space needed by arguments. Always allocate
+        * for max space.
+        */
+       extra_size = descr->max_tokens * descr->token_size;
+
+       /* Check need for ESSID compatibility for WE < 21 */
+       switch (cmd) {
+       case SIOCSIWESSID:
+       case SIOCGIWESSID:
+       case SIOCSIWNICKN:
+       case SIOCGIWNICKN:
+               if (iwp->length == descr->max_tokens + 1)
+                       essid_compat = 1;
+               else if (IW_IS_SET(cmd) && (iwp->length != 0)) {
+                       char essid[IW_ESSID_MAX_SIZE + 1];
+
+                       err = copy_from_user(essid, iwp->pointer,
+                                            iwp->length *
+                                            descr->token_size);
+                       if (err)
+                               return -EFAULT;
+
+                       if (essid[iwp->length - 1] == '\0')
+                               essid_compat = 1;
+               }
+               break;
+       default:
+               break;
+       }
+
+       iwp->length -= essid_compat;
+
+       /* Check what user space is giving us */
+       if (IW_IS_SET(cmd)) {
+               /* Check NULL pointer */
+               if (!iwp->pointer && iwp->length != 0)
+                       return -EFAULT;
+               /* Check if number of token fits within bounds */
+               if (iwp->length > descr->max_tokens)
+                       return -E2BIG;
+               if (iwp->length < descr->min_tokens)
+                       return -EINVAL;
+       } else {
+               /* Check NULL pointer */
+               if (!iwp->pointer)
+                       return -EFAULT;
+               /* Save user space buffer size for checking */
+               user_length = iwp->length;
+
+               /* Don't check if user_length > max to allow forward
+                * compatibility. The test user_length < min is
+                * implied by the test at the end.
+                */
+
+               /* Support for very large requests */
+               if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
+                   (user_length > descr->max_tokens)) {
+                       /* Allow userspace to GET more than max so
+                        * we can support any size GET requests.
+                        * There is still a limit : -ENOMEM.
+                        */
+                       extra_size = user_length * descr->token_size;
+
+                       /* Note : user_length is originally a __u16,
+                        * and token_size is controlled by us,
+                        * so extra_size won't get negative and
+                        * won't overflow...
+                        */
+               }
+       }
+
+       /* kzalloc() ensures NULL-termination for essid_compat. */
+       extra = kzalloc(extra_size, GFP_KERNEL);
+       if (!extra)
+               return -ENOMEM;
+
+       /* If it is a SET, get all the extra data in here */
+       if (IW_IS_SET(cmd) && (iwp->length != 0)) {
+               if (copy_from_user(extra, iwp->pointer,
+                                  iwp->length *
+                                  descr->token_size)) {
+                       err = -EFAULT;
+                       goto out;
+               }
+       }
+
+       err = handler(dev, info, (union iwreq_data *) iwp, extra);
+
+       iwp->length += essid_compat;
+
+       /* If we have something to return to the user */
+       if (!err && IW_IS_GET(cmd)) {
+               /* Check if there is enough buffer up there */
+               if (user_length < iwp->length) {
+                       err = -E2BIG;
+                       goto out;
+               }
+
+               if (copy_to_user(iwp->pointer, extra,
+                                iwp->length *
+                                descr->token_size)) {
+                       err = -EFAULT;
+                       goto out;
+               }
+       }
+
+       /* Generate an event to notify listeners of the change */
+       if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) {
+               union iwreq_data *data = (union iwreq_data *) iwp;
+
+               if (descr->flags & IW_DESCR_FLAG_RESTRICT)
+                       /* If the event is restricted, don't
+                        * export the payload.
+                        */
+                       wireless_send_event(dev, cmd, data, NULL);
+               else
+                       wireless_send_event(dev, cmd, data, extra);
+       }
+
+out:
+       kfree(extra);
+       return err;
+}
+
 /*
  * Wrapper to call a standard Wireless Extension handler.
  * We do various checks and also take care of moving data between
  * user space and kernel space.
  */
 static int ioctl_standard_call(struct net_device *     dev,
-                              struct ifreq *           ifr,
+                              struct iwreq             *iwr,
                               unsigned int             cmd,
+                              struct iw_request_info   *info,
                               iw_handler               handler)
 {
-       struct iwreq *                          iwr = (struct iwreq *) ifr;
        const struct iw_ioctl_description *     descr;
-       struct iw_request_info                  info;
        int                                     ret = -EINVAL;
 
        /* Get the description of the IOCTL */
@@ -715,145 +845,19 @@ static int ioctl_standard_call(struct net_device *       dev,
                return -EOPNOTSUPP;
        descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
 
-       /* Prepare the call */
-       info.cmd = cmd;
-       info.flags = 0;
-
        /* Check if we have a pointer to user space data or not */
        if (descr->header_type != IW_HEADER_TYPE_POINT) {
 
                /* No extra arguments. Trivial to handle */
-               ret = handler(dev, &info, &(iwr->u), NULL);
+               ret = handler(dev, info, &(iwr->u), NULL);
 
                /* Generate an event to notify listeners of the change */
                if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
                   ((ret == 0) || (ret == -EIWCOMMIT)))
                        wireless_send_event(dev, cmd, &(iwr->u), NULL);
        } else {
-               char *  extra;
-               int     extra_size;
-               int     user_length = 0;
-               int     err;
-               int     essid_compat = 0;
-
-               /* Calculate space needed by arguments. Always allocate
-                * for max space. Easier, and won't last long... */
-               extra_size = descr->max_tokens * descr->token_size;
-
-               /* Check need for ESSID compatibility for WE < 21 */
-               switch (cmd) {
-               case SIOCSIWESSID:
-               case SIOCGIWESSID:
-               case SIOCSIWNICKN:
-               case SIOCGIWNICKN:
-                       if (iwr->u.data.length == descr->max_tokens + 1)
-                               essid_compat = 1;
-                       else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
-                               char essid[IW_ESSID_MAX_SIZE + 1];
-
-                               err = copy_from_user(essid, iwr->u.data.pointer,
-                                                    iwr->u.data.length *
-                                                    descr->token_size);
-                               if (err)
-                                       return -EFAULT;
-
-                               if (essid[iwr->u.data.length - 1] == '\0')
-                                       essid_compat = 1;
-                       }
-                       break;
-               default:
-                       break;
-               }
-
-               iwr->u.data.length -= essid_compat;
-
-               /* Check what user space is giving us */
-               if (IW_IS_SET(cmd)) {
-                       /* Check NULL pointer */
-                       if ((iwr->u.data.pointer == NULL) &&
-                          (iwr->u.data.length != 0))
-                               return -EFAULT;
-                       /* Check if number of token fits within bounds */
-                       if (iwr->u.data.length > descr->max_tokens)
-                               return -E2BIG;
-                       if (iwr->u.data.length < descr->min_tokens)
-                               return -EINVAL;
-               } else {
-                       /* Check NULL pointer */
-                       if (iwr->u.data.pointer == NULL)
-                               return -EFAULT;
-                       /* Save user space buffer size for checking */
-                       user_length = iwr->u.data.length;
-
-                       /* Don't check if user_length > max to allow forward
-                        * compatibility. The test user_length < min is
-                        * implied by the test at the end. */
-
-                       /* Support for very large requests */
-                       if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
-                          (user_length > descr->max_tokens)) {
-                               /* Allow userspace to GET more than max so
-                                * we can support any size GET requests.
-                                * There is still a limit : -ENOMEM. */
-                               extra_size = user_length * descr->token_size;
-                               /* Note : user_length is originally a __u16,
-                                * and token_size is controlled by us,
-                                * so extra_size won't get negative and
-                                * won't overflow... */
-                       }
-               }
-
-               /* Create the kernel buffer */
-               /*    kzalloc ensures NULL-termination for essid_compat */
-               extra = kzalloc(extra_size, GFP_KERNEL);
-               if (extra == NULL)
-                       return -ENOMEM;
-
-               /* If it is a SET, get all the extra data in here */
-               if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
-                       err = copy_from_user(extra, iwr->u.data.pointer,
-                                            iwr->u.data.length *
-                                            descr->token_size);
-                       if (err) {
-                               kfree(extra);
-                               return -EFAULT;
-                       }
-               }
-
-               /* Call the handler */
-               ret = handler(dev, &info, &(iwr->u), extra);
-
-               iwr->u.data.length += essid_compat;
-
-               /* If we have something to return to the user */
-               if (!ret && IW_IS_GET(cmd)) {
-                       /* Check if there is enough buffer up there */
-                       if (user_length < iwr->u.data.length) {
-                               kfree(extra);
-                               return -E2BIG;
-                       }
-
-                       err = copy_to_user(iwr->u.data.pointer, extra,
-                                          iwr->u.data.length *
-                                          descr->token_size);
-                       if (err)
-                               ret =  -EFAULT;
-               }
-
-               /* Generate an event to notify listeners of the change */
-               if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
-                  ((ret == 0) || (ret == -EIWCOMMIT))) {
-                       if (descr->flags & IW_DESCR_FLAG_RESTRICT)
-                               /* If the event is restricted, don't
-                                * export the payload */
-                               wireless_send_event(dev, cmd, &(iwr->u), NULL);
-                       else
-                               wireless_send_event(dev, cmd, &(iwr->u),
-                                                   extra);
-               }
-
-               /* Cleanup - I told you it wasn't that long ;-) */
-               kfree(extra);
+               ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
+                                             handler, dev, info);
        }
 
        /* Call commit handler if needed and defined */
@@ -881,25 +885,22 @@ static int ioctl_standard_call(struct net_device *        dev,
  * a iw_handler but process it in your ioctl handler (i.e. use the
  * old driver API).
  */
-static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
-                             unsigned int cmd, iw_handler handler)
+static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
+                                  const struct iw_priv_args **descrp)
 {
-       struct iwreq *                  iwr = (struct iwreq *) ifr;
-       const struct iw_priv_args *     descr = NULL;
-       struct iw_request_info          info;
-       int                             extra_size = 0;
-       int                             i;
-       int                             ret = -EINVAL;
+       const struct iw_priv_args *descr;
+       int i, extra_size;
 
-       /* Get the description of the IOCTL */
-       for (i = 0; i < dev->wireless_handlers->num_private_args; i++)
+       descr = NULL;
+       for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
                if (cmd == dev->wireless_handlers->private_args[i].cmd) {
-                       descr = &(dev->wireless_handlers->private_args[i]);
+                       descr = &dev->wireless_handlers->private_args[i];
                        break;
                }
+       }
 
-       /* Compute the size of the set/get arguments */
-       if (descr != NULL) {
+       extra_size = 0;
+       if (descr) {
                if (IW_IS_SET(cmd)) {
                        int     offset = 0;     /* For sub-ioctls */
                        /* Check for sub-ioctl handler */
@@ -924,72 +925,77 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
                                extra_size = 0;
                }
        }
+       *descrp = descr;
+       return extra_size;
+}
 
-       /* Prepare the call */
-       info.cmd = cmd;
-       info.flags = 0;
+static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
+                                 const struct iw_priv_args *descr,
+                                 iw_handler handler, struct net_device *dev,
+                                 struct iw_request_info *info, int extra_size)
+{
+       char *extra;
+       int err;
 
-       /* Check if we have a pointer to user space data or not. */
-       if (extra_size == 0) {
-               /* No extra arguments. Trivial to handle */
-               ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
-       } else {
-               char *  extra;
-               int     err;
+       /* Check what user space is giving us */
+       if (IW_IS_SET(cmd)) {
+               if (!iwp->pointer && iwp->length != 0)
+                       return -EFAULT;
 
-               /* Check what user space is giving us */
-               if (IW_IS_SET(cmd)) {
-                       /* Check NULL pointer */
-                       if ((iwr->u.data.pointer == NULL) &&
-                          (iwr->u.data.length != 0))
-                               return -EFAULT;
+               if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
+                       return -E2BIG;
+       } else if (!iwp->pointer)
+               return -EFAULT;
 
-                       /* Does it fits within bounds ? */
-                       if (iwr->u.data.length > (descr->set_args &
-                                                IW_PRIV_SIZE_MASK))
-                               return -E2BIG;
-               } else if (iwr->u.data.pointer == NULL)
-                       return -EFAULT;
+       extra = kmalloc(extra_size, GFP_KERNEL);
+       if (!extra)
+               return -ENOMEM;
 
-               /* Always allocate for max space. Easier, and won't last
-                * long... */
-               extra = kmalloc(extra_size, GFP_KERNEL);
-               if (extra == NULL)
-                       return -ENOMEM;
-
-               /* If it is a SET, get all the extra data in here */
-               if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
-                       err = copy_from_user(extra, iwr->u.data.pointer,
-                                            extra_size);
-                       if (err) {
-                               kfree(extra);
-                               return -EFAULT;
-                       }
+       /* If it is a SET, get all the extra data in here */
+       if (IW_IS_SET(cmd) && (iwp->length != 0)) {
+               if (copy_from_user(extra, iwp->pointer, extra_size)) {
+                       err = -EFAULT;
+                       goto out;
                }
+       }
 
-               /* Call the handler */
-               ret = handler(dev, &info, &(iwr->u), extra);
+       /* Call the handler */
+       err = handler(dev, info, (union iwreq_data *) iwp, extra);
 
-               /* If we have something to return to the user */
-               if (!ret && IW_IS_GET(cmd)) {
+       /* If we have something to return to the user */
+       if (!err && IW_IS_GET(cmd)) {
+               /* Adjust for the actual length if it's variable,
+                * avoid leaking kernel bits outside.
+                */
+               if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
+                       extra_size = adjust_priv_size(descr->get_args, iwp);
 
-                       /* Adjust for the actual length if it's variable,
-                        * avoid leaking kernel bits outside. */
-                       if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
-                               extra_size = adjust_priv_size(descr->get_args,
-                                                             &(iwr->u));
-                       }
+               if (copy_to_user(iwp->pointer, extra, extra_size))
+                       err =  -EFAULT;
+       }
 
-                       err = copy_to_user(iwr->u.data.pointer, extra,
-                                          extra_size);
-                       if (err)
-                               ret =  -EFAULT;
-               }
+out:
+       kfree(extra);
+       return err;
+}
 
-               /* Cleanup - I told you it wasn't that long ;-) */
-               kfree(extra);
-       }
+static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
+                             unsigned int cmd, struct iw_request_info *info,
+                             iw_handler handler)
+{
+       int extra_size = 0, ret = -EINVAL;
+       const struct iw_priv_args *descr;
 
+       extra_size = get_priv_descr_and_size(dev, cmd, &descr);
+
+       /* Check if we have a pointer to user space data or not. */
+       if (extra_size == 0) {
+               /* No extra arguments. Trivial to handle */
+               ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
+       } else {
+               ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
+                                            handler, dev, info, extra_size);
+       }
 
        /* Call commit handler if needed and defined */
        if (ret == -EIWCOMMIT)
@@ -999,12 +1005,21 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
 }
 
 /* ---------------------------------------------------------------- */
+typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
+                              unsigned int, struct iw_request_info *,
+                              iw_handler);
+
 /*
  * Main IOCTl dispatcher.
  * Check the type of IOCTL and call the appropriate wrapper...
  */
-static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd)
+static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
+                                 unsigned int cmd,
+                                 struct iw_request_info *info,
+                                 wext_ioctl_func standard,
+                                 wext_ioctl_func private)
 {
+       struct iwreq *iwr = (struct iwreq *) ifr;
        struct net_device *dev;
        iw_handler      handler;
 
@@ -1019,12 +1034,12 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
         * Note that 'cmd' is already filtered in dev_ioctl() with
         * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
        if (cmd == SIOCGIWSTATS)
-               return ioctl_standard_call(dev, ifr, cmd,
-                                          &iw_handler_get_iwstats);
+               return standard(dev, iwr, cmd, info,
+                               &iw_handler_get_iwstats);
 
        if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
-               return ioctl_standard_call(dev, ifr, cmd,
-                                          &iw_handler_get_private);
+               return standard(dev, iwr, cmd, info,
+                               &iw_handler_get_private);
 
        /* Basic check */
        if (!netif_device_present(dev))
@@ -1035,9 +1050,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
        if (handler) {
                /* Standard and private are not the same */
                if (cmd < SIOCIWFIRSTPRIV)
-                       return ioctl_standard_call(dev, ifr, cmd, handler);
+                       return standard(dev, iwr, cmd, info, handler);
                else
-                       return ioctl_private_call(dev, ifr, cmd, handler);
+                       return private(dev, iwr, cmd, info, handler);
        }
        /* Old driver API : call driver ioctl handler */
        if (dev->do_ioctl)
@@ -1045,27 +1060,154 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
        return -EOPNOTSUPP;
 }
 
-/* entry point from dev ioctl */
-int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
-                     void __user *arg)
+/* If command is `set a parameter', or `get the encoding parameters',
+ * check if the user has the right to do it.
+ */
+static int wext_permission_check(unsigned int cmd)
 {
-       int ret;
-
-       /* If command is `set a parameter', or
-        * `get the encoding parameters', check if
-        * the user has the right to do it */
        if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
            && !capable(CAP_NET_ADMIN))
                return -EPERM;
 
+       return 0;
+}
+
+/* entry point from dev ioctl */
+static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
+                              unsigned int cmd, struct iw_request_info *info,
+                              wext_ioctl_func standard,
+                              wext_ioctl_func private)
+{
+       int ret = wext_permission_check(cmd);
+
+       if (ret)
+               return ret;
+
        dev_load(net, ifr->ifr_name);
        rtnl_lock();
-       ret = wireless_process_ioctl(net, ifr, cmd);
+       ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
        rtnl_unlock();
-       if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq)))
+
+       return ret;
+}
+
+int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
+                     void __user *arg)
+{
+       struct iw_request_info info = { .cmd = cmd, .flags = 0 };
+       int ret;
+
+       ret = wext_ioctl_dispatch(net, ifr, cmd, &info,
+                                 ioctl_standard_call,
+                                 ioctl_private_call);
+       if (ret >= 0 &&
+           IW_IS_GET(cmd) &&
+           copy_to_user(arg, ifr, sizeof(struct iwreq)))
+               return -EFAULT;
+
+       return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_standard_call(struct net_device      *dev,
+                               struct iwreq            *iwr,
+                               unsigned int            cmd,
+                               struct iw_request_info  *info,
+                               iw_handler              handler)
+{
+       const struct iw_ioctl_description *descr;
+       struct compat_iw_point *iwp_compat;
+       struct iw_point iwp;
+       int err;
+
+       descr = standard_ioctl + (cmd - SIOCIWFIRST);
+
+       if (descr->header_type != IW_HEADER_TYPE_POINT)
+               return ioctl_standard_call(dev, iwr, cmd, info, handler);
+
+       iwp_compat = (struct compat_iw_point *) &iwr->u.data;
+       iwp.pointer = compat_ptr(iwp_compat->pointer);
+       iwp.length = iwp_compat->length;
+       iwp.flags = iwp_compat->flags;
+
+       err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info);
+
+       iwp_compat->pointer = ptr_to_compat(iwp.pointer);
+       iwp_compat->length = iwp.length;
+       iwp_compat->flags = iwp.flags;
+
+       return err;
+}
+
+static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
+                              unsigned int cmd, struct iw_request_info *info,
+                              iw_handler handler)
+{
+       const struct iw_priv_args *descr;
+       int ret, extra_size;
+
+       extra_size = get_priv_descr_and_size(dev, cmd, &descr);
+
+       /* Check if we have a pointer to user space data or not. */
+       if (extra_size == 0) {
+               /* No extra arguments. Trivial to handle */
+               ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
+       } else {
+               struct compat_iw_point *iwp_compat;
+               struct iw_point iwp;
+
+               iwp_compat = (struct compat_iw_point *) &iwr->u.data;
+               iwp.pointer = compat_ptr(iwp_compat->pointer);
+               iwp.length = iwp_compat->length;
+               iwp.flags = iwp_compat->flags;
+
+               ret = ioctl_private_iw_point(&iwp, cmd, descr,
+                                            handler, dev, info, extra_size);
+
+               iwp_compat->pointer = ptr_to_compat(iwp.pointer);
+               iwp_compat->length = iwp.length;
+               iwp_compat->flags = iwp.flags;
+       }
+
+       /* Call commit handler if needed and defined */
+       if (ret == -EIWCOMMIT)
+               ret = call_commit_handler(dev);
+
+       return ret;
+}
+
+int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
+                            unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       struct iw_request_info info;
+       struct iwreq iwr;
+       char *colon;
+       int ret;
+
+       if (copy_from_user(&iwr, argp, sizeof(struct iwreq)))
+               return -EFAULT;
+
+       iwr.ifr_name[IFNAMSIZ-1] = 0;
+       colon = strchr(iwr.ifr_name, ':');
+       if (colon)
+               *colon = 0;
+
+       info.cmd = cmd;
+       info.flags = IW_REQUEST_FLAG_COMPAT;
+
+       ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info,
+                                 compat_standard_call,
+                                 compat_private_call);
+
+       if (ret >= 0 &&
+           IW_IS_GET(cmd) &&
+           copy_to_user(argp, &iwr, sizeof(struct iwreq)))
                return -EFAULT;
+
        return ret;
 }
+#endif
 
 /************************* EVENT PROCESSING *************************/
 /*