Browse Source

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-next-2.6

David S. Miller 17 years ago
parent
commit
28f49d8fec
84 changed files with 3384 additions and 4607 deletions
  1. 493 54
      Documentation/rfkill.txt
  2. 0 4
      MAINTAINERS
  3. 71 69
      drivers/net/b44.c
  4. 16 14
      drivers/net/ps3_gelic_wireless.c
  5. 0 24
      drivers/net/wireless/Kconfig
  6. 0 1
      drivers/net/wireless/Makefile
  7. 1 8
      drivers/net/wireless/adm8211.c
  8. 46 38
      drivers/net/wireless/airo.c
  9. 3 0
      drivers/net/wireless/ath5k/Kconfig
  10. 115 148
      drivers/net/wireless/ath5k/base.c
  11. 18 14
      drivers/net/wireless/ath5k/base.h
  12. 2 2
      drivers/net/wireless/ath5k/hw.c
  13. 18 6
      drivers/net/wireless/atmel.c
  14. 2 0
      drivers/net/wireless/b43/b43.h
  15. 321 38
      drivers/net/wireless/b43/debugfs.c
  16. 21 2
      drivers/net/wireless/b43/debugfs.h
  17. 35 30
      drivers/net/wireless/b43/dma.c
  18. 69 17
      drivers/net/wireless/b43/main.c
  19. 4 0
      drivers/net/wireless/b43/main.h
  20. 1 1
      drivers/net/wireless/b43/pio.c
  21. 5 2
      drivers/net/wireless/b43/rfkill.c
  22. 7 10
      drivers/net/wireless/b43/xmit.c
  23. 31 32
      drivers/net/wireless/b43legacy/dma.c
  24. 6 2
      drivers/net/wireless/b43legacy/rfkill.c
  25. 7 9
      drivers/net/wireless/b43legacy/xmit.c
  26. 2 1
      drivers/net/wireless/hostap/hostap.h
  27. 16 16
      drivers/net/wireless/hostap/hostap_ap.c
  28. 31 27
      drivers/net/wireless/hostap/hostap_ioctl.c
  29. 1 1
      drivers/net/wireless/iwlwifi/Kconfig
  30. 15 3
      drivers/net/wireless/iwlwifi/iwl-rfkill.c
  31. 19 17
      drivers/net/wireless/libertas/scan.c
  32. 4 3
      drivers/net/wireless/mac80211_hwsim.c
  33. 19 11
      drivers/net/wireless/orinoco.c
  34. 27 22
      drivers/net/wireless/prism54/isl_ioctl.c
  35. 17 15
      drivers/net/wireless/rndis_wlan.c
  36. 9 8
      drivers/net/wireless/rt2x00/rt2400pci.c
  37. 8 6
      drivers/net/wireless/rt2x00/rt2500pci.c
  38. 2 2
      drivers/net/wireless/rt2x00/rt2500usb.c
  39. 9 50
      drivers/net/wireless/rt2x00/rt2x00.h
  40. 80 20
      drivers/net/wireless/rt2x00/rt2x00dev.c
  41. 49 2
      drivers/net/wireless/rt2x00/rt2x00lib.h
  42. 19 107
      drivers/net/wireless/rt2x00/rt2x00pci.c
  43. 0 12
      drivers/net/wireless/rt2x00/rt2x00pci.h
  44. 112 29
      drivers/net/wireless/rt2x00/rt2x00queue.c
  45. 21 14
      drivers/net/wireless/rt2x00/rt2x00queue.h
  46. 5 2
      drivers/net/wireless/rt2x00/rt2x00rfkill.c
  47. 21 82
      drivers/net/wireless/rt2x00/rt2x00usb.c
  48. 6 0
      drivers/net/wireless/rt2x00/rt2x00usb.h
  49. 15 8
      drivers/net/wireless/rt2x00/rt61pci.c
  50. 7 1
      drivers/net/wireless/rt2x00/rt73usb.c
  51. 0 2804
      drivers/net/wireless/strip.c
  52. 5 5
      drivers/net/wireless/wl3501_cs.c
  53. 13 8
      drivers/net/wireless/zd1201.c
  54. 6 16
      drivers/net/wireless/zd1211rw/zd_mac.c
  55. 1 1
      drivers/ssb/Kconfig
  56. 59 16
      drivers/ssb/main.c
  57. 1 112
      fs/compat_ioctl.c
  58. 61 3
      include/linux/ieee80211.h
  59. 4 1
      include/linux/nl80211.h
  60. 43 3
      include/linux/rfkill.h
  61. 139 4
      include/linux/ssb/ssb.h
  62. 28 0
      include/linux/wireless.h
  63. 49 102
      include/net/iw_handler.h
  64. 11 3
      include/net/mac80211.h
  65. 7 0
      include/net/wext.h
  66. 28 20
      net/ieee80211/ieee80211_wx.c
  67. 1 1
      net/mac80211/Kconfig
  68. 13 1
      net/mac80211/ieee80211_i.h
  69. 12 25
      net/mac80211/key.h
  70. 1 1
      net/mac80211/main.c
  71. 157 50
      net/mac80211/mlme.c
  72. 3 4
      net/mac80211/rx.c
  73. 1 0
      net/mac80211/sta_info.c
  74. 27 13
      net/mac80211/sta_info.h
  75. 15 15
      net/mac80211/tkip.c
  76. 102 102
      net/mac80211/tx.c
  77. 15 24
      net/mac80211/wep.c
  78. 49 1
      net/mac80211/wext.c
  79. 14 6
      net/mac80211/wpa.c
  80. 74 24
      net/rfkill/rfkill-input.c
  81. 1 0
      net/rfkill/rfkill-input.h
  82. 266 38
      net/rfkill/rfkill.c
  83. 10 0
      net/socket.c
  84. 362 220
      net/wireless/wext.c

+ 493 - 54
Documentation/rfkill.txt

@@ -1,89 +1,528 @@
 rfkill - RF switch subsystem support
 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
 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()
 	- 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()
 	- 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:
 The following sysfs entries will be created:
 
 
 	name: Name assigned by driver to this key (interface or driver name).
 	name: Name assigned by driver to this key (interface or driver name).
 	type: Name of the key type ("wlan", "bluetooth", etc).
 	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
 	claim: 1: Userspace handles events, 0: Kernel handles events
 
 
 Both the "state" and "claim" entries are also writable. For the "state" entry
 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
 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
 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
 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.

+ 0 - 4
MAINTAINERS

@@ -3854,10 +3854,6 @@ P:	Ion Badulescu
 M:	ionut@cs.columbia.edu
 M:	ionut@cs.columbia.edu
 S:	Maintained
 S:	Maintained
 
 
-STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
-W:	http://mosquitonet.Stanford.EDU/strip.html
-S:	Unsupported ?
-
 STRADIS MPEG-2 DECODER DRIVER
 STRADIS MPEG-2 DECODER DRIVER
 P:	Nathan Laredo
 P:	Nathan Laredo
 M:	laredo@gnu.org
 M:	laredo@gnu.org

+ 71 - 69
drivers/net/b44.c

@@ -148,9 +148,9 @@ static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
 						unsigned long offset,
 						unsigned long offset,
 						enum dma_data_direction dir)
 						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,
 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,
 					     unsigned long offset,
 					     enum dma_data_direction dir)
 					     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)
 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);
 		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;
 		rp->skb = NULL;
 		dev_kfree_skb_irq(skb);
 		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)
 	if (skb == NULL)
 		return -ENOMEM;
 		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
 	/* Hardware bug work-around, the chip is unable to do PCI DMA
 	   to/from anything above 1GB :-( */
 	   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) {
 		mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
 		/* Sigh... */
 		/* 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);
 		dev_kfree_skb_any(skb);
 		skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
 		skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
 		if (skb == NULL)
 		if (skb == NULL)
 			return -ENOMEM;
 			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) {
 			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);
 			dev_kfree_skb_any(skb);
 			return -ENOMEM;
 			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),
 					     dest_idx * sizeof(dest_desc),
 					     DMA_BIDIRECTIONAL);
 					     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)
 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;
 		struct rx_header *rh;
 		u16 len;
 		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,
 					    RX_PKT_BUF_SZ,
 					    DMA_FROM_DEVICE);
 					    DMA_FROM_DEVICE);
 		rh = (struct rx_header *) skb->data;
 		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);
 			skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
 			if (skb_size < 0)
 			if (skb_size < 0)
 				goto drop_it;
 				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 */
 			/* Leave out rx_header */
                 	skb_put(skb, len + RX_PKT_OFFSET);
                 	skb_put(skb, len + RX_PKT_OFFSET);
             	        skb_pull(skb, 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;
 		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;
 		struct sk_buff *bounce_skb;
 
 
 		/* Chip can't handle DMA to/from >1GB, use bounce buffer */
 		/* 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);
 		bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
 		if (!bounce_skb)
 		if (!bounce_skb)
 			goto err_out;
 			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);
 			dev_kfree_skb_any(bounce_skb);
 			goto err_out;
 			goto err_out;
 		}
 		}
@@ -1082,8 +1082,8 @@ static void b44_free_rings(struct b44 *bp)
 
 
 		if (rp->skb == NULL)
 		if (rp->skb == NULL)
 			continue;
 			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);
 		dev_kfree_skb_any(rp->skb);
 		rp->skb = NULL;
 		rp->skb = NULL;
 	}
 	}
@@ -1094,8 +1094,8 @@ static void b44_free_rings(struct b44 *bp)
 
 
 		if (rp->skb == NULL)
 		if (rp->skb == NULL)
 			continue;
 			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);
 		dev_kfree_skb_any(rp->skb);
 		rp->skb = NULL;
 		rp->skb = NULL;
 	}
 	}
@@ -1117,14 +1117,14 @@ static void b44_init_rings(struct b44 *bp)
 	memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
 	memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
 
 
 	if (bp->flags & B44_FLAG_RX_RING_HACK)
 	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)
 	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++) {
 	for (i = 0; i < bp->rx_pending; i++) {
 		if (b44_alloc_rx_skb(bp, -1, i) < 0)
 		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;
 	bp->tx_buffers = NULL;
 	if (bp->rx_ring) {
 	if (bp->rx_ring) {
 		if (bp->flags & B44_FLAG_RX_RING_HACK) {
 		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);
 			kfree(bp->rx_ring);
 		} else
 		} 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->rx_ring = NULL;
 		bp->flags &= ~B44_FLAG_RX_RING_HACK;
 		bp->flags &= ~B44_FLAG_RX_RING_HACK;
 	}
 	}
 	if (bp->tx_ring) {
 	if (bp->tx_ring) {
 		if (bp->flags & B44_FLAG_TX_RING_HACK) {
 		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);
 			kfree(bp->tx_ring);
 		} else
 		} 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->tx_ring = NULL;
 		bp->flags &= ~B44_FLAG_TX_RING_HACK;
 		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;
 		goto out_err;
 
 
 	size = DMA_TABLE_BYTES;
 	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) {
 	if (!bp->rx_ring) {
 		/* Allocation may have failed due to pci_alloc_consistent
 		/* Allocation may have failed due to pci_alloc_consistent
 		   insisting on use of GFP_DMA, which is more restrictive
 		   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)
 		if (!rx_ring)
 			goto out_err;
 			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) {
 			rx_ring_dma + size > DMA_30BIT_MASK) {
 			kfree(rx_ring);
 			kfree(rx_ring);
 			goto out_err;
 			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->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) {
 	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
 		   insisting on use of GFP_DMA, which is more restrictive
 		   than necessary...  */
 		   than necessary...  */
 		struct dma_desc *tx_ring;
 		struct dma_desc *tx_ring;
@@ -1226,11 +1228,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
 		if (!tx_ring)
 		if (!tx_ring)
 			goto out_err;
 			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_TABLE_BYTES,
 			                    DMA_TO_DEVICE);
 			                    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) {
 			tx_ring_dma + size > DMA_30BIT_MASK) {
 			kfree(tx_ring);
 			kfree(tx_ring);
 			goto out_err;
 			goto out_err;

+ 16 - 14
drivers/net/ps3_gelic_wireless.c

@@ -571,6 +571,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
  * independent format
  * independent format
  */
  */
 static char *gelic_wl_translate_scan(struct net_device *netdev,
 static char *gelic_wl_translate_scan(struct net_device *netdev,
+				     struct iw_request_info *info,
 				     char *ev,
 				     char *ev,
 				     char *stop,
 				     char *stop,
 				     struct gelic_wl_scan_info *network)
 				     struct gelic_wl_scan_info *network)
@@ -588,26 +589,26 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
 	iwe.cmd = SIOCGIWAP;
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN);
 	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 */
 	/* ESSID */
 	iwe.cmd = SIOCGIWESSID;
 	iwe.cmd = SIOCGIWESSID;
 	iwe.u.data.flags = 1;
 	iwe.u.data.flags = 1;
 	iwe.u.data.length = strnlen(scan->essid, 32);
 	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 */
 	/* FREQUENCY */
 	iwe.cmd = SIOCGIWFREQ;
 	iwe.cmd = SIOCGIWFREQ;
 	iwe.u.freq.m = be16_to_cpu(scan->channel);
 	iwe.u.freq.m = be16_to_cpu(scan->channel);
 	iwe.u.freq.e = 0; /* table value in MHz */
 	iwe.u.freq.e = 0; /* table value in MHz */
 	iwe.u.freq.i = 0;
 	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 */
 	/* RATES */
 	iwe.cmd = SIOCGIWRATE;
 	iwe.cmd = SIOCGIWRATE;
 	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
 	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
 	/* to stuff multiple values in one event */
 	/* 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) */
 	/* put them in ascendant order (older is first) */
 	i = 0;
 	i = 0;
 	j = 0;
 	j = 0;
@@ -620,16 +621,16 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
 		else
 		else
 		    rate = scan->rate[i++] & 0x7f;
 		    rate = scan->rate[i++] & 0x7f;
 		iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */
 		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);
 					   IW_EV_PARAM_LEN);
 	}
 	}
 	while (j < network->rate_ext_len) {
 	while (j < network->rate_ext_len) {
 		iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000;
 		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);
 					   IW_EV_PARAM_LEN);
 	}
 	}
 	/* Check if we added any rate */
 	/* Check if we added any rate */
-	if (IW_EV_LCP_LEN < (tmp - ev))
+	if (iwe_stream_lcp_len(info) < (tmp - ev))
 		ev = tmp;
 		ev = tmp;
 
 
 	/* ENCODE */
 	/* ENCODE */
@@ -639,7 +640,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
 	else
 	else
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 	iwe.u.data.length = 0;
 	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 */
 	/* MODE */
 	iwe.cmd = SIOCGIWMODE;
 	iwe.cmd = SIOCGIWMODE;
@@ -649,7 +650,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
 			iwe.u.mode = IW_MODE_MASTER;
 			iwe.u.mode = IW_MODE_MASTER;
 		else
 		else
 			iwe.u.mode = IW_MODE_ADHOC;
 			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 */
 	/* 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.level = be16_to_cpu(scan->rssi);
 	iwe.u.qual.qual = be16_to_cpu(scan->rssi);
 	iwe.u.qual.qual = be16_to_cpu(scan->rssi);
 	iwe.u.qual.noise = 0;
 	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 */
 	/* RSN */
 	memset(&iwe, 0, sizeof(iwe));
 	memset(&iwe, 0, sizeof(iwe));
@@ -669,7 +670,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
 		if (len) {
 		if (len) {
 			iwe.cmd = IWEVGENIE;
 			iwe.cmd = IWEVGENIE;
 			iwe.u.data.length = len;
 			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 {
 	} else {
 		/* this scan info has IE data */
 		/* 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);
 			memcpy(buf, ie_info.wpa.data, ie_info.wpa.len);
 			iwe.cmd = IWEVGENIE;
 			iwe.cmd = IWEVGENIE;
 			iwe.u.data.length = ie_info.wpa.len;
 			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))) {
 		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);
 			memcpy(buf, ie_info.rsn.data, ie_info.rsn.len);
 			iwe.cmd = IWEVGENIE;
 			iwe.cmd = IWEVGENIE;
 			iwe.u.data.length = ie_info.rsn.len;
 			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 ||
 		if (wl->scan_age == 0 ||
 		    time_after(scan_info->last_scanned + wl->scan_age,
 		    time_after(scan_info->last_scanned + wl->scan_age,
 			       this_time))
 			       this_time))
-			ev = gelic_wl_translate_scan(netdev, ev, stop,
+			ev = gelic_wl_translate_scan(netdev, info,
+						     ev, stop,
 						     scan_info);
 						     scan_info);
 		else
 		else
 			pr_debug("%s:entry too old\n", __func__);
 			pr_debug("%s:entry too old\n", __func__);

+ 0 - 24
drivers/net/wireless/Kconfig

@@ -14,30 +14,6 @@ config WLAN_PRE80211
 	  This option does not affect the kernel build, it only
 	  This option does not affect the kernel build, it only
 	  lets you choose drivers.
 	  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
 config ARLAN
 	tristate "Aironet Arlan 655 & IC2200 DS support"
 	tristate "Aironet Arlan 655 & IC2200 DS support"
 	depends on ISA && !64BIT && WLAN_PRE80211
 	depends on ISA && !64BIT && WLAN_PRE80211

+ 0 - 1
drivers/net/wireless/Makefile

@@ -6,7 +6,6 @@ obj-$(CONFIG_IPW2100) += ipw2100.o
 
 
 obj-$(CONFIG_IPW2200) += ipw2200.o
 obj-$(CONFIG_IPW2200) += ipw2200.o
 
 
-obj-$(CONFIG_STRIP) += strip.o
 obj-$(CONFIG_ARLAN) += arlan.o 
 obj-$(CONFIG_ARLAN) += arlan.o 
 
 
 arlan-objs := arlan-main.o arlan-proc.o
 arlan-objs := arlan-main.o arlan-proc.o

+ 1 - 8
drivers/net/wireless/adm8211.c

@@ -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)
 static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 {
 	struct adm8211_tx_hdr *txhdr;
 	struct adm8211_tx_hdr *txhdr;
-	u16 fc;
 	size_t payload_len, hdrlen;
 	size_t payload_len, hdrlen;
 	int plcp, dur, len, plcp_signal, short_preamble;
 	int plcp, dur, len, plcp_signal, short_preamble;
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_hdr *hdr;
@@ -1696,8 +1695,7 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 	plcp_signal = txrate->bitrate;
 	plcp_signal = txrate->bitrate;
 
 
 	hdr = (struct ieee80211_hdr *)skb->data;
 	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);
 	memcpy(skb->cb, skb->data, hdrlen);
 	hdr = (struct ieee80211_hdr *)skb->cb;
 	hdr = (struct ieee80211_hdr *)skb->cb;
 	skb_pull(skb, hdrlen);
 	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;
 	txhdr->frame_control = hdr->frame_control;
 
 
 	len = hdrlen + payload_len + FCS_LEN;
 	len = hdrlen + payload_len + FCS_LEN;
-	if (fc & IEEE80211_FCTL_PROTECTED)
-		len += 8;
 
 
 	txhdr->frag = cpu_to_le16(0x0FFF);
 	txhdr->frag = cpu_to_le16(0x0FFF);
 	adm8211_calc_durations(&dur, &plcp, payload_len,
 	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)
 	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
 		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
 		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;
 	txhdr->retry_limit = info->control.retry_limit;
 
 
 	adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
 	adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);

+ 46 - 38
drivers/net/wireless/airo.c

@@ -85,10 +85,10 @@ static struct pci_driver airo_driver = {
 
 
 /* Include Wireless Extension definition and check version - Jean II */
 /* Include Wireless Extension definition and check version - Jean II */
 #include <linux/wireless.h>
 #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
 #ifdef CISCO_EXT
 #include <linux/delay.h>
 #include <linux/delay.h>
 #endif
 #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
 /* 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
    IN4500.  I would be extremely interested in the situation where this
    doesn't work though!!! */
    doesn't work though!!! */
-static int do8bitIO = 0;
+static int do8bitIO /* = 0 */;
 
 
 /* Return codes */
 /* Return codes */
 #define SUCCESS 0
 #define SUCCESS 0
@@ -398,8 +398,8 @@ static int do8bitIO = 0;
 #define MAXTXQ 64
 #define MAXTXQ 64
 
 
 /* BAP selectors */
 /* 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 */
 /* Flags */
 #define COMMAND_BUSY 0x8000
 #define COMMAND_BUSY 0x8000
@@ -5522,11 +5522,13 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 	Cmd cmd;
 	Cmd cmd;
 	Resp rsp;
 	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;
 		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;
 		return -ENOMEM;
 	readAPListRid(ai, ai->APList);
 	readAPListRid(ai, ai->APList);
 	readSsidRid(ai, ai->SSID);
 	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);
 	disable_MAC(ai, 0);
 	netif_device_detach(dev);
 	netif_device_detach(dev);
 	ai->power = state;
 	ai->power = state;
-	cmd.cmd=HOSTSLEEP;
+	cmd.cmd = HOSTSLEEP;
 	issuecommand(ai, &cmd, &rsp);
 	issuecommand(ai, &cmd, &rsp);
 
 
 	pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
 	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);
 		msleep(100);
 	}
 	}
 
 
-	set_bit (FLAG_COMMIT, &ai->flags);
+	set_bit(FLAG_COMMIT, &ai->flags);
 	disable_MAC(ai, 0);
 	disable_MAC(ai, 0);
         msleep(200);
         msleep(200);
 	if (ai->SSID) {
 	if (ai->SSID) {
@@ -5594,9 +5596,6 @@ static int airo_pci_resume(struct pci_dev *pdev)
 static int __init airo_init_module( void )
 static int __init airo_init_module( void )
 {
 {
 	int i;
 	int i;
-#if 0
-	int have_isa_dev = 0;
-#endif
 
 
 	airo_entry = create_proc_entry("driver/aironet",
 	airo_entry = create_proc_entry("driver/aironet",
 				       S_IFDIR | airo_perm,
 				       S_IFDIR | airo_perm,
@@ -5607,15 +5606,11 @@ static int __init airo_init_module( void )
 		airo_entry->gid = proc_gid;
 		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 "
 		airo_print_info("", "Trying to configure ISA adapter at irq=%d "
 			"io=0x%x", irq[i], io[i] );
 			"io=0x%x", irq[i], io[i] );
 		if (init_airo_card( irq[i], io[i], 0, NULL ))
 		if (init_airo_card( irq[i], io[i], 0, NULL ))
-#if 0
-			have_isa_dev = 1;
-#else
 			/* do nothing */ ;
 			/* do nothing */ ;
-#endif
 	}
 	}
 
 
 #ifdef CONFIG_PCI
 #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)
 static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
 {
 {
-	if( !rssi_rid )
+	if (!rssi_rid)
 		return 0;
 		return 0;
 
 
 	return (0x100 - rssi_rid[rssi].rssidBm);
 	return (0x100 - rssi_rid[rssi].rssidBm);
@@ -5671,10 +5666,10 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
 {
 {
 	int i;
 	int i;
 
 
-	if( !rssi_rid )
+	if (!rssi_rid)
 		return 0;
 		return 0;
 
 
-	for( i = 0; i < 256; i++ )
+	for (i = 0; i < 256; i++)
 		if (rssi_rid[i].rssidBm == dbm)
 		if (rssi_rid[i].rssidBm == dbm)
 			return rssi_rid[i].rssipct;
 			return rssi_rid[i].rssipct;
 
 
@@ -7156,6 +7151,7 @@ out:
  * format that the Wireless Tools will understand - Jean II
  * format that the Wireless Tools will understand - Jean II
  */
  */
 static inline char *airo_translate_scan(struct net_device *dev,
 static inline char *airo_translate_scan(struct net_device *dev,
+					struct iw_request_info *info,
 					char *current_ev,
 					char *current_ev,
 					char *end_buf,
 					char *end_buf,
 					BSSListRid *bss)
 					BSSListRid *bss)
@@ -7172,7 +7168,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
 	iwe.cmd = SIOCGIWAP;
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
 	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 */
 	/* 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.u.data.length = 32;
 	iwe.cmd = SIOCGIWESSID;
 	iwe.cmd = SIOCGIWESSID;
 	iwe.u.data.flags = 1;
 	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 */
 	/* Add mode */
 	iwe.cmd = SIOCGIWMODE;
 	iwe.cmd = SIOCGIWMODE;
@@ -7192,7 +7190,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
 			iwe.u.mode = IW_MODE_MASTER;
 			iwe.u.mode = IW_MODE_MASTER;
 		else
 		else
 			iwe.u.mode = IW_MODE_ADHOC;
 			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 */
 	/* 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.m = frequency_list[iwe.u.freq.m - 1] * 100000;
 	iwe.u.freq.e = 1;
 	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);
 	dBm = le16_to_cpu(bss->dBm);
 
 
@@ -7223,7 +7223,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
 				| IW_QUAL_DBM;
 				| IW_QUAL_DBM;
 	}
 	}
 	iwe.u.qual.noise = ai->wstats.qual.noise;
 	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 */
 	/* Add encryption capability */
 	iwe.cmd = SIOCGIWENCODE;
 	iwe.cmd = SIOCGIWENCODE;
@@ -7232,11 +7233,12 @@ static inline char *airo_translate_scan(struct net_device *dev,
 	else
 	else
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 	iwe.u.data.length = 0;
 	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
 	/* Rate : stuffing multiple values in a single event require a bit
 	 * more of magic - Jean II */
 	 * 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;
 	iwe.cmd = SIOCGIWRATE;
 	/* Those two flags are ignored... */
 	/* 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) */
 		/* Bit rate given in 500 kb/s units (+ 0x80) */
 		iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
 		iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
 		/* Add new value to event */
 		/* 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 */
 	/* 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;
 		current_ev = current_val;
 
 
 	/* Beacon interval */
 	/* Beacon interval */
@@ -7261,7 +7265,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
 		iwe.cmd = IWEVCUSTOM;
 		iwe.cmd = IWEVCUSTOM;
 		sprintf(buf, "bcn_int=%d", bss->beaconInterval);
 		sprintf(buf, "bcn_int=%d", bss->beaconInterval);
 		iwe.u.data.length = strlen(buf);
 		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);
 		kfree(buf);
 	}
 	}
 
 
@@ -7295,8 +7300,10 @@ static inline char *airo_translate_scan(struct net_device *dev,
 					iwe.cmd = IWEVGENIE;
 					iwe.cmd = IWEVGENIE;
 					iwe.u.data.length = min(info_element->len + 2,
 					iwe.u.data.length = min(info_element->len + 2,
 								  MAX_WPA_IE_LEN);
 								  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;
 				break;
 
 
@@ -7304,8 +7311,9 @@ static inline char *airo_translate_scan(struct net_device *dev,
 				iwe.cmd = IWEVGENIE;
 				iwe.cmd = IWEVGENIE;
 				iwe.u.data.length = min(info_element->len + 2,
 				iwe.u.data.length = min(info_element->len + 2,
 							  MAX_WPA_IE_LEN);
 							  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;
 				break;
 
 
 			default:
 			default:
@@ -7344,7 +7352,7 @@ static int airo_get_scan(struct net_device *dev,
 
 
 	list_for_each_entry (net, &ai->network_list, list) {
 	list_for_each_entry (net, &ai->network_list, list) {
 		/* Translate to WE format this entry */
 		/* 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,
 						 extra + dwrq->length,
 						 &net->bss);
 						 &net->bss);
 
 

+ 3 - 0
drivers/net/wireless/ath5k/Kconfig

@@ -1,6 +1,9 @@
 config ATH5K
 config ATH5K
 	tristate "Atheros 5xxx wireless cards support"
 	tristate "Atheros 5xxx wireless cards support"
 	depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
 	depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+	select MAC80211_LEDS
+	select LEDS_CLASS
+	select NEW_LEDS
 	---help---
 	---help---
 	  This module adds support for wireless adapters based on
 	  This module adds support for wireless adapters based on
 	  Atheros 5xxx chipset.
 	  Atheros 5xxx chipset.

+ 115 - 148
drivers/net/wireless/ath5k/base.c

@@ -58,11 +58,6 @@
 #include "reg.h"
 #include "reg.h"
 #include "debug.h"
 #include "debug.h"
 
 
-enum {
-	ATH_LED_TX,
-	ATH_LED_RX,
-};
-
 static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
 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);
 static void 	ath5k_calibrate(unsigned long data);
 /* LED functions */
 /* 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
  * 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 ieee80211_hw *hw = pci_get_drvdata(pdev);
 	struct ath5k_softc *sc = hw->priv;
 	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);
 	ath5k_stop_hw(sc);
 	pci_save_state(pdev);
 	pci_save_state(pdev);
@@ -632,10 +623,7 @@ ath5k_pci_resume(struct pci_dev *pdev)
 	pci_write_config_byte(pdev, 0x41, 0);
 	pci_write_config_byte(pdev, 0x41, 0);
 
 
 	ath5k_init(sc);
 	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
 	 * 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->txtq, ath5k_tasklet_tx, (unsigned long)sc);
 	tasklet_init(&sc->restq, ath5k_tasklet_reset, (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->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);
 	ath5k_hw_get_lladdr(ah, mac);
 	SET_IEEE80211_PERM_ADDR(hw, mac);
 	SET_IEEE80211_PERM_ADDR(hw, mac);
@@ -776,6 +743,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 		goto err_queues;
 		goto err_queues;
 	}
 	}
 
 
+	ath5k_init_leds(sc);
+
 	return 0;
 	return 0;
 err_queues:
 err_queues:
 	ath5k_txq_release(sc);
 	ath5k_txq_release(sc);
@@ -809,6 +778,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 	ath5k_desc_free(sc, pdev);
 	ath5k_desc_free(sc, pdev);
 	ath5k_txq_release(sc);
 	ath5k_txq_release(sc);
 	ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
 	ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
+	ath5k_unregister_leds(sc);
 
 
 	/*
 	/*
 	 * NB: can't reclaim these until after ieee80211_ifdetach
 	 * 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;
 	return 0;
 }
 }
 
 
-/*
- * TODO: CLEAN THIS !!!
- */
 static void
 static void
 ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
 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;
 	sc->curmode = mode;
 
 
 	if (mode == AR5K_MODE_11A) {
 	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
 	/* Apparently when a default key is used to decrypt the packet
 	   the hw does not set the index used to decrypt.  In such cases
 	   the hw does not set the index used to decrypt.  In such cases
 	   get the index from the packet. */
 	   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;
 		keyix = skb->data[hlen + 3] >> 6;
 
 
 		if (test_bit(keyix, sc->keymap))
 		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;
 	u32 hw_tu;
 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 	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 &&
 	    le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
 	    memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
 	    memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
 		/*
 		/*
@@ -1903,8 +1814,6 @@ accept:
 			ath5k_check_ibss_tsf(sc, skb, &rxs);
 			ath5k_check_ibss_tsf(sc, skb, &rxs);
 
 
 		__ieee80211_rx(sc->hw, skb, &rxs);
 		__ieee80211_rx(sc->hw, skb, &rxs);
-		sc->led_rxrate = rs.rs_rate;
-		ath5k_led_event(sc, ATH_LED_RX);
 next:
 next:
 		list_move_tail(&bf->list, &sc->rxbuf);
 		list_move_tail(&bf->list, &sc->rxbuf);
 	} while (ath5k_rxbuf_setup(sc, bf) == 0);
 	} while (ath5k_rxbuf_setup(sc, bf) == 0);
@@ -1985,13 +1894,9 @@ ath5k_tasklet_tx(unsigned long data)
 	struct ath5k_softc *sc = (void *)data;
 	struct ath5k_softc *sc = (void *)data;
 
 
 	ath5k_tx_processq(sc, sc->txq);
 	ath5k_tx_processq(sc, sc->txq);
-
-	ath5k_led_event(sc, ATH_LED_TX);
 }
 }
 
 
 
 
-
-
 /*****************\
 /*****************\
 * Beacon handling *
 * Beacon handling *
 \*****************/
 \*****************/
@@ -2366,11 +2271,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
 	ieee80211_stop_queues(sc->hw);
 	ieee80211_stop_queues(sc->hw);
 
 
 	if (!test_bit(ATH_STAT_INVALID, sc->status)) {
 	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_hw_set_intr(ah, 0);
 	}
 	}
 	ath5k_txq_cleanup(sc);
 	ath5k_txq_cleanup(sc);
@@ -2566,55 +2467,124 @@ ath5k_calibrate(unsigned long data)
 \***************/
 \***************/
 
 
 static void
 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
 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);
 	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
 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;
 		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 *
 * Mac80211 functions *
@@ -2625,7 +2595,6 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
 {
 	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_buf *bf;
 	struct ath5k_buf *bf;
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	unsigned long flags;
 	unsigned long flags;
 	int hdrlen;
 	int hdrlen;
 	int pad;
 	int pad;
@@ -2651,8 +2620,6 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 		memmove(skb->data, skb->data+pad, hdrlen);
 		memmove(skb->data, skb->data+pad, hdrlen);
 	}
 	}
 
 
-	sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value;
-
 	spin_lock_irqsave(&sc->txbuflock, flags);
 	spin_lock_irqsave(&sc->txbuflock, flags);
 	if (list_empty(&sc->txbuf)) {
 	if (list_empty(&sc->txbuf)) {
 		ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
 		ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");

+ 18 - 14
drivers/net/wireless/ath5k/base.h

@@ -45,6 +45,7 @@
 #include <linux/list.h>
 #include <linux/list.h>
 #include <linux/wireless.h>
 #include <linux/wireless.h>
 #include <linux/if_ether.h>
 #include <linux/if_ether.h>
+#include <linux/leds.h>
 
 
 #include "ath5k.h"
 #include "ath5k.h"
 #include "debug.h"
 #include "debug.h"
@@ -79,6 +80,19 @@ struct ath5k_txq {
 	bool			setup;
 	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
 #if CHAN_DEBUG
 #define ATH_CHAN_MAX	(26+26+26+200+200)
 #define ATH_CHAN_MAX	(26+26+26+200+200)
 #else
 #else
@@ -118,13 +132,11 @@ struct ath5k_softc {
 	size_t			desc_len;	/* size of TX/RX descriptors */
 	size_t			desc_len;	/* size of TX/RX descriptors */
 	u16			cachelsz;	/* cache line size */
 	u16			cachelsz;	/* cache line size */
 
 
-	DECLARE_BITMAP(status, 6);
+	DECLARE_BITMAP(status, 4);
 #define ATH_STAT_INVALID	0		/* disable hardware accesses */
 #define ATH_STAT_INVALID	0		/* disable hardware accesses */
 #define ATH_STAT_MRRETRY	1		/* multi-rate retry support */
 #define ATH_STAT_MRRETRY	1		/* multi-rate retry support */
 #define ATH_STAT_PROMISC	2
 #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		filter_flags;	/* HW flags, AR5K_RX_FILTER_* */
 	unsigned int		curmode;	/* current phy mode */
 	unsigned int		curmode;	/* current phy mode */
@@ -132,13 +144,6 @@ struct ath5k_softc {
 
 
 	struct ieee80211_vif *vif;
 	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 */
 	enum ath5k_int		imask;		/* interrupt mask copy */
 
 
 	DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */
 	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 */
 	unsigned int		led_pin,	/* GPIO pin for driving LED */
 				led_on,		/* pin setting for LED on */
 				led_on,		/* pin setting for LED on */
 				led_off;	/* off time for current blink */
 				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 */
 	struct tasklet_struct	restq;		/* reset tasklet */
 
 
@@ -159,6 +161,7 @@ struct ath5k_softc {
 	spinlock_t		rxbuflock;
 	spinlock_t		rxbuflock;
 	u32			*rxlink;	/* link ptr in last RX desc */
 	u32			*rxlink;	/* link ptr in last RX desc */
 	struct tasklet_struct	rxtq;		/* rx intr tasklet */
 	struct tasklet_struct	rxtq;		/* rx intr tasklet */
+	struct ath5k_led	rx_led;		/* rx led */
 
 
 	struct list_head	txbuf;		/* transmit buffer */
 	struct list_head	txbuf;		/* transmit buffer */
 	spinlock_t		txbuflock;
 	spinlock_t		txbuflock;
@@ -167,6 +170,7 @@ struct ath5k_softc {
 
 
 	struct ath5k_txq	*txq;		/* beacon and tx*/
 	struct ath5k_txq	*txq;		/* beacon and tx*/
 	struct tasklet_struct	txtq;		/* tx intr tasklet */
 	struct tasklet_struct	txtq;		/* tx intr tasklet */
+	struct ath5k_led	tx_led;		/* tx led */
 
 
 	struct ath5k_buf	*bbuf;		/* beacon buffer */
 	struct ath5k_buf	*bbuf;		/* beacon buffer */
 	unsigned int		bhalq,		/* SW q for outgoing beacons */
 	unsigned int		bhalq,		/* SW q for outgoing beacons */

+ 2 - 2
drivers/net/wireless/ath5k/hw.c

@@ -31,14 +31,14 @@
 #include "base.h"
 #include "base.h"
 #include "debug.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_11a = AR5K_RATES_11A;
 static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B;
 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_11g = AR5K_RATES_11G;
 static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO;
 static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO;
 static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR;
 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_reset(struct ath5k_hw *, u32);
 static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool);
 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 *,
 static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,

+ 18 - 6
drivers/net/wireless/atmel.c

@@ -2310,30 +2310,40 @@ static int atmel_get_scan(struct net_device *dev,
 		iwe.cmd = SIOCGIWAP;
 		iwe.cmd = SIOCGIWAP;
 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 		memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6);
 		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;
 		iwe.u.data.length =  priv->BSSinfo[i].SSIDsize;
 		if (iwe.u.data.length > 32)
 		if (iwe.u.data.length > 32)
 			iwe.u.data.length = 32;
 			iwe.u.data.length = 32;
 		iwe.cmd = SIOCGIWESSID;
 		iwe.cmd = SIOCGIWESSID;
 		iwe.u.data.flags = 1;
 		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.cmd = SIOCGIWMODE;
 		iwe.u.mode = priv->BSSinfo[i].BSStype;
 		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.cmd = SIOCGIWFREQ;
 		iwe.u.freq.m = priv->BSSinfo[i].channel;
 		iwe.u.freq.m = priv->BSSinfo[i].channel;
 		iwe.u.freq.e = 0;
 		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 */
 		/* Add quality statistics */
 		iwe.cmd = IWEVQUAL;
 		iwe.cmd = IWEVQUAL;
 		iwe.u.qual.level = priv->BSSinfo[i].RSSI;
 		iwe.u.qual.level = priv->BSSinfo[i].RSSI;
 		iwe.u.qual.qual  = iwe.u.qual.level;
 		iwe.u.qual.qual  = iwe.u.qual.level;
 		/* iwe.u.qual.noise  = SOMETHING */
 		/* 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;
 		iwe.cmd = SIOCGIWENCODE;
@@ -2342,7 +2352,9 @@ static int atmel_get_scan(struct net_device *dev,
 		else
 		else
 			iwe.u.data.flags = IW_ENCODE_DISABLED;
 			iwe.u.data.flags = IW_ENCODE_DISABLED;
 		iwe.u.data.length = 0;
 		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 */
 	/* Length of data */

+ 2 - 0
drivers/net/wireless/b43/b43.h

@@ -441,6 +441,8 @@ enum {
 #define B43_FWPANIC_DIE			0 /* Firmware died. Don't auto-restart it. */
 #define B43_FWPANIC_DIE			0 /* Firmware died. Don't auto-restart it. */
 #define B43_FWPANIC_RESTART		1 /* Firmware died. Schedule a controller reset. */
 #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.
 /* Device specific rate values.
  * The actual values defined here are (rate_in_mbps * 2).
  * The actual values defined here are (rate_in_mbps * 2).

+ 321 - 38
drivers/net/wireless/b43/debugfs.c

@@ -74,70 +74,327 @@ struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
 	} while (0)
 	} 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;
 	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;
 	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;
 		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;
 	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)
 				    char *buf, size_t bufsize)
 {
 {
 	ssize_t count = 0;
 	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;
 	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 */
 /* 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)
 			     char *buf, size_t bufsize)
 {
 {
 	ssize_t count = 0;
 	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;
 	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,
 static ssize_t txstat_read_file(struct b43_wldev *dev,
 				char *buf, size_t bufsize)
 				char *buf, size_t bufsize)
 {
 {
@@ -496,9 +753,15 @@ out_unlock:
 		.take_irqlock	= _take_irqlock,		\
 		.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(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(txstat, txstat_read_file, NULL, 0);
 B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
 B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
 B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
 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_fast", B43_DBG_PWORK_FAST, 0);
 	add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 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_lo", B43_DBG_LO, 0);
+	add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
 
 
 #undef add_dyn_dbg
 #undef add_dyn_dbg
 }
 }
@@ -584,6 +848,13 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
 		return;
 		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)	\
 #define ADD_FILE(name, mode)	\
 	do {							\
 	do {							\
 		struct dentry *d;				\
 		struct dentry *d;				\
@@ -596,9 +867,15 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
 	} while (0)
 	} 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(tsf, 0600);
-	ADD_FILE(ucode_regs, 0400);
-	ADD_FILE(shm, 0400);
 	ADD_FILE(txstat, 0400);
 	ADD_FILE(txstat, 0400);
 	ADD_FILE(txpower_g, 0600);
 	ADD_FILE(txpower_g, 0600);
 	ADD_FILE(restart, 0200);
 	ADD_FILE(restart, 0200);
@@ -620,9 +897,15 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)
 		return;
 		return;
 	b43_remove_dynamic_debug(dev);
 	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_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_txstat.dentry);
 	debugfs_remove(e->file_txpower_g.dentry);
 	debugfs_remove(e->file_txpower_g.dentry);
 	debugfs_remove(e->file_restart.dentry);
 	debugfs_remove(e->file_restart.dentry);

+ 21 - 2
drivers/net/wireless/b43/debugfs.h

@@ -11,6 +11,7 @@ enum b43_dyndbg {		/* Dynamic debugging features */
 	B43_DBG_PWORK_FAST,
 	B43_DBG_PWORK_FAST,
 	B43_DBG_PWORK_STOP,
 	B43_DBG_PWORK_STOP,
 	B43_DBG_LO,
 	B43_DBG_LO,
+	B43_DBG_FIRMWARE,
 	__B43_NR_DYNDBG,
 	__B43_NR_DYNDBG,
 };
 };
 
 
@@ -36,9 +37,15 @@ struct b43_dfsentry {
 	struct b43_wldev *dev;
 	struct b43_wldev *dev;
 	struct dentry *subdir;
 	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_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_txstat;
 	struct b43_dfs_file file_txpower_g;
 	struct b43_dfs_file file_txpower_g;
 	struct b43_dfs_file file_restart;
 	struct b43_dfs_file file_restart;
@@ -46,6 +53,18 @@ struct b43_dfsentry {
 
 
 	struct b43_txstatus_log txstatlog;
 	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. */
 	/* Enabled/Disabled list for the dynamic debugging features. */
 	u32 dyn_debug[__B43_NR_DYNDBG];
 	u32 dyn_debug[__B43_NR_DYNDBG];
 	/* Dentries for the dynamic debugging entries. */
 	/* Dentries for the dynamic debugging entries. */

+ 35 - 30
drivers/net/wireless/b43/dma.c

@@ -328,11 +328,11 @@ static inline
 	dma_addr_t dmaaddr;
 	dma_addr_t dmaaddr;
 
 
 	if (tx) {
 	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 {
 	} 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;
 	return dmaaddr;
@@ -343,11 +343,11 @@ static inline
 			  dma_addr_t addr, size_t len, int tx)
 			  dma_addr_t addr, size_t len, int tx)
 {
 {
 	if (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 {
 	} 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)
 				 dma_addr_t addr, size_t len)
 {
 {
 	B43_WARN_ON(ring->tx);
 	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
 static inline
@@ -365,8 +365,8 @@ static inline
 				    dma_addr_t addr, size_t len)
 				    dma_addr_t addr, size_t len)
 {
 {
 	B43_WARN_ON(ring->tx);
 	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
 static inline
@@ -381,7 +381,6 @@ static inline
 
 
 static int alloc_ringmemory(struct b43_dmaring *ring)
 static int alloc_ringmemory(struct b43_dmaring *ring)
 {
 {
-	struct device *dma_dev = ring->dev->dev->dma_dev;
 	gfp_t flags = GFP_KERNEL;
 	gfp_t flags = GFP_KERNEL;
 
 
 	/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
 	/* 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
 	 * For unknown reasons - possibly a hardware error - the BCM4311 rev
 	 * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
 	 * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
 	 * which accounts for the GFP_DMA flag below.
 	 * 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)
 	if (ring->type == B43_DMA_64BIT)
 		flags |= GFP_DMA;
 		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) {
 	if (!ring->descbase) {
 		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
 		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
 		return -ENOMEM;
 		return -ENOMEM;
@@ -408,10 +410,13 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
 
 
 static void free_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 */
 /* Reset the RX DMA channel */
@@ -518,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
 				  dma_addr_t addr,
 				  dma_addr_t addr,
 				  size_t buffersize, bool dma_to_device)
 				  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;
 		return 1;
 
 
 	switch (ring->type) {
 	switch (ring->type) {
@@ -844,10 +849,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 			goto err_kfree_meta;
 			goto err_kfree_meta;
 
 
 		/* test for ability to dma to txhdr_cache */
 		/* 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,
 		if (b43_dma_mapping_error(ring, dma_test,
 					  b43_txhdr_size(dev), 1)) {
 					  b43_txhdr_size(dev), 1)) {
@@ -859,10 +864,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 			if (!ring->txhdr_cache)
 			if (!ring->txhdr_cache)
 				goto err_kfree_meta;
 				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,
 			if (b43_dma_mapping_error(ring, dma_test,
 						  b43_txhdr_size(dev), 1)) {
 						  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);
 	err = alloc_ringmemory(ring);

+ 69 - 17
drivers/net/wireless/b43/main.c

@@ -373,13 +373,10 @@ static inline void b43_shm_control_word(struct b43_wldev *dev,
 	b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
 	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;
 	u32 ret;
 
 
-	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
 		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);
 	b43_shm_control_word(dev, routing, offset);
 	ret = b43_read32(dev, B43_MMIO_SHM_DATA);
 	ret = b43_read32(dev, B43_MMIO_SHM_DATA);
 out:
 out:
-	spin_unlock_irqrestore(&wl->shm_lock, flags);
-
 	return ret;
 	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;
 	struct b43_wl *wl = dev->wl;
 	unsigned long flags;
 	unsigned long flags;
-	u16 ret;
+	u32 ret;
 
 
 	spin_lock_irqsave(&wl->shm_lock, flags);
 	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) {
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
 		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);
 	b43_shm_control_word(dev, routing, offset);
 	ret = b43_read16(dev, B43_MMIO_SHM_DATA);
 	ret = b43_read16(dev, B43_MMIO_SHM_DATA);
 out:
 out:
-	spin_unlock_irqrestore(&wl->shm_lock, flags);
-
 	return ret;
 	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;
 	struct b43_wl *wl = dev->wl;
 	unsigned long flags;
 	unsigned long flags;
+	u16 ret;
 
 
 	spin_lock_irqsave(&wl->shm_lock, flags);
 	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) {
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
 		if (offset & 0x0003) {
@@ -443,35 +455,47 @@ void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
 				    (value >> 16) & 0xffff);
 				    (value >> 16) & 0xffff);
 			b43_shm_control_word(dev, routing, (offset >> 2) + 1);
 			b43_shm_control_word(dev, routing, (offset >> 2) + 1);
 			b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
 			b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
-			goto out;
+			return;
 		}
 		}
 		offset >>= 2;
 		offset >>= 2;
 	}
 	}
 	b43_shm_control_word(dev, routing, offset);
 	b43_shm_control_word(dev, routing, offset);
 	b43_write32(dev, B43_MMIO_SHM_DATA, value);
 	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;
 	struct b43_wl *wl = dev->wl;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&wl->shm_lock, 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) {
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
 		if (offset & 0x0003) {
 			/* Unaligned access */
 			/* Unaligned access */
 			b43_shm_control_word(dev, routing, offset >> 2);
 			b43_shm_control_word(dev, routing, offset >> 2);
 			b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
 			b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
-			goto out;
+			return;
 		}
 		}
 		offset >>= 2;
 		offset >>= 2;
 	}
 	}
 	b43_shm_control_word(dev, routing, offset);
 	b43_shm_control_word(dev, routing, offset);
 	b43_write16(dev, B43_MMIO_SHM_DATA, value);
 	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);
 	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 */
 /* http://bcm-specs.sipsolutions.net/EnableMac */
 void b43_mac_enable(struct b43_wldev *dev)
 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--;
 	dev->mac_suspended--;
 	B43_WARN_ON(dev->mac_suspended < 0);
 	B43_WARN_ON(dev->mac_suspended < 0);
 	if (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)
 static void b43_periodic_every15sec(struct b43_wldev *dev)
 {
 {
 	struct b43_phy *phy = &dev->phy;
 	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) {
 	if (phy->type == B43_PHYTYPE_G) {
 		//TODO: update_aci_moving_average
 		//TODO: update_aci_moving_average

+ 4 - 0
drivers/net/wireless/b43/main.h

@@ -95,9 +95,13 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
 void b43_tsf_write(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);
+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);
+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_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);
+void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
 
 
 u64 b43_hf_read(struct b43_wldev *dev);
 u64 b43_hf_read(struct b43_wldev *dev);
 void b43_hf_write(struct b43_wldev *dev, u64 value);
 void b43_hf_write(struct b43_wldev *dev, u64 value);

+ 1 - 1
drivers/net/wireless/b43/pio.c

@@ -586,7 +586,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
 
 
 	spin_lock(&q->lock); /* IRQs are already disabled. */
 	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));
 	memset(&info->status, 0, sizeof(info->status));
 
 
 	b43_fill_txstatus_report(info, status);
 	b43_fill_txstatus_report(info, status);

+ 5 - 2
drivers/net/wireless/b43/rfkill.c

@@ -88,7 +88,7 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
 		goto out_unlock;
 		goto out_unlock;
 	err = 0;
 	err = 0;
 	switch (state) {
 	switch (state) {
-	case RFKILL_STATE_ON:
+	case RFKILL_STATE_UNBLOCKED:
 		if (!dev->radio_hw_enable) {
 		if (!dev->radio_hw_enable) {
 			/* No luck. We can't toggle the hardware RF-kill
 			/* No luck. We can't toggle the hardware RF-kill
 			 * button from software. */
 			 * button from software. */
@@ -98,10 +98,13 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
 		if (!dev->phy.radio_on)
 		if (!dev->phy.radio_on)
 			b43_radio_turn_on(dev);
 			b43_radio_turn_on(dev);
 		break;
 		break;
-	case RFKILL_STATE_OFF:
+	case RFKILL_STATE_SOFT_BLOCKED:
 		if (dev->phy.radio_on)
 		if (dev->phy.radio_on)
 			b43_radio_turn_off(dev, 0);
 			b43_radio_turn_off(dev, 0);
 		break;
 		break;
+	default:
+		b43warn(wl, "Received unexpected rfkill state %d.\n", state);
+		break;
 	}
 	}
 out_unlock:
 out_unlock:
 	mutex_unlock(&wl->mutex);
 	mutex_unlock(&wl->mutex);

+ 7 - 10
drivers/net/wireless/b43/xmit.c

@@ -193,7 +193,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 	const struct ieee80211_hdr *wlhdr =
 	const struct ieee80211_hdr *wlhdr =
 	    (const struct ieee80211_hdr *)fragment_data;
 	    (const struct ieee80211_hdr *)fragment_data;
 	int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
 	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;
 	struct ieee80211_rate *fbrate;
 	u8 rate, rate_fb;
 	u8 rate, rate_fb;
 	int rate_ofdm, rate_fb_ofdm;
 	int rate_ofdm, rate_fb_ofdm;
@@ -259,7 +259,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 			   B43_TXH_MAC_KEYIDX;
 			   B43_TXH_MAC_KEYIDX;
 		mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
 		mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
 			   B43_TXH_MAC_KEYALG;
 			   B43_TXH_MAC_KEYALG;
-		wlhdr_len = ieee80211_get_hdrlen(fctl);
+		wlhdr_len = ieee80211_hdrlen(fctl);
 		iv_len = min((size_t) info->control.iv_len,
 		iv_len = min((size_t) info->control.iv_len,
 			     ARRAY_SIZE(txhdr->iv));
 			     ARRAY_SIZE(txhdr->iv));
 		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
 		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
@@ -317,8 +317,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 	/* MAC control */
 	/* MAC control */
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 		mac_ctl |= B43_TXH_MAC_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;
 		mac_ctl |= B43_TXH_MAC_HWSEQ;
 	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 		mac_ctl |= B43_TXH_MAC_STMSDU;
 		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 b43_plcp_hdr6 *plcp;
 	struct ieee80211_hdr *wlhdr;
 	struct ieee80211_hdr *wlhdr;
 	const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
 	const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
-	u16 fctl;
+	__le16 fctl;
 	u16 phystat0, phystat3, chanstat, mactime;
 	u16 phystat0, phystat3, chanstat, mactime;
 	u32 macstat;
 	u32 macstat;
 	u16 chanid;
 	u16 chanid;
@@ -549,7 +548,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 		goto drop;
 		goto drop;
 	}
 	}
 	wlhdr = (struct ieee80211_hdr *)(skb->data);
 	wlhdr = (struct ieee80211_hdr *)(skb->data);
-	fctl = le16_to_cpu(wlhdr->frame_control);
+	fctl = wlhdr->frame_control;
 
 
 	if (macstat & B43_RX_MAC_DEC) {
 	if (macstat & B43_RX_MAC_DEC) {
 		unsigned int keyidx;
 		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);
 		B43_WARN_ON(keyidx >= dev->max_nr_keys);
 
 
 		if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
 		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))) {
 			if (unlikely(skb->len < (wlhdr_len + 3))) {
 				b43dbg(dev->wl,
 				b43dbg(dev->wl,
 				       "RX: Packet size underrun (3)\n");
 				       "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
 	 * of timestamp, i.e. about 65 milliseconds after the PHY received
 	 * the first symbol.
 	 * 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;
 		u16 low_mactime_now;
 
 
 		b43_tsf_read(dev, &status.mactime);
 		b43_tsf_read(dev, &status.mactime);

+ 31 - 32
drivers/net/wireless/b43legacy/dma.c

@@ -393,13 +393,13 @@ dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
 	dma_addr_t dmaaddr;
 	dma_addr_t dmaaddr;
 
 
 	if (tx)
 	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
 	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;
 	return dmaaddr;
 }
 }
@@ -411,13 +411,13 @@ void unmap_descbuffer(struct b43legacy_dmaring *ring,
 		      int tx)
 		      int tx)
 {
 {
 	if (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
 	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
 static inline
@@ -427,8 +427,8 @@ void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
 {
 {
 	B43legacy_WARN_ON(ring->tx);
 	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
 static inline
@@ -438,8 +438,8 @@ void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
 {
 {
 	B43legacy_WARN_ON(ring->tx);
 	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
 static inline
@@ -458,10 +458,11 @@ void free_descriptor_buffer(struct b43legacy_dmaring *ring,
 
 
 static int alloc_ringmemory(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) {
 	if (!ring->descbase) {
 		b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
 		b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
 			     " failed\n");
 			     " failed\n");
@@ -474,10 +475,8 @@ static int alloc_ringmemory(struct b43legacy_dmaring *ring)
 
 
 static void free_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 */
 /* Reset the RX DMA channel */
@@ -589,7 +588,7 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
 					 size_t buffersize,
 					 size_t buffersize,
 					 bool dma_to_device)
 					 bool dma_to_device)
 {
 {
-	if (unlikely(dma_mapping_error(addr)))
+	if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
 		return 1;
 		return 1;
 
 
 	switch (ring->type) {
 	switch (ring->type) {
@@ -894,9 +893,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
 			goto err_kfree_meta;
 			goto err_kfree_meta;
 
 
 		/* test for ability to dma to txhdr_cache */
 		/* 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,
 		if (b43legacy_dma_mapping_error(ring, dma_test,
 					sizeof(struct b43legacy_txhdr_fw3), 1)) {
 					sizeof(struct b43legacy_txhdr_fw3), 1)) {
@@ -908,7 +907,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
 			if (!ring->txhdr_cache)
 			if (!ring->txhdr_cache)
 				goto err_kfree_meta;
 				goto err_kfree_meta;
 
 
-			dma_test = dma_map_single(dev->dev->dma_dev,
+				dma_test = ssb_dma_map_single(dev->dev,
 					ring->txhdr_cache,
 					ring->txhdr_cache,
 					sizeof(struct b43legacy_txhdr_fw3),
 					sizeof(struct b43legacy_txhdr_fw3),
 					DMA_TO_DEVICE);
 					DMA_TO_DEVICE);
@@ -918,9 +917,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
 				goto err_kfree_txhdr_cache;
 				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->nr_slots = nr_slots;
 	ring->nr_slots = nr_slots;

+ 6 - 2
drivers/net/wireless/b43legacy/rfkill.c

@@ -90,7 +90,7 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
 		goto out_unlock;
 		goto out_unlock;
 	err = 0;
 	err = 0;
 	switch (state) {
 	switch (state) {
-	case RFKILL_STATE_ON:
+	case RFKILL_STATE_UNBLOCKED:
 		if (!dev->radio_hw_enable) {
 		if (!dev->radio_hw_enable) {
 			/* No luck. We can't toggle the hardware RF-kill
 			/* No luck. We can't toggle the hardware RF-kill
 			 * button from software. */
 			 * button from software. */
@@ -100,10 +100,14 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
 		if (!dev->phy.radio_on)
 		if (!dev->phy.radio_on)
 			b43legacy_radio_turn_on(dev);
 			b43legacy_radio_turn_on(dev);
 		break;
 		break;
-	case RFKILL_STATE_OFF:
+	case RFKILL_STATE_SOFT_BLOCKED:
 		if (dev->phy.radio_on)
 		if (dev->phy.radio_on)
 			b43legacy_radio_turn_off(dev, 0);
 			b43legacy_radio_turn_off(dev, 0);
 		break;
 		break;
+	default:
+		b43legacywarn(wl, "Received unexpected rfkill state %d.\n",
+			      state);
+		break;
 	}
 	}
 
 
 out_unlock:
 out_unlock:

+ 7 - 9
drivers/net/wireless/b43legacy/xmit.c

@@ -442,7 +442,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
 	struct b43legacy_plcp_hdr6 *plcp;
 	struct b43legacy_plcp_hdr6 *plcp;
 	struct ieee80211_hdr *wlhdr;
 	struct ieee80211_hdr *wlhdr;
 	const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr;
 	const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr;
-	u16 fctl;
+	__le16 fctl;
 	u16 phystat0;
 	u16 phystat0;
 	u16 phystat3;
 	u16 phystat3;
 	u16 chanstat;
 	u16 chanstat;
@@ -480,7 +480,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
 		goto drop;
 		goto drop;
 	}
 	}
 	wlhdr = (struct ieee80211_hdr *)(skb->data);
 	wlhdr = (struct ieee80211_hdr *)(skb->data);
-	fctl = le16_to_cpu(wlhdr->frame_control);
+	fctl = wlhdr->frame_control;
 
 
 	if ((macstat & B43legacy_RX_MAC_DEC) &&
 	if ((macstat & B43legacy_RX_MAC_DEC) &&
 	    !(macstat & B43legacy_RX_MAC_DECERR)) {
 	    !(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) {
 		if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) {
 			/* Remove PROTECTED flag to mark it as decrypted. */
 			/* 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))) {
 			if (unlikely(skb->len < (wlhdr_len + 3))) {
 				b43legacydbg(dev->wl, "RX: Packet size"
 				b43legacydbg(dev->wl, "RX: Packet size"
 					     " underrun3\n");
 					     " underrun3\n");
@@ -556,9 +556,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
 	 * of timestamp, i.e. about 65 milliseconds after the PHY received
 	 * of timestamp, i.e. about 65 milliseconds after the PHY received
 	 * the first symbol.
 	 * 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;
 		u16 low_mactime_now;
 
 
 		b43legacy_tsf_read(dev, &status.mactime);
 		b43legacy_tsf_read(dev, &status.mactime);

+ 2 - 1
drivers/net/wireless/hostap/hostap.h

@@ -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[],
 int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
 			   struct iw_quality qual[], int buf_size,
 			   struct iw_quality qual[], int buf_size,
 			   int aplist);
 			   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);
 int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param);
 
 
 
 

+ 16 - 16
drivers/net/wireless/hostap/hostap_ap.c

@@ -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
 /* Translate our list of Access Points & Stations to a card independant
  * format that the Wireless Tools will understand - Jean II */
  * 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;
 	struct hostap_interface *iface;
 	local_info_t *local;
 	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;
 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 		memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN);
 		memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN);
 		iwe.len = IW_EV_ADDR_LEN;
 		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
 		/* Use the mode to indicate if it's a station or
 		 * an Access Point */
 		 * an Access Point */
@@ -2461,8 +2462,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
 		else
 		else
 			iwe.u.mode = IW_MODE_INFRA;
 			iwe.u.mode = IW_MODE_INFRA;
 		iwe.len = IW_EV_UINT_LEN;
 		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 */
 		/* Some quality */
 		memset(&iwe, 0, sizeof(iwe));
 		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.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
 		iwe.u.qual.updated = sta->last_rx_updated;
 		iwe.u.qual.updated = sta->last_rx_updated;
 		iwe.len = IW_EV_QUAL_LEN;
 		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
 #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
 		if (sta->ap) {
 		if (sta->ap) {
@@ -2486,8 +2487,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
 			iwe.cmd = SIOCGIWESSID;
 			iwe.cmd = SIOCGIWESSID;
 			iwe.u.data.length = sta->u.ap.ssid_len;
 			iwe.u.data.length = sta->u.ap.ssid_len;
 			iwe.u.data.flags = 1;
 			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);
 							  sta->u.ap.ssid);
 
 
 			memset(&iwe, 0, sizeof(iwe));
 			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;
 					IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
 			else
 			else
 				iwe.u.data.flags = IW_ENCODE_DISABLED;
 				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 &&
 			if (sta->u.ap.channel > 0 &&
 			    sta->u.ap.channel <= FREQ_COUNT) {
 			    sta->u.ap.channel <= FREQ_COUNT) {
@@ -2510,7 +2510,7 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
 					* 100000;
 					* 100000;
 				iwe.u.freq.e = 1;
 				iwe.u.freq.e = 1;
 				current_ev = iwe_stream_add_event(
 				current_ev = iwe_stream_add_event(
-					current_ev, end_buf, &iwe,
+					info, current_ev, end_buf, &iwe,
 					IW_EV_FREQ_LEN);
 					IW_EV_FREQ_LEN);
 			}
 			}
 
 
@@ -2519,8 +2519,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
 			sprintf(buf, "beacon_interval=%d",
 			sprintf(buf, "beacon_interval=%d",
 				sta->listen_interval);
 				sta->listen_interval);
 			iwe.u.data.length = strlen(buf);
 			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 */
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
 
 

+ 31 - 27
drivers/net/wireless/hostap/hostap_ioctl.c

@@ -1793,6 +1793,7 @@ static int prism2_ioctl_siwscan(struct net_device *dev,
 
 
 #ifndef PRISM2_NO_STATION_MODES
 #ifndef PRISM2_NO_STATION_MODES
 static char * __prism2_translate_scan(local_info_t *local,
 static char * __prism2_translate_scan(local_info_t *local,
+				      struct iw_request_info *info,
 				      struct hfa384x_hostscan_result *scan,
 				      struct hfa384x_hostscan_result *scan,
 				      struct hostap_bss_info *bss,
 				      struct hostap_bss_info *bss,
 				      char *current_ev, char *end_buf)
 				      char *current_ev, char *end_buf)
@@ -1823,7 +1824,7 @@ static char * __prism2_translate_scan(local_info_t *local,
 	iwe.cmd = SIOCGIWAP;
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN);
 	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);
 					  IW_EV_ADDR_LEN);
 
 
 	/* Other entries will be displayed in the order we give them */
 	/* 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.cmd = SIOCGIWESSID;
 	iwe.u.data.length = ssid_len;
 	iwe.u.data.length = ssid_len;
 	iwe.u.data.flags = 1;
 	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));
 	memset(&iwe, 0, sizeof(iwe));
 	iwe.cmd = SIOCGIWMODE;
 	iwe.cmd = SIOCGIWMODE;
@@ -1847,8 +1849,8 @@ static char * __prism2_translate_scan(local_info_t *local,
 			iwe.u.mode = IW_MODE_MASTER;
 			iwe.u.mode = IW_MODE_MASTER;
 		else
 		else
 			iwe.u.mode = IW_MODE_ADHOC;
 			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));
 	memset(&iwe, 0, sizeof(iwe));
@@ -1864,8 +1866,8 @@ static char * __prism2_translate_scan(local_info_t *local,
 	if (chan > 0) {
 	if (chan > 0) {
 		iwe.u.freq.m = freq_list[chan - 1] * 100000;
 		iwe.u.freq.m = freq_list[chan - 1] * 100000;
 		iwe.u.freq.e = 1;
 		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) {
 	if (scan) {
@@ -1884,8 +1886,8 @@ static char * __prism2_translate_scan(local_info_t *local,
 			| IW_QUAL_NOISE_UPDATED
 			| IW_QUAL_NOISE_UPDATED
 			| IW_QUAL_QUAL_INVALID
 			| IW_QUAL_QUAL_INVALID
 			| IW_QUAL_DBM;
 			| 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));
 	memset(&iwe, 0, sizeof(iwe));
@@ -1895,13 +1897,13 @@ static char * __prism2_translate_scan(local_info_t *local,
 	else
 	else
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 	iwe.u.data.length = 0;
 	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 */
 	/* TODO: add SuppRates into BSS table */
 	if (scan) {
 	if (scan) {
 		memset(&iwe, 0, sizeof(iwe));
 		memset(&iwe, 0, sizeof(iwe));
 		iwe.cmd = SIOCGIWRATE;
 		iwe.cmd = SIOCGIWRATE;
-		current_val = current_ev + IW_EV_LCP_LEN;
+		current_val = current_ev + iwe_stream_lcp_len(info);
 		pos = scan->sup_rates;
 		pos = scan->sup_rates;
 		for (i = 0; i < sizeof(scan->sup_rates); i++) {
 		for (i = 0; i < sizeof(scan->sup_rates); i++) {
 			if (pos[i] == 0)
 			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) */
 			/* Bit rate given in 500 kb/s units (+ 0x80) */
 			iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000);
 			iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000);
 			current_val = iwe_stream_add_value(
 			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);
 				IW_EV_PARAM_LEN);
 		}
 		}
 		/* Check if we added any event */
 		/* 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;
 			current_ev = current_val;
 	}
 	}
 
 
@@ -1924,15 +1926,15 @@ static char * __prism2_translate_scan(local_info_t *local,
 		iwe.cmd = IWEVCUSTOM;
 		iwe.cmd = IWEVCUSTOM;
 		sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval));
 		sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval));
 		iwe.u.data.length = strlen(buf);
 		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));
 		memset(&iwe, 0, sizeof(iwe));
 		iwe.cmd = IWEVCUSTOM;
 		iwe.cmd = IWEVCUSTOM;
 		sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate));
 		sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate));
 		iwe.u.data.length = strlen(buf);
 		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 &&
 		if (local->last_scan_type == PRISM2_HOSTSCAN &&
 		    (capabilities & WLAN_CAPABILITY_IBSS)) {
 		    (capabilities & WLAN_CAPABILITY_IBSS)) {
@@ -1940,8 +1942,8 @@ static char * __prism2_translate_scan(local_info_t *local,
 			iwe.cmd = IWEVCUSTOM;
 			iwe.cmd = IWEVCUSTOM;
 			sprintf(buf, "atim=%d", le16_to_cpu(scan->atim));
 			sprintf(buf, "atim=%d", le16_to_cpu(scan->atim));
 			iwe.u.data.length = strlen(buf);
 			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);
 	kfree(buf);
@@ -1950,16 +1952,16 @@ static char * __prism2_translate_scan(local_info_t *local,
 		memset(&iwe, 0, sizeof(iwe));
 		memset(&iwe, 0, sizeof(iwe));
 		iwe.cmd = IWEVGENIE;
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = bss->wpa_ie_len;
 		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) {
 	if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) {
 		memset(&iwe, 0, sizeof(iwe));
 		memset(&iwe, 0, sizeof(iwe));
 		iwe.cmd = IWEVGENIE;
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = bss->rsn_ie_len;
 		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;
 	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
 /* Translate scan data returned from the card to a card independant
  * format that the Wireless Tools will understand - Jean II */
  * format that the Wireless Tools will understand - Jean II */
 static inline int prism2_translate_scan(local_info_t *local,
 static inline int prism2_translate_scan(local_info_t *local,
+					struct iw_request_info *info,
 					char *buffer, int buflen)
 					char *buffer, int buflen)
 {
 {
 	struct hfa384x_hostscan_result *scan;
 	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) {
 			if (memcmp(bss->bssid, scan->bssid, ETH_ALEN) == 0) {
 				bss->included = 1;
 				bss->included = 1;
 				current_ev = __prism2_translate_scan(
 				current_ev = __prism2_translate_scan(
-					local, scan, bss, current_ev, end_buf);
+					local, info, scan, bss, current_ev,
+					end_buf);
 				found++;
 				found++;
 			}
 			}
 		}
 		}
 		if (!found) {
 		if (!found) {
 			current_ev = __prism2_translate_scan(
 			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 */
 		/* Check if there is space for one more entry */
 		if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
 		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);
 		bss = list_entry(ptr, struct hostap_bss_info, list);
 		if (bss->included)
 		if (bss->included)
 			continue;
 			continue;
-		current_ev = __prism2_translate_scan(local, NULL, bss,
+		current_ev = __prism2_translate_scan(local, info, NULL, bss,
 						     current_ev, end_buf);
 						     current_ev, end_buf);
 		/* Check if there is space for one more entry */
 		/* Check if there is space for one more entry */
 		if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
 		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;
 	local->scan_timestamp = 0;
 
 
-	res = prism2_translate_scan(local, extra, data->length);
+	res = prism2_translate_scan(local, info, extra, data->length);
 
 
 	if (res >= 0) {
 	if (res >= 0) {
 		data->length = res;
 		data->length = res;
@@ -2103,7 +2107,7 @@ static int prism2_ioctl_giwscan(struct net_device *dev,
 		 * Jean II */
 		 * Jean II */
 
 
 		/* Translate to WE format */
 		/* Translate to WE format */
-		res = prism2_ap_translate_scan(dev, extra);
+		res = prism2_ap_translate_scan(dev, info, extra);
 		if (res >= 0) {
 		if (res >= 0) {
 			printk(KERN_DEBUG "Scan result translation succeeded "
 			printk(KERN_DEBUG "Scan result translation succeeded "
 			       "(length=%d)\n", res);
 			       "(length=%d)\n", res);

+ 1 - 1
drivers/net/wireless/iwlwifi/Kconfig

@@ -8,7 +8,7 @@ config IWLCORE
 	select MAC80211_LEDS if IWLWIFI_LEDS
 	select MAC80211_LEDS if IWLWIFI_LEDS
 	select LEDS_CLASS if IWLWIFI_LEDS
 	select LEDS_CLASS if IWLWIFI_LEDS
 	select RFKILL if IWLWIFI_RFKILL
 	select RFKILL if IWLWIFI_RFKILL
-	select RFKILL_INPUT if IWLWIFI_RFKILL
+	select RFKILL_INPUT if (IWLWIFI_RFKILL && INPUT)
 
 
 config IWLWIFI_LEDS
 config IWLWIFI_LEDS
 	bool
 	bool

+ 15 - 3
drivers/net/wireless/iwlwifi/iwl-rfkill.c

@@ -54,17 +54,20 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
 	mutex_lock(&priv->mutex);
 	mutex_lock(&priv->mutex);
 
 
 	switch (state) {
 	switch (state) {
-	case RFKILL_STATE_ON:
+	case RFKILL_STATE_UNBLOCKED:
 		iwl_radio_kill_sw_enable_radio(priv);
 		iwl_radio_kill_sw_enable_radio(priv);
 		/* if HW rf-kill is set dont allow ON state */
 		/* if HW rf-kill is set dont allow ON state */
 		if (iwl_is_rfkill(priv))
 		if (iwl_is_rfkill(priv))
 			err = -EBUSY;
 			err = -EBUSY;
 		break;
 		break;
-	case RFKILL_STATE_OFF:
+	case RFKILL_STATE_SOFT_BLOCKED:
 		iwl_radio_kill_sw_disable_radio(priv);
 		iwl_radio_kill_sw_disable_radio(priv);
 		if (!iwl_is_rfkill(priv))
 		if (!iwl_is_rfkill(priv))
 			err = -EBUSY;
 			err = -EBUSY;
 		break;
 		break;
+	default:
+		IWL_WARNING("we recieved unexpected RFKILL state %d\n", state);
+		break;
 	}
 	}
 	mutex_unlock(&priv->mutex);
 	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->suspend = NULL;
 	priv->rfkill_mngr.rfkill->dev.class->resume = 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();
 	priv->rfkill_mngr.input_dev = input_allocate_device();
 	if (!priv->rfkill_mngr.input_dev) {
 	if (!priv->rfkill_mngr.input_dev) {
 		IWL_ERROR("Unable to allocate rfkill input device.\n");
 		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->dev.parent = device;
 	priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY);
 	priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY);
 	set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit);
 	set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit);
+#endif
 
 
 	ret = rfkill_register(priv->rfkill_mngr.rfkill);
 	ret = rfkill_register(priv->rfkill_mngr.rfkill);
 	if (ret) {
 	if (ret) {
@@ -116,11 +121,13 @@ int iwl_rfkill_init(struct iwl_priv *priv)
 		goto free_input_dev;
 		goto free_input_dev;
 	}
 	}
 
 
+#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
 	ret = input_register_device(priv->rfkill_mngr.input_dev);
 	ret = input_register_device(priv->rfkill_mngr.input_dev);
 	if (ret) {
 	if (ret) {
 		IWL_ERROR("Unable to register rfkill input device: %d\n", ret);
 		IWL_ERROR("Unable to register rfkill input device: %d\n", ret);
 		goto unregister_rfkill;
 		goto unregister_rfkill;
 	}
 	}
+#endif
 
 
 	IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
 	IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
 	return ret;
 	return ret;
@@ -130,8 +137,10 @@ unregister_rfkill:
 	priv->rfkill_mngr.rfkill = NULL;
 	priv->rfkill_mngr.rfkill = NULL;
 
 
 free_input_dev:
 free_input_dev:
+#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
 	input_free_device(priv->rfkill_mngr.input_dev);
 	input_free_device(priv->rfkill_mngr.input_dev);
 	priv->rfkill_mngr.input_dev = NULL;
 	priv->rfkill_mngr.input_dev = NULL;
+#endif
 
 
 freed_rfkill:
 freed_rfkill:
 	if (priv->rfkill_mngr.rfkill != NULL)
 	if (priv->rfkill_mngr.rfkill != NULL)
@@ -147,13 +156,16 @@ EXPORT_SYMBOL(iwl_rfkill_init);
 void iwl_rfkill_unregister(struct iwl_priv *priv)
 void iwl_rfkill_unregister(struct iwl_priv *priv)
 {
 {
 
 
+#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
 	if (priv->rfkill_mngr.input_dev)
 	if (priv->rfkill_mngr.input_dev)
 		input_unregister_device(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)
 	if (priv->rfkill_mngr.rfkill)
 		rfkill_unregister(priv->rfkill_mngr.rfkill);
 		rfkill_unregister(priv->rfkill_mngr.rfkill);
 
 
-	priv->rfkill_mngr.input_dev = NULL;
 	priv->rfkill_mngr.rfkill = NULL;
 	priv->rfkill_mngr.rfkill = NULL;
 }
 }
 EXPORT_SYMBOL(iwl_rfkill_unregister);
 EXPORT_SYMBOL(iwl_rfkill_unregister);

+ 19 - 17
drivers/net/wireless/libertas/scan.c

@@ -776,8 +776,9 @@ out:
 #define MAX_CUSTOM_LEN 64
 #define MAX_CUSTOM_LEN 64
 
 
 static inline char *lbs_translate_scan(struct lbs_private *priv,
 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;
 	struct chan_freq_power *cfp;
 	char *current_val;	/* For rates */
 	char *current_val;	/* For rates */
@@ -801,24 +802,24 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
 	iwe.cmd = SIOCGIWAP;
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
 	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 */
 	/* SSID */
 	iwe.cmd = SIOCGIWESSID;
 	iwe.cmd = SIOCGIWESSID;
 	iwe.u.data.flags = 1;
 	iwe.u.data.flags = 1;
 	iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE);
 	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 */
 	/* Mode */
 	iwe.cmd = SIOCGIWMODE;
 	iwe.cmd = SIOCGIWMODE;
 	iwe.u.mode = bss->mode;
 	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 */
 	/* Frequency */
 	iwe.cmd = SIOCGIWFREQ;
 	iwe.cmd = SIOCGIWFREQ;
 	iwe.u.freq.m = (long)cfp->freq * 100000;
 	iwe.u.freq.m = (long)cfp->freq * 100000;
 	iwe.u.freq.e = 1;
 	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 */
 	/* Add quality statistics */
 	iwe.cmd = IWEVQUAL;
 	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;
 		nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
 		iwe.u.qual.level = CAL_RSSI(snr, nf);
 		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 */
 	/* Add encryption capability */
 	iwe.cmd = SIOCGIWENCODE;
 	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.flags = IW_ENCODE_DISABLED;
 	}
 	}
 	iwe.u.data.length = 0;
 	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.cmd = SIOCGIWRATE;
 	iwe.u.bitrate.fixed = 0;
 	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++) {
 	for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
 		/* Bit rate given in 500 kb/s units */
 		/* Bit rate given in 500 kb/s units */
 		iwe.u.bitrate.value = bss->rates[j] * 500000;
 		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
 	if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
 	    && !lbs_ssid_cmp(priv->curbssparams.ssid,
 	    && !lbs_ssid_cmp(priv->curbssparams.ssid,
 			     priv->curbssparams.ssid_len,
 			     priv->curbssparams.ssid_len,
 			     bss->ssid, bss->ssid_len)) {
 			     bss->ssid, bss->ssid_len)) {
 		iwe.u.bitrate.value = 22 * 500000;
 		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);
 						   stop, &iwe, IW_EV_PARAM_LEN);
 	}
 	}
 	/* Check if we added any event */
 	/* 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;
 		start = current_val;
 
 
 	memset(&iwe, 0, sizeof(iwe));
 	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);
 		memcpy(buf, bss->wpa_ie, bss->wpa_ie_len);
 		iwe.cmd = IWEVGENIE;
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = bss->wpa_ie_len;
 		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));
 	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);
 		memcpy(buf, bss->rsn_ie, bss->rsn_ie_len);
 		iwe.cmd = IWEVGENIE;
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = bss->rsn_ie_len;
 		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) {
 	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");
 		p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");
 		iwe.u.data.length = p - custom;
 		iwe.u.data.length = p - custom;
 		if (iwe.u.data.length)
 		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:
 out:
@@ -1036,7 +1038,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
 		}
 		}
 
 
 		/* Translate to WE format this entry */
 		/* 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)
 		if (next_ev == NULL)
 			continue;
 			continue;
 		ev = next_ev;
 		ev = next_ev;

+ 4 - 3
drivers/net/wireless/mac80211_hwsim.c

@@ -430,15 +430,16 @@ static int __init init_mac80211_hwsim(void)
 		hwsim_radios[i] = hw;
 		hwsim_radios[i] = hw;
 
 
 		data = hw->priv;
 		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)) {
 		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));
 			       "failed (%ld)\n", PTR_ERR(data->dev));
 			err = -ENOMEM;
 			err = -ENOMEM;
 			goto failed;
 			goto failed;
 		}
 		}
 		data->dev->driver = &mac80211_hwsim_driver;
 		data->dev->driver = &mac80211_hwsim_driver;
-		dev_set_drvdata(data->dev, hw);
 
 
 		SET_IEEE80211_DEV(hw, data->dev);
 		SET_IEEE80211_DEV(hw, data->dev);
 		addr[3] = i >> 8;
 		addr[3] = i >> 8;

+ 19 - 11
drivers/net/wireless/orinoco.c

@@ -4046,6 +4046,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
  * format that the Wireless Tools will understand - Jean II
  * format that the Wireless Tools will understand - Jean II
  * Return message length or -errno for fatal errors */
  * Return message length or -errno for fatal errors */
 static inline char *orinoco_translate_scan(struct net_device *dev,
 static inline char *orinoco_translate_scan(struct net_device *dev,
+					   struct iw_request_info *info,
 					   char *current_ev,
 					   char *current_ev,
 					   char *end_buf,
 					   char *end_buf,
 					   union hermes_scan_info *bss,
 					   union hermes_scan_info *bss,
@@ -4062,7 +4063,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
 	iwe.cmd = SIOCGIWAP;
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
 	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 */
 	/* 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.u.data.length = 32;
 	iwe.cmd = SIOCGIWESSID;
 	iwe.cmd = SIOCGIWESSID;
 	iwe.u.data.flags = 1;
 	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 */
 	/* Add mode */
 	iwe.cmd = SIOCGIWMODE;
 	iwe.cmd = SIOCGIWMODE;
@@ -4082,7 +4085,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
 			iwe.u.mode = IW_MODE_MASTER;
 			iwe.u.mode = IW_MODE_MASTER;
 		else
 		else
 			iwe.u.mode = IW_MODE_ADHOC;
 			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;
 	channel = bss->s.channel;
@@ -4091,7 +4095,7 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
 		iwe.cmd = SIOCGIWFREQ;
 		iwe.cmd = SIOCGIWFREQ;
 		iwe.u.freq.m = channel_frequency[channel-1] * 100000;
 		iwe.u.freq.m = channel_frequency[channel-1] * 100000;
 		iwe.u.freq.e = 1;
 		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);
 						  &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;
 		iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
 	else
 	else
 		iwe.u.qual.qual = 0;
 		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 */
 	/* Add encryption capability */
 	iwe.cmd = SIOCGIWENCODE;
 	iwe.cmd = SIOCGIWENCODE;
@@ -4115,7 +4120,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
 	else
 	else
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 	iwe.u.data.length = 0;
 	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
 	/* Add EXTRA: Age to display seconds since last beacon/probe response
 	 * for given network. */
 	 * for given network. */
@@ -4126,11 +4132,12 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
 		      jiffies_to_msecs(jiffies - last_scanned));
 		      jiffies_to_msecs(jiffies - last_scanned));
 	iwe.u.data.length = p - custom;
 	iwe.u.data.length = p - custom;
 	if (iwe.u.data.length)
 	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 */
 	/* Bit rate is not available in Lucent/Agere firmwares */
 	if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
 	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 i;
 		int step;
 		int step;
 
 
@@ -4149,12 +4156,13 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
 				break;
 				break;
 			/* Bit rate given in 500 kb/s units (+ 0x80) */
 			/* Bit rate given in 500 kb/s units (+ 0x80) */
 			iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000);
 			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,
 							   end_buf, &iwe,
 							   IW_EV_PARAM_LEN);
 							   IW_EV_PARAM_LEN);
 		}
 		}
 		/* Check if we added any event */
 		/* 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;
 			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) {
 	list_for_each_entry(bss, &priv->bss_list, list) {
 		/* Translate to WE format this entry */
 		/* 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,
 						    extra + srq->length,
 						    &bss->bss,
 						    &bss->bss,
 						    bss->last_scanned);
 						    bss->last_scanned);

+ 27 - 22
drivers/net/wireless/prism54/isl_ioctl.c

@@ -571,8 +571,9 @@ prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
  */
  */
 
 
 static char *
 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 */
 	struct iw_event iwe;	/* Temporary buffer */
 	short cap;
 	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);
 	memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	iwe.cmd = SIOCGIWAP;
 	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 */
 	/* 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.length = bss->ssid.length;
 	iwe.u.data.flags = 1;
 	iwe.u.data.flags = 1;
 	iwe.cmd = SIOCGIWESSID;
 	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);
 					  &iwe, bss->ssid.octets);
 
 
 	/* Capabilities */
 	/* Capabilities */
@@ -610,9 +611,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
 		iwe.u.mode = IW_MODE_ADHOC;
 		iwe.u.mode = IW_MODE_ADHOC;
 	iwe.cmd = SIOCGIWMODE;
 	iwe.cmd = SIOCGIWMODE;
 	if (iwe.u.mode)
 	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 */
 	/* Encryption capability */
 	if (cap & CAP_CRYPT)
 	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.flags = IW_ENCODE_DISABLED;
 	iwe.u.data.length = 0;
 	iwe.u.data.length = 0;
 	iwe.cmd = SIOCGIWENCODE;
 	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 */
 	/* Add frequency. (short) bss->channel is the frequency in MHz */
 	iwe.u.freq.m = bss->channel;
 	iwe.u.freq.m = bss->channel;
 	iwe.u.freq.e = 6;
 	iwe.u.freq.e = 6;
 	iwe.cmd = SIOCGIWFREQ;
 	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 */
 	/* Add quality statistics */
 	iwe.u.qual.level = bss->rssi;
 	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 */
 	/* do a simple SNR for quality */
 	iwe.u.qual.qual = bss->rssi - noise;
 	iwe.u.qual.qual = bss->rssi - noise;
 	iwe.cmd = IWEVQUAL;
 	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 */
 	/* Add WPA/RSN Information Element, if any */
 	wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
 	wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
 	if (wpa_ie_len > 0) {
 	if (wpa_ie_len > 0) {
 		iwe.cmd = IWEVGENIE;
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
 		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 */
 	/* 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 i;
 		int mask;
 		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++) {
 		for(i = 0; i < sizeof(scan_rate_list); i++) {
 			if(bss->rates & mask) {
 			if(bss->rates & mask) {
 				iwe.u.bitrate.value = (scan_rate_list[i] * 500000);
 				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;
 			mask <<= 1;
 		}
 		}
 		/* Check if we added any event */
 		/* 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;
 			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 */
 	/* ok now, scan the list and translate its info */
 	for (i = 0; i < (int) bsslist->nr; i++) {
 	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,
 						   extra + dwrq->length,
 						   &(bsslist->bsslist[i]),
 						   &(bsslist->bsslist[i]),
 						   noise);
 						   noise);
@@ -2704,6 +2705,7 @@ prism2_ioctl_scan_req(struct net_device *ndev,
                      struct prism2_hostapd_param *param)
                      struct prism2_hostapd_param *param)
 {
 {
 	islpci_private *priv = netdev_priv(ndev);
 	islpci_private *priv = netdev_priv(ndev);
+	struct iw_request_info info;
 	int i, rvalue;
 	int i, rvalue;
 	struct obj_bsslist *bsslist;
 	struct obj_bsslist *bsslist;
 	u32 noise = 0;
 	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);
 	rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
 	bsslist = r.ptr;
 	bsslist = r.ptr;
 
 
+	info.cmd = PRISM54_HOSTAPD;
+	info.flags = 0;
+
 	/* ok now, scan the list and translate its info */
 	/* ok now, scan the list and translate its info */
 	for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
 	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,
 						   extra + IW_SCAN_MAX_DATA,
 						   &(bsslist->bsslist[i]),
 						   &(bsslist->bsslist[i]),
 						   noise);
 						   noise);

+ 17 - 15
drivers/net/wireless/rndis_wlan.c

@@ -1648,7 +1648,9 @@ static int rndis_iw_set_scan(struct net_device *dev,
 
 
 
 
 static char *rndis_translate_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
 #ifdef DEBUG
 	struct usbnet *usbdev = dev->priv;
 	struct usbnet *usbdev = dev->priv;
@@ -1667,14 +1669,14 @@ static char *rndis_translate_scan(struct net_device *dev,
 	iwe.cmd = SIOCGIWAP;
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN);
 	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),
 	devdbg(usbdev, "SSID(%d) %s", le32_to_cpu(bssid->ssid.length),
 						bssid->ssid.essid);
 						bssid->ssid.essid);
 	iwe.cmd = SIOCGIWESSID;
 	iwe.cmd = SIOCGIWESSID;
 	iwe.u.essid.length = le32_to_cpu(bssid->ssid.length);
 	iwe.u.essid.length = le32_to_cpu(bssid->ssid.length);
 	iwe.u.essid.flags = 1;
 	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));
 	devdbg(usbdev, "MODE %d", le32_to_cpu(bssid->net_infra));
 	iwe.cmd = SIOCGIWMODE;
 	iwe.cmd = SIOCGIWMODE;
@@ -1690,12 +1692,12 @@ static char *rndis_translate_scan(struct net_device *dev,
 		iwe.u.mode = IW_MODE_AUTO;
 		iwe.u.mode = IW_MODE_AUTO;
 		break;
 		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));
 	devdbg(usbdev, "FREQ %d kHz", le32_to_cpu(bssid->config.ds_config));
 	iwe.cmd = SIOCGIWFREQ;
 	iwe.cmd = SIOCGIWFREQ;
 	dsconfig_to_freq(le32_to_cpu(bssid->config.ds_config), &iwe.u.freq);
 	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));
 	devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->rssi));
 	iwe.cmd = IWEVQUAL;
 	iwe.cmd = IWEVQUAL;
@@ -1704,7 +1706,7 @@ static char *rndis_translate_scan(struct net_device *dev,
 	iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
 	iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
 			| IW_QUAL_LEVEL_UPDATED
 			| IW_QUAL_LEVEL_UPDATED
 			| IW_QUAL_NOISE_INVALID;
 			| 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));
 	devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->privacy));
 	iwe.cmd = SIOCGIWENCODE;
 	iwe.cmd = SIOCGIWENCODE;
@@ -1714,10 +1716,10 @@ static char *rndis_translate_scan(struct net_device *dev,
 	else
 	else
 		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
 		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:");
 	devdbg(usbdev, "RATES:");
-	current_val = cev + IW_EV_LCP_LEN;
+	current_val = cev + iwe_stream_lcp_len(info);
 	iwe.cmd = SIOCGIWRATE;
 	iwe.cmd = SIOCGIWRATE;
 	for (i = 0; i < sizeof(bssid->rates); i++) {
 	for (i = 0; i < sizeof(bssid->rates); i++) {
 		if (bssid->rates[i] & 0x7f) {
 		if (bssid->rates[i] & 0x7f) {
@@ -1725,13 +1727,13 @@ static char *rndis_translate_scan(struct net_device *dev,
 				((bssid->rates[i] & 0x7f) *
 				((bssid->rates[i] & 0x7f) *
 				500000);
 				500000);
 			devdbg(usbdev, " %d", iwe.u.bitrate.value);
 			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,
 				current_val, end_buf, &iwe,
 				IW_EV_PARAM_LEN);
 				IW_EV_PARAM_LEN);
 		}
 		}
 	}
 	}
 
 
-	if ((current_val - cev) > IW_EV_LCP_LEN)
+	if ((current_val - cev) > iwe_stream_lcp_len(info))
 		cev = current_val;
 		cev = current_val;
 
 
 	beacon = le32_to_cpu(bssid->config.beacon_period);
 	beacon = le32_to_cpu(bssid->config.beacon_period);
@@ -1739,14 +1741,14 @@ static char *rndis_translate_scan(struct net_device *dev,
 	iwe.cmd = IWEVCUSTOM;
 	iwe.cmd = IWEVCUSTOM;
 	snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon);
 	snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon);
 	iwe.u.data.length = strlen(sbuf);
 	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);
 	atim = le32_to_cpu(bssid->config.atim_window);
 	devdbg(usbdev, "ATIM %d", atim);
 	devdbg(usbdev, "ATIM %d", atim);
 	iwe.cmd = IWEVCUSTOM;
 	iwe.cmd = IWEVCUSTOM;
 	snprintf(sbuf, sizeof(sbuf), "atim=%u", atim);
 	snprintf(sbuf, sizeof(sbuf), "atim=%u", atim);
 	iwe.u.data.length = strlen(sbuf);
 	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 = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies));
 	ie_len = min(bssid_len - (int)sizeof(*bssid),
 	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);
 					(ie->id == MFIE_TYPE_RSN) ? 2 : 1);
 			iwe.cmd = IWEVGENIE;
 			iwe.cmd = IWEVGENIE;
 			iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN);
 			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);
 								(u8 *)ie);
 		}
 		}
 
 
@@ -1803,8 +1805,8 @@ static int rndis_iw_get_scan(struct net_device *dev,
 	devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count);
 	devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count);
 
 
 	while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
 	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 = (void *)bssid + bssid_len;
 		bssid_len = le32_to_cpu(bssid->length);
 		bssid_len = le32_to_cpu(bssid->length);
 		count--;
 		count--;

+ 9 - 8
drivers/net/wireless/rt2x00/rt2400pci.c

@@ -632,15 +632,15 @@ static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
 				   struct queue_entry *entry)
 				   struct queue_entry *entry)
 {
 {
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	u32 word;
 	u32 word;
 
 
 	rt2x00_desc_read(entry_priv->desc, 2, &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_write(entry_priv->desc, 2, word);
 
 
 	rt2x00_desc_read(entry_priv->desc, 1, &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_write(entry_priv->desc, 1, word);
 
 
 	rt2x00_desc_read(entry_priv->desc, 0, &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.
 	 * Start writing the descriptor words.
 	 */
 	 */
 	rt2x00_desc_read(entry_priv->desc, 1, &word);
 	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_write(entry_priv->desc, 1, word);
 
 
 	rt2x00_desc_read(txd, 2, &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);
 		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;
 			       IEEE80211_HW_SIGNAL_DBM;
 	rt2x00dev->hw->extra_tx_headroom = 0;
 	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,
 	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
 				rt2x00_eeprom_addr(rt2x00dev,
 				rt2x00_eeprom_addr(rt2x00dev,
 						   EEPROM_MAC_ADDR_0));
 						   EEPROM_MAC_ADDR_0));
@@ -1412,9 +1412,10 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 	rt2400pci_probe_hw_mode(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_ATIM_QUEUE, &rt2x00dev->flags);
+	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 
 
 	/*
 	/*
 	 * Set the rssi offset.
 	 * 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,
 	 * Write entire beacon with descriptor to register,
 	 * and kick the beacon generator.
 	 * 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);
 	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
 	rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 	rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 
 

+ 8 - 6
drivers/net/wireless/rt2x00/rt2500pci.c

@@ -727,10 +727,11 @@ static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
 				   struct queue_entry *entry)
 				   struct queue_entry *entry)
 {
 {
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	u32 word;
 	u32 word;
 
 
 	rt2x00_desc_read(entry_priv->desc, 1, &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_write(entry_priv->desc, 1, word);
 
 
 	rt2x00_desc_read(entry_priv->desc, 0, &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.
 	 * Start writing the descriptor words.
 	 */
 	 */
 	rt2x00_desc_read(entry_priv->desc, 1, &word);
 	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_write(entry_priv->desc, 1, word);
 
 
 	rt2x00_desc_read(txd, 2, &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);
 		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;
 	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,
 	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
 				rt2x00_eeprom_addr(rt2x00dev,
 				rt2x00_eeprom_addr(rt2x00dev,
 						   EEPROM_MAC_ADDR_0));
 						   EEPROM_MAC_ADDR_0));
@@ -1752,9 +1753,10 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 	rt2500pci_probe_hw_mode(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_ATIM_QUEUE, &rt2x00dev->flags);
+	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 
 
 	/*
 	/*
 	 * Set the rssi offset.
 	 * 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,
 	 * Write entire beacon with descriptor to register,
 	 * and kick the beacon generator.
 	 * 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);
 	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
 	rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 	rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 
 

+ 2 - 2
drivers/net/wireless/rt2x00/rt2500usb.c

@@ -1594,7 +1594,7 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 
 
 	rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
 	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,
 	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
 				rt2x00_eeprom_addr(rt2x00dev,
 				rt2x00_eeprom_addr(rt2x00dev,
 						   EEPROM_MAC_ADDR_0));
 						   EEPROM_MAC_ADDR_0));
@@ -1678,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)
 static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	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 ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
 	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
 	struct queue_entry_priv_usb_bcn *bcn_priv;
 	struct queue_entry_priv_usb_bcn *bcn_priv;

+ 9 - 50
drivers/net/wireless/rt2x00/rt2x00.h

@@ -44,7 +44,7 @@
 /*
 /*
  * Module information.
  * Module information.
  */
  */
-#define DRV_VERSION	"2.1.7"
+#define DRV_VERSION	"2.1.8"
 #define DRV_PROJECT	"http://rt2x00.serialmonkey.com"
 #define DRV_PROJECT	"http://rt2x00.serialmonkey.com"
 
 
 /*
 /*
@@ -110,33 +110,6 @@
 #define SHORT_DIFS		( SHORT_PIFS + SHORT_SLOT_TIME )
 #define SHORT_DIFS		( SHORT_PIFS + SHORT_SLOT_TIME )
 #define EIFS			( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) )
 #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
  * Chipset identification
  * The chipset on the device is composed of a RT and RF chip.
  * 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_BEACON_GUARD,
 	DRIVER_REQUIRE_ATIM_QUEUE,
 	DRIVER_REQUIRE_ATIM_QUEUE,
 	DRIVER_REQUIRE_SCHEDULED,
 	DRIVER_REQUIRE_SCHEDULED,
+	DRIVER_REQUIRE_DMA,
 
 
 	/*
 	/*
 	 * Driver configuration
 	 * Driver configuration
@@ -652,11 +626,7 @@ struct rt2x00_dev {
 	 * When accessing this variable, the rt2x00dev_{pci,usb}
 	 * When accessing this variable, the rt2x00dev_{pci,usb}
 	 * macro's should be used for correct typecasting.
 	 * 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.
 	 * Callback functions.
@@ -931,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
  * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
@@ -985,26 +956,14 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
 struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
 struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
 					  enum queue_index index);
 					  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.
  * Interrupt context handlers.
  */
  */
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
 void rt2x00lib_txdone(struct queue_entry *entry,
 void rt2x00lib_txdone(struct queue_entry *entry,
 		      struct txdone_entry_desc *txdesc);
 		      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.
  * mac80211 handlers.

+ 80 - 20
drivers/net/wireless/rt2x00/rt2x00dev.c

@@ -469,12 +469,19 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
 static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
 static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
 				      struct ieee80211_vif *vif)
 				      struct ieee80211_vif *vif)
 {
 {
+	struct rt2x00_dev *rt2x00dev = data;
 	struct rt2x00_intf *intf = vif_to_intf(vif);
 	struct rt2x00_intf *intf = vif_to_intf(vif);
 
 
 	if (vif->type != IEEE80211_IF_TYPE_AP &&
 	if (vif->type != IEEE80211_IF_TYPE_AP &&
 	    vif->type != IEEE80211_IF_TYPE_IBSS)
 	    vif->type != IEEE80211_IF_TYPE_IBSS)
 		return;
 		return;
 
 
+	/*
+	 * Clean up the beacon skb.
+	 */
+	rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
+	intf->beacon->skb = NULL;
+
 	spin_lock(&intf->lock);
 	spin_lock(&intf->lock);
 	intf->delayed_flags |= DELAYED_UPDATE_BEACON;
 	intf->delayed_flags |= DELAYED_UPDATE_BEACON;
 	spin_unlock(&intf->lock);
 	spin_unlock(&intf->lock);
@@ -498,6 +505,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 {
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
 	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
 	 * Send frame to debugfs immediately, after this call is completed
@@ -546,39 +559,77 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 		ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
 		ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
 	else
 	else
 		dev_kfree_skb_irq(entry->skb);
 		dev_kfree_skb_irq(entry->skb);
+
+	/*
+	 * Make this entry available for reuse.
+	 */
 	entry->skb = NULL;
 	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);
 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;
 	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_supported_band *sband;
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_hdr *hdr;
 	const struct rt2x00_rate *rate;
 	const struct rt2x00_rate *rate;
+	unsigned int header_size;
 	unsigned int align;
 	unsigned int align;
 	unsigned int i;
 	unsigned int i;
 	int idx = -1;
 	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
 	 * The data behind the ieee80211 header must be
 	 * aligned on a 4 byte boundary.
 	 * aligned on a 4 byte boundary.
 	 */
 	 */
+	header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
 	align = ((unsigned long)(entry->skb->data + header_size)) & 3;
 	align = ((unsigned long)(entry->skb->data + header_size)) & 3;
 
 
 	if (align) {
 	if (align) {
 		skb_push(entry->skb, align);
 		skb_push(entry->skb, align);
 		/* Move entire frame in 1 command */
 		/* Move entire frame in 1 command */
 		memmove(entry->skb->data, entry->skb->data + align,
 		memmove(entry->skb->data, entry->skb->data + align,
-			rxdesc->size);
+			rxdesc.size);
 	}
 	}
 
 
 	/* Update data pointers, trim buffer to correct size */
 	/* Update data pointers, trim buffer to correct size */
-	skb_trim(entry->skb, rxdesc->size);
+	skb_trim(entry->skb, rxdesc.size);
 
 
 	/*
 	/*
 	 * Update RX statistics.
 	 * Update RX statistics.
@@ -587,10 +638,10 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
 	for (i = 0; i < sband->n_bitrates; i++) {
 	for (i = 0; i < sband->n_bitrates; i++) {
 		rate = rt2x00_get_rate(sband->bitrates[i].hw_value);
 		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;
 			idx = i;
 			break;
 			break;
 		}
 		}
@@ -598,8 +649,8 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
 
 
 	if (idx < 0) {
 	if (idx < 0) {
 		WARNING(rt2x00dev, "Frame received with unrecognized signal,"
 		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;
 		idx = 0;
 	}
 	}
 
 
@@ -607,17 +658,17 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
 	 * Only update link status if this is a beacon frame carrying our bssid.
 	 * Only update link status if this is a beacon frame carrying our bssid.
 	 */
 	 */
 	hdr = (struct ieee80211_hdr *)entry->skb->data;
 	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++;
 	rt2x00dev->link.qual.rx_success++;
 
 
 	rx_status->rate_idx = idx;
 	rx_status->rate_idx = idx;
 	rx_status->qual =
 	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;
 	rx_status->antenna = rt2x00dev->link.ant.active.rx;
 
 
 	/*
 	/*
@@ -626,7 +677,16 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
 	 */
 	 */
 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
 	ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
 	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);
 EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
 
 

+ 49 - 2
drivers/net/wireless/rt2x00/rt2x00lib.h

@@ -98,10 +98,57 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 		      struct ieee80211_conf *conf, const int force_config);
 		      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);
 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_rx(struct rt2x00_dev *rt2x00dev);
 void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev);
 void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev);
 int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);
 int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);

+ 19 - 107
drivers/net/wireless/rt2x00/rt2x00pci.c

@@ -60,12 +60,8 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry)
 	 * Fill in skb descriptor
 	 * Fill in skb descriptor
 	 */
 	 */
 	skbdesc = get_skb_frame_desc(entry->skb);
 	skbdesc = get_skb_frame_desc(entry->skb);
-	memset(skbdesc, 0, sizeof(*skbdesc));
 	skbdesc->desc = entry_priv->desc;
 	skbdesc->desc = entry_priv->desc;
 	skbdesc->desc_len = entry->queue->desc_size;
 	skbdesc->desc_len = entry->queue->desc_size;
-	skbdesc->entry = entry;
-
-	memcpy(entry_priv->data, entry->skb->data, entry->skb->len);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -80,7 +76,6 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 	struct queue_entry *entry;
 	struct queue_entry *entry;
 	struct queue_entry_priv_pci *entry_priv;
 	struct queue_entry_priv_pci *entry_priv;
 	struct skb_frame_desc *skbdesc;
 	struct skb_frame_desc *skbdesc;
-	struct rxdone_entry_desc rxdesc;
 	u32 word;
 	u32 word;
 
 
 	while (1) {
 	while (1) {
@@ -91,110 +86,27 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 		if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
 		if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
 			break;
 			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);
 		skbdesc = get_skb_frame_desc(entry->skb);
-		memset(skbdesc, 0, sizeof(*skbdesc));
 		skbdesc->desc = entry_priv->desc;
 		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.
 		 * 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);
 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.
  * 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,
 static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
 				     struct data_queue *queue)
 				     struct data_queue *queue)
 {
 {
-	struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
 	struct queue_entry_priv_pci *entry_priv;
 	struct queue_entry_priv_pci *entry_priv;
 	void *addr;
 	void *addr;
 	dma_addr_t dma;
 	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.
 	 * 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)
 	if (!addr)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	memset(addr, 0, dma_size(queue));
+	memset(addr, 0, queue->limit * queue->desc_size);
 
 
 	/*
 	/*
 	 * Initialize all queue entries to contain valid addresses.
 	 * Initialize all queue entries to contain valid addresses.
 	 */
 	 */
 	for (i = 0; i < queue->limit; i++) {
 	for (i = 0; i < queue->limit; i++) {
 		entry_priv = queue->entries[i].priv_data;
 		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;
 	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,
 static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
 				     struct data_queue *queue)
 				     struct data_queue *queue)
 {
 {
-	struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
 	struct queue_entry_priv_pci *entry_priv =
 	struct queue_entry_priv_pci *entry_priv =
 	    queue->entries[0].priv_data;
 	    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)
 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;
 	struct data_queue *queue;
 	int status;
 	int status;
 
 
@@ -279,7 +191,7 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
 	/*
 	/*
 	 * Free irq line.
 	 * Free irq line.
 	 */
 	 */
-	free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev);
+	free_irq(to_pci_dev(rt2x00dev->dev)->irq, rt2x00dev);
 
 
 	/*
 	/*
 	 * Free DMA
 	 * Free DMA
@@ -308,7 +220,7 @@ static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
 
 
 static int rt2x00pci_alloc_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),
 	rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0),
 				      pci_resource_len(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))
 	if (pci_set_mwi(pci_dev))
 		ERROR_PROBE("MWI not available.\n");
 		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");
 		ERROR_PROBE("PCI DMA not supported.\n");
 		retval = -EIO;
 		retval = -EIO;
 		goto exit_disable_device;
 		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);
 	pci_set_drvdata(pci_dev, hw);
 
 
 	rt2x00dev = hw->priv;
 	rt2x00dev = hw->priv;
-	rt2x00dev->dev = pci_dev;
+	rt2x00dev->dev = &pci_dev->dev;
 	rt2x00dev->ops = ops;
 	rt2x00dev->ops = ops;
 	rt2x00dev->hw = hw;
 	rt2x00dev->hw = hw;
 
 

+ 0 - 12
drivers/net/wireless/rt2x00/rt2x00pci.h

@@ -107,9 +107,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry);
 struct queue_entry_priv_pci {
 struct queue_entry_priv_pci {
 	__le32 *desc;
 	__le32 *desc;
 	dma_addr_t desc_dma;
 	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);
 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.
  * Device initialization handlers.
  */
  */

+ 112 - 29
drivers/net/wireless/rt2x00/rt2x00queue.c

@@ -25,34 +25,30 @@
 
 
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/dma-mapping.h>
 
 
 #include "rt2x00.h"
 #include "rt2x00.h"
 #include "rt2x00lib.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 frame_size;
 	unsigned int reserved_size;
 	unsigned int reserved_size;
+	struct sk_buff *skb;
+	struct skb_frame_desc *skbdesc;
 
 
 	/*
 	/*
 	 * The frame size includes descriptor size, because the
 	 * The frame size includes descriptor size, because the
 	 * hardware directly receive the frame into the skbuffer.
 	 * 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.
 	 * Allocate skbuffer.
@@ -64,9 +60,56 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct data_queue *queue)
 	skb_reserve(skb, reserved_size);
 	skb_reserve(skb, reserved_size);
 	skb_put(skb, frame_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;
 	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,
 void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 				      struct txentry_desc *txdesc)
 				      struct txentry_desc *txdesc)
@@ -80,7 +123,6 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 	unsigned int data_length;
 	unsigned int data_length;
 	unsigned int duration;
 	unsigned int duration;
 	unsigned int residual;
 	unsigned int residual;
-	u16 frame_control;
 
 
 	memset(txdesc, 0, sizeof(*txdesc));
 	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 should be extended with 4 bytes for CRC */
 	data_length = entry->skb->len + 4;
 	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.
 	 * 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
 	 * 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);
 		__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);
 			__set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags);
 		else
 		else
 			__set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags);
 			__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
 	 * Beacons and probe responses require the tsf timestamp
 	 * to be inserted into the frame.
 	 * 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);
 		__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 queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
 	struct txentry_desc txdesc;
 	struct txentry_desc txdesc;
+	struct skb_frame_desc *skbdesc;
 
 
 	if (unlikely(rt2x00queue_full(queue)))
 	if (unlikely(rt2x00queue_full(queue)))
 		return -EINVAL;
 		return -EINVAL;
@@ -256,11 +296,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
 	entry->skb = skb;
 	entry->skb = skb;
 	rt2x00queue_create_tx_descriptor(entry, &txdesc);
 	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))) {
 	if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
 		__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
 		__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 
+	if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
+		rt2x00queue_map_txskb(queue->rt2x00dev, skb);
+
 	__set_bit(ENTRY_DATA_PENDING, &entry->flags);
 	__set_bit(ENTRY_DATA_PENDING, &entry->flags);
 
 
 	rt2x00queue_index_inc(queue, Q_INDEX);
 	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);
 	spin_unlock_irqrestore(&queue->lock, irqflags);
 }
 }
-EXPORT_SYMBOL_GPL(rt2x00queue_index_inc);
 
 
 static void rt2x00queue_reset(struct data_queue *queue)
 static void rt2x00queue_reset(struct data_queue *queue)
 {
 {
@@ -426,12 +475,41 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
 	return 0;
 	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)
 int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
 {
 {
 	struct data_queue *queue;
 	struct data_queue *queue;
 	int status;
 	int status;
 
 
-
 	status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx);
 	status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx);
 	if (status)
 	if (status)
 		goto exit;
 		goto exit;
@@ -446,11 +524,14 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
 	if (status)
 	if (status)
 		goto exit;
 		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)
 	if (status)
 		goto exit;
 		goto exit;
 
 
@@ -468,6 +549,8 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
 {
 {
 	struct data_queue *queue;
 	struct data_queue *queue;
 
 
+	rt2x00queue_free_skbs(rt2x00dev, rt2x00dev->rx);
+
 	queue_for_each(rt2x00dev, queue) {
 	queue_for_each(rt2x00dev, queue) {
 		kfree(queue->entries);
 		kfree(queue->entries);
 		queue->entries = NULL;
 		queue->entries = NULL;

+ 21 - 14
drivers/net/wireless/rt2x00/rt2x00queue.h

@@ -42,15 +42,18 @@
 /**
 /**
  * DOC: Number of entries per queue
  * 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 BEACON_ENTRIES	1
-#define ATIM_ENTRIES	1
+#define ATIM_ENTRIES	8
 
 
 /**
 /**
  * enum data_queue_qid: Queue identification
  * 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
  * 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
  * 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).
  * this structure should not exceed the size of that array (40 bytes).
  *
  *
  * @flags: Frame flags, see &enum skb_frame_desc_flags.
  * @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.
  * @desc: Pointer to descriptor part of the frame.
  *	Note that this pointer could point to something outside
  *	Note that this pointer could point to something outside
  *	of the scope of the skb->data pointer.
  *	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.
  * @entry: The entry to which this sk buffer belongs.
  */
  */
 struct skb_frame_desc {
 struct skb_frame_desc {
 	unsigned int flags;
 	unsigned int flags;
 
 
-	void *desc;
 	unsigned int desc_len;
 	unsigned int desc_len;
+	void *desc;
+
+	dma_addr_t skb_dma;
 
 
 	struct queue_entry *entry;
 	struct queue_entry *entry;
 };
 };

+ 5 - 2
drivers/net/wireless/rt2x00/rt2x00rfkill.c

@@ -45,14 +45,17 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
 	if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
 	if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
 		return 0;
 		return 0;
 
 
-	if (state == RFKILL_STATE_ON) {
+	if (state == RFKILL_STATE_UNBLOCKED) {
 		INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
 		INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
 		__clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
 		__clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
 		retval = rt2x00lib_enable_radio(rt2x00dev);
 		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");
 		INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n");
 		__set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
 		__set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
 		rt2x00lib_disable_radio(rt2x00dev);
 		rt2x00lib_disable_radio(rt2x00dev);
+	} else {
+		WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n",
+			state);
 	}
 	}
 
 
 	return retval;
 	return retval;

+ 21 - 82
drivers/net/wireless/rt2x00/rt2x00usb.c

@@ -40,7 +40,7 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
 			     void *buffer, const u16 buffer_length,
 			     void *buffer, const u16 buffer_length,
 			     const int timeout)
 			     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;
 	int status;
 	unsigned int i;
 	unsigned int i;
 	unsigned int pipe =
 	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 queue_entry *entry = (struct queue_entry *)urb->context;
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct txdone_entry_desc txdesc;
 	struct txdone_entry_desc txdesc;
-	enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
 
 
 	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
 	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;
 		return;
 
 
 	/*
 	/*
@@ -157,26 +156,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
 	txdesc.retry = 0;
 	txdesc.retry = 0;
 
 
 	rt2x00lib_txdone(entry, &txdesc);
 	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)
 int rt2x00usb_write_tx_data(struct queue_entry *entry)
 {
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	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 queue_entry_priv_usb *entry_priv = entry->priv_data;
 	struct skb_frame_desc *skbdesc;
 	struct skb_frame_desc *skbdesc;
 	u32 length;
 	u32 length;
@@ -191,10 +176,8 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
 	 * Fill in skb descriptor
 	 * Fill in skb descriptor
 	 */
 	 */
 	skbdesc = get_skb_frame_desc(entry->skb);
 	skbdesc = get_skb_frame_desc(entry->skb);
-	memset(skbdesc, 0, sizeof(*skbdesc));
 	skbdesc->desc = entry->skb->data;
 	skbdesc->desc = entry->skb->data;
 	skbdesc->desc_len = entry->queue->desc_size;
 	skbdesc->desc_len = entry->queue->desc_size;
-	skbdesc->entry = entry;
 
 
 	/*
 	/*
 	 * USB devices cannot blindly pass the skb->len as the
 	 * 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 queue_entry *entry = (struct queue_entry *)urb->context;
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	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];
 	u8 rxd[32];
 
 
 	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
 	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;
 		return;
 
 
 	/*
 	/*
@@ -278,50 +259,22 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
 	 * to be actually valid, or if the urb is signaling
 	 * to be actually valid, or if the urb is signaling
 	 * a problem.
 	 * 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 = rxd;
 	skbdesc->desc_len = entry->queue->desc_size;
 	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.
 	 * 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 *entry_priv;
 	struct queue_entry_priv_usb_bcn *bcn_priv;
 	struct queue_entry_priv_usb_bcn *bcn_priv;
+	struct data_queue *queue;
 	unsigned int i;
 	unsigned int i;
 
 
 	rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
 	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.
 	 * 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,
 void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
 			    struct queue_entry *entry)
 			    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;
 	struct queue_entry_priv_usb *entry_priv = entry->priv_data;
 
 
 	usb_fill_bulk_urb(entry_priv->urb, usb_dev,
 	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;
 		entry_priv = queue->entries[i].priv_data;
 		usb_kill_urb(entry_priv->urb);
 		usb_kill_urb(entry_priv->urb);
 		usb_free_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)
 int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
 {
 {
 	struct data_queue *queue;
 	struct data_queue *queue;
-	struct sk_buff *skb;
-	unsigned int entry_size;
-	unsigned int i;
-	int uninitialized_var(status);
+	int status;
 
 
 	/*
 	/*
 	 * Allocate DMA
 	 * Allocate DMA
@@ -468,18 +419,6 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
 			goto exit;
 			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;
 	return 0;
 
 
 exit:
 exit:
@@ -558,7 +497,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
 	usb_set_intfdata(usb_intf, hw);
 	usb_set_intfdata(usb_intf, hw);
 
 
 	rt2x00dev = hw->priv;
 	rt2x00dev = hw->priv;
-	rt2x00dev->dev = usb_intf;
+	rt2x00dev->dev = &usb_intf->dev;
 	rt2x00dev->ops = ops;
 	rt2x00dev->ops = ops;
 	rt2x00dev->hw = hw;
 	rt2x00dev->hw = hw;
 	mutex_init(&rt2x00dev->usb_cache_mutex);
 	mutex_init(&rt2x00dev->usb_cache_mutex);

+ 6 - 0
drivers/net/wireless/rt2x00/rt2x00usb.h

@@ -26,6 +26,12 @@
 #ifndef RT2X00USB_H
 #ifndef RT2X00USB_H
 #define 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
  * This variable should be used with the
  * usb_driver structure initialization.
  * usb_driver structure initialization.

+ 15 - 8
drivers/net/wireless/rt2x00/rt61pci.c

@@ -1030,11 +1030,12 @@ static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
 				 struct queue_entry *entry)
 				 struct queue_entry *entry)
 {
 {
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	u32 word;
 	u32 word;
 
 
 	rt2x00_desc_read(entry_priv->desc, 5, &word);
 	rt2x00_desc_read(entry_priv->desc, 5, &word);
 	rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
 	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_write(entry_priv->desc, 5, word);
 
 
 	rt2x00_desc_read(entry_priv->desc, 0, &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 txentry_desc *txdesc)
 {
 {
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
 	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;
 	__le32 *txd = skbdesc->desc;
 	u32 word;
 	u32 word;
 
 
@@ -1557,7 +1557,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 
 
 	rt2x00_desc_read(txd, 6, &word);
 	rt2x00_desc_read(txd, 6, &word);
 	rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
 	rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
-			   entry_priv->data_dma);
+			   skbdesc->skb_dma);
 	rt2x00_desc_write(txd, 6, word);
 	rt2x00_desc_write(txd, 6, word);
 
 
 	if (skbdesc->desc_len > TXINFO_SIZE) {
 	if (skbdesc->desc_len > TXINFO_SIZE) {
@@ -1767,7 +1767,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
 			__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
 			__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
 			txdesc.retry = 0;
 			txdesc.retry = 0;
 
 
-			rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc);
+			rt2x00lib_txdone(entry_done, &txdesc);
 			entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 			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);
 		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
 	 * To determine the RT chip we have to read the
 	 * PCI header of the device.
 	 * 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);
 			     PCI_CONFIG_HEADER_DEVICE, &device);
 	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
 	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
 	rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
 	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;
 	    IEEE80211_HW_SIGNAL_DBM;
 	rt2x00dev->hw->extra_tx_headroom = 0;
 	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,
 	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
 				rt2x00_eeprom_addr(rt2x00dev,
 				rt2x00_eeprom_addr(rt2x00dev,
 						   EEPROM_MAC_ADDR_0));
 						   EEPROM_MAC_ADDR_0));
@@ -2302,9 +2302,10 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 	rt61pci_probe_hw_mode(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_FIRMWARE, &rt2x00dev->flags);
+	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 
 
 	/*
 	/*
 	 * Set the rssi offset.
 	 * 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);
 				      skb->data, skb->len);
 	rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON);
 	rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON);
 
 
+	/*
+	 * Clean up beacon skb.
+	 */
+	dev_kfree_skb_any(skb);
+	intf->beacon->skb = NULL;
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 7 - 1
drivers/net/wireless/rt2x00/rt73usb.c

@@ -1827,7 +1827,7 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	    IEEE80211_HW_SIGNAL_DBM;
 	    IEEE80211_HW_SIGNAL_DBM;
 	rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
 	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,
 	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
 				rt2x00_eeprom_addr(rt2x00dev,
 				rt2x00_eeprom_addr(rt2x00dev,
 						   EEPROM_MAC_ADDR_0));
 						   EEPROM_MAC_ADDR_0));
@@ -2007,6 +2007,12 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 				 REGISTER_TIMEOUT32(skb->len));
 				 REGISTER_TIMEOUT32(skb->len));
 	rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON);
 	rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON);
 
 
+	/*
+	 * Clean up the beacon skb.
+	 */
+	dev_kfree_skb(skb);
+	intf->beacon->skb = NULL;
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 0 - 2804
drivers/net/wireless/strip.c

@@ -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");

+ 5 - 5
drivers/net/wireless/wl3501_cs.c

@@ -1624,25 +1624,25 @@ static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
 		iwe.cmd			= SIOCGIWAP;
 		iwe.cmd			= SIOCGIWAP;
 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 		memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].bssid, ETH_ALEN);
 		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,
 						  extra + IW_SCAN_MAX_DATA,
 						  &iwe, IW_EV_ADDR_LEN);
 						  &iwe, IW_EV_ADDR_LEN);
 		iwe.cmd		  = SIOCGIWESSID;
 		iwe.cmd		  = SIOCGIWESSID;
 		iwe.u.data.flags  = 1;
 		iwe.u.data.flags  = 1;
 		iwe.u.data.length = this->bss_set[i].ssid.el.len;
 		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,
 						  extra + IW_SCAN_MAX_DATA,
 						  &iwe,
 						  &iwe,
 						  this->bss_set[i].ssid.essid);
 						  this->bss_set[i].ssid.essid);
 		iwe.cmd	   = SIOCGIWMODE;
 		iwe.cmd	   = SIOCGIWMODE;
 		iwe.u.mode = this->bss_set[i].bss_type;
 		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,
 						  extra + IW_SCAN_MAX_DATA,
 						  &iwe, IW_EV_UINT_LEN);
 						  &iwe, IW_EV_UINT_LEN);
 		iwe.cmd = SIOCGIWFREQ;
 		iwe.cmd = SIOCGIWFREQ;
 		iwe.u.freq.m = this->bss_set[i].ds_pset.chan;
 		iwe.u.freq.m = this->bss_set[i].ds_pset.chan;
 		iwe.u.freq.e = 0;
 		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,
 						  extra + IW_SCAN_MAX_DATA,
 						  &iwe, IW_EV_FREQ_LEN);
 						  &iwe, IW_EV_FREQ_LEN);
 		iwe.cmd = SIOCGIWENCODE;
 		iwe.cmd = SIOCGIWENCODE;
@@ -1651,7 +1651,7 @@ static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
 		else
 		else
 			iwe.u.data.flags = IW_ENCODE_DISABLED;
 			iwe.u.data.flags = IW_ENCODE_DISABLED;
 		iwe.u.data.length = 0;
 		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,
 						  extra + IW_SCAN_MAX_DATA,
 						  &iwe, NULL);
 						  &iwe, NULL);
 	}
 	}

+ 13 - 8
drivers/net/wireless/zd1201.c

@@ -1152,32 +1152,36 @@ static int zd1201_get_scan(struct net_device *dev,
 		iwe.cmd = SIOCGIWAP;
 		iwe.cmd = SIOCGIWAP;
 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 		memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6);
 		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.cmd = SIOCGIWESSID;
 		iwe.u.data.length = zd->rxdata[i+16];
 		iwe.u.data.length = zd->rxdata[i+16];
 		iwe.u.data.flags = 1;
 		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;
 		iwe.cmd = SIOCGIWMODE;
 		if (zd->rxdata[i+14]&0x01)
 		if (zd->rxdata[i+14]&0x01)
 			iwe.u.mode = IW_MODE_MASTER;
 			iwe.u.mode = IW_MODE_MASTER;
 		else
 		else
 			iwe.u.mode = IW_MODE_ADHOC;
 			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.cmd = SIOCGIWFREQ;
 		iwe.u.freq.m = zd->rxdata[i+0];
 		iwe.u.freq.m = zd->rxdata[i+0];
 		iwe.u.freq.e = 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.cmd = SIOCGIWRATE;
 		iwe.u.bitrate.fixed = 0;
 		iwe.u.bitrate.fixed = 0;
 		iwe.u.bitrate.disabled = 0;
 		iwe.u.bitrate.disabled = 0;
 		for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) {
 		for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) {
 			iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000;
 			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;
 		iwe.cmd = SIOCGIWENCODE;
@@ -1186,14 +1190,15 @@ static int zd1201_get_scan(struct net_device *dev,
 			iwe.u.data.flags = IW_ENCODE_ENABLED;
 			iwe.u.data.flags = IW_ENCODE_ENABLED;
 		else
 		else
 			iwe.u.data.flags = IW_ENCODE_DISABLED;
 			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.cmd = IWEVQUAL;
 		iwe.u.qual.qual = zd->rxdata[i+4];
 		iwe.u.qual.qual = zd->rxdata[i+4];
 		iwe.u.qual.noise= zd->rxdata[i+2]/10-100;
 		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.level = (256+zd->rxdata[i+4]*100)/255-100;
 		iwe.u.qual.updated = 7;
 		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)
 	if (!enabled_save)

+ 6 - 16
drivers/net/wireless/zd1211rw/zd_mac.c

@@ -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,
 static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
 	                   struct ieee80211_hdr *header, u32 flags)
 	                   struct ieee80211_hdr *header, u32 flags)
 {
 {
-	u16 fctl = le16_to_cpu(header->frame_control);
-
 	/*
 	/*
 	 * CONTROL TODO:
 	 * CONTROL TODO:
 	 * - if backoff needed, enable bit 0
 	 * - 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;
 		cs->control |= ZD_CS_MULTICAST;
 
 
 	/* PS-POLL */
 	/* 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;
 		cs->control |= ZD_CS_PS_POLL_FRAME;
 
 
 	if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
 	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,
 static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
 		      struct ieee80211_rx_status *stats)
 		      struct ieee80211_rx_status *stats)
 {
 {
-	u16 fc = le16_to_cpu(rx_hdr->frame_control);
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	struct sk_buff_head *q;
 	struct sk_buff_head *q;
 	unsigned long flags;
 	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;
 		return 0;
 
 
 	q = &zd_hw_mac(hw)->ack_wait_queue;
 	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;
 	const struct rx_status *status;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	int bad_frame = 0;
 	int bad_frame = 0;
-	u16 fc;
-	bool is_qos, is_4addr, need_padding;
+	__le16 fc;
+	int need_padding;
 	int i;
 	int i;
 	u8 rate;
 	u8 rate;
 
 
@@ -644,13 +639,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
 			&& !mac->pass_ctrl)
 			&& !mac->pass_ctrl)
 		return 0;
 		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));
 	skb = dev_alloc_skb(length + (need_padding ? 2 : 0));
 	if (skb == NULL)
 	if (skb == NULL)

+ 1 - 1
drivers/ssb/Kconfig

@@ -2,7 +2,7 @@ menu "Sonics Silicon Backplane"
 
 
 config SSB_POSSIBLE
 config SSB_POSSIBLE
 	bool
 	bool
-	depends on HAS_IOMEM
+	depends on HAS_IOMEM && HAS_DMA
 	default y
 	default y
 
 
 config SSB
 config SSB

+ 59 - 16
drivers/ssb/main.c

@@ -462,18 +462,15 @@ static int ssb_devices_register(struct ssb_bus *bus)
 #ifdef CONFIG_SSB_PCIHOST
 #ifdef CONFIG_SSB_PCIHOST
 			sdev->irq = bus->host_pci->irq;
 			sdev->irq = bus->host_pci->irq;
 			dev->parent = &bus->host_pci->dev;
 			dev->parent = &bus->host_pci->dev;
-			sdev->dma_dev = &bus->host_pci->dev;
 #endif
 #endif
 			break;
 			break;
 		case SSB_BUSTYPE_PCMCIA:
 		case SSB_BUSTYPE_PCMCIA:
 #ifdef CONFIG_SSB_PCMCIAHOST
 #ifdef CONFIG_SSB_PCMCIAHOST
 			sdev->irq = bus->host_pcmcia->irq.AssignedIRQ;
 			sdev->irq = bus->host_pcmcia->irq.AssignedIRQ;
 			dev->parent = &bus->host_pcmcia->dev;
 			dev->parent = &bus->host_pcmcia->dev;
-			sdev->dma_dev = &bus->host_pcmcia->dev;
 #endif
 #endif
 			break;
 			break;
 		case SSB_BUSTYPE_SSB:
 		case SSB_BUSTYPE_SSB:
-			sdev->dma_dev = dev;
 			break;
 			break;
 		}
 		}
 
 
@@ -1156,36 +1153,82 @@ u32 ssb_dma_translation(struct ssb_device *dev)
 {
 {
 	switch (dev->bus->bustype) {
 	switch (dev->bus->bustype) {
 	case SSB_BUSTYPE_SSB:
 	case SSB_BUSTYPE_SSB:
-	case SSB_BUSTYPE_PCMCIA:
 		return 0;
 		return 0;
 	case SSB_BUSTYPE_PCI:
 	case SSB_BUSTYPE_PCI:
 		return SSB_PCI_DMA;
 		return SSB_PCI_DMA;
+	default:
+		__ssb_dma_not_implemented(dev);
 	}
 	}
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL(ssb_dma_translation);
 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)
 		if (err)
 			return 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;
 		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);
 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)
 int ssb_bus_may_powerdown(struct ssb_bus *bus)
 {
 {
 	struct ssb_chipcommon *cc;
 	struct ssb_chipcommon *cc;

+ 1 - 112
fs/compat_ioctl.c

@@ -58,7 +58,6 @@
 #include <linux/syscalls.h>
 #include <linux/syscalls.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
 #include <linux/i2c-dev.h>
-#include <linux/wireless.h>
 #include <linux/atalk.h>
 #include <linux/atalk.h>
 #include <linux/loop.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);
 	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
 /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
  * for some operations; this forces use of the newer bridge-utils that
  * for some operations; this forces use of the newer bridge-utils that
  * use compatiable ioctls
  * use compatiable ioctls
@@ -2495,36 +2436,6 @@ COMPATIBLE_IOCTL(I2C_TENBIT)
 COMPATIBLE_IOCTL(I2C_PEC)
 COMPATIBLE_IOCTL(I2C_PEC)
 COMPATIBLE_IOCTL(I2C_RETRIES)
 COMPATIBLE_IOCTL(I2C_RETRIES)
 COMPATIBLE_IOCTL(I2C_TIMEOUT)
 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 */
 /* hiddev */
 COMPATIBLE_IOCTL(HIDIOCGVERSION)
 COMPATIBLE_IOCTL(HIDIOCGVERSION)
 COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
 COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
@@ -2755,29 +2666,7 @@ COMPATIBLE_IOCTL(USBDEVFS_IOCTL32)
 HANDLE_IOCTL(I2C_FUNCS, w_long)
 HANDLE_IOCTL(I2C_FUNCS, w_long)
 HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
 HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
 HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_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(SIOCSIFBR, old_bridge_ioctl)
 HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
 HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
 /* Not implemented in the native kernel */
 /* Not implemented in the native kernel */

+ 61 - 3
include/linux/ieee80211.h

@@ -469,6 +469,40 @@ struct ieee80211s_hdr {
 	u8 eaddr3[6];
 	u8 eaddr3[6];
 } __attribute__ ((packed));
 } __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 {
 struct ieee80211_mgmt {
 	__le16 frame_control;
 	__le16 frame_control;
@@ -544,10 +578,15 @@ struct ieee80211_mgmt {
 					u8 action_code;
 					u8 action_code;
 					u8 element_id;
 					u8 element_id;
 					u8 length;
 					u8 length;
-					u8 switch_mode;
-					u8 new_chan;
-					u8 switch_count;
+					struct ieee80211_channel_sw_ie sw_elem;
 				} __attribute__((packed)) chan_switch;
 				} __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{
 				struct{
 					u8 action_code;
 					u8 action_code;
 					u8 dialog_token;
 					u8 dialog_token;
@@ -700,11 +739,21 @@ struct ieee80211_ht_addt_info {
 #define WLAN_CAPABILITY_SHORT_PREAMBLE	(1<<5)
 #define WLAN_CAPABILITY_SHORT_PREAMBLE	(1<<5)
 #define WLAN_CAPABILITY_PBCC		(1<<6)
 #define WLAN_CAPABILITY_PBCC		(1<<6)
 #define WLAN_CAPABILITY_CHANNEL_AGILITY	(1<<7)
 #define WLAN_CAPABILITY_CHANNEL_AGILITY	(1<<7)
+
 /* 802.11h */
 /* 802.11h */
 #define WLAN_CAPABILITY_SPECTRUM_MGMT	(1<<8)
 #define WLAN_CAPABILITY_SPECTRUM_MGMT	(1<<8)
 #define WLAN_CAPABILITY_QOS		(1<<9)
 #define WLAN_CAPABILITY_QOS		(1<<9)
 #define WLAN_CAPABILITY_SHORT_SLOT_TIME	(1<<10)
 #define WLAN_CAPABILITY_SHORT_SLOT_TIME	(1<<10)
 #define WLAN_CAPABILITY_DSSS_OFDM	(1<<13)
 #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 */
 /* 802.11g ERP information element */
 #define WLAN_ERP_NON_ERP_PRESENT (1<<0)
 #define WLAN_ERP_NON_ERP_PRESENT (1<<0)
@@ -875,6 +924,15 @@ enum ieee80211_category {
 	WLAN_CATEGORY_WMM = 17,
 	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 */
 /* BACK action code */
 enum ieee80211_back_actioncode {
 enum ieee80211_back_actioncode {
 	WLAN_ACTION_ADDBA_REQ = 0,
 	WLAN_ACTION_ADDBA_REQ = 0,

+ 4 - 1
include/linux/nl80211.h

@@ -241,7 +241,10 @@ enum nl80211_attrs {
 	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
 	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
  * enum nl80211_iftype - (virtual) interface types

+ 43 - 3
include/linux/rfkill.h

@@ -34,26 +34,37 @@
  * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
  * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
  * RFKILL_TYPE_UWB: switch is on a ultra wideband device.
  * RFKILL_TYPE_UWB: switch is on a ultra wideband device.
  * RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
  * RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
+ * RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
  */
  */
 enum rfkill_type {
 enum rfkill_type {
 	RFKILL_TYPE_WLAN ,
 	RFKILL_TYPE_WLAN ,
 	RFKILL_TYPE_BLUETOOTH,
 	RFKILL_TYPE_BLUETOOTH,
 	RFKILL_TYPE_UWB,
 	RFKILL_TYPE_UWB,
 	RFKILL_TYPE_WIMAX,
 	RFKILL_TYPE_WIMAX,
+	RFKILL_TYPE_WWAN,
 	RFKILL_TYPE_MAX,
 	RFKILL_TYPE_MAX,
 };
 };
 
 
 enum rfkill_state {
 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.
  * struct rfkill - rfkill control structure.
  * @name: Name of the switch.
  * @name: Name of the switch.
  * @type: Radio type which the button controls, the value stored
  * @type: Radio type which the button controls, the value stored
  *	here should be a value from enum rfkill_type.
  *	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
  * @user_claim_unsupported: Whether the hardware supports exclusive
  *	RF-kill control by userspace. Set this before registering.
  *	RF-kill control by userspace. Set this before registering.
  * @user_claim: Set when the switch is controlled exlusively by userspace.
  * @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
  * @data: Pointer to the RF button drivers private data which will be
  *	passed along when toggling radio state.
  *	passed along when toggling radio state.
  * @toggle_radio(): Mandatory handler to control state of the radio.
  * @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.
  * @led_trigger: A LED trigger for this button's LED.
  * @dev: Device structure integrating the switch into device tree.
  * @dev: Device structure integrating the switch into device tree.
  * @node: Used to place switch into list of all switches known to the
  * @node: Used to place switch into list of all switches known to the
@@ -80,6 +97,7 @@ struct rfkill {
 
 
 	void *data;
 	void *data;
 	int (*toggle_radio)(void *data, enum rfkill_state state);
 	int (*toggle_radio)(void *data, enum rfkill_state state);
+	int (*get_state)(void *data, enum rfkill_state *state);
 
 
 #ifdef CONFIG_RFKILL_LEDS
 #ifdef CONFIG_RFKILL_LEDS
 	struct led_trigger led_trigger;
 	struct led_trigger led_trigger;
@@ -95,6 +113,21 @@ void rfkill_free(struct rfkill *rfkill);
 int rfkill_register(struct rfkill *rfkill);
 int rfkill_register(struct rfkill *rfkill);
 void rfkill_unregister(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.
  * 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
  * 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
 #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 */
 #endif /* RFKILL_H */

+ 139 - 4
include/linux/ssb/ssb.h

@@ -137,9 +137,6 @@ struct ssb_device {
 	const struct ssb_bus_ops *ops;
 	const struct ssb_bus_ops *ops;
 
 
 	struct device *dev;
 	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_bus *bus;
 	struct ssb_device_id id;
 	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 */
 #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
 /* Translation (routing) bits that need to be ORed to DMA
  * addresses before they are given to a device. */
  * addresses before they are given to a device. */
 extern u32 ssb_dma_translation(struct ssb_device *dev);
 extern u32 ssb_dma_translation(struct ssb_device *dev);
 #define SSB_DMA_TRANSLATION_MASK	0xC0000000
 #define SSB_DMA_TRANSLATION_MASK	0xC0000000
 #define SSB_DMA_TRANSLATION_SHIFT	30
 #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
 #ifdef CONFIG_SSB_PCIHOST

+ 28 - 0
include/linux/wireless.h

@@ -677,6 +677,19 @@ struct	iw_point
   __u16		flags;		/* Optional params */
   __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
  *	A frequency
  *	For numbers lower than 10^9, we encode the number in 'm' and
  *	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) - \
 #define IW_EV_POINT_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_point) - \
 			 IW_EV_POINT_OFF)
 			 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 */
 /* Size of the Event prefix when packed in stream */
 #define IW_EV_LCP_PK_LEN	(4)
 #define IW_EV_LCP_PK_LEN	(4)
 /* Size of the various events when packed in stream */
 /* Size of the various events when packed in stream */

+ 49 - 102
include/net/iw_handler.h

@@ -256,7 +256,7 @@
 #define EIWCOMMIT	EINPROGRESS
 #define EIWCOMMIT	EINPROGRESS
 
 
 /* Flags available in struct iw_request_info */
 /* 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) */
 /* Type of headers we know about (basically union iwreq_data) */
 #define IW_HEADER_TYPE_NULL	0	/* Not available */
 #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
  * 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.
  * Wrapper to add an Wireless Event to a stream of events.
- * Same as above, with explicit error check...
  */
  */
 static inline char *
 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)) {
 	if(likely((stream + event_len) < ends)) {
 		iwe->len = event_len;
 		iwe->len = event_len;
 		/* Beware of alignement issues on 64 bits */
 		/* Beware of alignement issues on 64 bits */
 		memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
 		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;
 		stream += event_len;
-	} else
-		*perr = -E2BIG;
+	}
 	return stream;
 	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
  * Wrapper to add an short Wireless Event containing a pointer to a
  * stream of events.
  * stream of events.
- * Same as above, with explicit error check...
  */
  */
 static inline char *
 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 */
 	/* Check if it's possible */
 	if(likely((stream + event_len) < ends)) {
 	if(likely((stream + event_len) < ends)) {
 		iwe->len = event_len;
 		iwe->len = event_len;
 		memcpy(stream, (char *) iwe, IW_EV_LCP_PK_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);
 		       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;
 		stream += event_len;
-	} else
-		*perr = -E2BIG;
+	}
 	return stream;
 	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.
  * Wrapper to add a value to a Wireless Event in a stream of events.
  * Be careful, this one is tricky to use properly :
  * Be careful, this one is tricky to use properly :
  * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
  * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
- * Same as above, with explicit error check...
  */
  */
 static inline char *
 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 */
 	/* Don't duplicate LCP */
 	event_len -= IW_EV_LCP_LEN;
 	event_len -= IW_EV_LCP_LEN;
 
 
 	/* Check if it's possible */
 	/* Check if it's possible */
 	if(likely((value + event_len) < ends)) {
 	if(likely((value + event_len) < ends)) {
 		/* Add new value */
 		/* Add new value */
-		memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
+		memcpy(value, &iwe->u, event_len);
 		value += event_len;
 		value += event_len;
 		/* Patch LCP */
 		/* Patch LCP */
 		iwe->len = value - event;
 		iwe->len = value - event;
-		memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
-	} else
-		*perr = -E2BIG;
+		memcpy(event, (char *) iwe, lcp_len);
+	}
 	return value;
 	return value;
 }
 }
 
 

+ 11 - 3
include/net/mac80211.h

@@ -595,7 +595,12 @@ enum ieee80211_key_flags {
  * @flags: key flags, see &enum ieee80211_key_flags.
  * @flags: key flags, see &enum ieee80211_key_flags.
  * @keyidx: the key index (0-3)
  * @keyidx: the key index (0-3)
  * @keylen: key material length
  * @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 {
 struct ieee80211_key_conf {
 	enum ieee80211_key_alg alg;
 	enum ieee80211_key_alg alg;
@@ -733,8 +738,11 @@ enum ieee80211_hw_flags {
  * @conf: &struct ieee80211_conf, device configuration, don't use.
  * @conf: &struct ieee80211_conf, device configuration, don't use.
  *
  *
  * @workqueue: single threaded workqueue available for driver 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
  * @priv: pointer to private area that was allocated for driver use
  *	along with this structure.
  *	along with this structure.

+ 7 - 0
include/net/wext.h

@@ -12,6 +12,8 @@ extern int wext_proc_init(struct net *net);
 extern void wext_proc_exit(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,
 extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
 			     void __user *arg);
 			     void __user *arg);
+extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
+				    unsigned long arg);
 #else
 #else
 static inline int wext_proc_init(struct net *net)
 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;
 	return -EINVAL;
 }
 }
+static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
+					   unsigned long arg)
+{
+	return -EINVAL;
+}
 #endif
 #endif
 
 
 #endif /* __NET_WEXT_H */
 #endif /* __NET_WEXT_H */

+ 28 - 20
net/ieee80211/ieee80211_wx.c

@@ -43,8 +43,9 @@ static const char *ieee80211_modes[] = {
 
 
 #define MAX_CUSTOM_LEN 64
 #define MAX_CUSTOM_LEN 64
 static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
 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 custom[MAX_CUSTOM_LEN];
 	char *p;
 	char *p;
@@ -57,7 +58,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
 	iwe.cmd = SIOCGIWAP;
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
 	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 */
 	/* 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;
 	iwe.u.data.flags = 1;
 	if (network->flags & NETWORK_EMPTY_ESSID) {
 	if (network->flags & NETWORK_EMPTY_ESSID) {
 		iwe.u.data.length = sizeof("<hidden>");
 		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 {
 	} else {
 		iwe.u.data.length = min(network->ssid_len, (u8) 32);
 		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 */
 	/* Add the protocol name */
 	iwe.cmd = SIOCGIWNAME;
 	iwe.cmd = SIOCGIWNAME;
 	snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
 	snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
 		 ieee80211_modes[network->mode]);
 		 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 */
 	/* Add mode */
 	iwe.cmd = SIOCGIWMODE;
 	iwe.cmd = SIOCGIWMODE;
@@ -86,7 +89,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
 		else
 		else
 			iwe.u.mode = IW_MODE_ADHOC;
 			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 */
 	/* 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.m = ieee80211_channel_to_freq(ieee, network->channel);
 	iwe.u.freq.e = 6;
 	iwe.u.freq.e = 6;
 	iwe.u.freq.i = 0;
 	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 */
 	/* Add encryption capability */
 	iwe.cmd = SIOCGIWENCODE;
 	iwe.cmd = SIOCGIWENCODE;
@@ -104,12 +108,13 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
 	else
 	else
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 	iwe.u.data.length = 0;
 	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 */
 	/* Add basic and extended rates */
 	/* Rate : stuffing multiple values in a single event require a bit
 	/* Rate : stuffing multiple values in a single event require a bit
 	 * more of magic - Jean II */
 	 * more of magic - Jean II */
-	current_val = start + IW_EV_LCP_LEN;
+	current_val = start + iwe_stream_lcp_len(info);
 	iwe.cmd = SIOCGIWRATE;
 	iwe.cmd = SIOCGIWRATE;
 	/* Those two flags are ignored... */
 	/* Those two flags are ignored... */
 	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
 	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) */
 		/* Bit rate given in 500 kb/s units (+ 0x80) */
 		iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
 		iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
 		/* Add new value to event */
 		/* 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++) {
 	for (; j < network->rates_ex_len; j++) {
 		rate = network->rates_ex[j] & 0x7F;
 		rate = network->rates_ex[j] & 0x7F;
 		/* Bit rate given in 500 kb/s units (+ 0x80) */
 		/* Bit rate given in 500 kb/s units (+ 0x80) */
 		iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
 		iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
 		/* Add new value to event */
 		/* 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 */
 	/* 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;
 		start = current_val;
 
 
 	/* Add quality statistics */
 	/* Add quality statistics */
@@ -181,14 +188,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
 		iwe.u.qual.level = network->stats.signal;
 		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;
 	iwe.cmd = IWEVCUSTOM;
 	p = custom;
 	p = custom;
 
 
 	iwe.u.data.length = p - custom;
 	iwe.u.data.length = p - custom;
 	if (iwe.u.data.length)
 	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));
 	memset(&iwe, 0, sizeof(iwe));
 	if (network->wpa_ie_len) {
 	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);
 		memcpy(buf, network->wpa_ie, network->wpa_ie_len);
 		iwe.cmd = IWEVGENIE;
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = network->wpa_ie_len;
 		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));
 	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);
 		memcpy(buf, network->rsn_ie, network->rsn_ie_len);
 		iwe.cmd = IWEVGENIE;
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = network->rsn_ie_len;
 		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
 	/* 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));
 		      jiffies_to_msecs(jiffies - network->last_scanned));
 	iwe.u.data.length = p - custom;
 	iwe.u.data.length = p - custom;
 	if (iwe.u.data.length)
 	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 */
 	/* Add spectrum management information */
 	iwe.cmd = -1;
 	iwe.cmd = -1;
@@ -238,7 +245,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
 
 
 	if (iwe.cmd == IWEVCUSTOM) {
 	if (iwe.cmd == IWEVCUSTOM) {
 		iwe.u.data.length = p - custom;
 		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;
 	return start;
@@ -272,7 +279,8 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
 
 
 		if (ieee->scan_age == 0 ||
 		if (ieee->scan_age == 0 ||
 		    time_after(network->last_scanned + ieee->scan_age, jiffies))
 		    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
 		else
 			IEEE80211_DEBUG_SCAN("Not showing network '%s ("
 			IEEE80211_DEBUG_SCAN("Not showing network '%s ("
 					     "%s)' due to age (%dms).\n",
 					     "%s)' due to age (%dms).\n",

+ 1 - 1
net/mac80211/Kconfig

@@ -150,7 +150,7 @@ config MAC80211_LOWTX_FRAME_DUMP
 	  If unsure, say N and insert the debugging code
 	  If unsure, say N and insert the debugging code
 	  you require into the driver you are debugging.
 	  you require into the driver you are debugging.
 
 
-config TKIP_DEBUG
+config MAC80211_TKIP_DEBUG
 	bool "TKIP debugging"
 	bool "TKIP debugging"
 	depends on MAC80211_DEBUG
 	depends on MAC80211_DEBUG
 
 

+ 13 - 1
net/mac80211/ieee80211_i.h

@@ -24,6 +24,7 @@
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/etherdevice.h>
 #include <linux/etherdevice.h>
 #include <net/wireless.h>
 #include <net/wireless.h>
+#include <net/iw_handler.h>
 #include "key.h"
 #include "key.h"
 #include "sta_info.h"
 #include "sta_info.h"
 
 
@@ -790,6 +791,10 @@ struct ieee802_11_elems {
 	u8 *preq;
 	u8 *preq;
 	u8 *prep;
 	u8 *prep;
 	u8 *perr;
 	u8 *perr;
+	u8 *ch_switch_elem;
+	u8 *country_elem;
+	u8 *pwr_constr_elem;
+	u8 *quiet_elem; 	/* first quite element */
 
 
 	/* length of them, respectively */
 	/* length of them, respectively */
 	u8 ssid_len;
 	u8 ssid_len;
@@ -814,6 +819,11 @@ struct ieee802_11_elems {
 	u8 preq_len;
 	u8 preq_len;
 	u8 prep_len;
 	u8 prep_len;
 	u8 perr_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(
 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);
 int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
 void ieee80211_sta_req_auth(struct net_device *dev,
 void ieee80211_sta_req_auth(struct net_device *dev,
 			    struct ieee80211_if_sta *ifsta);
 			    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(
 ieee80211_rx_result ieee80211_sta_rx_scan(
 	struct net_device *dev, struct sk_buff *skb,
 	struct net_device *dev, struct sk_buff *skb,
 	struct ieee80211_rx_status *rx_status);
 	struct ieee80211_rx_status *rx_status);

+ 12 - 25
net/mac80211/key.h

@@ -16,31 +16,18 @@
 #include <linux/rcupdate.h>
 #include <linux/rcupdate.h>
 #include <net/mac80211.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_local;
 struct ieee80211_sub_if_data;
 struct ieee80211_sub_if_data;

+ 1 - 1
net/mac80211/main.c

@@ -1691,7 +1691,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	list_add_tail(&sdata->list, &local->interfaces);
 	list_add_tail(&sdata->list, &local->interfaces);
 
 
 	name = wiphy_dev(local->hw.wiphy)->driver->name;
 	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) {
 	if (!local->hw.workqueue) {
 		result = -ENOMEM;
 		result = -ENOMEM;
 		goto fail_workqueue;
 		goto fail_workqueue;

+ 157 - 50
net/mac80211/mlme.c

@@ -204,6 +204,25 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
 			elems->perr = pos;
 			elems->perr = pos;
 			elems->perr_len = elen;
 			elems->perr_len = elen;
 			break;
 			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:
 		default:
 			break;
 			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,
 static void ieee80211_rx_mgmt_auth(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta,
 				   struct ieee80211_if_sta *ifsta,
 				   struct ieee80211_mgmt *mgmt,
 				   struct ieee80211_mgmt *mgmt,
@@ -1753,11 +1837,12 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
 	       auth_transaction, status_code);
 	       auth_transaction, status_code);
 
 
 	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 	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.
 		 * networks and most implementations do not seem to use it.
 		 * However, try to reply to authentication attempts if someone
 		 * However, try to reply to authentication attempts if someone
 		 * has actually implemented this.
 		 * has actually implemented this.
-		 * TODO: Could implement shared key authentication. */
+		 */
 		if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
 		if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
 			printk(KERN_DEBUG "%s: unexpected IBSS authentication "
 			printk(KERN_DEBUG "%s: unexpected IBSS authentication "
 			       "frame (alg=%d transaction=%d)\n",
 			       "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_rx_status *rx_status)
 {
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	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)
 	if (len < IEEE80211_MIN_ACTION_SIZE)
 		return;
 		return;
 
 
 	switch (mgmt->u.action.category) {
 	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:
 	case WLAN_CATEGORY_BACK:
 		switch (mgmt->u.action.u.addba_req.action_code) {
 		switch (mgmt->u.action.u.addba_req.action_code) {
 		case WLAN_ACTION_ADDBA_REQ:
 		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_rx_status *rx_status)
 {
 {
 	struct ieee80211_mgmt *mgmt;
 	struct ieee80211_mgmt *mgmt;
-	u16 fc;
+	__le16 fc;
 
 
 	if (skb->len < 2)
 	if (skb->len < 2)
 		return RX_DROP_UNUSABLE;
 		return RX_DROP_UNUSABLE;
 
 
 	mgmt = (struct ieee80211_mgmt *) skb->data;
 	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;
 		return RX_CONTINUE;
 
 
 	if (skb->len < 24)
 	if (skb->len < 24)
 		return RX_DROP_MONITOR;
 		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;
 	return RX_CONTINUE;
 }
 }
 
 
@@ -3777,7 +3874,7 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
 {
 {
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	struct ieee80211_hdr *nullfunc;
 	struct ieee80211_hdr *nullfunc;
-	u16 fc;
+	__le16 fc;
 
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
 	if (!skb) {
 	if (!skb) {
@@ -3789,11 +3886,11 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
 
 
 	nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
 	nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
 	memset(nullfunc, 0, 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)
 	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->addr1, sdata->u.sta.bssid, ETH_ALEN);
 	memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
 	memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
 	memcpy(nullfunc->addr3, sdata->u.sta.bssid, 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 *
 static char *
 ieee80211_sta_scan_result(struct net_device *dev,
 ieee80211_sta_scan_result(struct net_device *dev,
+			  struct iw_request_info *info,
 			  struct ieee80211_sta_bss *bss,
 			  struct ieee80211_sta_bss *bss,
 			  char *current_ev, char *end_buf)
 			  char *current_ev, char *end_buf)
 {
 {
@@ -4101,7 +4199,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
 	iwe.cmd = SIOCGIWAP;
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
 	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);
 					  IW_EV_ADDR_LEN);
 
 
 	memset(&iwe, 0, sizeof(iwe));
 	memset(&iwe, 0, sizeof(iwe));
@@ -4109,13 +4207,13 @@ ieee80211_sta_scan_result(struct net_device *dev,
 	if (bss_mesh_cfg(bss)) {
 	if (bss_mesh_cfg(bss)) {
 		iwe.u.data.length = bss_mesh_id_len(bss);
 		iwe.u.data.length = bss_mesh_id_len(bss);
 		iwe.u.data.flags = 1;
 		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 {
 	} else {
 		iwe.u.data.length = bss->ssid_len;
 		iwe.u.data.length = bss->ssid_len;
 		iwe.u.data.flags = 1;
 		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)
 	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;
 			iwe.u.mode = IW_MODE_MASTER;
 		else
 		else
 			iwe.u.mode = IW_MODE_ADHOC;
 			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));
 	memset(&iwe, 0, sizeof(iwe));
 	iwe.cmd = SIOCGIWFREQ;
 	iwe.cmd = SIOCGIWFREQ;
 	iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
 	iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
 	iwe.u.freq.e = 0;
 	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);
 					  IW_EV_FREQ_LEN);
 
 
 	memset(&iwe, 0, sizeof(iwe));
 	memset(&iwe, 0, sizeof(iwe));
 	iwe.cmd = SIOCGIWFREQ;
 	iwe.cmd = SIOCGIWFREQ;
 	iwe.u.freq.m = bss->freq;
 	iwe.u.freq.m = bss->freq;
 	iwe.u.freq.e = 6;
 	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);
 					  IW_EV_FREQ_LEN);
 	memset(&iwe, 0, sizeof(iwe));
 	memset(&iwe, 0, sizeof(iwe));
 	iwe.cmd = IWEVQUAL;
 	iwe.cmd = IWEVQUAL;
@@ -4151,7 +4249,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
 	iwe.u.qual.level = bss->signal;
 	iwe.u.qual.level = bss->signal;
 	iwe.u.qual.noise = bss->noise;
 	iwe.u.qual.noise = bss->noise;
 	iwe.u.qual.updated = local->wstats_flags;
 	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);
 					  IW_EV_QUAL_LEN);
 
 
 	memset(&iwe, 0, sizeof(iwe));
 	memset(&iwe, 0, sizeof(iwe));
@@ -4161,35 +4259,36 @@ ieee80211_sta_scan_result(struct net_device *dev,
 	else
 	else
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
 	iwe.u.data.length = 0;
 	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) {
 	if (bss && bss->wpa_ie) {
 		memset(&iwe, 0, sizeof(iwe));
 		memset(&iwe, 0, sizeof(iwe));
 		iwe.cmd = IWEVGENIE;
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = bss->wpa_ie_len;
 		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) {
 	if (bss && bss->rsn_ie) {
 		memset(&iwe, 0, sizeof(iwe));
 		memset(&iwe, 0, sizeof(iwe));
 		iwe.cmd = IWEVGENIE;
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = bss->rsn_ie_len;
 		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) {
 	if (bss && bss->ht_ie) {
 		memset(&iwe, 0, sizeof(iwe));
 		memset(&iwe, 0, sizeof(iwe));
 		iwe.cmd = IWEVGENIE;
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = bss->ht_ie_len;
 		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) {
 	if (bss && bss->supp_rates_len > 0) {
 		/* display all supported rates in readable format */
 		/* 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;
 		int i;
 
 
 		memset(&iwe, 0, sizeof(iwe));
 		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++) {
 		for (i = 0; i < bss->supp_rates_len; i++) {
 			iwe.u.bitrate.value = ((bss->supp_rates[i] &
 			iwe.u.bitrate.value = ((bss->supp_rates[i] &
 							0x7f) * 500000);
 							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);
 					end_buf, &iwe, IW_EV_PARAM_LEN);
 		}
 		}
 		current_ev = p;
 		current_ev = p;
@@ -4214,7 +4313,8 @@ ieee80211_sta_scan_result(struct net_device *dev,
 			iwe.cmd = IWEVCUSTOM;
 			iwe.cmd = IWEVCUSTOM;
 			sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
 			sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
 			iwe.u.data.length = strlen(buf);
 			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);
 							  &iwe, buf);
 			kfree(buf);
 			kfree(buf);
 		}
 		}
@@ -4229,31 +4329,36 @@ ieee80211_sta_scan_result(struct net_device *dev,
 			iwe.cmd = IWEVCUSTOM;
 			iwe.cmd = IWEVCUSTOM;
 			sprintf(buf, "Mesh network (version %d)", cfg[0]);
 			sprintf(buf, "Mesh network (version %d)", cfg[0]);
 			iwe.u.data.length = strlen(buf);
 			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);
 							  &iwe, buf);
 			sprintf(buf, "Path Selection Protocol ID: "
 			sprintf(buf, "Path Selection Protocol ID: "
 				"0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
 				"0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
 							cfg[4]);
 							cfg[4]);
 			iwe.u.data.length = strlen(buf);
 			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);
 							  &iwe, buf);
 			sprintf(buf, "Path Selection Metric ID: "
 			sprintf(buf, "Path Selection Metric ID: "
 				"0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
 				"0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
 							cfg[8]);
 							cfg[8]);
 			iwe.u.data.length = strlen(buf);
 			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);
 							  &iwe, buf);
 			sprintf(buf, "Congestion Control Mode ID: "
 			sprintf(buf, "Congestion Control Mode ID: "
 				"0x%02X%02X%02X%02X", cfg[9], cfg[10],
 				"0x%02X%02X%02X%02X", cfg[9], cfg[10],
 							cfg[11], cfg[12]);
 							cfg[11], cfg[12]);
 			iwe.u.data.length = strlen(buf);
 			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);
 							  &iwe, buf);
 			sprintf(buf, "Channel Precedence: "
 			sprintf(buf, "Channel Precedence: "
 				"0x%02X%02X%02X%02X", cfg[13], cfg[14],
 				"0x%02X%02X%02X%02X", cfg[13], cfg[14],
 							cfg[15], cfg[16]);
 							cfg[15], cfg[16]);
 			iwe.u.data.length = strlen(buf);
 			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);
 							  &iwe, buf);
 			kfree(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);
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	char *current_ev = buf;
 	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);
 			spin_unlock_bh(&local->sta_bss_lock);
 			return -E2BIG;
 			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);
 	spin_unlock_bh(&local->sta_bss_lock);
 	return current_ev - buf;
 	return current_ev - buf;

+ 3 - 4
net/mac80211/rx.c

@@ -61,7 +61,7 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
 				    int present_fcs_len,
 				    int present_fcs_len,
 				    int radiotap_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))
 	if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
 		return 1;
 		return 1;
@@ -2123,7 +2123,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
 	struct tid_ampdu_rx *tid_agg_rx;
 	struct tid_ampdu_rx *tid_agg_rx;
 	u16 sc;
 	u16 sc;
 	u16 mpdu_seq_num;
 	u16 mpdu_seq_num;
-	u8 ret = 0, *qc;
+	u8 ret = 0;
 	int tid;
 	int tid;
 
 
 	sta = sta_info_get(local, hdr->addr2);
 	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))
 	if (!ieee80211_is_data_qos(hdr->frame_control))
 		goto end_reorder;
 		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)
 	if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
 		goto end_reorder;
 		goto end_reorder;

+ 1 - 0
net/mac80211/sta_info.c

@@ -235,6 +235,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 		return NULL;
 		return NULL;
 
 
 	spin_lock_init(&sta->lock);
 	spin_lock_init(&sta->lock);
+	spin_lock_init(&sta->flaglock);
 
 
 	memcpy(sta->addr, addr, ETH_ALEN);
 	memcpy(sta->addr, addr, ETH_ALEN);
 	sta->local = local;
 	sta->local = local;

+ 27 - 13
net/mac80211/sta_info.h

@@ -164,6 +164,7 @@ struct sta_ampdu_mlme {
  * @aid: STA's unique AID (1..2007, 0 = not assigned yet),
  * @aid: STA's unique AID (1..2007, 0 = not assigned yet),
  *	only used in AP (and IBSS?) mode
  *	only used in AP (and IBSS?) mode
  * @flags: STA flags, see &enum ieee80211_sta_info_flags
  * @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
  * @ps_tx_buf: buffer of frames to transmit to this station
  *	when it leaves power saving state
  *	when it leaves power saving state
  * @tx_filtered: buffer of frames we already tried to transmit
  * @tx_filtered: buffer of frames we already tried to transmit
@@ -186,6 +187,7 @@ struct sta_info {
 	struct rate_control_ref *rate_ctrl;
 	struct rate_control_ref *rate_ctrl;
 	void *rate_ctrl_priv;
 	void *rate_ctrl_priv;
 	spinlock_t lock;
 	spinlock_t lock;
+	spinlock_t flaglock;
 	struct ieee80211_ht_info ht_info;
 	struct ieee80211_ht_info ht_info;
 	u64 supp_rates[IEEE80211_NUM_BANDS];
 	u64 supp_rates[IEEE80211_NUM_BANDS];
 	u8 addr[ETH_ALEN];
 	u8 addr[ETH_ALEN];
@@ -198,7 +200,10 @@ struct sta_info {
 	 */
 	 */
 	u8 pin_status;
 	u8 pin_status;
 
 
-	/* frequently updated information, locked with lock spinlock */
+	/*
+	 * frequently updated, locked with own spinlock (flaglock),
+	 * use the accessors defined below
+	 */
 	u32 flags;
 	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)
 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;
 	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)
 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;
 	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,
 static inline void set_and_clear_sta_flags(struct sta_info *sta,
 					   const u32 set, const u32 clear)
 					   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 |= set;
 	sta->flags &= ~clear;
 	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)
 static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags)
 {
 {
 	u32 ret;
 	u32 ret;
+	unsigned long irqfl;
 
 
-	spin_lock_bh(&sta->lock);
+	spin_lock_irqsave(&sta->flaglock, irqfl);
 	ret = sta->flags & flags;
 	ret = sta->flags & flags;
-	spin_unlock_bh(&sta->lock);
+	spin_unlock_irqrestore(&sta->flaglock, irqfl);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -329,11 +341,12 @@ static inline u32 test_and_clear_sta_flags(struct sta_info *sta,
 					   const u32 flags)
 					   const u32 flags)
 {
 {
 	u32 ret;
 	u32 ret;
+	unsigned long irqfl;
 
 
-	spin_lock_bh(&sta->lock);
+	spin_lock_irqsave(&sta->flaglock, irqfl);
 	ret = sta->flags & flags;
 	ret = sta->flags & flags;
 	sta->flags &= ~flags;
 	sta->flags &= ~flags;
-	spin_unlock_bh(&sta->lock);
+	spin_unlock_irqrestore(&sta->flaglock, irqfl);
 
 
 	return ret;
 	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)
 static inline u32 get_sta_flags(struct sta_info *sta)
 {
 {
 	u32 ret;
 	u32 ret;
+	unsigned long irqfl;
 
 
-	spin_lock_bh(&sta->lock);
+	spin_lock_irqsave(&sta->flaglock, irqfl);
 	ret = sta->flags;
 	ret = sta->flags;
-	spin_unlock_bh(&sta->lock);
+	spin_unlock_irqrestore(&sta->flaglock, irqfl);
 
 
 	return ret;
 	return ret;
 }
 }

+ 15 - 15
net/mac80211/tkip.c

@@ -164,10 +164,10 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
 	iv16 = data[2] | (data[0] << 8);
 	iv16 = data[2] | (data[0] << 8);
 	iv32 = get_unaligned_le32(&data[4]);
 	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;
 	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",
 	printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
 			iv16, iv32);
 			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 "
 		printk(KERN_DEBUG "Wrap around of iv16 in the middle of a "
 			"fragmented packet\n");
 			"fragmented packet\n");
 	}
 	}
-#endif /* CONFIG_TKIP_DEBUG */
+#endif
 
 
 	/* Update the p1k only when the iv16 in the packet wraps around, this
 	/* 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
 	 * 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];
 	u8 rc4key[16];
 	struct tkip_ctx *ctx = &key->u.tkip.tx;
 	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 */
 	/* Calculate per-packet key */
 	if (ctx->iv16 == 0 || !ctx->initialized)
 	if (ctx->iv16 == 0 || !ctx->initialized)
@@ -231,7 +231,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 	u32 iv16;
 	u32 iv16;
 	u8 rc4key[16], keyid, *pos = payload;
 	u8 rc4key[16], keyid, *pos = payload;
 	int res;
 	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)
 	if (payload_len < 12)
 		return -1;
 		return -1;
@@ -240,7 +240,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 	keyid = pos[3];
 	keyid = pos[3];
 	iv32 = get_unaligned_le32(pos + 4);
 	iv32 = get_unaligned_le32(pos + 4);
 	pos += 8;
 	pos += 8;
-#ifdef CONFIG_TKIP_DEBUG
+#ifdef CONFIG_MAC80211_TKIP_DEBUG
 	{
 	{
 		int i;
 		int i;
 		printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len);
 		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",
 		printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n",
 		       iv16, iv32);
 		       iv16, iv32);
 	}
 	}
-#endif /* CONFIG_TKIP_DEBUG */
+#endif
 
 
 	if (!(keyid & (1 << 5)))
 	if (!(keyid & (1 << 5)))
 		return TKIP_DECRYPT_NO_EXT_IV;
 		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 ||
 	     (iv32 == key->u.tkip.rx[queue].iv32 &&
 	     (iv32 == key->u.tkip.rx[queue].iv32 &&
 	      iv16 <= key->u.tkip.rx[queue].iv16))) {
 	      iv16 <= key->u.tkip.rx[queue].iv16))) {
-#ifdef CONFIG_TKIP_DEBUG
+#ifdef CONFIG_MAC80211_TKIP_DEBUG
 		DECLARE_MAC_BUF(mac);
 		DECLARE_MAC_BUF(mac);
 		printk(KERN_DEBUG "TKIP replay detected for RX frame from "
 		printk(KERN_DEBUG "TKIP replay detected for RX frame from "
 		       "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
 		       "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
 		       print_mac(mac, ta),
 		       print_mac(mac, ta),
 		       iv32, iv16, key->u.tkip.rx[queue].iv32,
 		       iv32, iv16, key->u.tkip.rx[queue].iv32,
 		       key->u.tkip.rx[queue].iv16);
 		       key->u.tkip.rx[queue].iv16);
-#endif /* CONFIG_TKIP_DEBUG */
+#endif
 		return TKIP_DECRYPT_REPLAY;
 		return TKIP_DECRYPT_REPLAY;
 	}
 	}
 
 
@@ -283,23 +283,23 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 	    key->u.tkip.rx[queue].iv32 != iv32) {
 	    key->u.tkip.rx[queue].iv32 != iv32) {
 		/* IV16 wrapped around - perform TKIP phase 1 */
 		/* IV16 wrapped around - perform TKIP phase 1 */
 		tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
 		tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
-#ifdef CONFIG_TKIP_DEBUG
+#ifdef CONFIG_MAC80211_TKIP_DEBUG
 		{
 		{
 			int i;
 			int i;
+			u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY;
 			DECLARE_MAC_BUF(mac);
 			DECLARE_MAC_BUF(mac);
 			printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s"
 			printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s"
 			       " TK=", print_mac(mac, ta));
 			       " TK=", print_mac(mac, ta));
 			for (i = 0; i < 16; i++)
 			for (i = 0; i < 16; i++)
 				printk("%02x ",
 				printk("%02x ",
-				       key->conf.key[
-						ALG_TKIP_TEMP_ENCR_KEY + i]);
+				       key->conf.key[key_offset + i]);
 			printk("\n");
 			printk("\n");
 			printk(KERN_DEBUG "TKIP decrypt: P1K=");
 			printk(KERN_DEBUG "TKIP decrypt: P1K=");
 			for (i = 0; i < 5; i++)
 			for (i = 0; i < 5; i++)
 				printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
 				printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
 			printk("\n");
 			printk("\n");
 		}
 		}
-#endif /* CONFIG_TKIP_DEBUG */
+#endif
 		if (key->local->ops->update_tkip_key &&
 		if (key->local->ops->update_tkip_key &&
 			key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
 			key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
 			u8 bcast[ETH_ALEN] =
 			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);
 	tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
-#ifdef CONFIG_TKIP_DEBUG
+#ifdef CONFIG_MAC80211_TKIP_DEBUG
 	{
 	{
 		int i;
 		int i;
 		printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key=");
 		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("%02x ", rc4key[i]);
 		printk("\n");
 		printk("\n");
 	}
 	}
-#endif /* CONFIG_TKIP_DEBUG */
+#endif
 
 
 	res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
 	res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
  done:
  done:

+ 102 - 102
net/mac80211/tx.c

@@ -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,
 static void ieee80211_dump_frame(const char *ifname, const char *title,
 				 const struct sk_buff *skb)
 				 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);
 	DECLARE_MAC_BUF(mac);
 
 
 	printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
 	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;
 		return;
 	}
 	}
 
 
-	fc = le16_to_cpu(hdr->frame_control);
-	hdrlen = ieee80211_get_hdrlen(fc);
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	if (hdrlen > skb->len)
 	if (hdrlen > skb->len)
 		hdrlen = skb->len;
 		hdrlen = skb->len;
 	if (hdrlen >= 4)
 	if (hdrlen >= 4)
 		printk(" FC=0x%04x DUR=0x%04x",
 		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)
 	if (hdrlen >= 10)
 		printk(" A1=%s", print_mac(mac, hdr->addr1));
 		printk(" A1=%s", print_mac(mac, hdr->addr1));
 	if (hdrlen >= 16)
 	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 */
 #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;
 	int rate, mrate, erp, dur, i;
 	struct ieee80211_rate *txrate;
 	struct ieee80211_rate *txrate;
@@ -140,7 +138,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
 
 
 	/* data/mgmt */
 	/* data/mgmt */
 	if (0 /* FIX: data/mgmt during CFP */)
 	if (0 /* FIX: data/mgmt during CFP */)
-		return 32768;
+		return cpu_to_le16(32768);
 
 
 	if (group_addr) /* Group address as the destination - no ACK */
 	if (group_addr) /* Group address as the destination - no ACK */
 		return 0;
 		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);
 				tx->sdata->bss_conf.use_short_preamble);
 	}
 	}
 
 
-	return dur;
+	return cpu_to_le16(dur);
 }
 }
 
 
 static int inline is_ieee80211_device(struct net_device *dev,
 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;
 	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);
 		ieee80211_include_sequence(tx->sdata, hdr);
 
 
 	return TX_CONTINUE;
 	return TX_CONTINUE;
@@ -542,9 +540,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 static ieee80211_tx_result
 static ieee80211_tx_result
 ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
 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_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 	struct ieee80211_supported_band *sband;
 	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
 	/* Transmit data frames using short preambles if the driver supports
 	 * short preambles at the selected rate and short preambles are
 	 * short preambles at the selected rate and short preambles are
 	 * available on the network at the current point in time. */
 	 * 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) &&
 	    (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
 	    tx->sdata->bss_conf.use_short_preamble &&
 	    tx->sdata->bss_conf.use_short_preamble &&
 	    (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
 	    (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
 		info->flags |= IEEE80211_TX_CTL_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) ||
 	if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
 	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
 	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
 		struct ieee80211_rate *rate;
 		struct ieee80211_rate *rate;
@@ -647,7 +635,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
 static ieee80211_tx_result
 static ieee80211_tx_result
 ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 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;
 	size_t hdrlen, per_fragm, num_fragm, payload_len, left;
 	struct sk_buff **frags, *first, *frag;
 	struct sk_buff **frags, *first, *frag;
 	int i;
 	int i;
@@ -670,7 +658,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 
 
 	first = tx->skb;
 	first = tx->skb;
 
 
-	hdrlen = ieee80211_get_hdrlen(tx->fc);
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	payload_len = first->len - hdrlen;
 	payload_len = first->len - hdrlen;
 	per_fragm = frag_threshold - hdrlen - FCS_LEN;
 	per_fragm = frag_threshold - hdrlen - FCS_LEN;
 	num_fragm = DIV_ROUND_UP(payload_len, per_fragm);
 	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));
 		fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
 		copylen = left > per_fragm ? per_fragm : left;
 		copylen = left > per_fragm ? per_fragm : left;
 		memcpy(skb_put(frag, copylen), pos, copylen);
 		memcpy(skb_put(frag, copylen), pos, copylen);
+		memcpy(frag->cb, first->cb, sizeof(frag->cb));
+		skb_copy_queue_mapping(frag, first);
 
 
 		pos += copylen;
 		pos += copylen;
 		left -= copylen;
 		left -= copylen;
@@ -754,6 +744,36 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
 	return TX_DROP;
 	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
 static ieee80211_tx_result
 ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
 ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
 {
 {
@@ -788,6 +808,7 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] =
 	ieee80211_tx_h_fragment,
 	ieee80211_tx_h_fragment,
 	/* handlers after fragment must be aware of tx info fragmentation! */
 	/* handlers after fragment must be aware of tx info fragmentation! */
 	ieee80211_tx_h_encrypt,
 	ieee80211_tx_h_encrypt,
+	ieee80211_tx_h_calculate_duration,
 	ieee80211_tx_h_stats,
 	ieee80211_tx_h_stats,
 	NULL
 	NULL
 };
 };
@@ -1083,13 +1104,46 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
 	return IEEE80211_TX_OK;
 	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)
 static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
 {
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct sta_info *sta;
 	struct sta_info *sta;
-	ieee80211_tx_handler *handler;
 	struct ieee80211_tx_data tx;
 	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);
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	int ret, i;
 	int ret, i;
 	u16 queue;
 	u16 queue;
@@ -1118,44 +1172,8 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
 	tx.channel = local->hw.conf.channel;
 	tx.channel = local->hw.conf.channel;
 	info->band = tx.channel->band;
 	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:
 retry:
 	ret = __ieee80211_tx(local, skb, &tx);
 	ret = __ieee80211_tx(local, skb, &tx);
@@ -1198,6 +1216,7 @@ retry:
 		store->last_frag_rate_ctrl_probe =
 		store->last_frag_rate_ctrl_probe =
 			!!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
 			!!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
 	}
 	}
+ out:
 	rcu_read_unlock();
 	rcu_read_unlock();
 	return 0;
 	return 0;
 
 
@@ -1379,7 +1398,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 	struct ieee80211_tx_info *info;
 	struct ieee80211_tx_info *info;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_sub_if_data *sdata;
 	int ret = 1, head_need;
 	int ret = 1, head_need;
-	u16 ethertype, hdrlen,  meshhdrlen = 0, fc;
+	u16 ethertype, hdrlen,  meshhdrlen = 0;
+	__le16 fc;
 	struct ieee80211_hdr hdr;
 	struct ieee80211_hdr hdr;
 	struct ieee80211s_hdr mesh_hdr;
 	struct ieee80211s_hdr mesh_hdr;
 	const u8 *encaps_data;
 	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
 	/* convert Ethernet header to proper 802.11 header (based on
 	 * operation mode) */
 	 * operation mode) */
 	ethertype = (skb->data[12] << 8) | skb->data[13];
 	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) {
 	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_AP:
 	case IEEE80211_IF_TYPE_AP:
 	case IEEE80211_IF_TYPE_VLAN:
 	case IEEE80211_IF_TYPE_VLAN:
-		fc |= IEEE80211_FCTL_FROMDS;
+		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
 		/* DA BSSID SA */
 		/* DA BSSID SA */
 		memcpy(hdr.addr1, skb->data, ETH_ALEN);
 		memcpy(hdr.addr1, skb->data, ETH_ALEN);
 		memcpy(hdr.addr2, dev->dev_addr, 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;
 		hdrlen = 24;
 		break;
 		break;
 	case IEEE80211_IF_TYPE_WDS:
 	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 */
 		/* RA TA DA SA */
 		memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
 		memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
 		memcpy(hdr.addr2, dev->dev_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;
 		break;
 #ifdef CONFIG_MAC80211_MESH
 #ifdef CONFIG_MAC80211_MESH
 	case IEEE80211_IF_TYPE_MESH_POINT:
 	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 */
 		/* RA TA DA SA */
 		if (is_multicast_ether_addr(skb->data))
 		if (is_multicast_ether_addr(skb->data))
 			memcpy(hdr.addr1, skb->data, ETH_ALEN);
 			memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -1455,7 +1475,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 		break;
 		break;
 #endif
 #endif
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_STA:
-		fc |= IEEE80211_FCTL_TODS;
+		fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
 		/* BSSID SA DA */
 		/* BSSID SA DA */
 		memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
 		memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
 		memcpy(hdr.addr2, skb->data + ETH_ALEN, 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 */
 	/* receiver and we are QoS enabled, use a QoS type frame */
 	if (sta_flags & WLAN_STA_WME &&
 	if (sta_flags & WLAN_STA_WME &&
 	    ieee80211_num_regular_queues(&local->hw) >= 4) {
 	    ieee80211_num_regular_queues(&local->hw) >= 4) {
-		fc |= IEEE80211_STYPE_QOS_DATA;
+		fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
 		hdrlen += 2;
 		hdrlen += 2;
 	}
 	}
 
 
@@ -1518,7 +1538,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 		goto fail;
 		goto fail;
 	}
 	}
 
 
-	hdr.frame_control = cpu_to_le16(fc);
+	hdr.frame_control = fc;
 	hdr.duration_id = 0;
 	hdr.duration_id = 0;
 	hdr.seq_ctrl = 0;
 	hdr.seq_ctrl = 0;
 
 
@@ -1587,7 +1607,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 		h_pos += meshhdrlen;
 		h_pos += meshhdrlen;
 	}
 	}
 
 
-	if (fc & IEEE80211_STYPE_QOS_DATA) {
+	if (ieee80211_is_data_qos(fc)) {
 		__le16 *qos_control;
 		__le16 *qos_control;
 
 
 		qos_control = (__le16*) skb_push(skb, 2);
 		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 *)
 		mgmt = (struct ieee80211_mgmt *)
 			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
 			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
 		memset(mgmt, 0, 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);
 		memset(mgmt->da, 0xff, ETH_ALEN);
 		memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 		memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 		/* BSSID is left zeroed, wildcard value */
 		/* 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)
 		       struct ieee80211_rts *rts)
 {
 {
 	const struct ieee80211_hdr *hdr = frame;
 	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,
 	rts->duration = ieee80211_rts_duration(hw, vif, frame_len,
 					       frame_txctl);
 					       frame_txctl);
 	memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
 	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)
 			     struct ieee80211_cts *cts)
 {
 {
 	const struct ieee80211_hdr *hdr = frame;
 	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,
 	cts->duration = ieee80211_ctstoself_duration(hw, vif,
 						     frame_len, frame_txctl);
 						     frame_len, frame_txctl);
 	memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
 	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 ieee80211_local *local = hw_to_local(hw);
 	struct sk_buff *skb = NULL;
 	struct sk_buff *skb = NULL;
 	struct sta_info *sta;
 	struct sta_info *sta;
-	ieee80211_tx_handler *handler;
 	struct ieee80211_tx_data tx;
 	struct ieee80211_tx_data tx;
-	ieee80211_tx_result res = TX_DROP;
 	struct net_device *bdev;
 	struct net_device *bdev;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_ap *bss = NULL;
 	struct ieee80211_if_ap *bss = NULL;
@@ -2001,25 +2017,9 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 	tx.channel = local->hw.conf.channel;
 	tx.channel = local->hw.conf.channel;
 	info->band = tx.channel->band;
 	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;
 		skb = NULL;
-	} else if (res == TX_QUEUED) {
-		I802_DEBUG_INC(local->tx_handlers_queued);
-		skb = NULL;
-	}
-
-out:
+ out:
 	rcu_read_unlock();
 	rcu_read_unlock();
 
 
 	return skb;
 	return skb;

+ 15 - 24
net/mac80211/wep.c

@@ -84,20 +84,17 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
 				struct sk_buff *skb,
 				struct sk_buff *skb,
 				struct ieee80211_key *key)
 				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;
 	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 ||
 	if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN ||
 		    skb_headroom(skb) < WEP_IV_LEN))
 		    skb_headroom(skb) < WEP_IV_LEN))
 		return NULL;
 		return NULL;
 
 
-	hdrlen = ieee80211_get_hdrlen(fc);
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	newhdr = skb_push(skb, WEP_IV_LEN);
 	newhdr = skb_push(skb, WEP_IV_LEN);
 	memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
 	memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
 	ieee80211_wep_get_iv(local, key, newhdr + 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 sk_buff *skb,
 				    struct ieee80211_key *key)
 				    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);
 	memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen);
 	skb_pull(skb, WEP_IV_LEN);
 	skb_pull(skb, WEP_IV_LEN);
 }
 }
@@ -224,17 +219,15 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
 	u32 klen;
 	u32 klen;
 	u8 *rc4key;
 	u8 *rc4key;
 	u8 keyidx;
 	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;
 	size_t len;
 	int ret = 0;
 	int ret = 0;
 
 
-	fc = le16_to_cpu(hdr->frame_control);
-	if (!(fc & IEEE80211_FCTL_PROTECTED))
+	if (!ieee80211_has_protected(hdr->frame_control))
 		return -1;
 		return -1;
 
 
-	hdrlen = ieee80211_get_hdrlen(fc);
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
 
 	if (skb->len < 8 + hdrlen)
 	if (skb->len < 8 + hdrlen)
 		return -1;
 		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)
 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;
 	u8 *ivpos;
 	u32 iv;
 	u32 iv;
 
 
-	fc = le16_to_cpu(hdr->frame_control);
-	if (!(fc & IEEE80211_FCTL_PROTECTED))
+	if (!ieee80211_has_protected(hdr->frame_control))
 		return NULL;
 		return NULL;
 
 
-	hdrlen = ieee80211_get_hdrlen(fc);
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	ivpos = skb->data + hdrlen;
 	ivpos = skb->data + hdrlen;
 	iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
 	iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
 
 

+ 49 - 1
net/mac80211/wext.c

@@ -135,7 +135,39 @@ static int ieee80211_ioctl_giwname(struct net_device *dev,
 				   struct iw_request_info *info,
 				   struct iw_request_info *info,
 				   char *name, char *extra)
 				   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");
 	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;
 	return 0;
 }
 }
@@ -567,7 +599,7 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
 	if (local->sta_sw_scanning || local->sta_hw_scanning)
 	if (local->sta_sw_scanning || local->sta_hw_scanning)
 		return -EAGAIN;
 		return -EAGAIN;
 
 
-	res = ieee80211_sta_scan_results(dev, extra, data->length);
+	res = ieee80211_sta_scan_results(dev, info, extra, data->length);
 	if (res >= 0) {
 	if (res >= 0) {
 		data->length = res;
 		data->length = res;
 		return 0;
 		return 0;
@@ -721,6 +753,9 @@ static int ieee80211_ioctl_siwrts(struct net_device *dev,
 
 
 	if (rts->disabled)
 	if (rts->disabled)
 		local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
 		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)
 	else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
 		return -EINVAL;
 		return -EINVAL;
 	else
 	else
@@ -949,6 +984,19 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
 	erq->length = sdata->keys[idx]->conf.keylen;
 	erq->length = sdata->keys[idx]->conf.keylen;
 	erq->flags |= IW_ENCODE_ENABLED;
 	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;
 	return 0;
 }
 }
 
 

+ 14 - 6
net/mac80211/wpa.c

@@ -49,7 +49,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
 ieee80211_tx_result
 ieee80211_tx_result
 ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
 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;
 	size_t data_len;
 	u16 fc;
 	u16 fc;
 	struct sk_buff *skb = tx->skb;
 	struct sk_buff *skb = tx->skb;
@@ -88,8 +88,12 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
 #else
 #else
 	authenticator = 1;
 	authenticator = 1;
 #endif
 #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);
 	mic = skb_put(skb, MICHAEL_MIC_LEN);
 	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
 	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_result
 ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
 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;
 	size_t data_len;
 	u16 fc;
 	u16 fc;
 	u8 mic[MICHAEL_MIC_LEN];
 	u8 mic[MICHAEL_MIC_LEN];
@@ -131,8 +135,12 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
 #else
 #else
 	authenticator = 1;
 	authenticator = 1;
 #endif
 #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);
 	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 (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
 		if (!(rx->flags & IEEE80211_RX_RA_MATCH))
 		if (!(rx->flags & IEEE80211_RX_RA_MATCH))

+ 74 - 24
net/rfkill/rfkill-input.c

@@ -30,39 +30,62 @@ struct rfkill_task {
 	spinlock_t lock; /* for accessing last and desired state */
 	spinlock_t lock; /* for accessing last and desired state */
 	unsigned long last; /* last schedule */
 	unsigned long last; /* last schedule */
 	enum rfkill_state desired_state; /* on/off */
 	enum rfkill_state desired_state; /* on/off */
-	enum rfkill_state current_state; /* on/off */
 };
 };
 
 
 static void rfkill_task_handler(struct work_struct *work)
 static void rfkill_task_handler(struct work_struct *work)
 {
 {
 	struct rfkill_task *task = container_of(work, struct rfkill_task, work);
 	struct rfkill_task *task = container_of(work, struct rfkill_task, work);
-	enum rfkill_state state;
 
 
 	mutex_lock(&task->mutex);
 	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)
 static void rfkill_schedule_toggle(struct rfkill_task *task)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 
 
+	if (unlikely(work_pending(&epo_work)))
+		return;
+
 	spin_lock_irqsave(&task->lock, flags);
 	spin_lock_irqsave(&task->lock, flags);
 
 
 	if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
 	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;
 		task->last = jiffies;
 		schedule_work(&task->work);
 		schedule_work(&task->work);
 	}
 	}
@@ -70,26 +93,26 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
 	spin_unlock_irqrestore(&task->lock, flags);
 	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_wlan, RFKILL_TYPE_WLAN);
 static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
 static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
 static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
 static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
 static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
 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,
 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) {
 		switch (code) {
 		case KEY_WLAN:
 		case KEY_WLAN:
 			rfkill_schedule_toggle(&rfkill_wlan);
 			rfkill_schedule_toggle(&rfkill_wlan);
@@ -106,6 +129,28 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
 		default:
 		default:
 			break;
 			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) },
 		.evbit = { BIT_MASK(EV_KEY) },
 		.keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
 		.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) },
+	},
 	{ }
 	{ }
 };
 };
 
 

+ 1 - 0
net/rfkill/rfkill-input.h

@@ -12,5 +12,6 @@
 #define __RFKILL_INPUT_H
 #define __RFKILL_INPUT_H
 
 
 void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
 void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
+void rfkill_epo(void);
 
 
 #endif /* __RFKILL_INPUT_H */
 #endif /* __RFKILL_INPUT_H */

+ 266 - 38
net/rfkill/rfkill.c

@@ -39,8 +39,56 @@ MODULE_LICENSE("GPL");
 static LIST_HEAD(rfkill_list);	/* list of registered rf switches */
 static LIST_HEAD(rfkill_list);	/* list of registered rf switches */
 static DEFINE_MUTEX(rfkill_mutex);
 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 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,
 static void rfkill_led_trigger(struct rfkill *rfkill,
 			       enum rfkill_state state)
 			       enum rfkill_state state)
@@ -50,24 +98,99 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
 
 
 	if (!led->name)
 	if (!led->name)
 		return;
 		return;
-	if (state == RFKILL_STATE_OFF)
+	if (state != RFKILL_STATE_UNBLOCKED)
 		led_trigger_event(led, LED_OFF);
 		led_trigger_event(led, LED_OFF);
 	else
 	else
 		led_trigger_event(led, LED_FULL);
 		led_trigger_event(led, LED_FULL);
 #endif /* CONFIG_RFKILL_LEDS */
 #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,
 static int rfkill_toggle_radio(struct rfkill *rfkill,
-				enum rfkill_state state)
+				enum rfkill_state state,
+				int force)
 {
 {
 	int retval = 0;
 	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);
 		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->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;
 	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
  * a specific switch is claimed by userspace in which case it is
  * left alone.
  * left alone.
  */
  */
-
 void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
 void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
 {
 {
 	struct rfkill *rfkill;
 	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) {
 	list_for_each_entry(rfkill, &rfkill_list, node) {
 		if ((!rfkill->user_claim) && (rfkill->type == type))
 		if ((!rfkill->user_claim) && (rfkill->type == type))
-			rfkill_toggle_radio(rfkill, state);
+			rfkill_toggle_radio(rfkill, state, 0);
 	}
 	}
 
 
 	mutex_unlock(&rfkill_mutex);
 	mutex_unlock(&rfkill_mutex);
 }
 }
 EXPORT_SYMBOL(rfkill_switch_all);
 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,
 static ssize_t rfkill_name_show(struct device *dev,
 				struct device_attribute *attr,
 				struct device_attribute *attr,
 				char *buf)
 				char *buf)
@@ -109,31 +284,31 @@ static ssize_t rfkill_name_show(struct device *dev,
 	return sprintf(buf, "%s\n", rfkill->name);
 	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:
 	case RFKILL_TYPE_WLAN:
-		type = "wlan";
-		break;
+		return "wlan";
 	case RFKILL_TYPE_BLUETOOTH:
 	case RFKILL_TYPE_BLUETOOTH:
-		type = "bluetooth";
-		break;
+		return "bluetooth";
 	case RFKILL_TYPE_UWB:
 	case RFKILL_TYPE_UWB:
-		type = "ultrawideband";
-		break;
+		return "ultrawideband";
 	case RFKILL_TYPE_WIMAX:
 	case RFKILL_TYPE_WIMAX:
-		type = "wimax";
-		break;
+		return "wimax";
+	case RFKILL_TYPE_WWAN:
+		return "wwan";
 	default:
 	default:
 		BUG();
 		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,
 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);
 	struct rfkill *rfkill = to_rfkill(dev);
 
 
+	update_rfkill_state(rfkill);
 	return sprintf(buf, "%d\n", rfkill->state);
 	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))
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 		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))
 	if (mutex_lock_interruptible(&rfkill->mutex))
 		return -ERESTARTSYS;
 		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);
 	mutex_unlock(&rfkill->mutex);
 
 
 	return error ? error : count;
 	return error ? error : count;
@@ -200,7 +380,8 @@ static ssize_t rfkill_claim_store(struct device *dev,
 	if (rfkill->user_claim != claim) {
 	if (rfkill->user_claim != claim) {
 		if (!claim)
 		if (!claim)
 			rfkill_toggle_radio(rfkill,
 			rfkill_toggle_radio(rfkill,
-					    rfkill_states[rfkill->type]);
+					    rfkill_states[rfkill->type],
+					    0);
 		rfkill->user_claim = claim;
 		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 (dev->power.power_state.event != state.event) {
 		if (state.event & PM_EVENT_SLEEP) {
 		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);
 			mutex_unlock(&rfkill->mutex);
 		}
 		}
 
 
@@ -255,8 +436,8 @@ static int rfkill_resume(struct device *dev)
 	if (dev->power.power_state.event != PM_EVENT_ON) {
 	if (dev->power.power_state.event != PM_EVENT_ON) {
 		mutex_lock(&rfkill->mutex);
 		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);
 		mutex_unlock(&rfkill->mutex);
 	}
 	}
@@ -269,12 +450,51 @@ static int rfkill_resume(struct device *dev)
 #define rfkill_resume NULL
 #define rfkill_resume NULL
 #endif
 #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 = {
 static struct class rfkill_class = {
 	.name		= "rfkill",
 	.name		= "rfkill",
 	.dev_release	= rfkill_release,
 	.dev_release	= rfkill_release,
 	.dev_attrs	= rfkill_dev_attrs,
 	.dev_attrs	= rfkill_dev_attrs,
 	.suspend	= rfkill_suspend,
 	.suspend	= rfkill_suspend,
 	.resume		= rfkill_resume,
 	.resume		= rfkill_resume,
+	.dev_uevent	= rfkill_dev_uevent,
 };
 };
 
 
 static int rfkill_add_switch(struct rfkill *rfkill)
 static int rfkill_add_switch(struct rfkill *rfkill)
@@ -283,7 +503,7 @@ static int rfkill_add_switch(struct rfkill *rfkill)
 
 
 	mutex_lock(&rfkill_mutex);
 	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)
 	if (!error)
 		list_add_tail(&rfkill->node, &rfkill_list);
 		list_add_tail(&rfkill->node, &rfkill_list);
 
 
@@ -296,7 +516,7 @@ static void rfkill_remove_switch(struct rfkill *rfkill)
 {
 {
 	mutex_lock(&rfkill_mutex);
 	mutex_lock(&rfkill_mutex);
 	list_del_init(&rfkill->node);
 	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);
 	mutex_unlock(&rfkill_mutex);
 }
 }
 
 
@@ -412,7 +632,7 @@ int rfkill_register(struct rfkill *rfkill)
 EXPORT_SYMBOL(rfkill_register);
 EXPORT_SYMBOL(rfkill_register);
 
 
 /**
 /**
- * rfkill_unregister - Uegister a rfkill structure.
+ * rfkill_unregister - Unregister a rfkill structure.
  * @rfkill: rfkill structure to be unregistered
  * @rfkill: rfkill structure to be unregistered
  *
  *
  * This function should be called by the network driver during device
  * This function should be called by the network driver during device
@@ -436,8 +656,13 @@ static int __init rfkill_init(void)
 	int error;
 	int error;
 	int i;
 	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++)
 	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);
 	error = class_register(&rfkill_class);
 	if (error) {
 	if (error) {
@@ -445,11 +670,14 @@ static int __init rfkill_init(void)
 		return error;
 		return error;
 	}
 	}
 
 
+	register_rfkill_notifier(&rfkill_blocking_uevent_nb);
+
 	return 0;
 	return 0;
 }
 }
 
 
 static void __exit rfkill_exit(void)
 static void __exit rfkill_exit(void)
 {
 {
+	unregister_rfkill_notifier(&rfkill_blocking_uevent_nb);
 	class_unregister(&rfkill_class);
 	class_unregister(&rfkill_class);
 }
 }
 
 

+ 10 - 0
net/socket.c

@@ -90,6 +90,7 @@
 #include <asm/unistd.h>
 #include <asm/unistd.h>
 
 
 #include <net/compat.h>
 #include <net/compat.h>
+#include <net/wext.h>
 
 
 #include <net/sock.h>
 #include <net/sock.h>
 #include <linux/netfilter.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;
 	struct socket *sock = file->private_data;
 	int ret = -ENOIOCTLCMD;
 	int ret = -ENOIOCTLCMD;
+	struct sock *sk;
+	struct net *net;
+
+	sk = sock->sk;
+	net = sock_net(sk);
 
 
 	if (sock->ops->compat_ioctl)
 	if (sock->ops->compat_ioctl)
 		ret = sock->ops->compat_ioctl(sock, cmd, arg);
 		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;
 	return ret;
 }
 }
 #endif
 #endif

+ 362 - 220
net/wireless/wext.c

@@ -500,7 +500,7 @@ static int call_commit_handler(struct net_device *dev)
 /*
 /*
  * Calculate size of private arguments
  * 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	num = args & IW_PRIV_SIZE_MASK;
 	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
 	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
  * 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	max = args & IW_PRIV_SIZE_MASK;
 	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
 	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.
  * Wrapper to call a standard Wireless Extension handler.
  * We do various checks and also take care of moving data between
  * We do various checks and also take care of moving data between
  * user space and kernel space.
  * user space and kernel space.
  */
  */
 static int ioctl_standard_call(struct net_device *	dev,
 static int ioctl_standard_call(struct net_device *	dev,
-			       struct ifreq *		ifr,
+			       struct iwreq		*iwr,
 			       unsigned int		cmd,
 			       unsigned int		cmd,
+			       struct iw_request_info	*info,
 			       iw_handler		handler)
 			       iw_handler		handler)
 {
 {
-	struct iwreq *				iwr = (struct iwreq *) ifr;
 	const struct iw_ioctl_description *	descr;
 	const struct iw_ioctl_description *	descr;
-	struct iw_request_info			info;
 	int					ret = -EINVAL;
 	int					ret = -EINVAL;
 
 
 	/* Get the description of the IOCTL */
 	/* Get the description of the IOCTL */
@@ -715,145 +845,19 @@ static int ioctl_standard_call(struct net_device *	dev,
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
 	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 */
 	/* Check if we have a pointer to user space data or not */
 	if (descr->header_type != IW_HEADER_TYPE_POINT) {
 	if (descr->header_type != IW_HEADER_TYPE_POINT) {
 
 
 		/* No extra arguments. Trivial to handle */
 		/* 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 */
 		/* Generate an event to notify listeners of the change */
 		if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
 		if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
 		   ((ret == 0) || (ret == -EIWCOMMIT)))
 		   ((ret == 0) || (ret == -EIWCOMMIT)))
 			wireless_send_event(dev, cmd, &(iwr->u), NULL);
 			wireless_send_event(dev, cmd, &(iwr->u), NULL);
 	} else {
 	} 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 */
 	/* 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
  * a iw_handler but process it in your ioctl handler (i.e. use the
  * old driver API).
  * 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) {
 		if (cmd == dev->wireless_handlers->private_args[i].cmd) {
-			descr = &(dev->wireless_handlers->private_args[i]);
+			descr = &dev->wireless_handlers->private_args[i];
 			break;
 			break;
 		}
 		}
+	}
 
 
-	/* Compute the size of the set/get arguments */
-	if (descr != NULL) {
+	extra_size = 0;
+	if (descr) {
 		if (IW_IS_SET(cmd)) {
 		if (IW_IS_SET(cmd)) {
 			int	offset = 0;	/* For sub-ioctls */
 			int	offset = 0;	/* For sub-ioctls */
 			/* Check for sub-ioctl handler */
 			/* Check for sub-ioctl handler */
@@ -924,72 +925,77 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
 				extra_size = 0;
 				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 */
 	/* Call commit handler if needed and defined */
 	if (ret == -EIWCOMMIT)
 	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.
  * Main IOCTl dispatcher.
  * Check the type of IOCTL and call the appropriate wrapper...
  * 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;
 	struct net_device *dev;
 	iw_handler	handler;
 	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
 	 * Note that 'cmd' is already filtered in dev_ioctl() with
 	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
 	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
 	if (cmd == SIOCGIWSTATS)
 	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)
 	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 */
 	/* Basic check */
 	if (!netif_device_present(dev))
 	if (!netif_device_present(dev))
@@ -1035,9 +1050,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
 	if (handler) {
 	if (handler) {
 		/* Standard and private are not the same */
 		/* Standard and private are not the same */
 		if (cmd < SIOCIWFIRSTPRIV)
 		if (cmd < SIOCIWFIRSTPRIV)
-			return ioctl_standard_call(dev, ifr, cmd, handler);
+			return standard(dev, iwr, cmd, info, handler);
 		else
 		else
-			return ioctl_private_call(dev, ifr, cmd, handler);
+			return private(dev, iwr, cmd, info, handler);
 	}
 	}
 	/* Old driver API : call driver ioctl handler */
 	/* Old driver API : call driver ioctl handler */
 	if (dev->do_ioctl)
 	if (dev->do_ioctl)
@@ -1045,27 +1060,154 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
 	return -EOPNOTSUPP;
 	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)
 	if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
 	    && !capable(CAP_NET_ADMIN))
 	    && !capable(CAP_NET_ADMIN))
 		return -EPERM;
 		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);
 	dev_load(net, ifr->ifr_name);
 	rtnl_lock();
 	rtnl_lock();
-	ret = wireless_process_ioctl(net, ifr, cmd);
+	ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
 	rtnl_unlock();
 	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 -EFAULT;
+
 	return ret;
 	return ret;
 }
 }
+#endif
 
 
 /************************* EVENT PROCESSING *************************/
 /************************* EVENT PROCESSING *************************/
 /*
 /*