Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
28f49d8fec
84 changed files with 3421 additions and 4644 deletions
|
@ -1,89 +1,528 @@
|
|||
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. 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.
|
||||
|
||||
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 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
|
||||
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.
|
||||
|
||||
===============================================================================
|
||||
1: Implementation details
|
||||
2: Implementation details
|
||||
|
||||
The rfkill switch subsystem offers support for keys often found on laptops
|
||||
to enable wireless devices like WiFi and Bluetooth.
|
||||
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.
|
||||
|
||||
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.
|
||||
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 buttons to enable and disable the wireless radios are important in
|
||||
situations where the user is for example using his laptop on a location where
|
||||
wireless radios _must_ be disabled (e.g. airplanes).
|
||||
Because of this requirement, userspace support for the keys should not be
|
||||
made mandatory. Because userspace might want to perform some additional smarter
|
||||
tasks when the key is pressed, rfkill still provides userspace the possibility
|
||||
to take over the task to handle the key events.
|
||||
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 system inside the kernel has been split into 2 separate sections:
|
||||
1 - RFKILL
|
||||
2 - RFKILL_INPUT
|
||||
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.
|
||||
|
||||
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".
|
||||
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 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.
|
||||
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.
|
||||
|
||||
Please refer to the corner cases and examples section for more details.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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)
|
||||
|
||||
For polling drivers:
|
||||
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)...
|
||||
|
||||
- rfkill_allocate()
|
||||
- input_allocate_polled_device()
|
||||
- rfkill_register()
|
||||
- input_register_polled_device()
|
||||
On the other hand, some embedded devices do this:
|
||||
|
||||
When a key event has been detected, the correct event should be
|
||||
sent over the input device which has been registered by the driver.
|
||||
[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:
|
||||
====================================
|
||||
3: Userspace support
|
||||
|
||||
For each key an input device will be created which will send out the correct
|
||||
key event when the rfkill key has been pressed.
|
||||
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.
|
||||
|
||||
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()
|
||||
- modify rfkill fields (flags, name)
|
||||
- modify state to the current hardware state (THIS IS THE ONLY TIME
|
||||
YOU CAN ACCESS state DIRECTLY)
|
||||
- rfkill_register()
|
||||
|
||||
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().
|
||||
|
||||
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.
|
||||
|
||||
Please refer to the source for more documentation.
|
||||
|
||||
===============================================================================
|
||||
5: Userspace support
|
||||
|
||||
rfkill devices issue uevents (with an action of "change"), with the following
|
||||
environment variables set:
|
||||
|
||||
RFKILL_NAME
|
||||
RFKILL_STATE
|
||||
RFKILL_TYPE
|
||||
|
||||
The ABI for these variables is defined by the sysfs attributes. It is best
|
||||
to take a quick look at the source to make sure of the possible values.
|
||||
|
||||
It is expected that HAL will trap those, and bridge them to DBUS, etc. These
|
||||
events CAN and SHOULD be used to give feedback to the user about the rfkill
|
||||
status of the system.
|
||||
|
||||
Input devices may issue events that are related to rfkill. These are the
|
||||
various KEY_* events and SW_* events supported by rfkill-input.c.
|
||||
|
||||
******IMPORTANT******
|
||||
When rfkill-input is ACTIVE, userspace is NOT TO CHANGE THE STATE OF AN RFKILL
|
||||
SWITCH IN RESPONSE TO AN INPUT EVENT also handled by rfkill-input, unless it
|
||||
has set to true the user_claim attribute for that particular switch. This rule
|
||||
is *absolute*; do NOT violate it.
|
||||
******IMPORTANT******
|
||||
|
||||
Userspace must not assume it is the only source of control for rfkill switches.
|
||||
Their state CAN and WILL change due to firmware actions, direct user actions,
|
||||
and the rfkill-input EPO override for *_RFKILL_ALL.
|
||||
|
||||
When rfkill-input is not active, userspace must initiate a rfkill status
|
||||
change by writing to the "state" attribute in order for anything to happen.
|
||||
|
||||
Take particular care to implement EV_SW SW_RFKILL_ALL properly. When that
|
||||
switch is set to OFF, *every* rfkill device *MUST* be immediately put into the
|
||||
RFKILL_STATE_SOFT_BLOCKED state, no questions asked.
|
||||
|
||||
The following sysfs entries will be created:
|
||||
|
||||
name: Name assigned by driver to this key (interface or driver name).
|
||||
type: Name of the key type ("wlan", "bluetooth", etc).
|
||||
state: Current state of the key. 1: On, 0: Off.
|
||||
state: Current state of the transmitter
|
||||
0: RFKILL_STATE_SOFT_BLOCKED
|
||||
transmitter is forced off, but one can override it
|
||||
by a write to the state attribute;
|
||||
1: RFKILL_STATE_UNBLOCKED
|
||||
transmiter is NOT forced off, and may operate if
|
||||
all other conditions for such operation are met
|
||||
(such as interface is up and configured, etc);
|
||||
2: RFKILL_STATE_HARD_BLOCKED
|
||||
transmitter is forced off by something outside of
|
||||
the driver's control. One cannot set a device to
|
||||
this state through writes to the state attribute;
|
||||
claim: 1: Userspace handles events, 0: Kernel handles events
|
||||
|
||||
Both the "state" and "claim" entries are also writable. For the "state" entry
|
||||
this means that when 1 or 0 is written all radios, not yet in the requested
|
||||
state, will be will be toggled accordingly.
|
||||
this means that when 1 or 0 is written, the device rfkill state (if not yet in
|
||||
the requested state), will be will be toggled accordingly.
|
||||
|
||||
For the "claim" entry writing 1 to it means that the kernel no longer handles
|
||||
key events even though RFKILL_INPUT input was enabled. When "claim" has been
|
||||
set to 0, userspace should make sure that it listens for the input events or
|
||||
check the sysfs "state" entry regularly to correctly perform the required
|
||||
tasks when the rkfill key is pressed.
|
||||
check the sysfs "state" entry regularly to correctly perform the required tasks
|
||||
when the rkfill key is pressed.
|
||||
|
||||
A note about input devices and EV_SW events:
|
||||
|
||||
In order to know the current state of an input device switch (like
|
||||
SW_RFKILL_ALL), you will need to use an IOCTL. That information is not
|
||||
available through sysfs in a generic way at this time, and it is not available
|
||||
through the rfkill class AT ALL.
|
||||
|
|
|
@ -3854,10 +3854,6 @@ P: Ion Badulescu
|
|||
M: ionut@cs.columbia.edu
|
||||
S: Maintained
|
||||
|
||||
STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
|
||||
W: http://mosquitonet.Stanford.EDU/strip.html
|
||||
S: Unsupported ?
|
||||
|
||||
STRADIS MPEG-2 DECODER DRIVER
|
||||
P: Nathan Laredo
|
||||
M: laredo@gnu.org
|
||||
|
|
|
@ -148,9 +148,9 @@ static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
|
|||
unsigned long offset,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
dma_sync_single_range_for_device(sdev->dma_dev, dma_base,
|
||||
offset & dma_desc_align_mask,
|
||||
dma_desc_sync_size, dir);
|
||||
ssb_dma_sync_single_range_for_device(sdev, dma_base,
|
||||
offset & dma_desc_align_mask,
|
||||
dma_desc_sync_size, dir);
|
||||
}
|
||||
|
||||
static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
|
||||
|
@ -158,9 +158,9 @@ static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
|
|||
unsigned long offset,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
dma_sync_single_range_for_cpu(sdev->dma_dev, dma_base,
|
||||
offset & dma_desc_align_mask,
|
||||
dma_desc_sync_size, dir);
|
||||
ssb_dma_sync_single_range_for_cpu(sdev, dma_base,
|
||||
offset & dma_desc_align_mask,
|
||||
dma_desc_sync_size, dir);
|
||||
}
|
||||
|
||||
static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
|
||||
|
@ -613,10 +613,10 @@ static void b44_tx(struct b44 *bp)
|
|||
|
||||
BUG_ON(skb == NULL);
|
||||
|
||||
dma_unmap_single(bp->sdev->dma_dev,
|
||||
rp->mapping,
|
||||
skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
ssb_dma_unmap_single(bp->sdev,
|
||||
rp->mapping,
|
||||
skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
rp->skb = NULL;
|
||||
dev_kfree_skb_irq(skb);
|
||||
}
|
||||
|
@ -653,29 +653,29 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
|
|||
if (skb == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
|
||||
RX_PKT_BUF_SZ,
|
||||
DMA_FROM_DEVICE);
|
||||
mapping = ssb_dma_map_single(bp->sdev, skb->data,
|
||||
RX_PKT_BUF_SZ,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
/* Hardware bug work-around, the chip is unable to do PCI DMA
|
||||
to/from anything above 1GB :-( */
|
||||
if (dma_mapping_error(mapping) ||
|
||||
if (ssb_dma_mapping_error(bp->sdev, mapping) ||
|
||||
mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
|
||||
/* Sigh... */
|
||||
if (!dma_mapping_error(mapping))
|
||||
dma_unmap_single(bp->sdev->dma_dev, mapping,
|
||||
RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
|
||||
if (!ssb_dma_mapping_error(bp->sdev, mapping))
|
||||
ssb_dma_unmap_single(bp->sdev, mapping,
|
||||
RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
|
||||
if (skb == NULL)
|
||||
return -ENOMEM;
|
||||
mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
|
||||
RX_PKT_BUF_SZ,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(mapping) ||
|
||||
mapping = ssb_dma_map_single(bp->sdev, skb->data,
|
||||
RX_PKT_BUF_SZ,
|
||||
DMA_FROM_DEVICE);
|
||||
if (ssb_dma_mapping_error(bp->sdev, mapping) ||
|
||||
mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
|
||||
if (!dma_mapping_error(mapping))
|
||||
dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
|
||||
if (!ssb_dma_mapping_error(bp->sdev, mapping))
|
||||
ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -750,9 +750,9 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
|
|||
dest_idx * sizeof(dest_desc),
|
||||
DMA_BIDIRECTIONAL);
|
||||
|
||||
dma_sync_single_for_device(bp->sdev->dma_dev, le32_to_cpu(src_desc->addr),
|
||||
RX_PKT_BUF_SZ,
|
||||
DMA_FROM_DEVICE);
|
||||
ssb_dma_sync_single_for_device(bp->sdev, le32_to_cpu(src_desc->addr),
|
||||
RX_PKT_BUF_SZ,
|
||||
DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
static int b44_rx(struct b44 *bp, int budget)
|
||||
|
@ -772,7 +772,7 @@ static int b44_rx(struct b44 *bp, int budget)
|
|||
struct rx_header *rh;
|
||||
u16 len;
|
||||
|
||||
dma_sync_single_for_cpu(bp->sdev->dma_dev, map,
|
||||
ssb_dma_sync_single_for_cpu(bp->sdev, map,
|
||||
RX_PKT_BUF_SZ,
|
||||
DMA_FROM_DEVICE);
|
||||
rh = (struct rx_header *) skb->data;
|
||||
|
@ -806,8 +806,8 @@ static int b44_rx(struct b44 *bp, int budget)
|
|||
skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
|
||||
if (skb_size < 0)
|
||||
goto drop_it;
|
||||
dma_unmap_single(bp->sdev->dma_dev, map,
|
||||
skb_size, DMA_FROM_DEVICE);
|
||||
ssb_dma_unmap_single(bp->sdev, map,
|
||||
skb_size, DMA_FROM_DEVICE);
|
||||
/* Leave out rx_header */
|
||||
skb_put(skb, len + RX_PKT_OFFSET);
|
||||
skb_pull(skb, RX_PKT_OFFSET);
|
||||
|
@ -966,25 +966,25 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
|
||||
mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE);
|
||||
if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_30BIT_MASK) {
|
||||
struct sk_buff *bounce_skb;
|
||||
|
||||
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
|
||||
if (!dma_mapping_error(mapping))
|
||||
dma_unmap_single(bp->sdev->dma_dev, mapping, len,
|
||||
DMA_TO_DEVICE);
|
||||
if (!ssb_dma_mapping_error(bp->sdev, mapping))
|
||||
ssb_dma_unmap_single(bp->sdev, mapping, len,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
|
||||
if (!bounce_skb)
|
||||
goto err_out;
|
||||
|
||||
mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data,
|
||||
len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
|
||||
if (!dma_mapping_error(mapping))
|
||||
dma_unmap_single(bp->sdev->dma_dev, mapping,
|
||||
len, DMA_TO_DEVICE);
|
||||
mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data,
|
||||
len, DMA_TO_DEVICE);
|
||||
if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_30BIT_MASK) {
|
||||
if (!ssb_dma_mapping_error(bp->sdev, mapping))
|
||||
ssb_dma_unmap_single(bp->sdev, mapping,
|
||||
len, DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(bounce_skb);
|
||||
goto err_out;
|
||||
}
|
||||
|
@ -1082,8 +1082,8 @@ static void b44_free_rings(struct b44 *bp)
|
|||
|
||||
if (rp->skb == NULL)
|
||||
continue;
|
||||
dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ,
|
||||
DMA_FROM_DEVICE);
|
||||
ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ,
|
||||
DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(rp->skb);
|
||||
rp->skb = NULL;
|
||||
}
|
||||
|
@ -1094,8 +1094,8 @@ static void b44_free_rings(struct b44 *bp)
|
|||
|
||||
if (rp->skb == NULL)
|
||||
continue;
|
||||
dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(rp->skb);
|
||||
rp->skb = NULL;
|
||||
}
|
||||
|
@ -1117,14 +1117,14 @@ static void b44_init_rings(struct b44 *bp)
|
|||
memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
|
||||
|
||||
if (bp->flags & B44_FLAG_RX_RING_HACK)
|
||||
dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_BIDIRECTIONAL);
|
||||
ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_BIDIRECTIONAL);
|
||||
|
||||
if (bp->flags & B44_FLAG_TX_RING_HACK)
|
||||
dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_TO_DEVICE);
|
||||
ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
for (i = 0; i < bp->rx_pending; i++) {
|
||||
if (b44_alloc_rx_skb(bp, -1, i) < 0)
|
||||
|
@ -1144,25 +1144,27 @@ static void b44_free_consistent(struct b44 *bp)
|
|||
bp->tx_buffers = NULL;
|
||||
if (bp->rx_ring) {
|
||||
if (bp->flags & B44_FLAG_RX_RING_HACK) {
|
||||
dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_BIDIRECTIONAL);
|
||||
ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_BIDIRECTIONAL);
|
||||
kfree(bp->rx_ring);
|
||||
} else
|
||||
dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
|
||||
bp->rx_ring, bp->rx_ring_dma);
|
||||
ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
|
||||
bp->rx_ring, bp->rx_ring_dma,
|
||||
GFP_KERNEL);
|
||||
bp->rx_ring = NULL;
|
||||
bp->flags &= ~B44_FLAG_RX_RING_HACK;
|
||||
}
|
||||
if (bp->tx_ring) {
|
||||
if (bp->flags & B44_FLAG_TX_RING_HACK) {
|
||||
dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_TO_DEVICE);
|
||||
ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_TO_DEVICE);
|
||||
kfree(bp->tx_ring);
|
||||
} else
|
||||
dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
|
||||
bp->tx_ring, bp->tx_ring_dma);
|
||||
ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
|
||||
bp->tx_ring, bp->tx_ring_dma,
|
||||
GFP_KERNEL);
|
||||
bp->tx_ring = NULL;
|
||||
bp->flags &= ~B44_FLAG_TX_RING_HACK;
|
||||
}
|
||||
|
@ -1187,7 +1189,7 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
|
|||
goto out_err;
|
||||
|
||||
size = DMA_TABLE_BYTES;
|
||||
bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->rx_ring_dma, gfp);
|
||||
bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp);
|
||||
if (!bp->rx_ring) {
|
||||
/* Allocation may have failed due to pci_alloc_consistent
|
||||
insisting on use of GFP_DMA, which is more restrictive
|
||||
|
@ -1199,11 +1201,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
|
|||
if (!rx_ring)
|
||||
goto out_err;
|
||||
|
||||
rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_BIDIRECTIONAL);
|
||||
rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_BIDIRECTIONAL);
|
||||
|
||||
if (dma_mapping_error(rx_ring_dma) ||
|
||||
if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) ||
|
||||
rx_ring_dma + size > DMA_30BIT_MASK) {
|
||||
kfree(rx_ring);
|
||||
goto out_err;
|
||||
|
@ -1214,9 +1216,9 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
|
|||
bp->flags |= B44_FLAG_RX_RING_HACK;
|
||||
}
|
||||
|
||||
bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->tx_ring_dma, gfp);
|
||||
bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp);
|
||||
if (!bp->tx_ring) {
|
||||
/* Allocation may have failed due to dma_alloc_coherent
|
||||
/* Allocation may have failed due to ssb_dma_alloc_consistent
|
||||
insisting on use of GFP_DMA, which is more restrictive
|
||||
than necessary... */
|
||||
struct dma_desc *tx_ring;
|
||||
|
@ -1226,11 +1228,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
|
|||
if (!tx_ring)
|
||||
goto out_err;
|
||||
|
||||
tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring,
|
||||
tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring,
|
||||
DMA_TABLE_BYTES,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
if (dma_mapping_error(tx_ring_dma) ||
|
||||
if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) ||
|
||||
tx_ring_dma + size > DMA_30BIT_MASK) {
|
||||
kfree(tx_ring);
|
||||
goto out_err;
|
||||
|
|
|
@ -571,6 +571,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
|
|||
* independent format
|
||||
*/
|
||||
static char *gelic_wl_translate_scan(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
char *ev,
|
||||
char *stop,
|
||||
struct gelic_wl_scan_info *network)
|
||||
|
@ -588,26 +589,26 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN);
|
||||
ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_ADDR_LEN);
|
||||
ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
/* ESSID */
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.flags = 1;
|
||||
iwe.u.data.length = strnlen(scan->essid, 32);
|
||||
ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
|
||||
ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
|
||||
|
||||
/* FREQUENCY */
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = be16_to_cpu(scan->channel);
|
||||
iwe.u.freq.e = 0; /* table value in MHz */
|
||||
iwe.u.freq.i = 0;
|
||||
ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_FREQ_LEN);
|
||||
ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_FREQ_LEN);
|
||||
|
||||
/* RATES */
|
||||
iwe.cmd = SIOCGIWRATE;
|
||||
iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
|
||||
/* to stuff multiple values in one event */
|
||||
tmp = ev + IW_EV_LCP_LEN;
|
||||
tmp = ev + iwe_stream_lcp_len(info);
|
||||
/* put them in ascendant order (older is first) */
|
||||
i = 0;
|
||||
j = 0;
|
||||
|
@ -620,16 +621,16 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
|
|||
else
|
||||
rate = scan->rate[i++] & 0x7f;
|
||||
iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */
|
||||
tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
|
||||
tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
|
||||
IW_EV_PARAM_LEN);
|
||||
}
|
||||
while (j < network->rate_ext_len) {
|
||||
iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000;
|
||||
tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
|
||||
tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
|
||||
IW_EV_PARAM_LEN);
|
||||
}
|
||||
/* Check if we added any rate */
|
||||
if (IW_EV_LCP_LEN < (tmp - ev))
|
||||
if (iwe_stream_lcp_len(info) < (tmp - ev))
|
||||
ev = tmp;
|
||||
|
||||
/* ENCODE */
|
||||
|
@ -639,7 +640,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
|
||||
ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
|
||||
|
||||
/* MODE */
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
|
@ -649,7 +650,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
|
|||
iwe.u.mode = IW_MODE_MASTER;
|
||||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_UINT_LEN);
|
||||
ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_UINT_LEN);
|
||||
}
|
||||
|
||||
/* QUAL */
|
||||
|
@ -659,7 +660,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
|
|||
iwe.u.qual.level = be16_to_cpu(scan->rssi);
|
||||
iwe.u.qual.qual = be16_to_cpu(scan->rssi);
|
||||
iwe.u.qual.noise = 0;
|
||||
ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_QUAL_LEN);
|
||||
ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_QUAL_LEN);
|
||||
|
||||
/* RSN */
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -669,7 +670,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
|
|||
if (len) {
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = len;
|
||||
ev = iwe_stream_add_point(ev, stop, &iwe, buf);
|
||||
ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
|
||||
}
|
||||
} else {
|
||||
/* this scan info has IE data */
|
||||
|
@ -684,7 +685,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
|
|||
memcpy(buf, ie_info.wpa.data, ie_info.wpa.len);
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = ie_info.wpa.len;
|
||||
ev = iwe_stream_add_point(ev, stop, &iwe, buf);
|
||||
ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
|
||||
}
|
||||
|
||||
if (ie_info.rsn.len && (ie_info.rsn.len <= sizeof(buf))) {
|
||||
|
@ -692,7 +693,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
|
|||
memcpy(buf, ie_info.rsn.data, ie_info.rsn.len);
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = ie_info.rsn.len;
|
||||
ev = iwe_stream_add_point(ev, stop, &iwe, buf);
|
||||
ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -737,7 +738,8 @@ static int gelic_wl_get_scan(struct net_device *netdev,
|
|||
if (wl->scan_age == 0 ||
|
||||
time_after(scan_info->last_scanned + wl->scan_age,
|
||||
this_time))
|
||||
ev = gelic_wl_translate_scan(netdev, ev, stop,
|
||||
ev = gelic_wl_translate_scan(netdev, info,
|
||||
ev, stop,
|
||||
scan_info);
|
||||
else
|
||||
pr_debug("%s:entry too old\n", __func__);
|
||||
|
|
|
@ -14,30 +14,6 @@ config WLAN_PRE80211
|
|||
This option does not affect the kernel build, it only
|
||||
lets you choose drivers.
|
||||
|
||||
config STRIP
|
||||
tristate "STRIP (Metricom starmode radio IP)"
|
||||
depends on INET && WLAN_PRE80211
|
||||
select WIRELESS_EXT
|
||||
---help---
|
||||
Say Y if you have a Metricom radio and intend to use Starmode Radio
|
||||
IP. STRIP is a radio protocol developed for the MosquitoNet project
|
||||
(on the WWW at <http://mosquitonet.stanford.edu/>) to send Internet
|
||||
traffic using Metricom radios. Metricom radios are small, battery
|
||||
powered, 100kbit/sec packet radio transceivers, about the size and
|
||||
weight of a cellular telephone. (You may also have heard them called
|
||||
"Metricom modems" but we avoid the term "modem" because it misleads
|
||||
many people into thinking that you can plug a Metricom modem into a
|
||||
phone line and use it as a modem.)
|
||||
|
||||
You can use STRIP on any Linux machine with a serial port, although
|
||||
it is obviously most useful for people with laptop computers. If you
|
||||
think you might get a Metricom radio in the future, there is no harm
|
||||
in saying Y to STRIP now, except that it makes the kernel a bit
|
||||
bigger.
|
||||
|
||||
To compile this as a module, choose M here: the module will be
|
||||
called strip.
|
||||
|
||||
config ARLAN
|
||||
tristate "Aironet Arlan 655 & IC2200 DS support"
|
||||
depends on ISA && !64BIT && WLAN_PRE80211
|
||||
|
|
|
@ -6,7 +6,6 @@ obj-$(CONFIG_IPW2100) += ipw2100.o
|
|||
|
||||
obj-$(CONFIG_IPW2200) += ipw2200.o
|
||||
|
||||
obj-$(CONFIG_STRIP) += strip.o
|
||||
obj-$(CONFIG_ARLAN) += arlan.o
|
||||
|
||||
arlan-objs := arlan-main.o arlan-proc.o
|
||||
|
|
|
@ -1685,7 +1685,6 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
|
|||
static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct adm8211_tx_hdr *txhdr;
|
||||
u16 fc;
|
||||
size_t payload_len, hdrlen;
|
||||
int plcp, dur, len, plcp_signal, short_preamble;
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
@ -1696,8 +1695,7 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|||
plcp_signal = txrate->bitrate;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
|
||||
hdrlen = ieee80211_get_hdrlen(fc);
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
memcpy(skb->cb, skb->data, hdrlen);
|
||||
hdr = (struct ieee80211_hdr *)skb->cb;
|
||||
skb_pull(skb, hdrlen);
|
||||
|
@ -1711,8 +1709,6 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|||
txhdr->frame_control = hdr->frame_control;
|
||||
|
||||
len = hdrlen + payload_len + FCS_LEN;
|
||||
if (fc & IEEE80211_FCTL_PROTECTED)
|
||||
len += 8;
|
||||
|
||||
txhdr->frag = cpu_to_le16(0x0FFF);
|
||||
adm8211_calc_durations(&dur, &plcp, payload_len,
|
||||
|
@ -1730,9 +1726,6 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|||
if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
|
||||
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
|
||||
|
||||
if (fc & IEEE80211_FCTL_PROTECTED)
|
||||
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
|
||||
|
||||
txhdr->retry_limit = info->control.retry_limit;
|
||||
|
||||
adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
|
||||
|
|
|
@ -85,10 +85,10 @@ static struct pci_driver airo_driver = {
|
|||
|
||||
/* Include Wireless Extension definition and check version - Jean II */
|
||||
#include <linux/wireless.h>
|
||||
#define WIRELESS_SPY // enable iwspy support
|
||||
#include <net/iw_handler.h> // New driver API
|
||||
#define WIRELESS_SPY /* enable iwspy support */
|
||||
#include <net/iw_handler.h> /* New driver API */
|
||||
|
||||
#define CISCO_EXT // enable Cisco extensions
|
||||
#define CISCO_EXT /* enable Cisco extensions */
|
||||
#ifdef CISCO_EXT
|
||||
#include <linux/delay.h>
|
||||
#endif
|
||||
|
@ -281,7 +281,7 @@ MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc");
|
|||
/* This is a kind of sloppy hack to get this information to OUT4500 and
|
||||
IN4500. I would be extremely interested in the situation where this
|
||||
doesn't work though!!! */
|
||||
static int do8bitIO = 0;
|
||||
static int do8bitIO /* = 0 */;
|
||||
|
||||
/* Return codes */
|
||||
#define SUCCESS 0
|
||||
|
@ -398,8 +398,8 @@ static int do8bitIO = 0;
|
|||
#define MAXTXQ 64
|
||||
|
||||
/* BAP selectors */
|
||||
#define BAP0 0 // Used for receiving packets
|
||||
#define BAP1 2 // Used for xmiting packets and working with RIDS
|
||||
#define BAP0 0 /* Used for receiving packets */
|
||||
#define BAP1 2 /* Used for xmiting packets and working with RIDS */
|
||||
|
||||
/* Flags */
|
||||
#define COMMAND_BUSY 0x8000
|
||||
|
@ -5522,11 +5522,13 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
Cmd cmd;
|
||||
Resp rsp;
|
||||
|
||||
if ((ai->APList == NULL) &&
|
||||
(ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL)
|
||||
if (!ai->APList)
|
||||
ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL);
|
||||
if (!ai->APList)
|
||||
return -ENOMEM;
|
||||
if ((ai->SSID == NULL) &&
|
||||
(ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL)
|
||||
if (!ai->SSID)
|
||||
ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL);
|
||||
if (!ai->SSID)
|
||||
return -ENOMEM;
|
||||
readAPListRid(ai, ai->APList);
|
||||
readSsidRid(ai, ai->SSID);
|
||||
|
@ -5537,7 +5539,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
disable_MAC(ai, 0);
|
||||
netif_device_detach(dev);
|
||||
ai->power = state;
|
||||
cmd.cmd=HOSTSLEEP;
|
||||
cmd.cmd = HOSTSLEEP;
|
||||
issuecommand(ai, &cmd, &rsp);
|
||||
|
||||
pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
|
||||
|
@ -5567,7 +5569,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
|
|||
msleep(100);
|
||||
}
|
||||
|
||||
set_bit (FLAG_COMMIT, &ai->flags);
|
||||
set_bit(FLAG_COMMIT, &ai->flags);
|
||||
disable_MAC(ai, 0);
|
||||
msleep(200);
|
||||
if (ai->SSID) {
|
||||
|
@ -5594,9 +5596,6 @@ static int airo_pci_resume(struct pci_dev *pdev)
|
|||
static int __init airo_init_module( void )
|
||||
{
|
||||
int i;
|
||||
#if 0
|
||||
int have_isa_dev = 0;
|
||||
#endif
|
||||
|
||||
airo_entry = create_proc_entry("driver/aironet",
|
||||
S_IFDIR | airo_perm,
|
||||
|
@ -5607,15 +5606,11 @@ static int __init airo_init_module( void )
|
|||
airo_entry->gid = proc_gid;
|
||||
}
|
||||
|
||||
for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
|
||||
for (i = 0; i < 4 && io[i] && irq[i]; i++) {
|
||||
airo_print_info("", "Trying to configure ISA adapter at irq=%d "
|
||||
"io=0x%x", irq[i], io[i] );
|
||||
if (init_airo_card( irq[i], io[i], 0, NULL ))
|
||||
#if 0
|
||||
have_isa_dev = 1;
|
||||
#else
|
||||
/* do nothing */ ;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
@ -5661,7 +5656,7 @@ static void __exit airo_cleanup_module( void )
|
|||
|
||||
static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
|
||||
{
|
||||
if( !rssi_rid )
|
||||
if (!rssi_rid)
|
||||
return 0;
|
||||
|
||||
return (0x100 - rssi_rid[rssi].rssidBm);
|
||||
|
@ -5671,10 +5666,10 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
|
|||
{
|
||||
int i;
|
||||
|
||||
if( !rssi_rid )
|
||||
if (!rssi_rid)
|
||||
return 0;
|
||||
|
||||
for( i = 0; i < 256; i++ )
|
||||
for (i = 0; i < 256; i++)
|
||||
if (rssi_rid[i].rssidBm == dbm)
|
||||
return rssi_rid[i].rssipct;
|
||||
|
||||
|
@ -7156,6 +7151,7 @@ out:
|
|||
* format that the Wireless Tools will understand - Jean II
|
||||
*/
|
||||
static inline char *airo_translate_scan(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
char *current_ev,
|
||||
char *end_buf,
|
||||
BSSListRid *bss)
|
||||
|
@ -7172,7 +7168,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
/* Other entries will be displayed in the order we give them */
|
||||
|
||||
|
@ -7182,7 +7179,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
iwe.u.data.length = 32;
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->ssid);
|
||||
|
||||
/* Add mode */
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
|
@ -7192,7 +7190,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
iwe.u.mode = IW_MODE_MASTER;
|
||||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
}
|
||||
|
||||
/* Add frequency */
|
||||
|
@ -7203,7 +7202,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
*/
|
||||
iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000;
|
||||
iwe.u.freq.e = 1;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_FREQ_LEN);
|
||||
|
||||
dBm = le16_to_cpu(bss->dBm);
|
||||
|
||||
|
@ -7223,7 +7223,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
| IW_QUAL_DBM;
|
||||
}
|
||||
iwe.u.qual.noise = ai->wstats.qual.noise;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_QUAL_LEN);
|
||||
|
||||
/* Add encryption capability */
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
|
@ -7232,11 +7233,12 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->ssid);
|
||||
|
||||
/* Rate : stuffing multiple values in a single event require a bit
|
||||
* more of magic - Jean II */
|
||||
current_val = current_ev + IW_EV_LCP_LEN;
|
||||
current_val = current_ev + iwe_stream_lcp_len(info);
|
||||
|
||||
iwe.cmd = SIOCGIWRATE;
|
||||
/* Those two flags are ignored... */
|
||||
|
@ -7249,10 +7251,12 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
/* Bit rate given in 500 kb/s units (+ 0x80) */
|
||||
iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
|
||||
/* Add new value to event */
|
||||
current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
|
||||
current_val = iwe_stream_add_value(info, current_ev,
|
||||
current_val, end_buf,
|
||||
&iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
/* Check if we added any event */
|
||||
if((current_val - current_ev) > IW_EV_LCP_LEN)
|
||||
if ((current_val - current_ev) > iwe_stream_lcp_len(info))
|
||||
current_ev = current_val;
|
||||
|
||||
/* Beacon interval */
|
||||
|
@ -7261,7 +7265,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "bcn_int=%d", bss->beaconInterval);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
|
@ -7295,8 +7300,10 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = min(info_element->len + 2,
|
||||
MAX_WPA_IE_LEN);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
&iwe, (char *) info_element);
|
||||
current_ev = iwe_stream_add_point(
|
||||
info, current_ev,
|
||||
end_buf, &iwe,
|
||||
(char *) info_element);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -7304,8 +7311,9 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = min(info_element->len + 2,
|
||||
MAX_WPA_IE_LEN);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
&iwe, (char *) info_element);
|
||||
current_ev = iwe_stream_add_point(
|
||||
info, current_ev, end_buf,
|
||||
&iwe, (char *) info_element);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -7344,7 +7352,7 @@ static int airo_get_scan(struct net_device *dev,
|
|||
|
||||
list_for_each_entry (net, &ai->network_list, list) {
|
||||
/* Translate to WE format this entry */
|
||||
current_ev = airo_translate_scan(dev, current_ev,
|
||||
current_ev = airo_translate_scan(dev, info, current_ev,
|
||||
extra + dwrq->length,
|
||||
&net->bss);
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
config ATH5K
|
||||
tristate "Atheros 5xxx wireless cards support"
|
||||
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
|
||||
select MAC80211_LEDS
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros 5xxx chipset.
|
||||
|
|
|
@ -58,11 +58,6 @@
|
|||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
|
||||
enum {
|
||||
ATH_LED_TX,
|
||||
ATH_LED_RX,
|
||||
};
|
||||
|
||||
static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
|
||||
|
||||
|
||||
|
@ -309,13 +304,10 @@ static void ath5k_tasklet_reset(unsigned long data);
|
|||
|
||||
static void ath5k_calibrate(unsigned long data);
|
||||
/* LED functions */
|
||||
static void ath5k_led_off(unsigned long data);
|
||||
static void ath5k_led_blink(struct ath5k_softc *sc,
|
||||
unsigned int on,
|
||||
unsigned int off);
|
||||
static void ath5k_led_event(struct ath5k_softc *sc,
|
||||
int event);
|
||||
|
||||
static int ath5k_init_leds(struct ath5k_softc *sc);
|
||||
static void ath5k_led_enable(struct ath5k_softc *sc);
|
||||
static void ath5k_led_off(struct ath5k_softc *sc);
|
||||
static void ath5k_unregister_leds(struct ath5k_softc *sc);
|
||||
|
||||
/*
|
||||
* Module init/exit functions
|
||||
|
@ -596,8 +588,7 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
||||
struct ath5k_softc *sc = hw->priv;
|
||||
|
||||
if (test_bit(ATH_STAT_LEDSOFT, sc->status))
|
||||
ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1);
|
||||
ath5k_led_off(sc);
|
||||
|
||||
ath5k_stop_hw(sc);
|
||||
pci_save_state(pdev);
|
||||
|
@ -632,10 +623,7 @@ ath5k_pci_resume(struct pci_dev *pdev)
|
|||
pci_write_config_byte(pdev, 0x41, 0);
|
||||
|
||||
ath5k_init(sc);
|
||||
if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
|
||||
ath5k_hw_set_gpio_output(ah, sc->led_pin);
|
||||
ath5k_hw_set_gpio(ah, sc->led_pin, 0);
|
||||
}
|
||||
ath5k_led_enable(sc);
|
||||
|
||||
/*
|
||||
* Reset the key cache since some parts do not
|
||||
|
@ -742,27 +730,6 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
|||
tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
|
||||
tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
|
||||
setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
|
||||
setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc);
|
||||
|
||||
sc->led_on = 0; /* low true */
|
||||
/*
|
||||
* Auto-enable soft led processing for IBM cards and for
|
||||
* 5211 minipci cards.
|
||||
*/
|
||||
if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM ||
|
||||
pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
|
||||
__set_bit(ATH_STAT_LEDSOFT, sc->status);
|
||||
sc->led_pin = 0;
|
||||
}
|
||||
/* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
|
||||
if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
|
||||
__set_bit(ATH_STAT_LEDSOFT, sc->status);
|
||||
sc->led_pin = 0;
|
||||
}
|
||||
if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
|
||||
ath5k_hw_set_gpio_output(ah, sc->led_pin);
|
||||
ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
|
||||
}
|
||||
|
||||
ath5k_hw_get_lladdr(ah, mac);
|
||||
SET_IEEE80211_PERM_ADDR(hw, mac);
|
||||
|
@ -776,6 +743,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
|||
goto err_queues;
|
||||
}
|
||||
|
||||
ath5k_init_leds(sc);
|
||||
|
||||
return 0;
|
||||
err_queues:
|
||||
ath5k_txq_release(sc);
|
||||
|
@ -809,6 +778,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
|||
ath5k_desc_free(sc, pdev);
|
||||
ath5k_txq_release(sc);
|
||||
ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
|
||||
ath5k_unregister_leds(sc);
|
||||
|
||||
/*
|
||||
* NB: can't reclaim these until after ieee80211_ifdetach
|
||||
|
@ -1060,65 +1030,9 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: CLEAN THIS !!!
|
||||
*/
|
||||
static void
|
||||
ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
|
||||
{
|
||||
if (unlikely(test_bit(ATH_STAT_LEDSOFT, sc->status))) {
|
||||
/* from Atheros NDIS driver, w/ permission */
|
||||
static const struct {
|
||||
u16 rate; /* tx/rx 802.11 rate */
|
||||
u16 timeOn; /* LED on time (ms) */
|
||||
u16 timeOff; /* LED off time (ms) */
|
||||
} blinkrates[] = {
|
||||
{ 108, 40, 10 },
|
||||
{ 96, 44, 11 },
|
||||
{ 72, 50, 13 },
|
||||
{ 48, 57, 14 },
|
||||
{ 36, 67, 16 },
|
||||
{ 24, 80, 20 },
|
||||
{ 22, 100, 25 },
|
||||
{ 18, 133, 34 },
|
||||
{ 12, 160, 40 },
|
||||
{ 10, 200, 50 },
|
||||
{ 6, 240, 58 },
|
||||
{ 4, 267, 66 },
|
||||
{ 2, 400, 100 },
|
||||
{ 0, 500, 130 }
|
||||
};
|
||||
const struct ath5k_rate_table *rt =
|
||||
ath5k_hw_get_rate_table(sc->ah, mode);
|
||||
unsigned int i, j;
|
||||
|
||||
BUG_ON(rt == NULL);
|
||||
|
||||
memset(sc->hwmap, 0, sizeof(sc->hwmap));
|
||||
for (i = 0; i < 32; i++) {
|
||||
u8 ix = rt->rate_code_to_index[i];
|
||||
if (ix == 0xff) {
|
||||
sc->hwmap[i].ledon = msecs_to_jiffies(500);
|
||||
sc->hwmap[i].ledoff = msecs_to_jiffies(130);
|
||||
continue;
|
||||
}
|
||||
sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD;
|
||||
/* receive frames include FCS */
|
||||
sc->hwmap[i].rxflags = sc->hwmap[i].txflags |
|
||||
IEEE80211_RADIOTAP_F_FCS;
|
||||
/* setup blink rate table to avoid per-packet lookup */
|
||||
for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++)
|
||||
if (blinkrates[j].rate == /* XXX why 7f? */
|
||||
(rt->rates[ix].dot11_rate&0x7f))
|
||||
break;
|
||||
|
||||
sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j].
|
||||
timeOn);
|
||||
sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j].
|
||||
timeOff);
|
||||
}
|
||||
}
|
||||
|
||||
sc->curmode = mode;
|
||||
|
||||
if (mode == AR5K_MODE_11A) {
|
||||
|
@ -1691,9 +1605,9 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
|
|||
/* Apparently when a default key is used to decrypt the packet
|
||||
the hw does not set the index used to decrypt. In such cases
|
||||
get the index from the packet. */
|
||||
if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) &&
|
||||
!(rs->rs_status & AR5K_RXERR_DECRYPT) &&
|
||||
skb->len >= hlen + 4) {
|
||||
if (ieee80211_has_protected(hdr->frame_control) &&
|
||||
!(rs->rs_status & AR5K_RXERR_DECRYPT) &&
|
||||
skb->len >= hlen + 4) {
|
||||
keyix = skb->data[hlen + 3] >> 6;
|
||||
|
||||
if (test_bit(keyix, sc->keymap))
|
||||
|
@ -1712,10 +1626,7 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
|
|||
u32 hw_tu;
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
|
||||
if ((le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_FTYPE) ==
|
||||
IEEE80211_FTYPE_MGMT &&
|
||||
(le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) ==
|
||||
IEEE80211_STYPE_BEACON &&
|
||||
if (ieee80211_is_beacon(mgmt->frame_control) &&
|
||||
le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
|
||||
memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
|
||||
/*
|
||||
|
@ -1903,8 +1814,6 @@ accept:
|
|||
ath5k_check_ibss_tsf(sc, skb, &rxs);
|
||||
|
||||
__ieee80211_rx(sc->hw, skb, &rxs);
|
||||
sc->led_rxrate = rs.rs_rate;
|
||||
ath5k_led_event(sc, ATH_LED_RX);
|
||||
next:
|
||||
list_move_tail(&bf->list, &sc->rxbuf);
|
||||
} while (ath5k_rxbuf_setup(sc, bf) == 0);
|
||||
|
@ -1985,13 +1894,9 @@ ath5k_tasklet_tx(unsigned long data)
|
|||
struct ath5k_softc *sc = (void *)data;
|
||||
|
||||
ath5k_tx_processq(sc, sc->txq);
|
||||
|
||||
ath5k_led_event(sc, ATH_LED_TX);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************\
|
||||
* Beacon handling *
|
||||
\*****************/
|
||||
|
@ -2366,11 +2271,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
|
|||
ieee80211_stop_queues(sc->hw);
|
||||
|
||||
if (!test_bit(ATH_STAT_INVALID, sc->status)) {
|
||||
if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
|
||||
del_timer_sync(&sc->led_tim);
|
||||
ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
|
||||
__clear_bit(ATH_STAT_LEDBLINKING, sc->status);
|
||||
}
|
||||
ath5k_led_off(sc);
|
||||
ath5k_hw_set_intr(ah, 0);
|
||||
}
|
||||
ath5k_txq_cleanup(sc);
|
||||
|
@ -2566,54 +2467,123 @@ ath5k_calibrate(unsigned long data)
|
|||
\***************/
|
||||
|
||||
static void
|
||||
ath5k_led_off(unsigned long data)
|
||||
ath5k_led_enable(struct ath5k_softc *sc)
|
||||
{
|
||||
struct ath5k_softc *sc = (void *)data;
|
||||
|
||||
if (test_bit(ATH_STAT_LEDENDBLINK, sc->status))
|
||||
__clear_bit(ATH_STAT_LEDBLINKING, sc->status);
|
||||
else {
|
||||
__set_bit(ATH_STAT_LEDENDBLINK, sc->status);
|
||||
ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on);
|
||||
mod_timer(&sc->led_tim, jiffies + sc->led_off);
|
||||
if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
|
||||
ath5k_hw_set_gpio_output(sc->ah, sc->led_pin);
|
||||
ath5k_led_off(sc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Blink the LED according to the specified on/off times.
|
||||
*/
|
||||
static void
|
||||
ath5k_led_blink(struct ath5k_softc *sc, unsigned int on,
|
||||
unsigned int off)
|
||||
ath5k_led_on(struct ath5k_softc *sc)
|
||||
{
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off);
|
||||
ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
|
||||
__set_bit(ATH_STAT_LEDBLINKING, sc->status);
|
||||
__clear_bit(ATH_STAT_LEDENDBLINK, sc->status);
|
||||
sc->led_off = off;
|
||||
mod_timer(&sc->led_tim, jiffies + on);
|
||||
}
|
||||
|
||||
static void
|
||||
ath5k_led_event(struct ath5k_softc *sc, int event)
|
||||
{
|
||||
if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status)))
|
||||
if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
|
||||
return;
|
||||
if (unlikely(test_bit(ATH_STAT_LEDBLINKING, sc->status)))
|
||||
return; /* don't interrupt active blink */
|
||||
switch (event) {
|
||||
case ATH_LED_TX:
|
||||
ath5k_led_blink(sc, sc->hwmap[sc->led_txrate].ledon,
|
||||
sc->hwmap[sc->led_txrate].ledoff);
|
||||
break;
|
||||
case ATH_LED_RX:
|
||||
ath5k_led_blink(sc, sc->hwmap[sc->led_rxrate].ledon,
|
||||
sc->hwmap[sc->led_rxrate].ledoff);
|
||||
break;
|
||||
ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
|
||||
}
|
||||
|
||||
static void
|
||||
ath5k_led_off(struct ath5k_softc *sc)
|
||||
{
|
||||
if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
|
||||
return;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/********************\
|
||||
|
@ -2625,7 +2595,6 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
{
|
||||
struct ath5k_softc *sc = hw->priv;
|
||||
struct ath5k_buf *bf;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
unsigned long flags;
|
||||
int hdrlen;
|
||||
int pad;
|
||||
|
@ -2651,8 +2620,6 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
memmove(skb->data, skb->data+pad, hdrlen);
|
||||
}
|
||||
|
||||
sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value;
|
||||
|
||||
spin_lock_irqsave(&sc->txbuflock, flags);
|
||||
if (list_empty(&sc->txbuf)) {
|
||||
ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "debug.h"
|
||||
|
@ -79,6 +80,19 @@ struct ath5k_txq {
|
|||
bool setup;
|
||||
};
|
||||
|
||||
#define ATH5K_LED_MAX_NAME_LEN 31
|
||||
|
||||
/*
|
||||
* State for LED triggers
|
||||
*/
|
||||
struct ath5k_led
|
||||
{
|
||||
char name[ATH5K_LED_MAX_NAME_LEN + 1]; /* name of the LED in sysfs */
|
||||
struct ath5k_softc *sc; /* driver state */
|
||||
struct led_classdev led_dev; /* led classdev */
|
||||
};
|
||||
|
||||
|
||||
#if CHAN_DEBUG
|
||||
#define ATH_CHAN_MAX (26+26+26+200+200)
|
||||
#else
|
||||
|
@ -118,13 +132,11 @@ struct ath5k_softc {
|
|||
size_t desc_len; /* size of TX/RX descriptors */
|
||||
u16 cachelsz; /* cache line size */
|
||||
|
||||
DECLARE_BITMAP(status, 6);
|
||||
DECLARE_BITMAP(status, 4);
|
||||
#define ATH_STAT_INVALID 0 /* disable hardware accesses */
|
||||
#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */
|
||||
#define ATH_STAT_PROMISC 2
|
||||
#define ATH_STAT_LEDBLINKING 3 /* LED blink operation active */
|
||||
#define ATH_STAT_LEDENDBLINK 4 /* finish LED blink operation */
|
||||
#define ATH_STAT_LEDSOFT 5 /* enable LED gpio status */
|
||||
#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */
|
||||
|
||||
unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
|
||||
unsigned int curmode; /* current phy mode */
|
||||
|
@ -132,13 +144,6 @@ struct ath5k_softc {
|
|||
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
struct {
|
||||
u8 rxflags; /* radiotap rx flags */
|
||||
u8 txflags; /* radiotap tx flags */
|
||||
u16 ledon; /* softled on time */
|
||||
u16 ledoff; /* softled off time */
|
||||
} hwmap[32]; /* h/w rate ix mappings */
|
||||
|
||||
enum ath5k_int imask; /* interrupt mask copy */
|
||||
|
||||
DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */
|
||||
|
@ -148,9 +153,6 @@ struct ath5k_softc {
|
|||
unsigned int led_pin, /* GPIO pin for driving LED */
|
||||
led_on, /* pin setting for LED on */
|
||||
led_off; /* off time for current blink */
|
||||
struct timer_list led_tim; /* led off timer */
|
||||
u8 led_rxrate; /* current rx rate for LED */
|
||||
u8 led_txrate; /* current tx rate for LED */
|
||||
|
||||
struct tasklet_struct restq; /* reset tasklet */
|
||||
|
||||
|
@ -159,6 +161,7 @@ struct ath5k_softc {
|
|||
spinlock_t rxbuflock;
|
||||
u32 *rxlink; /* link ptr in last RX desc */
|
||||
struct tasklet_struct rxtq; /* rx intr tasklet */
|
||||
struct ath5k_led rx_led; /* rx led */
|
||||
|
||||
struct list_head txbuf; /* transmit buffer */
|
||||
spinlock_t txbuflock;
|
||||
|
@ -167,6 +170,7 @@ struct ath5k_softc {
|
|||
|
||||
struct ath5k_txq *txq; /* beacon and tx*/
|
||||
struct tasklet_struct txtq; /* tx intr tasklet */
|
||||
struct ath5k_led tx_led; /* tx led */
|
||||
|
||||
struct ath5k_buf *bbuf; /* beacon buffer */
|
||||
unsigned int bhalq, /* SW q for outgoing beacons */
|
||||
|
|
|
@ -31,14 +31,14 @@
|
|||
#include "base.h"
|
||||
#include "debug.h"
|
||||
|
||||
/*Rate tables*/
|
||||
/* Rate tables */
|
||||
static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A;
|
||||
static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B;
|
||||
static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G;
|
||||
static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO;
|
||||
static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR;
|
||||
|
||||
/*Prototypes*/
|
||||
/* Prototypes */
|
||||
static int ath5k_hw_nic_reset(struct ath5k_hw *, u32);
|
||||
static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool);
|
||||
static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
|
||||
|
|
|
@ -2310,30 +2310,40 @@ static int atmel_get_scan(struct net_device *dev,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6);
|
||||
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
iwe.u.data.length = priv->BSSinfo[i].SSIDsize;
|
||||
if (iwe.u.data.length > 32)
|
||||
iwe.u.data.length = 32;
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, priv->BSSinfo[i].SSID);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe, priv->BSSinfo[i].SSID);
|
||||
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
iwe.u.mode = priv->BSSinfo[i].BSStype;
|
||||
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = priv->BSSinfo[i].channel;
|
||||
iwe.u.freq.e = 0;
|
||||
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe, IW_EV_FREQ_LEN);
|
||||
|
||||
/* Add quality statistics */
|
||||
iwe.cmd = IWEVQUAL;
|
||||
iwe.u.qual.level = priv->BSSinfo[i].RSSI;
|
||||
iwe.u.qual.qual = iwe.u.qual.level;
|
||||
/* iwe.u.qual.noise = SOMETHING */
|
||||
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA , &iwe, IW_EV_QUAL_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe, IW_EV_QUAL_LEN);
|
||||
|
||||
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
|
@ -2342,7 +2352,9 @@ static int atmel_get_scan(struct net_device *dev,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe, NULL);
|
||||
}
|
||||
|
||||
/* Length of data */
|
||||
|
|
|
@ -441,6 +441,8 @@ enum {
|
|||
#define B43_FWPANIC_DIE 0 /* Firmware died. Don't auto-restart it. */
|
||||
#define B43_FWPANIC_RESTART 1 /* Firmware died. Schedule a controller reset. */
|
||||
|
||||
/* The firmware register that contains the watchdog counter. */
|
||||
#define B43_WATCHDOG_REG 1
|
||||
|
||||
/* Device specific rate values.
|
||||
* The actual values defined here are (rate_in_mbps * 2).
|
||||
|
|
|
@ -74,6 +74,299 @@ struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
|
|||
} while (0)
|
||||
|
||||
|
||||
/* 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;
|
||||
unsigned int routing, addr;
|
||||
u16 val;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int shm16read__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->shm16read_routing_next = routing;
|
||||
dev->dfsentry->shm16read_addr_next = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shm16write__write_file(struct b43_wldev *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int routing, addr, mask, set;
|
||||
u16 val;
|
||||
int res;
|
||||
unsigned long flags;
|
||||
|
||||
res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
|
||||
&routing, &addr, &mask, &set);
|
||||
if (res != 4)
|
||||
return -EINVAL;
|
||||
if (routing > B43_MAX_SHM_ROUTING)
|
||||
return -EADDRNOTAVAIL;
|
||||
if (addr > B43_MAX_SHM_ADDR)
|
||||
return -EADDRNOTAVAIL;
|
||||
if (routing == B43_SHM_SHARED) {
|
||||
if ((addr % 2) != 0)
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
if ((mask > 0xFFFF) || (set > 0xFFFF))
|
||||
return -E2BIG;
|
||||
|
||||
spin_lock_irqsave(&dev->wl->shm_lock, flags);
|
||||
if (mask == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = __b43_shm_read16(dev, routing, addr);
|
||||
val &= mask;
|
||||
val |= set;
|
||||
__b43_shm_write16(dev, routing, addr, val);
|
||||
spin_unlock_irqrestore(&dev->wl->shm_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t shm32read__read_file(struct b43_wldev *dev,
|
||||
char *buf, size_t bufsize)
|
||||
{
|
||||
ssize_t count = 0;
|
||||
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;
|
||||
|
||||
val = b43_shm_read32(dev, routing, addr);
|
||||
fappend("0x%08X\n", val);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int shm32read__write_file(struct b43_wldev *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int routing, addr;
|
||||
int res;
|
||||
|
||||
res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
|
||||
if (res != 2)
|
||||
return -EINVAL;
|
||||
if (routing > B43_MAX_SHM_ROUTING)
|
||||
return -EADDRNOTAVAIL;
|
||||
if (addr > B43_MAX_SHM_ADDR)
|
||||
return -EADDRNOTAVAIL;
|
||||
if (routing == B43_SHM_SHARED) {
|
||||
if ((addr % 2) != 0)
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
dev->dfsentry->shm32read_routing_next = routing;
|
||||
dev->dfsentry->shm32read_addr_next = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shm32write__write_file(struct b43_wldev *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int routing, addr, mask, set;
|
||||
u32 val;
|
||||
int res;
|
||||
unsigned long flags;
|
||||
|
||||
res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
|
||||
&routing, &addr, &mask, &set);
|
||||
if (res != 4)
|
||||
return -EINVAL;
|
||||
if (routing > B43_MAX_SHM_ROUTING)
|
||||
return -EADDRNOTAVAIL;
|
||||
if (addr > B43_MAX_SHM_ADDR)
|
||||
return -EADDRNOTAVAIL;
|
||||
if (routing == B43_SHM_SHARED) {
|
||||
if ((addr % 2) != 0)
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
|
||||
return -E2BIG;
|
||||
|
||||
spin_lock_irqsave(&dev->wl->shm_lock, flags);
|
||||
if (mask == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = __b43_shm_read32(dev, routing, addr);
|
||||
val &= mask;
|
||||
val |= set;
|
||||
__b43_shm_write32(dev, routing, addr, val);
|
||||
spin_unlock_irqrestore(&dev->wl->shm_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The biggest MMIO address that we allow access to from the debugfs files. */
|
||||
#define B43_MAX_MMIO_ACCESS (0xF00 - 1)
|
||||
|
||||
static ssize_t mmio16read__read_file(struct b43_wldev *dev,
|
||||
char *buf, size_t bufsize)
|
||||
{
|
||||
ssize_t count = 0;
|
||||
unsigned int addr;
|
||||
u16 val;
|
||||
|
||||
addr = dev->dfsentry->mmio16read_next;
|
||||
if (addr > B43_MAX_MMIO_ACCESS)
|
||||
return -EDESTADDRREQ;
|
||||
|
||||
val = b43_read16(dev, addr);
|
||||
fappend("0x%04X\n", val);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int mmio16read__write_file(struct b43_wldev *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int addr;
|
||||
int res;
|
||||
|
||||
res = sscanf(buf, "0x%X", &addr);
|
||||
if (res != 1)
|
||||
return -EINVAL;
|
||||
if (addr > B43_MAX_MMIO_ACCESS)
|
||||
return -EADDRNOTAVAIL;
|
||||
if ((addr % 2) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
dev->dfsentry->mmio16read_next = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmio16write__write_file(struct b43_wldev *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int addr, mask, set;
|
||||
int res;
|
||||
u16 val;
|
||||
|
||||
res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
|
||||
if (res != 3)
|
||||
return -EINVAL;
|
||||
if (addr > B43_MAX_MMIO_ACCESS)
|
||||
return -EADDRNOTAVAIL;
|
||||
if ((mask > 0xFFFF) || (set > 0xFFFF))
|
||||
return -E2BIG;
|
||||
if ((addr % 2) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (mask == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = b43_read16(dev, addr);
|
||||
val &= mask;
|
||||
val |= set;
|
||||
b43_write16(dev, addr, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t mmio32read__read_file(struct b43_wldev *dev,
|
||||
char *buf, size_t bufsize)
|
||||
{
|
||||
ssize_t count = 0;
|
||||
unsigned int addr;
|
||||
u32 val;
|
||||
|
||||
addr = dev->dfsentry->mmio32read_next;
|
||||
if (addr > B43_MAX_MMIO_ACCESS)
|
||||
return -EDESTADDRREQ;
|
||||
|
||||
val = b43_read32(dev, addr);
|
||||
fappend("0x%08X\n", val);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int mmio32read__write_file(struct b43_wldev *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int addr;
|
||||
int res;
|
||||
|
||||
res = sscanf(buf, "0x%X", &addr);
|
||||
if (res != 1)
|
||||
return -EINVAL;
|
||||
if (addr > B43_MAX_MMIO_ACCESS)
|
||||
return -EADDRNOTAVAIL;
|
||||
if ((addr % 4) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
dev->dfsentry->mmio32read_next = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmio32write__write_file(struct b43_wldev *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int addr, mask, set;
|
||||
int res;
|
||||
u32 val;
|
||||
|
||||
res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
|
||||
if (res != 3)
|
||||
return -EINVAL;
|
||||
if (addr > B43_MAX_MMIO_ACCESS)
|
||||
return -EADDRNOTAVAIL;
|
||||
if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
|
||||
return -E2BIG;
|
||||
if ((addr % 4) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (mask == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = b43_read32(dev, addr);
|
||||
val &= mask;
|
||||
val |= set;
|
||||
b43_write32(dev, addr, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wl->irq_lock is locked */
|
||||
static ssize_t tsf_read_file(struct b43_wldev *dev,
|
||||
char *buf, size_t bufsize)
|
||||
|
@ -102,42 +395,6 @@ static int tsf_write_file(struct b43_wldev *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* wl->irq_lock is locked */
|
||||
static ssize_t ucode_regs_read_file(struct b43_wldev *dev,
|
||||
char *buf, size_t bufsize)
|
||||
{
|
||||
ssize_t count = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
fappend("r%d = 0x%04x\n", i,
|
||||
b43_shm_read16(dev, B43_SHM_SCRATCH, i));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* wl->irq_lock is locked */
|
||||
static ssize_t shm_read_file(struct b43_wldev *dev,
|
||||
char *buf, size_t bufsize)
|
||||
{
|
||||
ssize_t count = 0;
|
||||
int i;
|
||||
u16 tmp;
|
||||
__le16 *le16buf = (__le16 *)buf;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t txstat_read_file(struct b43_wldev *dev,
|
||||
char *buf, size_t bufsize)
|
||||
{
|
||||
|
@ -496,9 +753,15 @@ out_unlock:
|
|||
.take_irqlock = _take_irqlock, \
|
||||
}
|
||||
|
||||
B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1);
|
||||
B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1);
|
||||
B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1);
|
||||
B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1);
|
||||
B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1);
|
||||
B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1);
|
||||
B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1);
|
||||
B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1);
|
||||
B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
|
||||
B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
|
||||
B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
|
||||
B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
|
||||
B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
|
||||
B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
|
||||
|
@ -538,6 +801,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev)
|
|||
add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
|
||||
add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
|
||||
add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
|
||||
add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
|
||||
|
||||
#undef add_dyn_dbg
|
||||
}
|
||||
|
@ -584,6 +848,13 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
|
|||
return;
|
||||
}
|
||||
|
||||
e->mmio16read_next = 0xFFFF; /* invalid address */
|
||||
e->mmio32read_next = 0xFFFF; /* invalid address */
|
||||
e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */
|
||||
e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */
|
||||
e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */
|
||||
e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */
|
||||
|
||||
#define ADD_FILE(name, mode) \
|
||||
do { \
|
||||
struct dentry *d; \
|
||||
|
@ -596,9 +867,15 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
|
|||
} while (0)
|
||||
|
||||
|
||||
ADD_FILE(shm16read, 0600);
|
||||
ADD_FILE(shm16write, 0200);
|
||||
ADD_FILE(shm32read, 0600);
|
||||
ADD_FILE(shm32write, 0200);
|
||||
ADD_FILE(mmio16read, 0600);
|
||||
ADD_FILE(mmio16write, 0200);
|
||||
ADD_FILE(mmio32read, 0600);
|
||||
ADD_FILE(mmio32write, 0200);
|
||||
ADD_FILE(tsf, 0600);
|
||||
ADD_FILE(ucode_regs, 0400);
|
||||
ADD_FILE(shm, 0400);
|
||||
ADD_FILE(txstat, 0400);
|
||||
ADD_FILE(txpower_g, 0600);
|
||||
ADD_FILE(restart, 0200);
|
||||
|
@ -620,9 +897,15 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)
|
|||
return;
|
||||
b43_remove_dynamic_debug(dev);
|
||||
|
||||
debugfs_remove(e->file_shm16read.dentry);
|
||||
debugfs_remove(e->file_shm16write.dentry);
|
||||
debugfs_remove(e->file_shm32read.dentry);
|
||||
debugfs_remove(e->file_shm32write.dentry);
|
||||
debugfs_remove(e->file_mmio16read.dentry);
|
||||
debugfs_remove(e->file_mmio16write.dentry);
|
||||
debugfs_remove(e->file_mmio32read.dentry);
|
||||
debugfs_remove(e->file_mmio32write.dentry);
|
||||
debugfs_remove(e->file_tsf.dentry);
|
||||
debugfs_remove(e->file_ucode_regs.dentry);
|
||||
debugfs_remove(e->file_shm.dentry);
|
||||
debugfs_remove(e->file_txstat.dentry);
|
||||
debugfs_remove(e->file_txpower_g.dentry);
|
||||
debugfs_remove(e->file_restart.dentry);
|
||||
|
|
|
@ -11,6 +11,7 @@ enum b43_dyndbg { /* Dynamic debugging features */
|
|||
B43_DBG_PWORK_FAST,
|
||||
B43_DBG_PWORK_STOP,
|
||||
B43_DBG_LO,
|
||||
B43_DBG_FIRMWARE,
|
||||
__B43_NR_DYNDBG,
|
||||
};
|
||||
|
||||
|
@ -36,9 +37,15 @@ struct b43_dfsentry {
|
|||
struct b43_wldev *dev;
|
||||
struct dentry *subdir;
|
||||
|
||||
struct b43_dfs_file file_shm16read;
|
||||
struct b43_dfs_file file_shm16write;
|
||||
struct b43_dfs_file file_shm32read;
|
||||
struct b43_dfs_file file_shm32write;
|
||||
struct b43_dfs_file file_mmio16read;
|
||||
struct b43_dfs_file file_mmio16write;
|
||||
struct b43_dfs_file file_mmio32read;
|
||||
struct b43_dfs_file file_mmio32write;
|
||||
struct b43_dfs_file file_tsf;
|
||||
struct b43_dfs_file file_ucode_regs;
|
||||
struct b43_dfs_file file_shm;
|
||||
struct b43_dfs_file file_txstat;
|
||||
struct b43_dfs_file file_txpower_g;
|
||||
struct b43_dfs_file file_restart;
|
||||
|
@ -46,6 +53,18 @@ struct b43_dfsentry {
|
|||
|
||||
struct b43_txstatus_log txstatlog;
|
||||
|
||||
/* The cached address for the next mmio16read file read */
|
||||
u16 mmio16read_next;
|
||||
/* The cached address for the next mmio32read file read */
|
||||
u16 mmio32read_next;
|
||||
|
||||
/* The cached address for the next shm16read file read */
|
||||
u32 shm16read_routing_next;
|
||||
u32 shm16read_addr_next;
|
||||
/* The cached address for the next shm32read file read */
|
||||
u32 shm32read_routing_next;
|
||||
u32 shm32read_addr_next;
|
||||
|
||||
/* Enabled/Disabled list for the dynamic debugging features. */
|
||||
u32 dyn_debug[__B43_NR_DYNDBG];
|
||||
/* Dentries for the dynamic debugging entries. */
|
||||
|
|
|
@ -328,11 +328,11 @@ static inline
|
|||
dma_addr_t dmaaddr;
|
||||
|
||||
if (tx) {
|
||||
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
|
||||
buf, len, DMA_TO_DEVICE);
|
||||
dmaaddr = ssb_dma_map_single(ring->dev->dev,
|
||||
buf, len, DMA_TO_DEVICE);
|
||||
} else {
|
||||
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
|
||||
buf, len, DMA_FROM_DEVICE);
|
||||
dmaaddr = ssb_dma_map_single(ring->dev->dev,
|
||||
buf, len, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
return dmaaddr;
|
||||
|
@ -343,11 +343,11 @@ static inline
|
|||
dma_addr_t addr, size_t len, int tx)
|
||||
{
|
||||
if (tx) {
|
||||
dma_unmap_single(ring->dev->dev->dma_dev,
|
||||
addr, len, DMA_TO_DEVICE);
|
||||
ssb_dma_unmap_single(ring->dev->dev,
|
||||
addr, len, DMA_TO_DEVICE);
|
||||
} else {
|
||||
dma_unmap_single(ring->dev->dev->dma_dev,
|
||||
addr, len, DMA_FROM_DEVICE);
|
||||
ssb_dma_unmap_single(ring->dev->dev,
|
||||
addr, len, DMA_FROM_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,8 +356,8 @@ static inline
|
|||
dma_addr_t addr, size_t len)
|
||||
{
|
||||
B43_WARN_ON(ring->tx);
|
||||
dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
|
||||
addr, len, DMA_FROM_DEVICE);
|
||||
ssb_dma_sync_single_for_cpu(ring->dev->dev,
|
||||
addr, len, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
static inline
|
||||
|
@ -365,8 +365,8 @@ static inline
|
|||
dma_addr_t addr, size_t len)
|
||||
{
|
||||
B43_WARN_ON(ring->tx);
|
||||
dma_sync_single_for_device(ring->dev->dev->dma_dev,
|
||||
addr, len, DMA_FROM_DEVICE);
|
||||
ssb_dma_sync_single_for_device(ring->dev->dev,
|
||||
addr, len, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
static inline
|
||||
|
@ -381,7 +381,6 @@ static inline
|
|||
|
||||
static int alloc_ringmemory(struct b43_dmaring *ring)
|
||||
{
|
||||
struct device *dma_dev = ring->dev->dev->dma_dev;
|
||||
gfp_t flags = GFP_KERNEL;
|
||||
|
||||
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
|
||||
|
@ -392,11 +391,14 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
|
|||
* For unknown reasons - possibly a hardware error - the BCM4311 rev
|
||||
* 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
|
||||
* which accounts for the GFP_DMA flag below.
|
||||
*
|
||||
* The flags here must match the flags in free_ringmemory below!
|
||||
*/
|
||||
if (ring->type == B43_DMA_64BIT)
|
||||
flags |= GFP_DMA;
|
||||
ring->descbase = dma_alloc_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
|
||||
&(ring->dmabase), flags);
|
||||
ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
|
||||
B43_DMA_RINGMEMSIZE,
|
||||
&(ring->dmabase), flags);
|
||||
if (!ring->descbase) {
|
||||
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
|
||||
return -ENOMEM;
|
||||
|
@ -408,10 +410,13 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
|
|||
|
||||
static void free_ringmemory(struct b43_dmaring *ring)
|
||||
{
|
||||
struct device *dma_dev = ring->dev->dev->dma_dev;
|
||||
gfp_t flags = GFP_KERNEL;
|
||||
|
||||
dma_free_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
|
||||
ring->descbase, ring->dmabase);
|
||||
if (ring->type == B43_DMA_64BIT)
|
||||
flags |= GFP_DMA;
|
||||
|
||||
ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
|
||||
ring->descbase, ring->dmabase, flags);
|
||||
}
|
||||
|
||||
/* Reset the RX DMA channel */
|
||||
|
@ -518,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
|
|||
dma_addr_t addr,
|
||||
size_t buffersize, bool dma_to_device)
|
||||
{
|
||||
if (unlikely(dma_mapping_error(addr)))
|
||||
if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
|
||||
return 1;
|
||||
|
||||
switch (ring->type) {
|
||||
|
@ -844,10 +849,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
|||
goto err_kfree_meta;
|
||||
|
||||
/* test for ability to dma to txhdr_cache */
|
||||
dma_test = dma_map_single(dev->dev->dma_dev,
|
||||
ring->txhdr_cache,
|
||||
b43_txhdr_size(dev),
|
||||
DMA_TO_DEVICE);
|
||||
dma_test = ssb_dma_map_single(dev->dev,
|
||||
ring->txhdr_cache,
|
||||
b43_txhdr_size(dev),
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
if (b43_dma_mapping_error(ring, dma_test,
|
||||
b43_txhdr_size(dev), 1)) {
|
||||
|
@ -859,10 +864,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
|||
if (!ring->txhdr_cache)
|
||||
goto err_kfree_meta;
|
||||
|
||||
dma_test = dma_map_single(dev->dev->dma_dev,
|
||||
ring->txhdr_cache,
|
||||
b43_txhdr_size(dev),
|
||||
DMA_TO_DEVICE);
|
||||
dma_test = ssb_dma_map_single(dev->dev,
|
||||
ring->txhdr_cache,
|
||||
b43_txhdr_size(dev),
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
if (b43_dma_mapping_error(ring, dma_test,
|
||||
b43_txhdr_size(dev), 1)) {
|
||||
|
@ -873,9 +878,9 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
|||
}
|
||||
}
|
||||
|
||||
dma_unmap_single(dev->dev->dma_dev,
|
||||
dma_test, b43_txhdr_size(dev),
|
||||
DMA_TO_DEVICE);
|
||||
ssb_dma_unmap_single(dev->dev,
|
||||
dma_test, b43_txhdr_size(dev),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
err = alloc_ringmemory(ring);
|
||||
|
|
|
@ -373,13 +373,10 @@ static inline void b43_shm_control_word(struct b43_wldev *dev,
|
|||
b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
|
||||
}
|
||||
|
||||
u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
|
||||
u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
unsigned long flags;
|
||||
u32 ret;
|
||||
|
||||
spin_lock_irqsave(&wl->shm_lock, flags);
|
||||
if (routing == B43_SHM_SHARED) {
|
||||
B43_WARN_ON(offset & 0x0001);
|
||||
if (offset & 0x0003) {
|
||||
|
@ -397,18 +394,26 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
|
|||
b43_shm_control_word(dev, routing, offset);
|
||||
ret = b43_read32(dev, B43_MMIO_SHM_DATA);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
unsigned long flags;
|
||||
u32 ret;
|
||||
|
||||
spin_lock_irqsave(&wl->shm_lock, flags);
|
||||
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 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
unsigned long flags;
|
||||
u16 ret;
|
||||
|
||||
spin_lock_irqsave(&wl->shm_lock, flags);
|
||||
if (routing == B43_SHM_SHARED) {
|
||||
B43_WARN_ON(offset & 0x0001);
|
||||
if (offset & 0x0003) {
|
||||
|
@ -423,17 +428,24 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
|
|||
b43_shm_control_word(dev, routing, offset);
|
||||
ret = b43_read16(dev, B43_MMIO_SHM_DATA);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
unsigned long flags;
|
||||
u16 ret;
|
||||
|
||||
spin_lock_irqsave(&wl->shm_lock, flags);
|
||||
ret = __b43_shm_read16(dev, routing, offset);
|
||||
spin_unlock_irqrestore(&wl->shm_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
|
||||
void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&wl->shm_lock, flags);
|
||||
if (routing == B43_SHM_SHARED) {
|
||||
B43_WARN_ON(offset & 0x0001);
|
||||
if (offset & 0x0003) {
|
||||
|
@ -443,35 +455,47 @@ void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
|
|||
(value >> 16) & 0xffff);
|
||||
b43_shm_control_word(dev, routing, (offset >> 2) + 1);
|
||||
b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
offset >>= 2;
|
||||
}
|
||||
b43_shm_control_word(dev, routing, offset);
|
||||
b43_write32(dev, B43_MMIO_SHM_DATA, value);
|
||||
out:
|
||||
}
|
||||
|
||||
void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&wl->shm_lock, flags);
|
||||
__b43_shm_write32(dev, routing, offset, value);
|
||||
spin_unlock_irqrestore(&wl->shm_lock, flags);
|
||||
}
|
||||
|
||||
void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
|
||||
{
|
||||
if (routing == B43_SHM_SHARED) {
|
||||
B43_WARN_ON(offset & 0x0001);
|
||||
if (offset & 0x0003) {
|
||||
/* Unaligned access */
|
||||
b43_shm_control_word(dev, routing, offset >> 2);
|
||||
b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
|
||||
return;
|
||||
}
|
||||
offset >>= 2;
|
||||
}
|
||||
b43_shm_control_word(dev, routing, offset);
|
||||
b43_write16(dev, B43_MMIO_SHM_DATA, value);
|
||||
}
|
||||
|
||||
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);
|
||||
if (routing == B43_SHM_SHARED) {
|
||||
B43_WARN_ON(offset & 0x0001);
|
||||
if (offset & 0x0003) {
|
||||
/* Unaligned access */
|
||||
b43_shm_control_word(dev, routing, offset >> 2);
|
||||
b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
|
||||
goto out;
|
||||
}
|
||||
offset >>= 2;
|
||||
}
|
||||
b43_shm_control_word(dev, routing, offset);
|
||||
b43_write16(dev, B43_MMIO_SHM_DATA, value);
|
||||
out:
|
||||
__b43_shm_write16(dev, routing, offset, value);
|
||||
spin_unlock_irqrestore(&wl->shm_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -2463,6 +2487,19 @@ static void b43_gpio_cleanup(struct b43_wldev *dev)
|
|||
/* http://bcm-specs.sipsolutions.net/EnableMac */
|
||||
void b43_mac_enable(struct b43_wldev *dev)
|
||||
{
|
||||
if (b43_debug(dev, B43_DBG_FIRMWARE)) {
|
||||
u16 fwstate;
|
||||
|
||||
fwstate = b43_shm_read16(dev, B43_SHM_SHARED,
|
||||
B43_SHM_SH_UCODESTAT);
|
||||
if ((fwstate != B43_SHM_SH_UCODESTAT_SUSP) &&
|
||||
(fwstate != B43_SHM_SH_UCODESTAT_SLEEP)) {
|
||||
b43err(dev->wl, "b43_mac_enable(): The firmware "
|
||||
"should be suspended, but current state is %u\n",
|
||||
fwstate);
|
||||
}
|
||||
}
|
||||
|
||||
dev->mac_suspended--;
|
||||
B43_WARN_ON(dev->mac_suspended < 0);
|
||||
if (dev->mac_suspended == 0) {
|
||||
|
@ -2783,6 +2820,21 @@ static void b43_periodic_every30sec(struct b43_wldev *dev)
|
|||
static void b43_periodic_every15sec(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
u16 wdr;
|
||||
|
||||
if (dev->fw.opensource) {
|
||||
/* Check if the firmware is still alive.
|
||||
* It will reset the watchdog counter to 0 in its idle loop. */
|
||||
wdr = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_WATCHDOG_REG);
|
||||
if (unlikely(wdr)) {
|
||||
b43err(dev->wl, "Firmware watchdog: The firmware died!\n");
|
||||
b43_controller_restart(dev, "Firmware watchdog");
|
||||
return;
|
||||
} else {
|
||||
b43_shm_write16(dev, B43_SHM_SCRATCH,
|
||||
B43_WATCHDOG_REG, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (phy->type == B43_PHYTYPE_G) {
|
||||
//TODO: update_aci_moving_average
|
||||
|
|
|
@ -95,9 +95,13 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
|
|||
void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
|
||||
|
||||
u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
|
||||
u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
|
||||
u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
|
||||
u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
|
||||
void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
|
||||
void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
|
||||
void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
|
||||
void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
|
||||
|
||||
u64 b43_hf_read(struct b43_wldev *dev);
|
||||
void b43_hf_write(struct b43_wldev *dev, u64 value);
|
||||
|
|
|
@ -586,7 +586,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
|
|||
|
||||
spin_lock(&q->lock); /* IRQs are already disabled. */
|
||||
|
||||
info = (void *)pack->skb;
|
||||
info = IEEE80211_SKB_CB(pack->skb);
|
||||
memset(&info->status, 0, sizeof(info->status));
|
||||
|
||||
b43_fill_txstatus_report(info, status);
|
||||
|
|
|
@ -88,7 +88,7 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
|
|||
goto out_unlock;
|
||||
err = 0;
|
||||
switch (state) {
|
||||
case RFKILL_STATE_ON:
|
||||
case RFKILL_STATE_UNBLOCKED:
|
||||
if (!dev->radio_hw_enable) {
|
||||
/* No luck. We can't toggle the hardware RF-kill
|
||||
* button from software. */
|
||||
|
@ -98,10 +98,13 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
|
|||
if (!dev->phy.radio_on)
|
||||
b43_radio_turn_on(dev);
|
||||
break;
|
||||
case RFKILL_STATE_OFF:
|
||||
case RFKILL_STATE_SOFT_BLOCKED:
|
||||
if (dev->phy.radio_on)
|
||||
b43_radio_turn_off(dev, 0);
|
||||
break;
|
||||
default:
|
||||
b43warn(wl, "Received unexpected rfkill state %d.\n", state);
|
||||
break;
|
||||
}
|
||||
out_unlock:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
|
|
@ -193,7 +193,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
|
|||
const struct ieee80211_hdr *wlhdr =
|
||||
(const struct ieee80211_hdr *)fragment_data;
|
||||
int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
|
||||
u16 fctl = le16_to_cpu(wlhdr->frame_control);
|
||||
__le16 fctl = wlhdr->frame_control;
|
||||
struct ieee80211_rate *fbrate;
|
||||
u8 rate, rate_fb;
|
||||
int rate_ofdm, rate_fb_ofdm;
|
||||
|
@ -259,7 +259,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
|
|||
B43_TXH_MAC_KEYIDX;
|
||||
mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
|
||||
B43_TXH_MAC_KEYALG;
|
||||
wlhdr_len = ieee80211_get_hdrlen(fctl);
|
||||
wlhdr_len = ieee80211_hdrlen(fctl);
|
||||
iv_len = min((size_t) info->control.iv_len,
|
||||
ARRAY_SIZE(txhdr->iv));
|
||||
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
|
||||
|
@ -317,8 +317,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
|
|||
/* MAC control */
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
mac_ctl |= B43_TXH_MAC_ACK;
|
||||
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
|
||||
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
|
||||
if (!ieee80211_is_pspoll(fctl))
|
||||
mac_ctl |= B43_TXH_MAC_HWSEQ;
|
||||
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
|
||||
mac_ctl |= B43_TXH_MAC_STMSDU;
|
||||
|
@ -509,7 +508,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
|||
struct b43_plcp_hdr6 *plcp;
|
||||
struct ieee80211_hdr *wlhdr;
|
||||
const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
|
||||
u16 fctl;
|
||||
__le16 fctl;
|
||||
u16 phystat0, phystat3, chanstat, mactime;
|
||||
u32 macstat;
|
||||
u16 chanid;
|
||||
|
@ -549,7 +548,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
|||
goto drop;
|
||||
}
|
||||
wlhdr = (struct ieee80211_hdr *)(skb->data);
|
||||
fctl = le16_to_cpu(wlhdr->frame_control);
|
||||
fctl = wlhdr->frame_control;
|
||||
|
||||
if (macstat & B43_RX_MAC_DEC) {
|
||||
unsigned int keyidx;
|
||||
|
@ -564,7 +563,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
|||
B43_WARN_ON(keyidx >= dev->max_nr_keys);
|
||||
|
||||
if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
|
||||
wlhdr_len = ieee80211_get_hdrlen(fctl);
|
||||
wlhdr_len = ieee80211_hdrlen(fctl);
|
||||
if (unlikely(skb->len < (wlhdr_len + 3))) {
|
||||
b43dbg(dev->wl,
|
||||
"RX: Packet size underrun (3)\n");
|
||||
|
@ -604,9 +603,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
|||
* of timestamp, i.e. about 65 milliseconds after the PHY received
|
||||
* the first symbol.
|
||||
*/
|
||||
if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
|
||||
== (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) ||
|
||||
dev->wl->radiotap_enabled) {
|
||||
if (ieee80211_is_beacon(fctl) || dev->wl->radiotap_enabled) {
|
||||
u16 low_mactime_now;
|
||||
|
||||
b43_tsf_read(dev, &status.mactime);
|
||||
|
|
|
@ -393,13 +393,13 @@ dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
|
|||
dma_addr_t dmaaddr;
|
||||
|
||||
if (tx)
|
||||
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
|
||||
buf, len,
|
||||
DMA_TO_DEVICE);
|
||||
dmaaddr = ssb_dma_map_single(ring->dev->dev,
|
||||
buf, len,
|
||||
DMA_TO_DEVICE);
|
||||
else
|
||||
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
|
||||
buf, len,
|
||||
DMA_FROM_DEVICE);
|
||||
dmaaddr = ssb_dma_map_single(ring->dev->dev,
|
||||
buf, len,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
return dmaaddr;
|
||||
}
|
||||
|
@ -411,13 +411,13 @@ void unmap_descbuffer(struct b43legacy_dmaring *ring,
|
|||
int tx)
|
||||
{
|
||||
if (tx)
|
||||
dma_unmap_single(ring->dev->dev->dma_dev,
|
||||
addr, len,
|
||||
DMA_TO_DEVICE);
|
||||
ssb_dma_unmap_single(ring->dev->dev,
|
||||
addr, len,
|
||||
DMA_TO_DEVICE);
|
||||
else
|
||||
dma_unmap_single(ring->dev->dev->dma_dev,
|
||||
addr, len,
|
||||
DMA_FROM_DEVICE);
|
||||
ssb_dma_unmap_single(ring->dev->dev,
|
||||
addr, len,
|
||||
DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
static inline
|
||||
|
@ -427,8 +427,8 @@ void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
|
|||
{
|
||||
B43legacy_WARN_ON(ring->tx);
|
||||
|
||||
dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
|
||||
addr, len, DMA_FROM_DEVICE);
|
||||
ssb_dma_sync_single_for_cpu(ring->dev->dev,
|
||||
addr, len, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
static inline
|
||||
|
@ -438,8 +438,8 @@ void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
|
|||
{
|
||||
B43legacy_WARN_ON(ring->tx);
|
||||
|
||||
dma_sync_single_for_device(ring->dev->dev->dma_dev,
|
||||
addr, len, DMA_FROM_DEVICE);
|
||||
ssb_dma_sync_single_for_device(ring->dev->dev,
|
||||
addr, len, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
static inline
|
||||
|
@ -458,10 +458,11 @@ void free_descriptor_buffer(struct b43legacy_dmaring *ring,
|
|||
|
||||
static int alloc_ringmemory(struct b43legacy_dmaring *ring)
|
||||
{
|
||||
struct device *dma_dev = ring->dev->dev->dma_dev;
|
||||
|
||||
ring->descbase = dma_alloc_coherent(dma_dev, B43legacy_DMA_RINGMEMSIZE,
|
||||
&(ring->dmabase), GFP_KERNEL);
|
||||
/* GFP flags must match the flags in free_ringmemory()! */
|
||||
ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
|
||||
B43legacy_DMA_RINGMEMSIZE,
|
||||
&(ring->dmabase),
|
||||
GFP_KERNEL);
|
||||
if (!ring->descbase) {
|
||||
b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
|
||||
" failed\n");
|
||||
|
@ -474,10 +475,8 @@ static int alloc_ringmemory(struct b43legacy_dmaring *ring)
|
|||
|
||||
static void free_ringmemory(struct b43legacy_dmaring *ring)
|
||||
{
|
||||
struct device *dma_dev = ring->dev->dev->dma_dev;
|
||||
|
||||
dma_free_coherent(dma_dev, B43legacy_DMA_RINGMEMSIZE,
|
||||
ring->descbase, ring->dmabase);
|
||||
ssb_dma_free_consistent(ring->dev->dev, B43legacy_DMA_RINGMEMSIZE,
|
||||
ring->descbase, ring->dmabase, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/* Reset the RX DMA channel */
|
||||
|
@ -589,7 +588,7 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
|
|||
size_t buffersize,
|
||||
bool dma_to_device)
|
||||
{
|
||||
if (unlikely(dma_mapping_error(addr)))
|
||||
if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
|
||||
return 1;
|
||||
|
||||
switch (ring->type) {
|
||||
|
@ -894,9 +893,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
|
|||
goto err_kfree_meta;
|
||||
|
||||
/* test for ability to dma to txhdr_cache */
|
||||
dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache,
|
||||
sizeof(struct b43legacy_txhdr_fw3),
|
||||
DMA_TO_DEVICE);
|
||||
dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache,
|
||||
sizeof(struct b43legacy_txhdr_fw3),
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
if (b43legacy_dma_mapping_error(ring, dma_test,
|
||||
sizeof(struct b43legacy_txhdr_fw3), 1)) {
|
||||
|
@ -908,7 +907,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
|
|||
if (!ring->txhdr_cache)
|
||||
goto err_kfree_meta;
|
||||
|
||||
dma_test = dma_map_single(dev->dev->dma_dev,
|
||||
dma_test = ssb_dma_map_single(dev->dev,
|
||||
ring->txhdr_cache,
|
||||
sizeof(struct b43legacy_txhdr_fw3),
|
||||
DMA_TO_DEVICE);
|
||||
|
@ -918,9 +917,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
|
|||
goto err_kfree_txhdr_cache;
|
||||
}
|
||||
|
||||
dma_unmap_single(dev->dev->dma_dev,
|
||||
dma_test, sizeof(struct b43legacy_txhdr_fw3),
|
||||
DMA_TO_DEVICE);
|
||||
ssb_dma_unmap_single(dev->dev, dma_test,
|
||||
sizeof(struct b43legacy_txhdr_fw3),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
ring->nr_slots = nr_slots;
|
||||
|
|
|
@ -90,7 +90,7 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
|
|||
goto out_unlock;
|
||||
err = 0;
|
||||
switch (state) {
|
||||
case RFKILL_STATE_ON:
|
||||
case RFKILL_STATE_UNBLOCKED:
|
||||
if (!dev->radio_hw_enable) {
|
||||
/* No luck. We can't toggle the hardware RF-kill
|
||||
* button from software. */
|
||||
|
@ -100,10 +100,14 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
|
|||
if (!dev->phy.radio_on)
|
||||
b43legacy_radio_turn_on(dev);
|
||||
break;
|
||||
case RFKILL_STATE_OFF:
|
||||
case RFKILL_STATE_SOFT_BLOCKED:
|
||||
if (dev->phy.radio_on)
|
||||
b43legacy_radio_turn_off(dev, 0);
|
||||
break;
|
||||
default:
|
||||
b43legacywarn(wl, "Received unexpected rfkill state %d.\n",
|
||||
state);
|
||||
break;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
|
|
|
@ -442,7 +442,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
|
|||
struct b43legacy_plcp_hdr6 *plcp;
|
||||
struct ieee80211_hdr *wlhdr;
|
||||
const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr;
|
||||
u16 fctl;
|
||||
__le16 fctl;
|
||||
u16 phystat0;
|
||||
u16 phystat3;
|
||||
u16 chanstat;
|
||||
|
@ -480,7 +480,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
|
|||
goto drop;
|
||||
}
|
||||
wlhdr = (struct ieee80211_hdr *)(skb->data);
|
||||
fctl = le16_to_cpu(wlhdr->frame_control);
|
||||
fctl = wlhdr->frame_control;
|
||||
|
||||
if ((macstat & B43legacy_RX_MAC_DEC) &&
|
||||
!(macstat & B43legacy_RX_MAC_DECERR)) {
|
||||
|
@ -499,11 +499,11 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
|
|||
|
||||
if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) {
|
||||
/* Remove PROTECTED flag to mark it as decrypted. */
|
||||
B43legacy_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED));
|
||||
fctl &= ~IEEE80211_FCTL_PROTECTED;
|
||||
wlhdr->frame_control = cpu_to_le16(fctl);
|
||||
B43legacy_WARN_ON(!ieee80211_has_protected(fctl));
|
||||
fctl &= ~cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
wlhdr->frame_control = fctl;
|
||||
|
||||
wlhdr_len = ieee80211_get_hdrlen(fctl);
|
||||
wlhdr_len = ieee80211_hdrlen(fctl);
|
||||
if (unlikely(skb->len < (wlhdr_len + 3))) {
|
||||
b43legacydbg(dev->wl, "RX: Packet size"
|
||||
" underrun3\n");
|
||||
|
@ -556,9 +556,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
|
|||
* of timestamp, i.e. about 65 milliseconds after the PHY received
|
||||
* the first symbol.
|
||||
*/
|
||||
if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
|
||||
== (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) ||
|
||||
dev->wl->radiotap_enabled) {
|
||||
if (ieee80211_is_beacon(fctl) || dev->wl->radiotap_enabled) {
|
||||
u16 low_mactime_now;
|
||||
|
||||
b43legacy_tsf_read(dev, &status.mactime);
|
||||
|
|
|
@ -67,7 +67,8 @@ void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
|
|||
int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
|
||||
struct iw_quality qual[], int buf_size,
|
||||
int aplist);
|
||||
int prism2_ap_translate_scan(struct net_device *dev, char *buffer);
|
||||
int prism2_ap_translate_scan(struct net_device *dev,
|
||||
struct iw_request_info *info, char *buffer);
|
||||
int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param);
|
||||
|
||||
|
||||
|
|
|
@ -2420,7 +2420,8 @@ int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
|
|||
|
||||
/* Translate our list of Access Points & Stations to a card independant
|
||||
* format that the Wireless Tools will understand - Jean II */
|
||||
int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
|
||||
int prism2_ap_translate_scan(struct net_device *dev,
|
||||
struct iw_request_info *info, char *buffer)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
|
@ -2449,8 +2450,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
|
|||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN);
|
||||
iwe.len = IW_EV_ADDR_LEN;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
IW_EV_ADDR_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
/* Use the mode to indicate if it's a station or
|
||||
* an Access Point */
|
||||
|
@ -2461,8 +2462,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
|
|||
else
|
||||
iwe.u.mode = IW_MODE_INFRA;
|
||||
iwe.len = IW_EV_UINT_LEN;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
IW_EV_UINT_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
|
||||
/* Some quality */
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -2477,8 +2478,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
|
|||
iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
|
||||
iwe.u.qual.updated = sta->last_rx_updated;
|
||||
iwe.len = IW_EV_QUAL_LEN;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
IW_EV_QUAL_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_QUAL_LEN);
|
||||
|
||||
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
|
||||
if (sta->ap) {
|
||||
|
@ -2486,8 +2487,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
|
|||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.length = sta->u.ap.ssid_len;
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
&iwe,
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
sta->u.ap.ssid);
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -2497,10 +2498,9 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
|
|||
IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
|
||||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
&iwe,
|
||||
sta->u.ap.ssid
|
||||
/* 0 byte memcpy */);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
sta->u.ap.ssid);
|
||||
|
||||
if (sta->u.ap.channel > 0 &&
|
||||
sta->u.ap.channel <= FREQ_COUNT) {
|
||||
|
@ -2510,7 +2510,7 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
|
|||
* 100000;
|
||||
iwe.u.freq.e = 1;
|
||||
current_ev = iwe_stream_add_event(
|
||||
current_ev, end_buf, &iwe,
|
||||
info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
}
|
||||
|
||||
|
@ -2519,8 +2519,8 @@ int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
|
|||
sprintf(buf, "beacon_interval=%d",
|
||||
sta->listen_interval);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf, &iwe, buf);
|
||||
}
|
||||
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
|
||||
|
||||
|
|
|
@ -1793,6 +1793,7 @@ static int prism2_ioctl_siwscan(struct net_device *dev,
|
|||
|
||||
#ifndef PRISM2_NO_STATION_MODES
|
||||
static char * __prism2_translate_scan(local_info_t *local,
|
||||
struct iw_request_info *info,
|
||||
struct hfa384x_hostscan_result *scan,
|
||||
struct hostap_bss_info *bss,
|
||||
char *current_ev, char *end_buf)
|
||||
|
@ -1823,7 +1824,7 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN);
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_ADDR_LEN);
|
||||
|
||||
/* Other entries will be displayed in the order we give them */
|
||||
|
@ -1832,7 +1833,8 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.length = ssid_len;
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, ssid);
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
|
@ -1847,8 +1849,8 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
iwe.u.mode = IW_MODE_MASTER;
|
||||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
IW_EV_UINT_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
}
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -1864,8 +1866,8 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
if (chan > 0) {
|
||||
iwe.u.freq.m = freq_list[chan - 1] * 100000;
|
||||
iwe.u.freq.e = 1;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_FREQ_LEN);
|
||||
}
|
||||
|
||||
if (scan) {
|
||||
|
@ -1884,8 +1886,8 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
| IW_QUAL_NOISE_UPDATED
|
||||
| IW_QUAL_QUAL_INVALID
|
||||
| IW_QUAL_DBM;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
IW_EV_QUAL_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_QUAL_LEN);
|
||||
}
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -1895,13 +1897,13 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, "");
|
||||
|
||||
/* TODO: add SuppRates into BSS table */
|
||||
if (scan) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWRATE;
|
||||
current_val = current_ev + IW_EV_LCP_LEN;
|
||||
current_val = current_ev + iwe_stream_lcp_len(info);
|
||||
pos = scan->sup_rates;
|
||||
for (i = 0; i < sizeof(scan->sup_rates); i++) {
|
||||
if (pos[i] == 0)
|
||||
|
@ -1909,11 +1911,11 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
/* Bit rate given in 500 kb/s units (+ 0x80) */
|
||||
iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000);
|
||||
current_val = iwe_stream_add_value(
|
||||
current_ev, current_val, end_buf, &iwe,
|
||||
info, current_ev, current_val, end_buf, &iwe,
|
||||
IW_EV_PARAM_LEN);
|
||||
}
|
||||
/* Check if we added any event */
|
||||
if ((current_val - current_ev) > IW_EV_LCP_LEN)
|
||||
if ((current_val - current_ev) > iwe_stream_lcp_len(info))
|
||||
current_ev = current_val;
|
||||
}
|
||||
|
||||
|
@ -1924,15 +1926,15 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
|
||||
buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
|
||||
buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
|
||||
if (local->last_scan_type == PRISM2_HOSTSCAN &&
|
||||
(capabilities & WLAN_CAPABILITY_IBSS)) {
|
||||
|
@ -1940,8 +1942,8 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "atim=%d", le16_to_cpu(scan->atim));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf, &iwe, buf);
|
||||
}
|
||||
}
|
||||
kfree(buf);
|
||||
|
@ -1950,16 +1952,16 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = bss->wpa_ie_len;
|
||||
current_ev = iwe_stream_add_point(
|
||||
current_ev, end_buf, &iwe, bss->wpa_ie);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->wpa_ie);
|
||||
}
|
||||
|
||||
if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = bss->rsn_ie_len;
|
||||
current_ev = iwe_stream_add_point(
|
||||
current_ev, end_buf, &iwe, bss->rsn_ie);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->rsn_ie);
|
||||
}
|
||||
|
||||
return current_ev;
|
||||
|
@ -1969,6 +1971,7 @@ static char * __prism2_translate_scan(local_info_t *local,
|
|||
/* Translate scan data returned from the card to a card independant
|
||||
* format that the Wireless Tools will understand - Jean II */
|
||||
static inline int prism2_translate_scan(local_info_t *local,
|
||||
struct iw_request_info *info,
|
||||
char *buffer, int buflen)
|
||||
{
|
||||
struct hfa384x_hostscan_result *scan;
|
||||
|
@ -1999,13 +2002,14 @@ static inline int prism2_translate_scan(local_info_t *local,
|
|||
if (memcmp(bss->bssid, scan->bssid, ETH_ALEN) == 0) {
|
||||
bss->included = 1;
|
||||
current_ev = __prism2_translate_scan(
|
||||
local, scan, bss, current_ev, end_buf);
|
||||
local, info, scan, bss, current_ev,
|
||||
end_buf);
|
||||
found++;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
current_ev = __prism2_translate_scan(
|
||||
local, scan, NULL, current_ev, end_buf);
|
||||
local, info, scan, NULL, current_ev, end_buf);
|
||||
}
|
||||
/* Check if there is space for one more entry */
|
||||
if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
|
||||
|
@ -2023,7 +2027,7 @@ static inline int prism2_translate_scan(local_info_t *local,
|
|||
bss = list_entry(ptr, struct hostap_bss_info, list);
|
||||
if (bss->included)
|
||||
continue;
|
||||
current_ev = __prism2_translate_scan(local, NULL, bss,
|
||||
current_ev = __prism2_translate_scan(local, info, NULL, bss,
|
||||
current_ev, end_buf);
|
||||
/* Check if there is space for one more entry */
|
||||
if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
|
||||
|
@ -2070,7 +2074,7 @@ static inline int prism2_ioctl_giwscan_sta(struct net_device *dev,
|
|||
}
|
||||
local->scan_timestamp = 0;
|
||||
|
||||
res = prism2_translate_scan(local, extra, data->length);
|
||||
res = prism2_translate_scan(local, info, extra, data->length);
|
||||
|
||||
if (res >= 0) {
|
||||
data->length = res;
|
||||
|
@ -2103,7 +2107,7 @@ static int prism2_ioctl_giwscan(struct net_device *dev,
|
|||
* Jean II */
|
||||
|
||||
/* Translate to WE format */
|
||||
res = prism2_ap_translate_scan(dev, extra);
|
||||
res = prism2_ap_translate_scan(dev, info, extra);
|
||||
if (res >= 0) {
|
||||
printk(KERN_DEBUG "Scan result translation succeeded "
|
||||
"(length=%d)\n", res);
|
||||
|
|
|
@ -8,7 +8,7 @@ config IWLCORE
|
|||
select MAC80211_LEDS if IWLWIFI_LEDS
|
||||
select LEDS_CLASS if IWLWIFI_LEDS
|
||||
select RFKILL if IWLWIFI_RFKILL
|
||||
select RFKILL_INPUT if IWLWIFI_RFKILL
|
||||
select RFKILL_INPUT if (IWLWIFI_RFKILL && INPUT)
|
||||
|
||||
config IWLWIFI_LEDS
|
||||
bool
|
||||
|
|
|
@ -54,17 +54,20 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
|
|||
mutex_lock(&priv->mutex);
|
||||
|
||||
switch (state) {
|
||||
case RFKILL_STATE_ON:
|
||||
case RFKILL_STATE_UNBLOCKED:
|
||||
iwl_radio_kill_sw_enable_radio(priv);
|
||||
/* if HW rf-kill is set dont allow ON state */
|
||||
if (iwl_is_rfkill(priv))
|
||||
err = -EBUSY;
|
||||
break;
|
||||
case RFKILL_STATE_OFF:
|
||||
case RFKILL_STATE_SOFT_BLOCKED:
|
||||
iwl_radio_kill_sw_disable_radio(priv);
|
||||
if (!iwl_is_rfkill(priv))
|
||||
err = -EBUSY;
|
||||
break;
|
||||
default:
|
||||
IWL_WARNING("we recieved unexpected RFKILL state %d\n", state);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
|
@ -95,6 +98,7 @@ int iwl_rfkill_init(struct iwl_priv *priv)
|
|||
priv->rfkill_mngr.rfkill->dev.class->suspend = NULL;
|
||||
priv->rfkill_mngr.rfkill->dev.class->resume = NULL;
|
||||
|
||||
#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
|
||||
priv->rfkill_mngr.input_dev = input_allocate_device();
|
||||
if (!priv->rfkill_mngr.input_dev) {
|
||||
IWL_ERROR("Unable to allocate rfkill input device.\n");
|
||||
|
@ -109,6 +113,7 @@ int iwl_rfkill_init(struct iwl_priv *priv)
|
|||
priv->rfkill_mngr.input_dev->dev.parent = device;
|
||||
priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit);
|
||||
#endif
|
||||
|
||||
ret = rfkill_register(priv->rfkill_mngr.rfkill);
|
||||
if (ret) {
|
||||
|
@ -116,11 +121,13 @@ int iwl_rfkill_init(struct iwl_priv *priv)
|
|||
goto free_input_dev;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
|
||||
ret = input_register_device(priv->rfkill_mngr.input_dev);
|
||||
if (ret) {
|
||||
IWL_ERROR("Unable to register rfkill input device: %d\n", ret);
|
||||
goto unregister_rfkill;
|
||||
}
|
||||
#endif
|
||||
|
||||
IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
|
||||
return ret;
|
||||
|
@ -130,8 +137,10 @@ unregister_rfkill:
|
|||
priv->rfkill_mngr.rfkill = NULL;
|
||||
|
||||
free_input_dev:
|
||||
#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
|
||||
input_free_device(priv->rfkill_mngr.input_dev);
|
||||
priv->rfkill_mngr.input_dev = NULL;
|
||||
#endif
|
||||
|
||||
freed_rfkill:
|
||||
if (priv->rfkill_mngr.rfkill != NULL)
|
||||
|
@ -147,13 +156,16 @@ EXPORT_SYMBOL(iwl_rfkill_init);
|
|||
void iwl_rfkill_unregister(struct iwl_priv *priv)
|
||||
{
|
||||
|
||||
#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE)
|
||||
if (priv->rfkill_mngr.input_dev)
|
||||
input_unregister_device(priv->rfkill_mngr.input_dev);
|
||||
input_free_device(priv->rfkill_mngr.input_dev);
|
||||
priv->rfkill_mngr.input_dev = NULL;
|
||||
#endif
|
||||
|
||||
if (priv->rfkill_mngr.rfkill)
|
||||
rfkill_unregister(priv->rfkill_mngr.rfkill);
|
||||
|
||||
priv->rfkill_mngr.input_dev = NULL;
|
||||
priv->rfkill_mngr.rfkill = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_rfkill_unregister);
|
||||
|
|
|
@ -776,8 +776,9 @@ out:
|
|||
#define MAX_CUSTOM_LEN 64
|
||||
|
||||
static inline char *lbs_translate_scan(struct lbs_private *priv,
|
||||
char *start, char *stop,
|
||||
struct bss_descriptor *bss)
|
||||
struct iw_request_info *info,
|
||||
char *start, char *stop,
|
||||
struct bss_descriptor *bss)
|
||||
{
|
||||
struct chan_freq_power *cfp;
|
||||
char *current_val; /* For rates */
|
||||
|
@ -801,24 +802,24 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
|
||||
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
|
||||
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
/* SSID */
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.flags = 1;
|
||||
iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE);
|
||||
start = iwe_stream_add_point(start, stop, &iwe, bss->ssid);
|
||||
start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
|
||||
|
||||
/* Mode */
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
iwe.u.mode = bss->mode;
|
||||
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
|
||||
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
|
||||
|
||||
/* Frequency */
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = (long)cfp->freq * 100000;
|
||||
iwe.u.freq.e = 1;
|
||||
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
|
||||
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
|
||||
|
||||
/* Add quality statistics */
|
||||
iwe.cmd = IWEVQUAL;
|
||||
|
@ -852,7 +853,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
|||
nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
|
||||
iwe.u.qual.level = CAL_RSSI(snr, nf);
|
||||
}
|
||||
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
|
||||
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
|
||||
|
||||
/* Add encryption capability */
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
|
@ -862,9 +863,9 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
|||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
}
|
||||
iwe.u.data.length = 0;
|
||||
start = iwe_stream_add_point(start, stop, &iwe, bss->ssid);
|
||||
start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
|
||||
|
||||
current_val = start + IW_EV_LCP_LEN;
|
||||
current_val = start + iwe_stream_lcp_len(info);
|
||||
|
||||
iwe.cmd = SIOCGIWRATE;
|
||||
iwe.u.bitrate.fixed = 0;
|
||||
|
@ -874,19 +875,19 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
|||
for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
|
||||
/* Bit rate given in 500 kb/s units */
|
||||
iwe.u.bitrate.value = bss->rates[j] * 500000;
|
||||
current_val = iwe_stream_add_value(start, current_val,
|
||||
stop, &iwe, IW_EV_PARAM_LEN);
|
||||
current_val = iwe_stream_add_value(info, start, current_val,
|
||||
stop, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
|
||||
&& !lbs_ssid_cmp(priv->curbssparams.ssid,
|
||||
priv->curbssparams.ssid_len,
|
||||
bss->ssid, bss->ssid_len)) {
|
||||
iwe.u.bitrate.value = 22 * 500000;
|
||||
current_val = iwe_stream_add_value(start, current_val,
|
||||
current_val = iwe_stream_add_value(info, start, current_val,
|
||||
stop, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
/* Check if we added any event */
|
||||
if((current_val - start) > IW_EV_LCP_LEN)
|
||||
if ((current_val - start) > iwe_stream_lcp_len(info))
|
||||
start = current_val;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -895,7 +896,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
|||
memcpy(buf, bss->wpa_ie, bss->wpa_ie_len);
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = bss->wpa_ie_len;
|
||||
start = iwe_stream_add_point(start, stop, &iwe, buf);
|
||||
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
|
||||
}
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -904,7 +905,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
|||
memcpy(buf, bss->rsn_ie, bss->rsn_ie_len);
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = bss->rsn_ie_len;
|
||||
start = iwe_stream_add_point(start, stop, &iwe, buf);
|
||||
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
|
||||
}
|
||||
|
||||
if (bss->mesh) {
|
||||
|
@ -915,7 +916,8 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
|||
p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");
|
||||
iwe.u.data.length = p - custom;
|
||||
if (iwe.u.data.length)
|
||||
start = iwe_stream_add_point(start, stop, &iwe, custom);
|
||||
start = iwe_stream_add_point(info, start, stop,
|
||||
&iwe, custom);
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -1036,7 +1038,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
|
|||
}
|
||||
|
||||
/* Translate to WE format this entry */
|
||||
next_ev = lbs_translate_scan(priv, ev, stop, iter_bss);
|
||||
next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss);
|
||||
if (next_ev == NULL)
|
||||
continue;
|
||||
ev = next_ev;
|
||||
|
|
|
@ -430,15 +430,16 @@ static int __init init_mac80211_hwsim(void)
|
|||
hwsim_radios[i] = hw;
|
||||
|
||||
data = hw->priv;
|
||||
data->dev = device_create(hwsim_class, NULL, 0, "hwsim%d", i);
|
||||
data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw,
|
||||
"hwsim%d", i);
|
||||
if (IS_ERR(data->dev)) {
|
||||
printk(KERN_DEBUG "mac80211_hwsim: device_create "
|
||||
printk(KERN_DEBUG
|
||||
"mac80211_hwsim: device_create_drvdata "
|
||||
"failed (%ld)\n", PTR_ERR(data->dev));
|
||||
err = -ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
data->dev->driver = &mac80211_hwsim_driver;
|
||||
dev_set_drvdata(data->dev, hw);
|
||||
|
||||
SET_IEEE80211_DEV(hw, data->dev);
|
||||
addr[3] = i >> 8;
|
||||
|
|
|
@ -4046,6 +4046,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
|
|||
* format that the Wireless Tools will understand - Jean II
|
||||
* Return message length or -errno for fatal errors */
|
||||
static inline char *orinoco_translate_scan(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
char *current_ev,
|
||||
char *end_buf,
|
||||
union hermes_scan_info *bss,
|
||||
|
@ -4062,7 +4063,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
/* Other entries will be displayed in the order we give them */
|
||||
|
||||
|
@ -4072,7 +4074,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
|
|||
iwe.u.data.length = 32;
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->a.essid);
|
||||
|
||||
/* Add mode */
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
|
@ -4082,7 +4085,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
|
|||
iwe.u.mode = IW_MODE_MASTER;
|
||||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
}
|
||||
|
||||
channel = bss->s.channel;
|
||||
|
@ -4091,7 +4095,7 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
|
|||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = channel_frequency[channel-1] * 100000;
|
||||
iwe.u.freq.e = 1;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf,
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_FREQ_LEN);
|
||||
}
|
||||
|
||||
|
@ -4106,7 +4110,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
|
|||
iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
|
||||
else
|
||||
iwe.u.qual.qual = 0;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_QUAL_LEN);
|
||||
|
||||
/* Add encryption capability */
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
|
@ -4115,7 +4120,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->a.essid);
|
||||
|
||||
/* Add EXTRA: Age to display seconds since last beacon/probe response
|
||||
* for given network. */
|
||||
|
@ -4126,11 +4132,12 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
|
|||
jiffies_to_msecs(jiffies - last_scanned));
|
||||
iwe.u.data.length = p - custom;
|
||||
if (iwe.u.data.length)
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, custom);
|
||||
|
||||
/* Bit rate is not available in Lucent/Agere firmwares */
|
||||
if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
|
||||
char *current_val = current_ev + IW_EV_LCP_LEN;
|
||||
char *current_val = current_ev + iwe_stream_lcp_len(info);
|
||||
int i;
|
||||
int step;
|
||||
|
||||
|
@ -4149,12 +4156,13 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
|
|||
break;
|
||||
/* Bit rate given in 500 kb/s units (+ 0x80) */
|
||||
iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000);
|
||||
current_val = iwe_stream_add_value(current_ev, current_val,
|
||||
current_val = iwe_stream_add_value(info, current_ev,
|
||||
current_val,
|
||||
end_buf, &iwe,
|
||||
IW_EV_PARAM_LEN);
|
||||
}
|
||||
/* Check if we added any event */
|
||||
if ((current_val - current_ev) > IW_EV_LCP_LEN)
|
||||
if ((current_val - current_ev) > iwe_stream_lcp_len(info))
|
||||
current_ev = current_val;
|
||||
}
|
||||
|
||||
|
@ -4190,7 +4198,7 @@ static int orinoco_ioctl_getscan(struct net_device *dev,
|
|||
|
||||
list_for_each_entry(bss, &priv->bss_list, list) {
|
||||
/* Translate to WE format this entry */
|
||||
current_ev = orinoco_translate_scan(dev, current_ev,
|
||||
current_ev = orinoco_translate_scan(dev, info, current_ev,
|
||||
extra + srq->length,
|
||||
&bss->bss,
|
||||
bss->last_scanned);
|
||||
|
|
|
@ -571,8 +571,9 @@ prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
|
|||
*/
|
||||
|
||||
static char *
|
||||
prism54_translate_bss(struct net_device *ndev, char *current_ev,
|
||||
char *end_buf, struct obj_bss *bss, char noise)
|
||||
prism54_translate_bss(struct net_device *ndev, struct iw_request_info *info,
|
||||
char *current_ev, char *end_buf, struct obj_bss *bss,
|
||||
char noise)
|
||||
{
|
||||
struct iw_event iwe; /* Temporary buffer */
|
||||
short cap;
|
||||
|
@ -584,8 +585,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
|
|||
memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
iwe.cmd = SIOCGIWAP;
|
||||
current_ev =
|
||||
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
/* The following entries will be displayed in the same order we give them */
|
||||
|
||||
|
@ -593,7 +594,7 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
|
|||
iwe.u.data.length = bss->ssid.length;
|
||||
iwe.u.data.flags = 1;
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->ssid.octets);
|
||||
|
||||
/* Capabilities */
|
||||
|
@ -610,9 +611,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
|
|||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
if (iwe.u.mode)
|
||||
current_ev =
|
||||
iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
IW_EV_UINT_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
|
||||
/* Encryption capability */
|
||||
if (cap & CAP_CRYPT)
|
||||
|
@ -621,14 +621,15 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
|
|||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, NULL);
|
||||
|
||||
/* Add frequency. (short) bss->channel is the frequency in MHz */
|
||||
iwe.u.freq.m = bss->channel;
|
||||
iwe.u.freq.e = 6;
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
current_ev =
|
||||
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_FREQ_LEN);
|
||||
|
||||
/* Add quality statistics */
|
||||
iwe.u.qual.level = bss->rssi;
|
||||
|
@ -636,20 +637,20 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
|
|||
/* do a simple SNR for quality */
|
||||
iwe.u.qual.qual = bss->rssi - noise;
|
||||
iwe.cmd = IWEVQUAL;
|
||||
current_ev =
|
||||
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_QUAL_LEN);
|
||||
|
||||
/* Add WPA/RSN Information Element, if any */
|
||||
wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
|
||||
if (wpa_ie_len > 0) {
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
&iwe, wpa_ie);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, wpa_ie);
|
||||
}
|
||||
/* Do the bitrates */
|
||||
{
|
||||
char * current_val = current_ev + IW_EV_LCP_LEN;
|
||||
char *current_val = current_ev + iwe_stream_lcp_len(info);
|
||||
int i;
|
||||
int mask;
|
||||
|
||||
|
@ -662,14 +663,14 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
|
|||
for(i = 0; i < sizeof(scan_rate_list); i++) {
|
||||
if(bss->rates & mask) {
|
||||
iwe.u.bitrate.value = (scan_rate_list[i] * 500000);
|
||||
current_val = iwe_stream_add_value(current_ev, current_val,
|
||||
end_buf, &iwe,
|
||||
IW_EV_PARAM_LEN);
|
||||
current_val = iwe_stream_add_value(
|
||||
info, current_ev, current_val,
|
||||
end_buf, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
mask <<= 1;
|
||||
}
|
||||
/* Check if we added any event */
|
||||
if ((current_val - current_ev) > IW_EV_LCP_LEN)
|
||||
if ((current_val - current_ev) > iwe_stream_lcp_len(info))
|
||||
current_ev = current_val;
|
||||
}
|
||||
|
||||
|
@ -710,7 +711,7 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
|
|||
|
||||
/* ok now, scan the list and translate its info */
|
||||
for (i = 0; i < (int) bsslist->nr; i++) {
|
||||
current_ev = prism54_translate_bss(ndev, current_ev,
|
||||
current_ev = prism54_translate_bss(ndev, info, current_ev,
|
||||
extra + dwrq->length,
|
||||
&(bsslist->bsslist[i]),
|
||||
noise);
|
||||
|
@ -2704,6 +2705,7 @@ prism2_ioctl_scan_req(struct net_device *ndev,
|
|||
struct prism2_hostapd_param *param)
|
||||
{
|
||||
islpci_private *priv = netdev_priv(ndev);
|
||||
struct iw_request_info info;
|
||||
int i, rvalue;
|
||||
struct obj_bsslist *bsslist;
|
||||
u32 noise = 0;
|
||||
|
@ -2727,9 +2729,12 @@ prism2_ioctl_scan_req(struct net_device *ndev,
|
|||
rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
|
||||
bsslist = r.ptr;
|
||||
|
||||
info.cmd = PRISM54_HOSTAPD;
|
||||
info.flags = 0;
|
||||
|
||||
/* ok now, scan the list and translate its info */
|
||||
for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
|
||||
current_ev = prism54_translate_bss(ndev, current_ev,
|
||||
current_ev = prism54_translate_bss(ndev, &info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&(bsslist->bsslist[i]),
|
||||
noise);
|
||||
|
|
|
@ -1648,7 +1648,9 @@ static int rndis_iw_set_scan(struct net_device *dev,
|
|||
|
||||
|
||||
static char *rndis_translate_scan(struct net_device *dev,
|
||||
char *cev, char *end_buf, struct ndis_80211_bssid_ex *bssid)
|
||||
struct iw_request_info *info, char *cev,
|
||||
char *end_buf,
|
||||
struct ndis_80211_bssid_ex *bssid)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
struct usbnet *usbdev = dev->priv;
|
||||
|
@ -1667,14 +1669,14 @@ static char *rndis_translate_scan(struct net_device *dev,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN);
|
||||
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN);
|
||||
cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
devdbg(usbdev, "SSID(%d) %s", le32_to_cpu(bssid->ssid.length),
|
||||
bssid->ssid.essid);
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.essid.length = le32_to_cpu(bssid->ssid.length);
|
||||
iwe.u.essid.flags = 1;
|
||||
cev = iwe_stream_add_point(cev, end_buf, &iwe, bssid->ssid.essid);
|
||||
cev = iwe_stream_add_point(info, cev, end_buf, &iwe, bssid->ssid.essid);
|
||||
|
||||
devdbg(usbdev, "MODE %d", le32_to_cpu(bssid->net_infra));
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
|
@ -1690,12 +1692,12 @@ static char *rndis_translate_scan(struct net_device *dev,
|
|||
iwe.u.mode = IW_MODE_AUTO;
|
||||
break;
|
||||
}
|
||||
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN);
|
||||
cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_UINT_LEN);
|
||||
|
||||
devdbg(usbdev, "FREQ %d kHz", le32_to_cpu(bssid->config.ds_config));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
dsconfig_to_freq(le32_to_cpu(bssid->config.ds_config), &iwe.u.freq);
|
||||
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN);
|
||||
cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_FREQ_LEN);
|
||||
|
||||
devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->rssi));
|
||||
iwe.cmd = IWEVQUAL;
|
||||
|
@ -1704,7 +1706,7 @@ static char *rndis_translate_scan(struct net_device *dev,
|
|||
iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
|
||||
| IW_QUAL_LEVEL_UPDATED
|
||||
| IW_QUAL_NOISE_INVALID;
|
||||
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN);
|
||||
cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_QUAL_LEN);
|
||||
|
||||
devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->privacy));
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
|
@ -1714,10 +1716,10 @@ static char *rndis_translate_scan(struct net_device *dev,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
|
||||
|
||||
cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL);
|
||||
cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL);
|
||||
|
||||
devdbg(usbdev, "RATES:");
|
||||
current_val = cev + IW_EV_LCP_LEN;
|
||||
current_val = cev + iwe_stream_lcp_len(info);
|
||||
iwe.cmd = SIOCGIWRATE;
|
||||
for (i = 0; i < sizeof(bssid->rates); i++) {
|
||||
if (bssid->rates[i] & 0x7f) {
|
||||
|
@ -1725,13 +1727,13 @@ static char *rndis_translate_scan(struct net_device *dev,
|
|||
((bssid->rates[i] & 0x7f) *
|
||||
500000);
|
||||
devdbg(usbdev, " %d", iwe.u.bitrate.value);
|
||||
current_val = iwe_stream_add_value(cev,
|
||||
current_val = iwe_stream_add_value(info, cev,
|
||||
current_val, end_buf, &iwe,
|
||||
IW_EV_PARAM_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
if ((current_val - cev) > IW_EV_LCP_LEN)
|
||||
if ((current_val - cev) > iwe_stream_lcp_len(info))
|
||||
cev = current_val;
|
||||
|
||||
beacon = le32_to_cpu(bssid->config.beacon_period);
|
||||
|
@ -1739,14 +1741,14 @@ static char *rndis_translate_scan(struct net_device *dev,
|
|||
iwe.cmd = IWEVCUSTOM;
|
||||
snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon);
|
||||
iwe.u.data.length = strlen(sbuf);
|
||||
cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf);
|
||||
cev = iwe_stream_add_point(info, cev, end_buf, &iwe, sbuf);
|
||||
|
||||
atim = le32_to_cpu(bssid->config.atim_window);
|
||||
devdbg(usbdev, "ATIM %d", atim);
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
snprintf(sbuf, sizeof(sbuf), "atim=%u", atim);
|
||||
iwe.u.data.length = strlen(sbuf);
|
||||
cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf);
|
||||
cev = iwe_stream_add_point(info, cev, end_buf, &iwe, sbuf);
|
||||
|
||||
ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies));
|
||||
ie_len = min(bssid_len - (int)sizeof(*bssid),
|
||||
|
@ -1760,7 +1762,7 @@ static char *rndis_translate_scan(struct net_device *dev,
|
|||
(ie->id == MFIE_TYPE_RSN) ? 2 : 1);
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN);
|
||||
cev = iwe_stream_add_point(cev, end_buf, &iwe,
|
||||
cev = iwe_stream_add_point(info, cev, end_buf, &iwe,
|
||||
(u8 *)ie);
|
||||
}
|
||||
|
||||
|
@ -1803,8 +1805,8 @@ static int rndis_iw_get_scan(struct net_device *dev,
|
|||
devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count);
|
||||
|
||||
while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
|
||||
cev = rndis_translate_scan(dev, cev, extra + IW_SCAN_MAX_DATA,
|
||||
bssid);
|
||||
cev = rndis_translate_scan(dev, info, cev,
|
||||
extra + IW_SCAN_MAX_DATA, bssid);
|
||||
bssid = (void *)bssid + bssid_len;
|
||||
bssid_len = le32_to_cpu(bssid->length);
|
||||
count--;
|
||||
|
|
|
@ -632,15 +632,15 @@ static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
|
|||
struct queue_entry *entry)
|
||||
{
|
||||
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
u32 word;
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 2, &word);
|
||||
rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
|
||||
entry->queue->data_size);
|
||||
rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len);
|
||||
rt2x00_desc_write(entry_priv->desc, 2, word);
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 1, &word);
|
||||
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
|
||||
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
|
||||
rt2x00_desc_write(entry_priv->desc, 1, word);
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 0, &word);
|
||||
|
@ -1012,7 +1012,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
|||
* Start writing the descriptor words.
|
||||
*/
|
||||
rt2x00_desc_read(entry_priv->desc, 1, &word);
|
||||
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
|
||||
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
|
||||
rt2x00_desc_write(entry_priv->desc, 1, word);
|
||||
|
||||
rt2x00_desc_read(txd, 2, &word);
|
||||
|
@ -1154,7 +1154,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
|
|||
}
|
||||
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
|
||||
|
||||
rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
|
||||
rt2x00lib_txdone(entry, &txdesc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1366,7 +1366,7 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
IEEE80211_HW_SIGNAL_DBM;
|
||||
rt2x00dev->hw->extra_tx_headroom = 0;
|
||||
|
||||
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
|
||||
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
|
||||
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
|
||||
rt2x00_eeprom_addr(rt2x00dev,
|
||||
EEPROM_MAC_ADDR_0));
|
||||
|
@ -1412,9 +1412,10 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
rt2400pci_probe_hw_mode(rt2x00dev);
|
||||
|
||||
/*
|
||||
* This device requires the atim queue
|
||||
* This device requires the atim queue and DMA-mapped skbs.
|
||||
*/
|
||||
__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
|
||||
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
|
||||
|
||||
/*
|
||||
* Set the rssi offset.
|
||||
|
@ -1526,7 +1527,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
* Write entire beacon with descriptor to register,
|
||||
* and kick the beacon generator.
|
||||
*/
|
||||
memcpy(entry_priv->data, skb->data, skb->len);
|
||||
rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
|
||||
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
|
||||
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
|
|
|
@ -727,10 +727,11 @@ static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
|
|||
struct queue_entry *entry)
|
||||
{
|
||||
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
u32 word;
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 1, &word);
|
||||
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
|
||||
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
|
||||
rt2x00_desc_write(entry_priv->desc, 1, word);
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 0, &word);
|
||||
|
@ -1171,7 +1172,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
|||
* Start writing the descriptor words.
|
||||
*/
|
||||
rt2x00_desc_read(entry_priv->desc, 1, &word);
|
||||
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
|
||||
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
|
||||
rt2x00_desc_write(entry_priv->desc, 1, word);
|
||||
|
||||
rt2x00_desc_read(txd, 2, &word);
|
||||
|
@ -1311,7 +1312,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
|
|||
}
|
||||
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
|
||||
|
||||
rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
|
||||
rt2x00lib_txdone(entry, &txdesc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1688,7 +1689,7 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
|
||||
rt2x00dev->hw->extra_tx_headroom = 0;
|
||||
|
||||
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
|
||||
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
|
||||
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
|
||||
rt2x00_eeprom_addr(rt2x00dev,
|
||||
EEPROM_MAC_ADDR_0));
|
||||
|
@ -1752,9 +1753,10 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
rt2500pci_probe_hw_mode(rt2x00dev);
|
||||
|
||||
/*
|
||||
* This device requires the atim queue
|
||||
* This device requires the atim queue and DMA-mapped skbs.
|
||||
*/
|
||||
__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
|
||||
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
|
||||
|
||||
/*
|
||||
* Set the rssi offset.
|
||||
|
@ -1842,7 +1844,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
* Write entire beacon with descriptor to register,
|
||||
* and kick the beacon generator.
|
||||
*/
|
||||
memcpy(entry_priv->data, skb->data, skb->len);
|
||||
rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
|
||||
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
|
||||
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
|
|
|
@ -1594,7 +1594,7 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
|
||||
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
|
||||
|
||||
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
|
||||
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
|
||||
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
|
||||
rt2x00_eeprom_addr(rt2x00dev,
|
||||
EEPROM_MAC_ADDR_0));
|
||||
|
@ -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)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
|
||||
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
|
||||
struct queue_entry_priv_usb_bcn *bcn_priv;
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
/*
|
||||
* Module information.
|
||||
*/
|
||||
#define DRV_VERSION "2.1.7"
|
||||
#define DRV_VERSION "2.1.8"
|
||||
#define DRV_PROJECT "http://rt2x00.serialmonkey.com"
|
||||
|
||||
/*
|
||||
|
@ -110,33 +110,6 @@
|
|||
#define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME )
|
||||
#define EIFS ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) )
|
||||
|
||||
/*
|
||||
* IEEE802.11 header defines
|
||||
*/
|
||||
static inline int is_rts_frame(u16 fc)
|
||||
{
|
||||
return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
|
||||
((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS));
|
||||
}
|
||||
|
||||
static inline int is_cts_frame(u16 fc)
|
||||
{
|
||||
return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
|
||||
((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS));
|
||||
}
|
||||
|
||||
static inline int is_probe_resp(u16 fc)
|
||||
{
|
||||
return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
|
||||
((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP));
|
||||
}
|
||||
|
||||
static inline int is_beacon(u16 fc)
|
||||
{
|
||||
return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
|
||||
((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON));
|
||||
}
|
||||
|
||||
/*
|
||||
* Chipset identification
|
||||
* The chipset on the device is composed of a RT and RF chip.
|
||||
|
@ -628,6 +601,7 @@ enum rt2x00_flags {
|
|||
DRIVER_REQUIRE_BEACON_GUARD,
|
||||
DRIVER_REQUIRE_ATIM_QUEUE,
|
||||
DRIVER_REQUIRE_SCHEDULED,
|
||||
DRIVER_REQUIRE_DMA,
|
||||
|
||||
/*
|
||||
* Driver configuration
|
||||
|
@ -652,11 +626,7 @@ struct rt2x00_dev {
|
|||
* When accessing this variable, the rt2x00dev_{pci,usb}
|
||||
* macro's should be used for correct typecasting.
|
||||
*/
|
||||
void *dev;
|
||||
#define rt2x00dev_pci(__dev) ( (struct pci_dev *)(__dev)->dev )
|
||||
#define rt2x00dev_usb(__dev) ( (struct usb_interface *)(__dev)->dev )
|
||||
#define rt2x00dev_usb_dev(__dev)\
|
||||
( (struct usb_device *)interface_to_usbdev(rt2x00dev_usb(__dev)) )
|
||||
struct device *dev;
|
||||
|
||||
/*
|
||||
* Callback functions.
|
||||
|
@ -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
|
||||
|
@ -985,26 +956,14 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
|
|||
struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
|
||||
enum queue_index index);
|
||||
|
||||
/**
|
||||
* rt2x00queue_index_inc - Index incrementation function
|
||||
* @queue: Queue (&struct data_queue) to perform the action on.
|
||||
* @index: Index type (&enum queue_index) to perform the action on.
|
||||
*
|
||||
* This function will increase the requested index on the queue,
|
||||
* it will grab the appropriate locks and handle queue overflow events by
|
||||
* resetting the index to the start of the queue.
|
||||
*/
|
||||
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
|
||||
|
||||
|
||||
/*
|
||||
* Interrupt context handlers.
|
||||
*/
|
||||
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00lib_txdone(struct queue_entry *entry,
|
||||
struct txdone_entry_desc *txdesc);
|
||||
void rt2x00lib_rxdone(struct queue_entry *entry,
|
||||
struct rxdone_entry_desc *rxdesc);
|
||||
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
||||
struct queue_entry *entry);
|
||||
|
||||
/*
|
||||
* mac80211 handlers.
|
||||
|
|
|
@ -469,12 +469,19 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
|
|||
static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = data;
|
||||
struct rt2x00_intf *intf = vif_to_intf(vif);
|
||||
|
||||
if (vif->type != IEEE80211_IF_TYPE_AP &&
|
||||
vif->type != IEEE80211_IF_TYPE_IBSS)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Clean up the beacon skb.
|
||||
*/
|
||||
rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
|
||||
intf->beacon->skb = NULL;
|
||||
|
||||
spin_lock(&intf->lock);
|
||||
intf->delayed_flags |= DELAYED_UPDATE_BEACON;
|
||||
spin_unlock(&intf->lock);
|
||||
|
@ -498,6 +505,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
|
|||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
|
||||
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
|
||||
|
||||
/*
|
||||
* Unmap the skb.
|
||||
*/
|
||||
rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
|
||||
|
||||
/*
|
||||
* Send frame to debugfs immediately, after this call is completed
|
||||
|
@ -546,39 +559,77 @@ void rt2x00lib_txdone(struct queue_entry *entry,
|
|||
ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
|
||||
else
|
||||
dev_kfree_skb_irq(entry->skb);
|
||||
|
||||
/*
|
||||
* Make this entry available for reuse.
|
||||
*/
|
||||
entry->skb = NULL;
|
||||
entry->flags = 0;
|
||||
|
||||
rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry);
|
||||
|
||||
__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
|
||||
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
|
||||
|
||||
/*
|
||||
* If the data queue was below the threshold before the txdone
|
||||
* handler we must make sure the packet queue in the mac80211 stack
|
||||
* is reenabled when the txdone handler has finished.
|
||||
*/
|
||||
if (!rt2x00queue_threshold(entry->queue))
|
||||
ieee80211_wake_queue(rt2x00dev->hw, qid);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
|
||||
|
||||
void rt2x00lib_rxdone(struct queue_entry *entry,
|
||||
struct rxdone_entry_desc *rxdesc)
|
||||
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
||||
struct queue_entry *entry)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct rxdone_entry_desc rxdesc;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
|
||||
unsigned int header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_hdr *hdr;
|
||||
const struct rt2x00_rate *rate;
|
||||
unsigned int header_size;
|
||||
unsigned int align;
|
||||
unsigned int i;
|
||||
int idx = -1;
|
||||
u16 fc;
|
||||
|
||||
/*
|
||||
* Allocate a new sk_buffer. If no new buffer available, drop the
|
||||
* received frame and reuse the existing buffer.
|
||||
*/
|
||||
skb = rt2x00queue_alloc_rxskb(rt2x00dev, entry);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Unmap the skb.
|
||||
*/
|
||||
rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
|
||||
|
||||
/*
|
||||
* Extract the RXD details.
|
||||
*/
|
||||
memset(&rxdesc, 0, sizeof(rxdesc));
|
||||
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
|
||||
|
||||
/*
|
||||
* The data behind the ieee80211 header must be
|
||||
* aligned on a 4 byte boundary.
|
||||
*/
|
||||
header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
|
||||
align = ((unsigned long)(entry->skb->data + header_size)) & 3;
|
||||
|
||||
if (align) {
|
||||
skb_push(entry->skb, align);
|
||||
/* Move entire frame in 1 command */
|
||||
memmove(entry->skb->data, entry->skb->data + align,
|
||||
rxdesc->size);
|
||||
rxdesc.size);
|
||||
}
|
||||
|
||||
/* Update data pointers, trim buffer to correct size */
|
||||
skb_trim(entry->skb, rxdesc->size);
|
||||
skb_trim(entry->skb, rxdesc.size);
|
||||
|
||||
/*
|
||||
* Update RX statistics.
|
||||
|
@ -587,10 +638,10 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
|
|||
for (i = 0; i < sband->n_bitrates; i++) {
|
||||
rate = rt2x00_get_rate(sband->bitrates[i].hw_value);
|
||||
|
||||
if (((rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) &&
|
||||
(rate->plcp == rxdesc->signal)) ||
|
||||
(!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) &&
|
||||
(rate->bitrate == rxdesc->signal))) {
|
||||
if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
|
||||
(rate->plcp == rxdesc.signal)) ||
|
||||
(!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
|
||||
(rate->bitrate == rxdesc.signal))) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
|
@ -598,8 +649,8 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
|
|||
|
||||
if (idx < 0) {
|
||||
WARNING(rt2x00dev, "Frame received with unrecognized signal,"
|
||||
"signal=0x%.2x, plcp=%d.\n", rxdesc->signal,
|
||||
!!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP));
|
||||
"signal=0x%.2x, plcp=%d.\n", rxdesc.signal,
|
||||
!!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP));
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
|
@ -607,17 +658,17 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
|
|||
* Only update link status if this is a beacon frame carrying our bssid.
|
||||
*/
|
||||
hdr = (struct ieee80211_hdr *)entry->skb->data;
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
if (is_beacon(fc) && (rxdesc->dev_flags & RXDONE_MY_BSS))
|
||||
rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc->rssi);
|
||||
if (ieee80211_is_beacon(hdr->frame_control) &&
|
||||
(rxdesc.dev_flags & RXDONE_MY_BSS))
|
||||
rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi);
|
||||
|
||||
rt2x00dev->link.qual.rx_success++;
|
||||
|
||||
rx_status->rate_idx = idx;
|
||||
rx_status->qual =
|
||||
rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi);
|
||||
rx_status->signal = rxdesc->rssi;
|
||||
rx_status->flag = rxdesc->flags;
|
||||
rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc.rssi);
|
||||
rx_status->signal = rxdesc.rssi;
|
||||
rx_status->flag = rxdesc.flags;
|
||||
rx_status->antenna = rt2x00dev->link.ant.active.rx;
|
||||
|
||||
/*
|
||||
|
@ -626,7 +677,16 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
|
|||
*/
|
||||
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
|
||||
ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
|
||||
entry->skb = NULL;
|
||||
|
||||
/*
|
||||
* Replace the skb with the freshly allocated one.
|
||||
*/
|
||||
entry->skb = skb;
|
||||
entry->flags = 0;
|
||||
|
||||
rt2x00dev->ops->lib->init_rxentry(rt2x00dev, entry);
|
||||
|
||||
rt2x00queue_index_inc(entry->queue, Q_INDEX);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
|
||||
|
||||
|
|
|
@ -98,10 +98,57 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
|
|||
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_conf *conf, const int force_config);
|
||||
|
||||
/*
|
||||
* Queue handlers.
|
||||
/**
|
||||
* DOC: Queue handlers
|
||||
*/
|
||||
|
||||
/**
|
||||
* rt2x00queue_alloc_rxskb - allocate a skb for RX purposes.
|
||||
* @rt2x00dev: Pointer to &struct rt2x00_dev.
|
||||
* @queue: The queue for which the skb will be applicable.
|
||||
*/
|
||||
struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
|
||||
struct queue_entry *entry);
|
||||
|
||||
/**
|
||||
* rt2x00queue_unmap_skb - Unmap a skb from DMA.
|
||||
* @rt2x00dev: Pointer to &struct rt2x00_dev.
|
||||
* @skb: The skb to unmap.
|
||||
*/
|
||||
void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* rt2x00queue_free_skb - free a skb
|
||||
* @rt2x00dev: Pointer to &struct rt2x00_dev.
|
||||
* @skb: The skb to free.
|
||||
*/
|
||||
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* rt2x00queue_free_skb - free a skb
|
||||
* @rt2x00dev: Pointer to &struct rt2x00_dev.
|
||||
* @skb: The skb to free.
|
||||
*/
|
||||
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* rt2x00queue_write_tx_frame - Write TX frame to hardware
|
||||
* @queue: Queue over which the frame should be send
|
||||
* @skb: The skb to send
|
||||
*/
|
||||
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* rt2x00queue_index_inc - Index incrementation function
|
||||
* @queue: Queue (&struct data_queue) to perform the action on.
|
||||
* @index: Index type (&enum queue_index) to perform the action on.
|
||||
*
|
||||
* This function will increase the requested index on the queue,
|
||||
* it will grab the appropriate locks and handle queue overflow events by
|
||||
* resetting the index to the start of the queue.
|
||||
*/
|
||||
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
|
||||
|
||||
void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev);
|
||||
int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);
|
||||
|
|
|
@ -60,12 +60,8 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry)
|
|||
* Fill in skb descriptor
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(entry->skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->desc = entry_priv->desc;
|
||||
skbdesc->desc_len = entry->queue->desc_size;
|
||||
skbdesc->entry = entry;
|
||||
|
||||
memcpy(entry_priv->data, entry->skb->data, entry->skb->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -80,7 +76,6 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
|
|||
struct queue_entry *entry;
|
||||
struct queue_entry_priv_pci *entry_priv;
|
||||
struct skb_frame_desc *skbdesc;
|
||||
struct rxdone_entry_desc rxdesc;
|
||||
u32 word;
|
||||
|
||||
while (1) {
|
||||
|
@ -91,110 +86,27 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
|
|||
if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
|
||||
break;
|
||||
|
||||
memset(&rxdesc, 0, sizeof(rxdesc));
|
||||
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
|
||||
|
||||
/*
|
||||
* Allocate the sk_buffer and copy all data into it.
|
||||
*/
|
||||
entry->skb = rt2x00queue_alloc_rxskb(queue);
|
||||
if (!entry->skb)
|
||||
return;
|
||||
|
||||
memcpy(entry->skb->data, entry_priv->data, rxdesc.size);
|
||||
skb_trim(entry->skb, rxdesc.size);
|
||||
|
||||
/*
|
||||
* Fill in skb descriptor
|
||||
* Fill in desc fields of the skb descriptor
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(entry->skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->desc = entry_priv->desc;
|
||||
skbdesc->desc_len = queue->desc_size;
|
||||
skbdesc->entry = entry;
|
||||
skbdesc->desc_len = entry->queue->desc_size;
|
||||
|
||||
/*
|
||||
* Send the frame to rt2x00lib for further processing.
|
||||
*/
|
||||
rt2x00lib_rxdone(entry, &rxdesc);
|
||||
|
||||
if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) {
|
||||
rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
|
||||
rt2x00_desc_write(entry_priv->desc, 0, word);
|
||||
}
|
||||
|
||||
rt2x00queue_index_inc(queue, Q_INDEX);
|
||||
rt2x00lib_rxdone(rt2x00dev, entry);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
|
||||
|
||||
void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
|
||||
struct txdone_entry_desc *txdesc)
|
||||
{
|
||||
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
|
||||
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
|
||||
u32 word;
|
||||
|
||||
rt2x00lib_txdone(entry, txdesc);
|
||||
|
||||
/*
|
||||
* Make this entry available for reuse.
|
||||
*/
|
||||
entry->flags = 0;
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 0, &word);
|
||||
rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0);
|
||||
rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0);
|
||||
rt2x00_desc_write(entry_priv->desc, 0, word);
|
||||
|
||||
__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
|
||||
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
|
||||
|
||||
/*
|
||||
* If the data queue was below the threshold before the txdone
|
||||
* handler we must make sure the packet queue in the mac80211 stack
|
||||
* is reenabled when the txdone handler has finished.
|
||||
*/
|
||||
if (!rt2x00queue_threshold(entry->queue))
|
||||
ieee80211_wake_queue(rt2x00dev->hw, qid);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
|
||||
|
||||
/*
|
||||
* Device initialization handlers.
|
||||
*/
|
||||
#define desc_size(__queue) \
|
||||
({ \
|
||||
((__queue)->limit * (__queue)->desc_size);\
|
||||
})
|
||||
|
||||
#define data_size(__queue) \
|
||||
({ \
|
||||
((__queue)->limit * (__queue)->data_size);\
|
||||
})
|
||||
|
||||
#define dma_size(__queue) \
|
||||
({ \
|
||||
data_size(__queue) + desc_size(__queue);\
|
||||
})
|
||||
|
||||
#define desc_offset(__queue, __base, __i) \
|
||||
({ \
|
||||
(__base) + data_size(__queue) + \
|
||||
((__i) * (__queue)->desc_size); \
|
||||
})
|
||||
|
||||
#define data_offset(__queue, __base, __i) \
|
||||
({ \
|
||||
(__base) + \
|
||||
((__i) * (__queue)->data_size); \
|
||||
})
|
||||
|
||||
static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
|
||||
struct data_queue *queue)
|
||||
{
|
||||
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
|
||||
struct queue_entry_priv_pci *entry_priv;
|
||||
void *addr;
|
||||
dma_addr_t dma;
|
||||
|
@ -203,21 +115,21 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
|
|||
/*
|
||||
* Allocate DMA memory for descriptor and buffer.
|
||||
*/
|
||||
addr = pci_alloc_consistent(pci_dev, dma_size(queue), &dma);
|
||||
addr = dma_alloc_coherent(rt2x00dev->dev,
|
||||
queue->limit * queue->desc_size,
|
||||
&dma, GFP_KERNEL | GFP_DMA);
|
||||
if (!addr)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(addr, 0, dma_size(queue));
|
||||
memset(addr, 0, queue->limit * queue->desc_size);
|
||||
|
||||
/*
|
||||
* Initialize all queue entries to contain valid addresses.
|
||||
*/
|
||||
for (i = 0; i < queue->limit; i++) {
|
||||
entry_priv = queue->entries[i].priv_data;
|
||||
entry_priv->desc = desc_offset(queue, addr, i);
|
||||
entry_priv->desc_dma = desc_offset(queue, dma, i);
|
||||
entry_priv->data = data_offset(queue, addr, i);
|
||||
entry_priv->data_dma = data_offset(queue, dma, i);
|
||||
entry_priv->desc = addr + i * queue->desc_size;
|
||||
entry_priv->desc_dma = dma + i * queue->desc_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -226,19 +138,19 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
|
|||
static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
|
||||
struct data_queue *queue)
|
||||
{
|
||||
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
|
||||
struct queue_entry_priv_pci *entry_priv =
|
||||
queue->entries[0].priv_data;
|
||||
|
||||
if (entry_priv->data)
|
||||
pci_free_consistent(pci_dev, dma_size(queue),
|
||||
entry_priv->data, entry_priv->data_dma);
|
||||
entry_priv->data = NULL;
|
||||
if (entry_priv->desc)
|
||||
dma_free_coherent(rt2x00dev->dev,
|
||||
queue->limit * queue->desc_size,
|
||||
entry_priv->desc, entry_priv->desc_dma);
|
||||
entry_priv->desc = NULL;
|
||||
}
|
||||
|
||||
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
|
||||
struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
|
||||
struct data_queue *queue;
|
||||
int status;
|
||||
|
||||
|
@ -279,7 +191,7 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
|
|||
/*
|
||||
* Free irq line.
|
||||
*/
|
||||
free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev);
|
||||
free_irq(to_pci_dev(rt2x00dev->dev)->irq, rt2x00dev);
|
||||
|
||||
/*
|
||||
* Free DMA
|
||||
|
@ -308,7 +220,7 @@ static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
|
|||
|
||||
static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
|
||||
struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
|
||||
|
||||
rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0),
|
||||
pci_resource_len(pci_dev, 0));
|
||||
|
@ -357,7 +269,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
|
|||
if (pci_set_mwi(pci_dev))
|
||||
ERROR_PROBE("MWI not available.\n");
|
||||
|
||||
if (pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
|
||||
if (dma_set_mask(&pci_dev->dev, DMA_32BIT_MASK)) {
|
||||
ERROR_PROBE("PCI DMA not supported.\n");
|
||||
retval = -EIO;
|
||||
goto exit_disable_device;
|
||||
|
@ -373,7 +285,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
|
|||
pci_set_drvdata(pci_dev, hw);
|
||||
|
||||
rt2x00dev = hw->priv;
|
||||
rt2x00dev->dev = pci_dev;
|
||||
rt2x00dev->dev = &pci_dev->dev;
|
||||
rt2x00dev->ops = ops;
|
||||
rt2x00dev->hw = hw;
|
||||
|
||||
|
|
|
@ -107,9 +107,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry);
|
|||
struct queue_entry_priv_pci {
|
||||
__le32 *desc;
|
||||
dma_addr_t desc_dma;
|
||||
|
||||
void *data;
|
||||
dma_addr_t data_dma;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -118,15 +115,6 @@ struct queue_entry_priv_pci {
|
|||
*/
|
||||
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
|
||||
|
||||
/**
|
||||
* rt2x00pci_txdone - Handle TX done events
|
||||
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
|
||||
* @entry: Entry which has completed the transmission of a frame.
|
||||
* @desc: TX done descriptor
|
||||
*/
|
||||
void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
|
||||
struct txdone_entry_desc *desc);
|
||||
|
||||
/*
|
||||
* Device initialization handlers.
|
||||
*/
|
||||
|
|
|
@ -25,34 +25,30 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "rt2x00.h"
|
||||
#include "rt2x00lib.h"
|
||||
|
||||
struct sk_buff *rt2x00queue_alloc_rxskb(struct data_queue *queue)
|
||||
struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
|
||||
struct queue_entry *entry)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
unsigned int frame_size;
|
||||
unsigned int reserved_size;
|
||||
struct sk_buff *skb;
|
||||
struct skb_frame_desc *skbdesc;
|
||||
|
||||
/*
|
||||
* The frame size includes descriptor size, because the
|
||||
* hardware directly receive the frame into the skbuffer.
|
||||
*/
|
||||
frame_size = queue->data_size + queue->desc_size;
|
||||
frame_size = entry->queue->data_size + entry->queue->desc_size;
|
||||
|
||||
/*
|
||||
* For the allocation we should keep a few things in mind:
|
||||
* 1) 4byte alignment of 802.11 payload
|
||||
*
|
||||
* For (1) we need at most 4 bytes to guarentee the correct
|
||||
* alignment. We are going to optimize the fact that the chance
|
||||
* that the 802.11 header_size % 4 == 2 is much bigger then
|
||||
* anything else. However since we need to move the frame up
|
||||
* to 3 bytes to the front, which means we need to preallocate
|
||||
* 6 bytes.
|
||||
* Reserve a few bytes extra headroom to allow drivers some moving
|
||||
* space (e.g. for alignment), while keeping the skb aligned.
|
||||
*/
|
||||
reserved_size = 6;
|
||||
reserved_size = 8;
|
||||
|
||||
/*
|
||||
* Allocate skbuffer.
|
||||
|
@ -64,9 +60,56 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct data_queue *queue)
|
|||
skb_reserve(skb, reserved_size);
|
||||
skb_put(skb, frame_size);
|
||||
|
||||
/*
|
||||
* Populate skbdesc.
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->entry = entry;
|
||||
|
||||
if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) {
|
||||
skbdesc->skb_dma = dma_map_single(rt2x00dev->dev,
|
||||
skb->data,
|
||||
skb->len,
|
||||
DMA_FROM_DEVICE);
|
||||
skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00queue_alloc_rxskb);
|
||||
|
||||
void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
|
||||
{
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
|
||||
|
||||
skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
|
||||
|
||||
void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
|
||||
{
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
|
||||
|
||||
if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) {
|
||||
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
|
||||
DMA_FROM_DEVICE);
|
||||
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX;
|
||||
}
|
||||
|
||||
if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
|
||||
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
|
||||
}
|
||||
}
|
||||
|
||||
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
|
||||
{
|
||||
rt2x00queue_unmap_skb(rt2x00dev, skb);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
||||
struct txentry_desc *txdesc)
|
||||
|
@ -80,7 +123,6 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
|||
unsigned int data_length;
|
||||
unsigned int duration;
|
||||
unsigned int residual;
|
||||
u16 frame_control;
|
||||
|
||||
memset(txdesc, 0, sizeof(*txdesc));
|
||||
|
||||
|
@ -95,11 +137,6 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
|||
/* Data length should be extended with 4 bytes for CRC */
|
||||
data_length = entry->skb->len + 4;
|
||||
|
||||
/*
|
||||
* Read required fields from ieee80211 header.
|
||||
*/
|
||||
frame_control = le16_to_cpu(hdr->frame_control);
|
||||
|
||||
/*
|
||||
* Check whether this frame is to be acked.
|
||||
*/
|
||||
|
@ -109,9 +146,10 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
|||
/*
|
||||
* Check if this is a RTS/CTS frame
|
||||
*/
|
||||
if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
|
||||
if (ieee80211_is_rts(hdr->frame_control) ||
|
||||
ieee80211_is_cts(hdr->frame_control)) {
|
||||
__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
|
||||
if (is_rts_frame(frame_control))
|
||||
if (ieee80211_is_rts(hdr->frame_control))
|
||||
__set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags);
|
||||
else
|
||||
__set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags);
|
||||
|
@ -139,7 +177,8 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
|||
* Beacons and probe responses require the tsf timestamp
|
||||
* to be inserted into the frame.
|
||||
*/
|
||||
if (txdesc->queue == QID_BEACON || is_probe_resp(frame_control))
|
||||
if (ieee80211_is_beacon(hdr->frame_control) ||
|
||||
ieee80211_is_probe_resp(hdr->frame_control))
|
||||
__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
|
||||
|
||||
/*
|
||||
|
@ -236,6 +275,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
|
|||
{
|
||||
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
|
||||
struct txentry_desc txdesc;
|
||||
struct skb_frame_desc *skbdesc;
|
||||
|
||||
if (unlikely(rt2x00queue_full(queue)))
|
||||
return -EINVAL;
|
||||
|
@ -256,11 +296,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
|
|||
entry->skb = skb;
|
||||
rt2x00queue_create_tx_descriptor(entry, &txdesc);
|
||||
|
||||
/*
|
||||
* skb->cb array is now ours and we are free to use it.
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(entry->skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->entry = entry;
|
||||
|
||||
if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
|
||||
__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
|
||||
rt2x00queue_map_txskb(queue->rt2x00dev, skb);
|
||||
|
||||
__set_bit(ENTRY_DATA_PENDING, &entry->flags);
|
||||
|
||||
rt2x00queue_index_inc(queue, Q_INDEX);
|
||||
|
@ -336,7 +386,6 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
|
|||
|
||||
spin_unlock_irqrestore(&queue->lock, irqflags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00queue_index_inc);
|
||||
|
||||
static void rt2x00queue_reset(struct data_queue *queue)
|
||||
{
|
||||
|
@ -426,12 +475,41 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev,
|
||||
struct data_queue *queue)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!queue->entries)
|
||||
return;
|
||||
|
||||
for (i = 0; i < queue->limit; i++) {
|
||||
if (queue->entries[i].skb)
|
||||
rt2x00queue_free_skb(rt2x00dev, queue->entries[i].skb);
|
||||
}
|
||||
}
|
||||
|
||||
static int rt2x00queue_alloc_rxskbs(struct rt2x00_dev *rt2x00dev,
|
||||
struct data_queue *queue)
|
||||
{
|
||||
unsigned int i;
|
||||
struct sk_buff *skb;
|
||||
|
||||
for (i = 0; i < queue->limit; i++) {
|
||||
skb = rt2x00queue_alloc_rxskb(rt2x00dev, &queue->entries[i]);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
queue->entries[i].skb = skb;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct data_queue *queue;
|
||||
int status;
|
||||
|
||||
|
||||
status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx);
|
||||
if (status)
|
||||
goto exit;
|
||||
|
@ -446,11 +524,14 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
|
|||
if (status)
|
||||
goto exit;
|
||||
|
||||
if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
|
||||
return 0;
|
||||
if (test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) {
|
||||
status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1],
|
||||
rt2x00dev->ops->atim);
|
||||
if (status)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1],
|
||||
rt2x00dev->ops->atim);
|
||||
status = rt2x00queue_alloc_rxskbs(rt2x00dev, rt2x00dev->rx);
|
||||
if (status)
|
||||
goto exit;
|
||||
|
||||
|
@ -468,6 +549,8 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
|
|||
{
|
||||
struct data_queue *queue;
|
||||
|
||||
rt2x00queue_free_skbs(rt2x00dev, rt2x00dev->rx);
|
||||
|
||||
queue_for_each(rt2x00dev, queue) {
|
||||
kfree(queue->entries);
|
||||
queue->entries = NULL;
|
||||
|
|
|
@ -42,15 +42,18 @@
|
|||
/**
|
||||
* DOC: Number of entries per queue
|
||||
*
|
||||
* After research it was concluded that 12 entries in a RX and TX
|
||||
* queue would be sufficient. Although this is almost one third of
|
||||
* the amount the legacy driver allocated, the queues aren't getting
|
||||
* filled to the maximum even when working with the maximum rate.
|
||||
* Under normal load without fragmentation 12 entries are sufficient
|
||||
* without the queue being filled up to the maximum. When using fragmentation
|
||||
* and the queue threshold code we need to add some additional margins to
|
||||
* make sure the queue will never (or only under extreme load) fill up
|
||||
* completely.
|
||||
* Since we don't use preallocated DMA having a large number of queue entries
|
||||
* will have only minimal impact on the memory requirements for the queue.
|
||||
*/
|
||||
#define RX_ENTRIES 12
|
||||
#define TX_ENTRIES 12
|
||||
#define RX_ENTRIES 24
|
||||
#define TX_ENTRIES 24
|
||||
#define BEACON_ENTRIES 1
|
||||
#define ATIM_ENTRIES 1
|
||||
#define ATIM_ENTRIES 8
|
||||
|
||||
/**
|
||||
* enum data_queue_qid: Queue identification
|
||||
|
@ -82,10 +85,13 @@ enum data_queue_qid {
|
|||
/**
|
||||
* enum skb_frame_desc_flags: Flags for &struct skb_frame_desc
|
||||
*
|
||||
* @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX
|
||||
* @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX
|
||||
*/
|
||||
//enum skb_frame_desc_flags {
|
||||
// TEMPORARILY EMPTY
|
||||
//};
|
||||
enum skb_frame_desc_flags {
|
||||
SKBDESC_DMA_MAPPED_RX = (1 << 0),
|
||||
SKBDESC_DMA_MAPPED_TX = (1 << 1),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct skb_frame_desc: Descriptor information for the skb buffer
|
||||
|
@ -94,19 +100,20 @@ enum data_queue_qid {
|
|||
* this structure should not exceed the size of that array (40 bytes).
|
||||
*
|
||||
* @flags: Frame flags, see &enum skb_frame_desc_flags.
|
||||
* @data: Pointer to data part of frame (Start of ieee80211 header).
|
||||
* @desc_len: Length of the frame descriptor.
|
||||
* @desc: Pointer to descriptor part of the frame.
|
||||
* Note that this pointer could point to something outside
|
||||
* of the scope of the skb->data pointer.
|
||||
* @data_len: Length of the frame data.
|
||||
* @desc_len: Length of the frame descriptor.
|
||||
* @skb_dma: (PCI-only) the DMA address associated with the sk buffer.
|
||||
* @entry: The entry to which this sk buffer belongs.
|
||||
*/
|
||||
struct skb_frame_desc {
|
||||
unsigned int flags;
|
||||
|
||||
void *desc;
|
||||
unsigned int desc_len;
|
||||
void *desc;
|
||||
|
||||
dma_addr_t skb_dma;
|
||||
|
||||
struct queue_entry *entry;
|
||||
};
|
||||
|
|
|
@ -45,14 +45,17 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
|
|||
if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
|
||||
return 0;
|
||||
|
||||
if (state == RFKILL_STATE_ON) {
|
||||
if (state == RFKILL_STATE_UNBLOCKED) {
|
||||
INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
|
||||
__clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
|
||||
retval = rt2x00lib_enable_radio(rt2x00dev);
|
||||
} else if (state == RFKILL_STATE_OFF) {
|
||||
} else if (state == RFKILL_STATE_SOFT_BLOCKED) {
|
||||
INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n");
|
||||
__set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
|
||||
rt2x00lib_disable_radio(rt2x00dev);
|
||||
} else {
|
||||
WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n",
|
||||
state);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
|
|
@ -40,7 +40,7 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
|
|||
void *buffer, const u16 buffer_length,
|
||||
const int timeout)
|
||||
{
|
||||
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
|
||||
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
|
||||
int status;
|
||||
unsigned int i;
|
||||
unsigned int pipe =
|
||||
|
@ -130,10 +130,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
|
|||
struct queue_entry *entry = (struct queue_entry *)urb->context;
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct txdone_entry_desc txdesc;
|
||||
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
|
||||
|
||||
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
|
||||
!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
|
||||
!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -157,26 +156,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
|
|||
txdesc.retry = 0;
|
||||
|
||||
rt2x00lib_txdone(entry, &txdesc);
|
||||
|
||||
/*
|
||||
* Make this entry available for reuse.
|
||||
*/
|
||||
entry->flags = 0;
|
||||
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
|
||||
|
||||
/*
|
||||
* If the data queue was below the threshold before the txdone
|
||||
* handler we must make sure the packet queue in the mac80211 stack
|
||||
* is reenabled when the txdone handler has finished.
|
||||
*/
|
||||
if (!rt2x00queue_threshold(entry->queue))
|
||||
ieee80211_wake_queue(rt2x00dev->hw, qid);
|
||||
}
|
||||
|
||||
int rt2x00usb_write_tx_data(struct queue_entry *entry)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
|
||||
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
|
||||
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
|
||||
struct skb_frame_desc *skbdesc;
|
||||
u32 length;
|
||||
|
@ -191,10 +176,8 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
|
|||
* Fill in skb descriptor
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(entry->skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->desc = entry->skb->data;
|
||||
skbdesc->desc_len = entry->queue->desc_size;
|
||||
skbdesc->entry = entry;
|
||||
|
||||
/*
|
||||
* USB devices cannot blindly pass the skb->len as the
|
||||
|
@ -264,13 +247,11 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
|
|||
{
|
||||
struct queue_entry *entry = (struct queue_entry *)urb->context;
|
||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||
struct sk_buff *skb;
|
||||
struct skb_frame_desc *skbdesc;
|
||||
struct rxdone_entry_desc rxdesc;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
u8 rxd[32];
|
||||
|
||||
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
|
||||
!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
|
||||
!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -278,50 +259,22 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
|
|||
* to be actually valid, or if the urb is signaling
|
||||
* a problem.
|
||||
*/
|
||||
if (urb->actual_length < entry->queue->desc_size || urb->status)
|
||||
goto skip_entry;
|
||||
if (urb->actual_length < entry->queue->desc_size || urb->status) {
|
||||
__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
|
||||
usb_submit_urb(urb, GFP_ATOMIC);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in skb descriptor
|
||||
* Fill in desc fields of the skb descriptor
|
||||
*/
|
||||
skbdesc = get_skb_frame_desc(entry->skb);
|
||||
memset(skbdesc, 0, sizeof(*skbdesc));
|
||||
skbdesc->entry = entry;
|
||||
skbdesc->desc = rxd;
|
||||
skbdesc->desc_len = entry->queue->desc_size;
|
||||
|
||||
memset(&rxdesc, 0, sizeof(rxdesc));
|
||||
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
|
||||
|
||||
/*
|
||||
* Allocate a new sk buffer to replace the current one.
|
||||
* If allocation fails, we should drop the current frame
|
||||
* so we can recycle the existing sk buffer for the new frame.
|
||||
*/
|
||||
skb = rt2x00queue_alloc_rxskb(entry->queue);
|
||||
if (!skb)
|
||||
goto skip_entry;
|
||||
|
||||
/*
|
||||
* Send the frame to rt2x00lib for further processing.
|
||||
*/
|
||||
rt2x00lib_rxdone(entry, &rxdesc);
|
||||
|
||||
/*
|
||||
* Replace current entry's skb with the newly allocated one,
|
||||
* and reinitialize the urb.
|
||||
*/
|
||||
entry->skb = skb;
|
||||
urb->transfer_buffer = entry->skb->data;
|
||||
urb->transfer_buffer_length = entry->skb->len;
|
||||
|
||||
skip_entry:
|
||||
if (test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) {
|
||||
__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
|
||||
usb_submit_urb(urb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
rt2x00queue_index_inc(entry->queue, Q_INDEX);
|
||||
rt2x00lib_rxdone(rt2x00dev, entry);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -331,6 +284,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
|
|||
{
|
||||
struct queue_entry_priv_usb *entry_priv;
|
||||
struct queue_entry_priv_usb_bcn *bcn_priv;
|
||||
struct data_queue *queue;
|
||||
unsigned int i;
|
||||
|
||||
rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
|
||||
|
@ -339,9 +293,11 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
|
|||
/*
|
||||
* Cancel all queues.
|
||||
*/
|
||||
for (i = 0; i < rt2x00dev->rx->limit; i++) {
|
||||
entry_priv = rt2x00dev->rx->entries[i].priv_data;
|
||||
usb_kill_urb(entry_priv->urb);
|
||||
queue_for_each(rt2x00dev, queue) {
|
||||
for (i = 0; i < queue->limit; i++) {
|
||||
entry_priv = queue->entries[i].priv_data;
|
||||
usb_kill_urb(entry_priv->urb);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -364,7 +320,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
|
|||
void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
|
||||
struct queue_entry *entry)
|
||||
{
|
||||
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
|
||||
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
|
||||
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
|
||||
|
||||
usb_fill_bulk_urb(entry_priv->urb, usb_dev,
|
||||
|
@ -431,8 +387,6 @@ static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
|
|||
entry_priv = queue->entries[i].priv_data;
|
||||
usb_kill_urb(entry_priv->urb);
|
||||
usb_free_urb(entry_priv->urb);
|
||||
if (queue->entries[i].skb)
|
||||
kfree_skb(queue->entries[i].skb);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -454,10 +408,7 @@ static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
|
|||
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct data_queue *queue;
|
||||
struct sk_buff *skb;
|
||||
unsigned int entry_size;
|
||||
unsigned int i;
|
||||
int uninitialized_var(status);
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Allocate DMA
|
||||
|
@ -468,18 +419,6 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the RX queue, skb's should be allocated.
|
||||
*/
|
||||
entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size;
|
||||
for (i = 0; i < rt2x00dev->rx->limit; i++) {
|
||||
skb = rt2x00queue_alloc_rxskb(rt2x00dev->rx);
|
||||
if (!skb)
|
||||
goto exit;
|
||||
|
||||
rt2x00dev->rx->entries[i].skb = skb;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
|
@ -558,7 +497,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
|
|||
usb_set_intfdata(usb_intf, hw);
|
||||
|
||||
rt2x00dev = hw->priv;
|
||||
rt2x00dev->dev = usb_intf;
|
||||
rt2x00dev->dev = &usb_intf->dev;
|
||||
rt2x00dev->ops = ops;
|
||||
rt2x00dev->hw = hw;
|
||||
mutex_init(&rt2x00dev->usb_cache_mutex);
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
#ifndef RT2X00USB_H
|
||||
#define RT2X00USB_H
|
||||
|
||||
#define to_usb_device_intf(d) \
|
||||
({ \
|
||||
struct usb_interface *intf = to_usb_interface(d); \
|
||||
interface_to_usbdev(intf); \
|
||||
})
|
||||
|
||||
/*
|
||||
* This variable should be used with the
|
||||
* usb_driver structure initialization.
|
||||
|
|
|
@ -1030,11 +1030,12 @@ static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
|
|||
struct queue_entry *entry)
|
||||
{
|
||||
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
|
||||
u32 word;
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 5, &word);
|
||||
rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
|
||||
entry_priv->data_dma);
|
||||
skbdesc->skb_dma);
|
||||
rt2x00_desc_write(entry_priv->desc, 5, word);
|
||||
|
||||
rt2x00_desc_read(entry_priv->desc, 0, &word);
|
||||
|
@ -1522,7 +1523,6 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
|||
struct txentry_desc *txdesc)
|
||||
{
|
||||
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
|
||||
struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
|
||||
__le32 *txd = skbdesc->desc;
|
||||
u32 word;
|
||||
|
||||
|
@ -1557,7 +1557,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
|||
|
||||
rt2x00_desc_read(txd, 6, &word);
|
||||
rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
|
||||
entry_priv->data_dma);
|
||||
skbdesc->skb_dma);
|
||||
rt2x00_desc_write(txd, 6, word);
|
||||
|
||||
if (skbdesc->desc_len > TXINFO_SIZE) {
|
||||
|
@ -1767,7 +1767,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
|
|||
__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
|
||||
txdesc.retry = 0;
|
||||
|
||||
rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc);
|
||||
rt2x00lib_txdone(entry_done, &txdesc);
|
||||
entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
|
||||
}
|
||||
|
||||
|
@ -1787,7 +1787,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
|
|||
}
|
||||
txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
|
||||
|
||||
rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
|
||||
rt2x00lib_txdone(entry, &txdesc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1973,7 +1973,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
|
|||
* To determine the RT chip we have to read the
|
||||
* PCI header of the device.
|
||||
*/
|
||||
pci_read_config_word(rt2x00dev_pci(rt2x00dev),
|
||||
pci_read_config_word(to_pci_dev(rt2x00dev->dev),
|
||||
PCI_CONFIG_HEADER_DEVICE, &device);
|
||||
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
|
||||
rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®);
|
||||
|
@ -2239,7 +2239,7 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
IEEE80211_HW_SIGNAL_DBM;
|
||||
rt2x00dev->hw->extra_tx_headroom = 0;
|
||||
|
||||
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
|
||||
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
|
||||
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
|
||||
rt2x00_eeprom_addr(rt2x00dev,
|
||||
EEPROM_MAC_ADDR_0));
|
||||
|
@ -2302,9 +2302,10 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
rt61pci_probe_hw_mode(rt2x00dev);
|
||||
|
||||
/*
|
||||
* This device requires firmware.
|
||||
* This device requires firmware and DMA mapped skbs.
|
||||
*/
|
||||
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
|
||||
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
|
||||
|
||||
/*
|
||||
* Set the rssi offset.
|
||||
|
@ -2402,6 +2403,12 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
skb->data, skb->len);
|
||||
rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
/*
|
||||
* Clean up beacon skb.
|
||||
*/
|
||||
dev_kfree_skb_any(skb);
|
||||
intf->beacon->skb = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1827,7 +1827,7 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
IEEE80211_HW_SIGNAL_DBM;
|
||||
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
|
||||
|
||||
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
|
||||
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
|
||||
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
|
||||
rt2x00_eeprom_addr(rt2x00dev,
|
||||
EEPROM_MAC_ADDR_0));
|
||||
|
@ -2007,6 +2007,12 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
REGISTER_TIMEOUT32(skb->len));
|
||||
rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
/*
|
||||
* Clean up the beacon skb.
|
||||
*/
|
||||
dev_kfree_skb(skb);
|
||||
intf->beacon->skb = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1624,25 +1624,25 @@ static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].bssid, ETH_ALEN);
|
||||
current_ev = iwe_stream_add_event(current_ev,
|
||||
current_ev = iwe_stream_add_event(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe, IW_EV_ADDR_LEN);
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.flags = 1;
|
||||
iwe.u.data.length = this->bss_set[i].ssid.el.len;
|
||||
current_ev = iwe_stream_add_point(current_ev,
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe,
|
||||
this->bss_set[i].ssid.essid);
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
iwe.u.mode = this->bss_set[i].bss_type;
|
||||
current_ev = iwe_stream_add_event(current_ev,
|
||||
current_ev = iwe_stream_add_event(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = this->bss_set[i].ds_pset.chan;
|
||||
iwe.u.freq.e = 0;
|
||||
current_ev = iwe_stream_add_event(current_ev,
|
||||
current_ev = iwe_stream_add_event(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe, IW_EV_FREQ_LEN);
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
|
@ -1651,7 +1651,7 @@ static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
current_ev = iwe_stream_add_point(current_ev,
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
extra + IW_SCAN_MAX_DATA,
|
||||
&iwe, NULL);
|
||||
}
|
||||
|
|
|
@ -1152,32 +1152,36 @@ static int zd1201_get_scan(struct net_device *dev,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6);
|
||||
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN);
|
||||
cev = iwe_stream_add_event(info, cev, end_buf,
|
||||
&iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.length = zd->rxdata[i+16];
|
||||
iwe.u.data.flags = 1;
|
||||
cev = iwe_stream_add_point(cev, end_buf, &iwe, zd->rxdata+i+18);
|
||||
cev = iwe_stream_add_point(info, cev, end_buf,
|
||||
&iwe, zd->rxdata+i+18);
|
||||
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
if (zd->rxdata[i+14]&0x01)
|
||||
iwe.u.mode = IW_MODE_MASTER;
|
||||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN);
|
||||
cev = iwe_stream_add_event(info, cev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = zd->rxdata[i+0];
|
||||
iwe.u.freq.e = 0;
|
||||
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN);
|
||||
cev = iwe_stream_add_event(info, cev, end_buf,
|
||||
&iwe, IW_EV_FREQ_LEN);
|
||||
|
||||
iwe.cmd = SIOCGIWRATE;
|
||||
iwe.u.bitrate.fixed = 0;
|
||||
iwe.u.bitrate.disabled = 0;
|
||||
for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) {
|
||||
iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000;
|
||||
cev=iwe_stream_add_event(cev, end_buf, &iwe,
|
||||
IW_EV_PARAM_LEN);
|
||||
cev = iwe_stream_add_event(info, cev, end_buf,
|
||||
&iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
|
@ -1186,14 +1190,15 @@ static int zd1201_get_scan(struct net_device *dev,
|
|||
iwe.u.data.flags = IW_ENCODE_ENABLED;
|
||||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL);
|
||||
cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL);
|
||||
|
||||
iwe.cmd = IWEVQUAL;
|
||||
iwe.u.qual.qual = zd->rxdata[i+4];
|
||||
iwe.u.qual.noise= zd->rxdata[i+2]/10-100;
|
||||
iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100;
|
||||
iwe.u.qual.updated = 7;
|
||||
cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN);
|
||||
cev = iwe_stream_add_event(info, cev, end_buf,
|
||||
&iwe, IW_EV_QUAL_LEN);
|
||||
}
|
||||
|
||||
if (!enabled_save)
|
||||
|
|
|
@ -376,8 +376,6 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
|
|||
static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
|
||||
struct ieee80211_hdr *header, u32 flags)
|
||||
{
|
||||
u16 fctl = le16_to_cpu(header->frame_control);
|
||||
|
||||
/*
|
||||
* CONTROL TODO:
|
||||
* - if backoff needed, enable bit 0
|
||||
|
@ -395,8 +393,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
|
|||
cs->control |= ZD_CS_MULTICAST;
|
||||
|
||||
/* PS-POLL */
|
||||
if ((fctl & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) ==
|
||||
(IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL))
|
||||
if (ieee80211_is_pspoll(header->frame_control))
|
||||
cs->control |= ZD_CS_PS_POLL_FRAME;
|
||||
|
||||
if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
|
||||
|
@ -550,13 +547,11 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
|
||||
struct ieee80211_rx_status *stats)
|
||||
{
|
||||
u16 fc = le16_to_cpu(rx_hdr->frame_control);
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff_head *q;
|
||||
unsigned long flags;
|
||||
|
||||
if ((fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) !=
|
||||
(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK))
|
||||
if (!ieee80211_is_ack(rx_hdr->frame_control))
|
||||
return 0;
|
||||
|
||||
q = &zd_hw_mac(hw)->ack_wait_queue;
|
||||
|
@ -584,8 +579,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
|
|||
const struct rx_status *status;
|
||||
struct sk_buff *skb;
|
||||
int bad_frame = 0;
|
||||
u16 fc;
|
||||
bool is_qos, is_4addr, need_padding;
|
||||
__le16 fc;
|
||||
int need_padding;
|
||||
int i;
|
||||
u8 rate;
|
||||
|
||||
|
@ -644,13 +639,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
|
|||
&& !mac->pass_ctrl)
|
||||
return 0;
|
||||
|
||||
fc = le16_to_cpu(*((__le16 *) buffer));
|
||||
|
||||
is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
|
||||
(fc & IEEE80211_STYPE_QOS_DATA);
|
||||
is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
|
||||
(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
|
||||
need_padding = is_qos ^ is_4addr;
|
||||
fc = *(__le16 *)buffer;
|
||||
need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc);
|
||||
|
||||
skb = dev_alloc_skb(length + (need_padding ? 2 : 0));
|
||||
if (skb == NULL)
|
||||
|
|
|
@ -2,7 +2,7 @@ menu "Sonics Silicon Backplane"
|
|||
|
||||
config SSB_POSSIBLE
|
||||
bool
|
||||
depends on HAS_IOMEM
|
||||
depends on HAS_IOMEM && HAS_DMA
|
||||
default y
|
||||
|
||||
config SSB
|
||||
|
|
|
@ -462,18 +462,15 @@ static int ssb_devices_register(struct ssb_bus *bus)
|
|||
#ifdef CONFIG_SSB_PCIHOST
|
||||
sdev->irq = bus->host_pci->irq;
|
||||
dev->parent = &bus->host_pci->dev;
|
||||
sdev->dma_dev = &bus->host_pci->dev;
|
||||
#endif
|
||||
break;
|
||||
case SSB_BUSTYPE_PCMCIA:
|
||||
#ifdef CONFIG_SSB_PCMCIAHOST
|
||||
sdev->irq = bus->host_pcmcia->irq.AssignedIRQ;
|
||||
dev->parent = &bus->host_pcmcia->dev;
|
||||
sdev->dma_dev = &bus->host_pcmcia->dev;
|
||||
#endif
|
||||
break;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
sdev->dma_dev = dev;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1156,36 +1153,82 @@ u32 ssb_dma_translation(struct ssb_device *dev)
|
|||
{
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_SSB:
|
||||
case SSB_BUSTYPE_PCMCIA:
|
||||
return 0;
|
||||
case SSB_BUSTYPE_PCI:
|
||||
return SSB_PCI_DMA;
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ssb_dma_translation);
|
||||
|
||||
int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)
|
||||
int ssb_dma_set_mask(struct ssb_device *dev, u64 mask)
|
||||
{
|
||||
struct device *dma_dev = ssb_dev->dma_dev;
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI) {
|
||||
err = pci_set_dma_mask(ssb_dev->bus->host_pci, mask);
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_PCI:
|
||||
err = pci_set_dma_mask(dev->bus->host_pci, mask);
|
||||
if (err)
|
||||
return err;
|
||||
err = pci_set_consistent_dma_mask(ssb_dev->bus->host_pci, mask);
|
||||
err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask);
|
||||
return err;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
return dma_set_mask(dev->dev, mask);
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
#endif
|
||||
dma_dev->coherent_dma_mask = mask;
|
||||
dma_dev->dma_mask = &dma_dev->coherent_dma_mask;
|
||||
|
||||
return err;
|
||||
return -ENOSYS;
|
||||
}
|
||||
EXPORT_SYMBOL(ssb_dma_set_mask);
|
||||
|
||||
void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t gfp_flags)
|
||||
{
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_PCI:
|
||||
if (gfp_flags & GFP_DMA) {
|
||||
/* Workaround: The PCI API does not support passing
|
||||
* a GFP flag. */
|
||||
return dma_alloc_coherent(&dev->bus->host_pci->dev,
|
||||
size, dma_handle, gfp_flags);
|
||||
}
|
||||
return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle);
|
||||
case SSB_BUSTYPE_SSB:
|
||||
return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags);
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ssb_dma_alloc_consistent);
|
||||
|
||||
void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
|
||||
void *vaddr, dma_addr_t dma_handle,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_PCI:
|
||||
if (gfp_flags & GFP_DMA) {
|
||||
/* Workaround: The PCI API does not support passing
|
||||
* a GFP flag. */
|
||||
dma_free_coherent(&dev->bus->host_pci->dev,
|
||||
size, vaddr, dma_handle);
|
||||
return;
|
||||
}
|
||||
pci_free_consistent(dev->bus->host_pci, size,
|
||||
vaddr, dma_handle);
|
||||
return;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
dma_free_coherent(dev->dev, size, vaddr, dma_handle);
|
||||
return;
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ssb_dma_free_consistent);
|
||||
|
||||
int ssb_bus_may_powerdown(struct ssb_bus *bus)
|
||||
{
|
||||
struct ssb_chipcommon *cc;
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
#include <linux/syscalls.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/atalk.h>
|
||||
#include <linux/loop.h>
|
||||
|
||||
|
@ -1757,64 +1756,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a
|
|||
return sys_ioctl(fd, cmd, (unsigned long)tdata);
|
||||
}
|
||||
|
||||
struct compat_iw_point {
|
||||
compat_caddr_t pointer;
|
||||
__u16 length;
|
||||
__u16 flags;
|
||||
};
|
||||
|
||||
static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct iwreq __user *iwr;
|
||||
struct iwreq __user *iwr_u;
|
||||
struct iw_point __user *iwp;
|
||||
struct compat_iw_point __user *iwp_u;
|
||||
compat_caddr_t pointer_u;
|
||||
void __user *pointer;
|
||||
__u16 length, flags;
|
||||
int ret;
|
||||
|
||||
iwr_u = compat_ptr(arg);
|
||||
iwp_u = (struct compat_iw_point __user *) &iwr_u->u.data;
|
||||
iwr = compat_alloc_user_space(sizeof(*iwr));
|
||||
if (iwr == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
iwp = &iwr->u.data;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, iwr, sizeof(*iwr)))
|
||||
return -EFAULT;
|
||||
|
||||
if (__copy_in_user(&iwr->ifr_ifrn.ifrn_name[0],
|
||||
&iwr_u->ifr_ifrn.ifrn_name[0],
|
||||
sizeof(iwr->ifr_ifrn.ifrn_name)))
|
||||
return -EFAULT;
|
||||
|
||||
if (__get_user(pointer_u, &iwp_u->pointer) ||
|
||||
__get_user(length, &iwp_u->length) ||
|
||||
__get_user(flags, &iwp_u->flags))
|
||||
return -EFAULT;
|
||||
|
||||
if (__put_user(compat_ptr(pointer_u), &iwp->pointer) ||
|
||||
__put_user(length, &iwp->length) ||
|
||||
__put_user(flags, &iwp->flags))
|
||||
return -EFAULT;
|
||||
|
||||
ret = sys_ioctl(fd, cmd, (unsigned long) iwr);
|
||||
|
||||
if (__get_user(pointer, &iwp->pointer) ||
|
||||
__get_user(length, &iwp->length) ||
|
||||
__get_user(flags, &iwp->flags))
|
||||
return -EFAULT;
|
||||
|
||||
if (__put_user(ptr_to_compat(pointer), &iwp_u->pointer) ||
|
||||
__put_user(length, &iwp_u->length) ||
|
||||
__put_user(flags, &iwp_u->flags))
|
||||
return -EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
|
||||
* for some operations; this forces use of the newer bridge-utils that
|
||||
* use compatiable ioctls
|
||||
|
@ -2495,36 +2436,6 @@ COMPATIBLE_IOCTL(I2C_TENBIT)
|
|||
COMPATIBLE_IOCTL(I2C_PEC)
|
||||
COMPATIBLE_IOCTL(I2C_RETRIES)
|
||||
COMPATIBLE_IOCTL(I2C_TIMEOUT)
|
||||
/* wireless */
|
||||
COMPATIBLE_IOCTL(SIOCSIWCOMMIT)
|
||||
COMPATIBLE_IOCTL(SIOCGIWNAME)
|
||||
COMPATIBLE_IOCTL(SIOCSIWNWID)
|
||||
COMPATIBLE_IOCTL(SIOCGIWNWID)
|
||||
COMPATIBLE_IOCTL(SIOCSIWFREQ)
|
||||
COMPATIBLE_IOCTL(SIOCGIWFREQ)
|
||||
COMPATIBLE_IOCTL(SIOCSIWMODE)
|
||||
COMPATIBLE_IOCTL(SIOCGIWMODE)
|
||||
COMPATIBLE_IOCTL(SIOCSIWSENS)
|
||||
COMPATIBLE_IOCTL(SIOCGIWSENS)
|
||||
COMPATIBLE_IOCTL(SIOCSIWRANGE)
|
||||
COMPATIBLE_IOCTL(SIOCSIWPRIV)
|
||||
COMPATIBLE_IOCTL(SIOCSIWSTATS)
|
||||
COMPATIBLE_IOCTL(SIOCSIWAP)
|
||||
COMPATIBLE_IOCTL(SIOCGIWAP)
|
||||
COMPATIBLE_IOCTL(SIOCSIWRATE)
|
||||
COMPATIBLE_IOCTL(SIOCGIWRATE)
|
||||
COMPATIBLE_IOCTL(SIOCSIWRTS)
|
||||
COMPATIBLE_IOCTL(SIOCGIWRTS)
|
||||
COMPATIBLE_IOCTL(SIOCSIWFRAG)
|
||||
COMPATIBLE_IOCTL(SIOCGIWFRAG)
|
||||
COMPATIBLE_IOCTL(SIOCSIWTXPOW)
|
||||
COMPATIBLE_IOCTL(SIOCGIWTXPOW)
|
||||
COMPATIBLE_IOCTL(SIOCSIWRETRY)
|
||||
COMPATIBLE_IOCTL(SIOCGIWRETRY)
|
||||
COMPATIBLE_IOCTL(SIOCSIWPOWER)
|
||||
COMPATIBLE_IOCTL(SIOCGIWPOWER)
|
||||
COMPATIBLE_IOCTL(SIOCSIWAUTH)
|
||||
COMPATIBLE_IOCTL(SIOCGIWAUTH)
|
||||
/* hiddev */
|
||||
COMPATIBLE_IOCTL(HIDIOCGVERSION)
|
||||
COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
|
||||
|
@ -2755,29 +2666,7 @@ COMPATIBLE_IOCTL(USBDEVFS_IOCTL32)
|
|||
HANDLE_IOCTL(I2C_FUNCS, w_long)
|
||||
HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
|
||||
HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl)
|
||||
/* wireless */
|
||||
HANDLE_IOCTL(SIOCGIWRANGE, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWPRIV, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWSTATS, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCSIWSPY, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWSPY, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCSIWTHRSPY, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWTHRSPY, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCSIWMLME, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWAPLIST, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCSIWSCAN, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWSCAN, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCSIWESSID, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWESSID, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCSIWNICKN, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWNICKN, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCSIWENCODE, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWENCODE, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCSIWGENIE, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWGENIE, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCSIWENCODEEXT, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIWENCODEEXT, do_wireless_ioctl)
|
||||
HANDLE_IOCTL(SIOCSIWPMKSA, do_wireless_ioctl)
|
||||
/* bridge */
|
||||
HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl)
|
||||
HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
|
||||
/* Not implemented in the native kernel */
|
||||
|
|
|
@ -469,6 +469,40 @@ struct ieee80211s_hdr {
|
|||
u8 eaddr3[6];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* struct ieee80211_quiet_ie
|
||||
*
|
||||
* This structure refers to "Quiet information element"
|
||||
*/
|
||||
struct ieee80211_quiet_ie {
|
||||
u8 count;
|
||||
u8 period;
|
||||
__le16 duration;
|
||||
__le16 offset;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* struct ieee80211_msrment_ie
|
||||
*
|
||||
* This structure refers to "Measurement Request/Report information element"
|
||||
*/
|
||||
struct ieee80211_msrment_ie {
|
||||
u8 token;
|
||||
u8 mode;
|
||||
u8 type;
|
||||
u8 request[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* struct ieee80211_channel_sw_ie
|
||||
*
|
||||
* This structure refers to "Channel Switch Announcement information element"
|
||||
*/
|
||||
struct ieee80211_channel_sw_ie {
|
||||
u8 mode;
|
||||
u8 new_ch_num;
|
||||
u8 count;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_mgmt {
|
||||
__le16 frame_control;
|
||||
|
@ -544,10 +578,15 @@ struct ieee80211_mgmt {
|
|||
u8 action_code;
|
||||
u8 element_id;
|
||||
u8 length;
|
||||
u8 switch_mode;
|
||||
u8 new_chan;
|
||||
u8 switch_count;
|
||||
struct ieee80211_channel_sw_ie sw_elem;
|
||||
} __attribute__((packed)) chan_switch;
|
||||
struct{
|
||||
u8 action_code;
|
||||
u8 dialog_token;
|
||||
u8 element_id;
|
||||
u8 length;
|
||||
struct ieee80211_msrment_ie msr_elem;
|
||||
} __attribute__((packed)) measurement;
|
||||
struct{
|
||||
u8 action_code;
|
||||
u8 dialog_token;
|
||||
|
@ -700,11 +739,21 @@ struct ieee80211_ht_addt_info {
|
|||
#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
|
||||
#define WLAN_CAPABILITY_PBCC (1<<6)
|
||||
#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
|
||||
|
||||
/* 802.11h */
|
||||
#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
|
||||
#define WLAN_CAPABILITY_QOS (1<<9)
|
||||
#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
|
||||
#define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
|
||||
/* measurement */
|
||||
#define IEEE80211_SPCT_MSR_RPRT_MODE_LATE (1<<0)
|
||||
#define IEEE80211_SPCT_MSR_RPRT_MODE_INCAPABLE (1<<1)
|
||||
#define IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED (1<<2)
|
||||
|
||||
#define IEEE80211_SPCT_MSR_RPRT_TYPE_BASIC 0
|
||||
#define IEEE80211_SPCT_MSR_RPRT_TYPE_CCA 1
|
||||
#define IEEE80211_SPCT_MSR_RPRT_TYPE_RPI 2
|
||||
|
||||
|
||||
/* 802.11g ERP information element */
|
||||
#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
|
||||
|
@ -875,6 +924,15 @@ enum ieee80211_category {
|
|||
WLAN_CATEGORY_WMM = 17,
|
||||
};
|
||||
|
||||
/* SPECTRUM_MGMT action code */
|
||||
enum ieee80211_spectrum_mgmt_actioncode {
|
||||
WLAN_ACTION_SPCT_MSR_REQ = 0,
|
||||
WLAN_ACTION_SPCT_MSR_RPRT = 1,
|
||||
WLAN_ACTION_SPCT_TPC_REQ = 2,
|
||||
WLAN_ACTION_SPCT_TPC_RPRT = 3,
|
||||
WLAN_ACTION_SPCT_CHL_SWITCH = 4,
|
||||
};
|
||||
|
||||
/* BACK action code */
|
||||
enum ieee80211_back_actioncode {
|
||||
WLAN_ACTION_ADDBA_REQ = 0,
|
||||
|
|
|
@ -241,7 +241,10 @@ enum nl80211_attrs {
|
|||
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
#define NL80211_MAX_SUPP_RATES 32
|
||||
#define NL80211_MAX_SUPP_RATES 32
|
||||
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
|
||||
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
|
||||
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
|
||||
|
||||
/**
|
||||
* enum nl80211_iftype - (virtual) interface types
|
||||
|
|
|
@ -34,26 +34,37 @@
|
|||
* RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
|
||||
* RFKILL_TYPE_UWB: switch is on a ultra wideband device.
|
||||
* RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
|
||||
* RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
|
||||
*/
|
||||
enum rfkill_type {
|
||||
RFKILL_TYPE_WLAN ,
|
||||
RFKILL_TYPE_BLUETOOTH,
|
||||
RFKILL_TYPE_UWB,
|
||||
RFKILL_TYPE_WIMAX,
|
||||
RFKILL_TYPE_WWAN,
|
||||
RFKILL_TYPE_MAX,
|
||||
};
|
||||
|
||||
enum rfkill_state {
|
||||
RFKILL_STATE_OFF = 0,
|
||||
RFKILL_STATE_ON = 1,
|
||||
RFKILL_STATE_SOFT_BLOCKED = 0, /* Radio output blocked */
|
||||
RFKILL_STATE_UNBLOCKED = 1, /* Radio output allowed */
|
||||
RFKILL_STATE_HARD_BLOCKED = 2, /* Output blocked, non-overrideable */
|
||||
};
|
||||
|
||||
/*
|
||||
* These are DEPRECATED, drivers using them should be verified to
|
||||
* comply with the rfkill usage guidelines in Documentation/rfkill.txt
|
||||
* and then converted to use the new names for rfkill_state
|
||||
*/
|
||||
#define RFKILL_STATE_OFF RFKILL_STATE_SOFT_BLOCKED
|
||||
#define RFKILL_STATE_ON RFKILL_STATE_UNBLOCKED
|
||||
|
||||
/**
|
||||
* struct rfkill - rfkill control structure.
|
||||
* @name: Name of the switch.
|
||||
* @type: Radio type which the button controls, the value stored
|
||||
* here should be a value from enum rfkill_type.
|
||||
* @state: State of the switch (on/off).
|
||||
* @state: State of the switch, "UNBLOCKED" means radio can operate.
|
||||
* @user_claim_unsupported: Whether the hardware supports exclusive
|
||||
* RF-kill control by userspace. Set this before registering.
|
||||
* @user_claim: Set when the switch is controlled exlusively by userspace.
|
||||
|
@ -61,6 +72,12 @@ enum rfkill_state {
|
|||
* @data: Pointer to the RF button drivers private data which will be
|
||||
* passed along when toggling radio state.
|
||||
* @toggle_radio(): Mandatory handler to control state of the radio.
|
||||
* only RFKILL_STATE_SOFT_BLOCKED and RFKILL_STATE_UNBLOCKED are
|
||||
* valid parameters.
|
||||
* @get_state(): handler to read current radio state from hardware,
|
||||
* may be called from atomic context, should return 0 on success.
|
||||
* Either this handler OR judicious use of rfkill_force_state() is
|
||||
* MANDATORY for any driver capable of RFKILL_STATE_HARD_BLOCKED.
|
||||
* @led_trigger: A LED trigger for this button's LED.
|
||||
* @dev: Device structure integrating the switch into device tree.
|
||||
* @node: Used to place switch into list of all switches known to the
|
||||
|
@ -80,6 +97,7 @@ struct rfkill {
|
|||
|
||||
void *data;
|
||||
int (*toggle_radio)(void *data, enum rfkill_state state);
|
||||
int (*get_state)(void *data, enum rfkill_state *state);
|
||||
|
||||
#ifdef CONFIG_RFKILL_LEDS
|
||||
struct led_trigger led_trigger;
|
||||
|
@ -95,6 +113,21 @@ void rfkill_free(struct rfkill *rfkill);
|
|||
int rfkill_register(struct rfkill *rfkill);
|
||||
void rfkill_unregister(struct rfkill *rfkill);
|
||||
|
||||
int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state);
|
||||
|
||||
/**
|
||||
* rfkill_state_complement - return complementar state
|
||||
* @state: state to return the complement of
|
||||
*
|
||||
* Returns RFKILL_STATE_SOFT_BLOCKED if @state is RFKILL_STATE_UNBLOCKED,
|
||||
* returns RFKILL_STATE_UNBLOCKED otherwise.
|
||||
*/
|
||||
static inline enum rfkill_state rfkill_state_complement(enum rfkill_state state)
|
||||
{
|
||||
return (state == RFKILL_STATE_UNBLOCKED) ?
|
||||
RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED;
|
||||
}
|
||||
|
||||
/**
|
||||
* rfkill_get_led_name - Get the LED trigger name for the button's LED.
|
||||
* This function might return a NULL pointer if registering of the
|
||||
|
@ -110,4 +143,11 @@ static inline char *rfkill_get_led_name(struct rfkill *rfkill)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* rfkill notification chain */
|
||||
#define RFKILL_STATE_CHANGED 0x0001 /* state of a normal rfkill
|
||||
switch has changed */
|
||||
|
||||
int register_rfkill_notifier(struct notifier_block *nb);
|
||||
int unregister_rfkill_notifier(struct notifier_block *nb);
|
||||
|
||||
#endif /* RFKILL_H */
|
||||
|
|
|
@ -137,9 +137,6 @@ struct ssb_device {
|
|||
const struct ssb_bus_ops *ops;
|
||||
|
||||
struct device *dev;
|
||||
/* Pointer to the device that has to be used for
|
||||
* any DMA related operation. */
|
||||
struct device *dma_dev;
|
||||
|
||||
struct ssb_bus *bus;
|
||||
struct ssb_device_id id;
|
||||
|
@ -399,13 +396,151 @@ static inline void ssb_block_write(struct ssb_device *dev, const void *buffer,
|
|||
#endif /* CONFIG_SSB_BLOCKIO */
|
||||
|
||||
|
||||
/* The SSB DMA API. Use this API for any DMA operation on the device.
|
||||
* This API basically is a wrapper that calls the correct DMA API for
|
||||
* the host device type the SSB device is attached to. */
|
||||
|
||||
/* Translation (routing) bits that need to be ORed to DMA
|
||||
* addresses before they are given to a device. */
|
||||
extern u32 ssb_dma_translation(struct ssb_device *dev);
|
||||
#define SSB_DMA_TRANSLATION_MASK 0xC0000000
|
||||
#define SSB_DMA_TRANSLATION_SHIFT 30
|
||||
|
||||
extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask);
|
||||
extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask);
|
||||
|
||||
extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t gfp_flags);
|
||||
extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
|
||||
void *vaddr, dma_addr_t dma_handle,
|
||||
gfp_t gfp_flags);
|
||||
|
||||
static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_SSB_DEBUG
|
||||
printk(KERN_ERR "SSB: BUG! Calling DMA API for "
|
||||
"unsupported bustype %d\n", dev->bus->bustype);
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
|
||||
static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr)
|
||||
{
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_PCI:
|
||||
return pci_dma_mapping_error(addr);
|
||||
case SSB_BUSTYPE_SSB:
|
||||
return dma_mapping_error(addr);
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
{
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_PCI:
|
||||
return pci_map_single(dev->bus->host_pci, p, size, dir);
|
||||
case SSB_BUSTYPE_SSB:
|
||||
return dma_map_single(dev->dev, p, size, dir);
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
{
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_PCI:
|
||||
pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir);
|
||||
return;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
dma_unmap_single(dev->dev, dma_addr, size, dir);
|
||||
return;
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev,
|
||||
dma_addr_t dma_addr,
|
||||
size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_PCI:
|
||||
pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
|
||||
size, dir);
|
||||
return;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir);
|
||||
return;
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev,
|
||||
dma_addr_t dma_addr,
|
||||
size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_PCI:
|
||||
pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
|
||||
size, dir);
|
||||
return;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
dma_sync_single_for_device(dev->dev, dma_addr, size, dir);
|
||||
return;
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev,
|
||||
dma_addr_t dma_addr,
|
||||
unsigned long offset,
|
||||
size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_PCI:
|
||||
/* Just sync everything. That's all the PCI API can do. */
|
||||
pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
|
||||
offset + size, dir);
|
||||
return;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset,
|
||||
size, dir);
|
||||
return;
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev,
|
||||
dma_addr_t dma_addr,
|
||||
unsigned long offset,
|
||||
size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
switch (dev->bus->bustype) {
|
||||
case SSB_BUSTYPE_PCI:
|
||||
/* Just sync everything. That's all the PCI API can do. */
|
||||
pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
|
||||
offset + size, dir);
|
||||
return;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
dma_sync_single_range_for_device(dev->dev, dma_addr, offset,
|
||||
size, dir);
|
||||
return;
|
||||
default:
|
||||
__ssb_dma_not_implemented(dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
|
|
|
@ -677,6 +677,19 @@ struct iw_point
|
|||
__u16 flags; /* Optional params */
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
#include <linux/compat.h>
|
||||
|
||||
struct compat_iw_point {
|
||||
compat_caddr_t pointer;
|
||||
__u16 length;
|
||||
__u16 flags;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A frequency
|
||||
* For numbers lower than 10^9, we encode the number in 'm' and
|
||||
|
@ -1100,6 +1113,21 @@ struct iw_event
|
|||
#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \
|
||||
IW_EV_POINT_OFF)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct __compat_iw_event {
|
||||
__u16 len; /* Real length of this stuff */
|
||||
__u16 cmd; /* Wireless IOCTL */
|
||||
compat_caddr_t pointer;
|
||||
};
|
||||
#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer)
|
||||
#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length)
|
||||
#define IW_EV_COMPAT_POINT_LEN \
|
||||
(IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \
|
||||
IW_EV_COMPAT_POINT_OFF)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Size of the Event prefix when packed in stream */
|
||||
#define IW_EV_LCP_PK_LEN (4)
|
||||
/* Size of the various events when packed in stream */
|
||||
|
|
|
@ -256,7 +256,7 @@
|
|||
#define EIWCOMMIT EINPROGRESS
|
||||
|
||||
/* Flags available in struct iw_request_info */
|
||||
#define IW_REQUEST_FLAG_NONE 0x0000 /* No flag so far */
|
||||
#define IW_REQUEST_FLAG_COMPAT 0x0001 /* Compat ioctl call */
|
||||
|
||||
/* Type of headers we know about (basically union iwreq_data) */
|
||||
#define IW_HEADER_TYPE_NULL 0 /* Not available */
|
||||
|
@ -478,24 +478,56 @@ extern void wireless_spy_update(struct net_device * dev,
|
|||
* Function that are so simple that it's more efficient inlining them
|
||||
*/
|
||||
|
||||
static inline int iwe_stream_lcp_len(struct iw_request_info *info)
|
||||
{
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (info->flags & IW_REQUEST_FLAG_COMPAT)
|
||||
return IW_EV_COMPAT_LCP_LEN;
|
||||
#endif
|
||||
return IW_EV_LCP_LEN;
|
||||
}
|
||||
|
||||
static inline int iwe_stream_point_len(struct iw_request_info *info)
|
||||
{
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (info->flags & IW_REQUEST_FLAG_COMPAT)
|
||||
return IW_EV_COMPAT_POINT_LEN;
|
||||
#endif
|
||||
return IW_EV_POINT_LEN;
|
||||
}
|
||||
|
||||
static inline int iwe_stream_event_len_adjust(struct iw_request_info *info,
|
||||
int event_len)
|
||||
{
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (info->flags & IW_REQUEST_FLAG_COMPAT) {
|
||||
event_len -= IW_EV_LCP_LEN;
|
||||
event_len += IW_EV_COMPAT_LCP_LEN;
|
||||
}
|
||||
#endif
|
||||
|
||||
return event_len;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
* 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 */
|
||||
iwe_stream_add_event(struct iw_request_info *info, char *stream, char *ends,
|
||||
struct iw_event *iwe, int event_len)
|
||||
{
|
||||
int lcp_len = iwe_stream_lcp_len(info);
|
||||
|
||||
event_len = iwe_stream_event_len_adjust(info, event_len);
|
||||
|
||||
/* Check if it's possible */
|
||||
if(likely((stream + event_len) < ends)) {
|
||||
iwe->len = event_len;
|
||||
/* Beware of alignement issues on 64 bits */
|
||||
memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
|
||||
memcpy(stream + IW_EV_LCP_LEN,
|
||||
((char *) iwe) + IW_EV_LCP_LEN,
|
||||
event_len - IW_EV_LCP_LEN);
|
||||
memcpy(stream + lcp_len, &iwe->u,
|
||||
event_len - lcp_len);
|
||||
stream += event_len;
|
||||
}
|
||||
return stream;
|
||||
|
@ -507,20 +539,21 @@ iwe_stream_add_event(char * stream, /* Stream of events */
|
|||
* 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 */
|
||||
iwe_stream_add_point(struct iw_request_info *info, char *stream, char *ends,
|
||||
struct iw_event *iwe, char *extra)
|
||||
{
|
||||
int event_len = IW_EV_POINT_LEN + iwe->u.data.length;
|
||||
int event_len = iwe_stream_point_len(info) + iwe->u.data.length;
|
||||
int point_len = iwe_stream_point_len(info);
|
||||
int lcp_len = iwe_stream_lcp_len(info);
|
||||
|
||||
/* Check if it's possible */
|
||||
if(likely((stream + event_len) < ends)) {
|
||||
iwe->len = event_len;
|
||||
memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
|
||||
memcpy(stream + IW_EV_LCP_LEN,
|
||||
((char *) iwe) + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
|
||||
memcpy(stream + lcp_len,
|
||||
((char *) &iwe->u) + IW_EV_POINT_OFF,
|
||||
IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
|
||||
memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
|
||||
memcpy(stream + point_len, extra, iwe->u.data.length);
|
||||
stream += event_len;
|
||||
}
|
||||
return stream;
|
||||
|
@ -533,110 +566,24 @@ iwe_stream_add_point(char * stream, /* Stream of events */
|
|||
* 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 */
|
||||
iwe_stream_add_value(struct iw_request_info *info, char *event, char *value,
|
||||
char *ends, struct iw_event *iwe, int event_len)
|
||||
{
|
||||
int lcp_len = iwe_stream_lcp_len(info);
|
||||
|
||||
/* Don't duplicate LCP */
|
||||
event_len -= IW_EV_LCP_LEN;
|
||||
|
||||
/* Check if it's possible */
|
||||
if(likely((value + event_len) < ends)) {
|
||||
/* Add new value */
|
||||
memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
|
||||
memcpy(value, &iwe->u, event_len);
|
||||
value += event_len;
|
||||
/* Patch LCP */
|
||||
iwe->len = value - event;
|
||||
memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
|
||||
memcpy(event, (char *) iwe, lcp_len);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
* Wrapper to add an Wireless Event to a stream of events.
|
||||
* Same as above, with explicit error check...
|
||||
*/
|
||||
static inline char *
|
||||
iwe_stream_check_add_event(char * stream, /* Stream of events */
|
||||
char * ends, /* End of stream */
|
||||
struct iw_event *iwe, /* Payload */
|
||||
int event_len, /* Size of payload */
|
||||
int * perr) /* Error report */
|
||||
{
|
||||
/* Check if it's possible, set error if not */
|
||||
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;
|
||||
} else
|
||||
*perr = -E2BIG;
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
* Wrapper to add an short Wireless Event containing a pointer to a
|
||||
* stream of events.
|
||||
* Same as above, with explicit error check...
|
||||
*/
|
||||
static inline char *
|
||||
iwe_stream_check_add_point(char * stream, /* Stream of events */
|
||||
char * ends, /* End of stream */
|
||||
struct iw_event *iwe, /* Payload length + flags */
|
||||
char * extra, /* More payload */
|
||||
int * perr) /* Error report */
|
||||
{
|
||||
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;
|
||||
} else
|
||||
*perr = -E2BIG;
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
* Wrapper to add a value to a Wireless Event in a stream of events.
|
||||
* Be careful, this one is tricky to use properly :
|
||||
* At the first run, you need to have (value = event + IW_EV_LCP_LEN).
|
||||
* Same as above, with explicit error check...
|
||||
*/
|
||||
static inline char *
|
||||
iwe_stream_check_add_value(char * event, /* Event in the stream */
|
||||
char * value, /* Value in event */
|
||||
char * ends, /* End of stream */
|
||||
struct iw_event *iwe, /* Payload */
|
||||
int event_len, /* Size of payload */
|
||||
int * perr) /* Error report */
|
||||
{
|
||||
/* 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);
|
||||
} else
|
||||
*perr = -E2BIG;
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif /* _IW_HANDLER_H */
|
||||
|
|
|
@ -595,7 +595,12 @@ enum ieee80211_key_flags {
|
|||
* @flags: key flags, see &enum ieee80211_key_flags.
|
||||
* @keyidx: the key index (0-3)
|
||||
* @keylen: key material length
|
||||
* @key: key material
|
||||
* @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte)
|
||||
* data block:
|
||||
* - Temporal Encryption Key (128 bits)
|
||||
* - Temporal Authenticator Tx MIC Key (64 bits)
|
||||
* - Temporal Authenticator Rx MIC Key (64 bits)
|
||||
*
|
||||
*/
|
||||
struct ieee80211_key_conf {
|
||||
enum ieee80211_key_alg alg;
|
||||
|
@ -733,8 +738,11 @@ enum ieee80211_hw_flags {
|
|||
* @conf: &struct ieee80211_conf, device configuration, don't use.
|
||||
*
|
||||
* @workqueue: single threaded workqueue available for driver use,
|
||||
* allocated by mac80211 on registration and flushed on
|
||||
* unregistration.
|
||||
* allocated by mac80211 on registration and flushed when an
|
||||
* interface is removed.
|
||||
* NOTICE: All work performed on this workqueue should NEVER
|
||||
* acquire the RTNL lock (i.e. Don't use the function
|
||||
* ieee80211_iterate_active_interfaces())
|
||||
*
|
||||
* @priv: pointer to private area that was allocated for driver use
|
||||
* along with this structure.
|
||||
|
|
|
@ -12,6 +12,8 @@ extern int wext_proc_init(struct net *net);
|
|||
extern void wext_proc_exit(struct net *net);
|
||||
extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
|
||||
void __user *arg);
|
||||
extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
#else
|
||||
static inline int wext_proc_init(struct net *net)
|
||||
{
|
||||
|
@ -26,6 +28,11 @@ static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned
|
|||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NET_WEXT_H */
|
||||
|
|
|
@ -43,8 +43,9 @@ static const char *ieee80211_modes[] = {
|
|||
|
||||
#define MAX_CUSTOM_LEN 64
|
||||
static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
||||
char *start, char *stop,
|
||||
struct ieee80211_network *network)
|
||||
char *start, char *stop,
|
||||
struct ieee80211_network *network,
|
||||
struct iw_request_info *info)
|
||||
{
|
||||
char custom[MAX_CUSTOM_LEN];
|
||||
char *p;
|
||||
|
@ -57,7 +58,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
|
||||
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
|
||||
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
/* Remaining entries will be displayed in the order we provide them */
|
||||
|
||||
|
@ -66,17 +67,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
iwe.u.data.flags = 1;
|
||||
if (network->flags & NETWORK_EMPTY_ESSID) {
|
||||
iwe.u.data.length = sizeof("<hidden>");
|
||||
start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
|
||||
start = iwe_stream_add_point(info, start, stop,
|
||||
&iwe, "<hidden>");
|
||||
} else {
|
||||
iwe.u.data.length = min(network->ssid_len, (u8) 32);
|
||||
start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
|
||||
start = iwe_stream_add_point(info, start, stop,
|
||||
&iwe, network->ssid);
|
||||
}
|
||||
|
||||
/* Add the protocol name */
|
||||
iwe.cmd = SIOCGIWNAME;
|
||||
snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
|
||||
ieee80211_modes[network->mode]);
|
||||
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
|
||||
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
|
||||
|
||||
/* Add mode */
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
|
@ -86,7 +89,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
|
||||
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
|
||||
start = iwe_stream_add_event(info, start, stop,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
}
|
||||
|
||||
/* Add channel and frequency */
|
||||
|
@ -95,7 +99,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
|
||||
iwe.u.freq.e = 6;
|
||||
iwe.u.freq.i = 0;
|
||||
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
|
||||
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
|
||||
|
||||
/* Add encryption capability */
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
|
@ -104,12 +108,13 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
|
||||
start = iwe_stream_add_point(info, start, stop,
|
||||
&iwe, network->ssid);
|
||||
|
||||
/* Add basic and extended rates */
|
||||
/* Rate : stuffing multiple values in a single event require a bit
|
||||
* more of magic - Jean II */
|
||||
current_val = start + IW_EV_LCP_LEN;
|
||||
current_val = start + iwe_stream_lcp_len(info);
|
||||
iwe.cmd = SIOCGIWRATE;
|
||||
/* Those two flags are ignored... */
|
||||
iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
|
||||
|
@ -124,17 +129,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
/* Bit rate given in 500 kb/s units (+ 0x80) */
|
||||
iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
|
||||
/* Add new value to event */
|
||||
current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
|
||||
current_val = iwe_stream_add_value(info, start, current_val,
|
||||
stop, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
for (; j < network->rates_ex_len; j++) {
|
||||
rate = network->rates_ex[j] & 0x7F;
|
||||
/* Bit rate given in 500 kb/s units (+ 0x80) */
|
||||
iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
|
||||
/* Add new value to event */
|
||||
current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
|
||||
current_val = iwe_stream_add_value(info, start, current_val,
|
||||
stop, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
/* Check if we added any rate */
|
||||
if((current_val - start) > IW_EV_LCP_LEN)
|
||||
if ((current_val - start) > iwe_stream_lcp_len(info))
|
||||
start = current_val;
|
||||
|
||||
/* Add quality statistics */
|
||||
|
@ -181,14 +188,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
iwe.u.qual.level = network->stats.signal;
|
||||
}
|
||||
|
||||
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
|
||||
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
|
||||
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
p = custom;
|
||||
|
||||
iwe.u.data.length = p - custom;
|
||||
if (iwe.u.data.length)
|
||||
start = iwe_stream_add_point(start, stop, &iwe, custom);
|
||||
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
if (network->wpa_ie_len) {
|
||||
|
@ -196,7 +203,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
memcpy(buf, network->wpa_ie, network->wpa_ie_len);
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = network->wpa_ie_len;
|
||||
start = iwe_stream_add_point(start, stop, &iwe, buf);
|
||||
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
|
||||
}
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -205,7 +212,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
memcpy(buf, network->rsn_ie, network->rsn_ie_len);
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = network->rsn_ie_len;
|
||||
start = iwe_stream_add_point(start, stop, &iwe, buf);
|
||||
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
|
||||
}
|
||||
|
||||
/* Add EXTRA: Age to display seconds since last beacon/probe response
|
||||
|
@ -217,7 +224,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
jiffies_to_msecs(jiffies - network->last_scanned));
|
||||
iwe.u.data.length = p - custom;
|
||||
if (iwe.u.data.length)
|
||||
start = iwe_stream_add_point(start, stop, &iwe, custom);
|
||||
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
|
||||
|
||||
/* Add spectrum management information */
|
||||
iwe.cmd = -1;
|
||||
|
@ -238,7 +245,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
|||
|
||||
if (iwe.cmd == IWEVCUSTOM) {
|
||||
iwe.u.data.length = p - custom;
|
||||
start = iwe_stream_add_point(start, stop, &iwe, custom);
|
||||
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
|
||||
}
|
||||
|
||||
return start;
|
||||
|
@ -272,7 +279,8 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
|
|||
|
||||
if (ieee->scan_age == 0 ||
|
||||
time_after(network->last_scanned + ieee->scan_age, jiffies))
|
||||
ev = ieee80211_translate_scan(ieee, ev, stop, network);
|
||||
ev = ieee80211_translate_scan(ieee, ev, stop, network,
|
||||
info);
|
||||
else
|
||||
IEEE80211_DEBUG_SCAN("Not showing network '%s ("
|
||||
"%s)' due to age (%dms).\n",
|
||||
|
|
|
@ -150,7 +150,7 @@ config MAC80211_LOWTX_FRAME_DUMP
|
|||
If unsure, say N and insert the debugging code
|
||||
you require into the driver you are debugging.
|
||||
|
||||
config TKIP_DEBUG
|
||||
config MAC80211_TKIP_DEBUG
|
||||
bool "TKIP debugging"
|
||||
depends on MAC80211_DEBUG
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include "key.h"
|
||||
#include "sta_info.h"
|
||||
|
||||
|
@ -790,6 +791,10 @@ struct ieee802_11_elems {
|
|||
u8 *preq;
|
||||
u8 *prep;
|
||||
u8 *perr;
|
||||
u8 *ch_switch_elem;
|
||||
u8 *country_elem;
|
||||
u8 *pwr_constr_elem;
|
||||
u8 *quiet_elem; /* first quite element */
|
||||
|
||||
/* length of them, respectively */
|
||||
u8 ssid_len;
|
||||
|
@ -814,6 +819,11 @@ struct ieee802_11_elems {
|
|||
u8 preq_len;
|
||||
u8 prep_len;
|
||||
u8 perr_len;
|
||||
u8 ch_switch_elem_len;
|
||||
u8 country_elem_len;
|
||||
u8 pwr_constr_elem_len;
|
||||
u8 quiet_elem_len;
|
||||
u8 num_of_quiet_elem; /* can be more the one */
|
||||
};
|
||||
|
||||
static inline struct ieee80211_local *hw_to_local(
|
||||
|
@ -867,7 +877,9 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid);
|
|||
int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
|
||||
void ieee80211_sta_req_auth(struct net_device *dev,
|
||||
struct ieee80211_if_sta *ifsta);
|
||||
int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
|
||||
int ieee80211_sta_scan_results(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
char *buf, size_t len);
|
||||
ieee80211_rx_result ieee80211_sta_rx_scan(
|
||||
struct net_device *dev, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
|
|
|
@ -16,31 +16,18 @@
|
|||
#include <linux/rcupdate.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
/* ALG_TKIP
|
||||
* struct ieee80211_key::key is encoded as a 256-bit (32 byte) data block:
|
||||
* Temporal Encryption Key (128 bits)
|
||||
* Temporal Authenticator Tx MIC Key (64 bits)
|
||||
* Temporal Authenticator Rx MIC Key (64 bits)
|
||||
*/
|
||||
#define WEP_IV_LEN 4
|
||||
#define WEP_ICV_LEN 4
|
||||
#define ALG_TKIP_KEY_LEN 32
|
||||
#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 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 NUM_RX_DATA_QUEUES 17
|
||||
|
||||
struct ieee80211_local;
|
||||
struct ieee80211_sub_if_data;
|
||||
|
|
|
@ -1691,7 +1691,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
list_add_tail(&sdata->list, &local->interfaces);
|
||||
|
||||
name = wiphy_dev(local->hw.wiphy)->driver->name;
|
||||
local->hw.workqueue = create_singlethread_workqueue(name);
|
||||
local->hw.workqueue = create_freezeable_workqueue(name);
|
||||
if (!local->hw.workqueue) {
|
||||
result = -ENOMEM;
|
||||
goto fail_workqueue;
|
||||
|
|
|
@ -204,6 +204,25 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
|
|||
elems->perr = pos;
|
||||
elems->perr_len = elen;
|
||||
break;
|
||||
case WLAN_EID_CHANNEL_SWITCH:
|
||||
elems->ch_switch_elem = pos;
|
||||
elems->ch_switch_elem_len = elen;
|
||||
break;
|
||||
case WLAN_EID_QUIET:
|
||||
if (!elems->quiet_elem) {
|
||||
elems->quiet_elem = pos;
|
||||
elems->quiet_elem_len = elen;
|
||||
}
|
||||
elems->num_of_quiet_elem++;
|
||||
break;
|
||||
case WLAN_EID_COUNTRY:
|
||||
elems->country_elem = pos;
|
||||
elems->country_elem_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PWR_CONSTRAINT:
|
||||
elems->pwr_constr_elem = pos;
|
||||
elems->pwr_constr_elem_len = elen;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1701,6 +1720,71 @@ void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr)
|
|||
}
|
||||
}
|
||||
|
||||
static void ieee80211_send_refuse_measurement_request(struct net_device *dev,
|
||||
struct ieee80211_msrment_ie *request_ie,
|
||||
const u8 *da, const u8 *bssid,
|
||||
u8 dialog_token)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *msr_report;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
|
||||
sizeof(struct ieee80211_msrment_ie));
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "%s: failed to allocate buffer for "
|
||||
"measurement report frame\n", dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
|
||||
memset(msr_report, 0, 24);
|
||||
memcpy(msr_report->da, da, ETH_ALEN);
|
||||
memcpy(msr_report->sa, dev->dev_addr, ETH_ALEN);
|
||||
memcpy(msr_report->bssid, bssid, ETH_ALEN);
|
||||
msr_report->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
||||
skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement));
|
||||
msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
|
||||
msr_report->u.action.u.measurement.action_code =
|
||||
WLAN_ACTION_SPCT_MSR_RPRT;
|
||||
msr_report->u.action.u.measurement.dialog_token = dialog_token;
|
||||
|
||||
msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT;
|
||||
msr_report->u.action.u.measurement.length =
|
||||
sizeof(struct ieee80211_msrment_ie);
|
||||
|
||||
memset(&msr_report->u.action.u.measurement.msr_elem, 0,
|
||||
sizeof(struct ieee80211_msrment_ie));
|
||||
msr_report->u.action.u.measurement.msr_elem.token = request_ie->token;
|
||||
msr_report->u.action.u.measurement.msr_elem.mode |=
|
||||
IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
|
||||
msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
|
||||
|
||||
ieee80211_sta_tx(dev, skb, 0);
|
||||
}
|
||||
|
||||
static void ieee80211_sta_process_measurement_req(struct net_device *dev,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len)
|
||||
{
|
||||
/*
|
||||
* Ignoring measurement request is spec violation.
|
||||
* Mandatory measurements must be reported optional
|
||||
* measurements might be refused or reported incapable
|
||||
* For now just refuse
|
||||
* TODO: Answer basic measurement as unmeasured
|
||||
*/
|
||||
ieee80211_send_refuse_measurement_request(dev,
|
||||
&mgmt->u.action.u.measurement.msr_elem,
|
||||
mgmt->sa, mgmt->bssid,
|
||||
mgmt->u.action.u.measurement.dialog_token);
|
||||
}
|
||||
|
||||
|
||||
static void ieee80211_rx_mgmt_auth(struct net_device *dev,
|
||||
struct ieee80211_if_sta *ifsta,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
|
@ -1753,11 +1837,12 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
|
|||
auth_transaction, status_code);
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
|
||||
/* IEEE 802.11 standard does not require authentication in IBSS
|
||||
/*
|
||||
* IEEE 802.11 standard does not require authentication in IBSS
|
||||
* networks and most implementations do not seem to use it.
|
||||
* However, try to reply to authentication attempts if someone
|
||||
* has actually implemented this.
|
||||
* TODO: Could implement shared key authentication. */
|
||||
*/
|
||||
if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
|
||||
printk(KERN_DEBUG "%s: unexpected IBSS authentication "
|
||||
"frame (alg=%d transaction=%d)\n",
|
||||
|
@ -3025,11 +3110,24 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev,
|
|||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
|
||||
if (len < IEEE80211_MIN_ACTION_SIZE)
|
||||
return;
|
||||
|
||||
switch (mgmt->u.action.category) {
|
||||
case WLAN_CATEGORY_SPECTRUM_MGMT:
|
||||
if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
|
||||
break;
|
||||
switch (mgmt->u.action.u.chan_switch.action_code) {
|
||||
case WLAN_ACTION_SPCT_MSR_REQ:
|
||||
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
||||
sizeof(mgmt->u.action.u.measurement)))
|
||||
break;
|
||||
ieee80211_sta_process_measurement_req(dev, mgmt, len);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WLAN_CATEGORY_BACK:
|
||||
switch (mgmt->u.action.u.addba_req.action_code) {
|
||||
case WLAN_ACTION_ADDBA_REQ:
|
||||
|
@ -3173,33 +3271,32 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
|
|||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u16 fc;
|
||||
__le16 fc;
|
||||
|
||||
if (skb->len < 2)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
mgmt = (struct ieee80211_mgmt *) skb->data;
|
||||
fc = le16_to_cpu(mgmt->frame_control);
|
||||
fc = mgmt->frame_control;
|
||||
|
||||
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
|
||||
if (ieee80211_is_ctl(fc))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (skb->len < 24)
|
||||
return RX_DROP_MONITOR;
|
||||
|
||||
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
|
||||
if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
|
||||
ieee80211_rx_mgmt_probe_resp(dev, mgmt,
|
||||
skb->len, rx_status);
|
||||
dev_kfree_skb(skb);
|
||||
return RX_QUEUED;
|
||||
} else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
|
||||
ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
|
||||
rx_status);
|
||||
dev_kfree_skb(skb);
|
||||
return RX_QUEUED;
|
||||
}
|
||||
if (ieee80211_is_probe_resp(fc)) {
|
||||
ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status);
|
||||
dev_kfree_skb(skb);
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
||||
if (ieee80211_is_beacon(fc)) {
|
||||
ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
|
||||
dev_kfree_skb(skb);
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -3777,7 +3874,7 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
|||
{
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_hdr *nullfunc;
|
||||
u16 fc;
|
||||
__le16 fc;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
|
||||
if (!skb) {
|
||||
|
@ -3789,11 +3886,11 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
|||
|
||||
nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
|
||||
memset(nullfunc, 0, 24);
|
||||
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_TODS;
|
||||
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_TODS);
|
||||
if (powersave)
|
||||
fc |= IEEE80211_FCTL_PM;
|
||||
nullfunc->frame_control = cpu_to_le16(fc);
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
nullfunc->frame_control = fc;
|
||||
memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
|
||||
memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
|
||||
memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
|
||||
|
@ -4087,6 +4184,7 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
|
|||
|
||||
static char *
|
||||
ieee80211_sta_scan_result(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct ieee80211_sta_bss *bss,
|
||||
char *current_ev, char *end_buf)
|
||||
{
|
||||
|
@ -4101,7 +4199,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_ADDR_LEN);
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -4109,13 +4207,13 @@ ieee80211_sta_scan_result(struct net_device *dev,
|
|||
if (bss_mesh_cfg(bss)) {
|
||||
iwe.u.data.length = bss_mesh_id_len(bss);
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
|
||||
bss_mesh_id(bss));
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss_mesh_id(bss));
|
||||
} else {
|
||||
iwe.u.data.length = bss->ssid_len;
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
|
||||
bss->ssid);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->ssid);
|
||||
}
|
||||
|
||||
if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
|
||||
|
@ -4128,22 +4226,22 @@ ieee80211_sta_scan_result(struct net_device *dev,
|
|||
iwe.u.mode = IW_MODE_MASTER;
|
||||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
IW_EV_UINT_LEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
}
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
|
||||
iwe.u.freq.e = 0;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = bss->freq;
|
||||
iwe.u.freq.e = 6;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVQUAL;
|
||||
|
@ -4151,7 +4249,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
|
|||
iwe.u.qual.level = bss->signal;
|
||||
iwe.u.qual.noise = bss->noise;
|
||||
iwe.u.qual.updated = local->wstats_flags;
|
||||
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_QUAL_LEN);
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -4161,35 +4259,36 @@ ieee80211_sta_scan_result(struct net_device *dev,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, "");
|
||||
|
||||
if (bss && bss->wpa_ie) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = bss->wpa_ie_len;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
|
||||
bss->wpa_ie);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->wpa_ie);
|
||||
}
|
||||
|
||||
if (bss && bss->rsn_ie) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = bss->rsn_ie_len;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
|
||||
bss->rsn_ie);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->rsn_ie);
|
||||
}
|
||||
|
||||
if (bss && bss->ht_ie) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = bss->ht_ie_len;
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
|
||||
bss->ht_ie);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, bss->ht_ie);
|
||||
}
|
||||
|
||||
if (bss && bss->supp_rates_len > 0) {
|
||||
/* display all supported rates in readable format */
|
||||
char *p = current_ev + IW_EV_LCP_LEN;
|
||||
char *p = current_ev + iwe_stream_lcp_len(info);
|
||||
int i;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -4200,7 +4299,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
|
|||
for (i = 0; i < bss->supp_rates_len; i++) {
|
||||
iwe.u.bitrate.value = ((bss->supp_rates[i] &
|
||||
0x7f) * 500000);
|
||||
p = iwe_stream_add_value(current_ev, p,
|
||||
p = iwe_stream_add_value(info, current_ev, p,
|
||||
end_buf, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
current_ev = p;
|
||||
|
@ -4214,7 +4313,8 @@ ieee80211_sta_scan_result(struct net_device *dev,
|
|||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
@ -4229,31 +4329,36 @@ ieee80211_sta_scan_result(struct net_device *dev,
|
|||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "Mesh network (version %d)", cfg[0]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
sprintf(buf, "Path Selection Protocol ID: "
|
||||
"0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
|
||||
cfg[4]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
sprintf(buf, "Path Selection Metric ID: "
|
||||
"0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
|
||||
cfg[8]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
sprintf(buf, "Congestion Control Mode ID: "
|
||||
"0x%02X%02X%02X%02X", cfg[9], cfg[10],
|
||||
cfg[11], cfg[12]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
sprintf(buf, "Channel Precedence: "
|
||||
"0x%02X%02X%02X%02X", cfg[13], cfg[14],
|
||||
cfg[15], cfg[16]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(current_ev, end_buf,
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
@ -4263,7 +4368,9 @@ ieee80211_sta_scan_result(struct net_device *dev,
|
|||
}
|
||||
|
||||
|
||||
int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
|
||||
int ieee80211_sta_scan_results(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
char *current_ev = buf;
|
||||
|
@ -4276,8 +4383,8 @@ int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
|
|||
spin_unlock_bh(&local->sta_bss_lock);
|
||||
return -E2BIG;
|
||||
}
|
||||
current_ev = ieee80211_sta_scan_result(dev, bss, current_ev,
|
||||
end_buf);
|
||||
current_ev = ieee80211_sta_scan_result(dev, info, bss,
|
||||
current_ev, end_buf);
|
||||
}
|
||||
spin_unlock_bh(&local->sta_bss_lock);
|
||||
return current_ev - buf;
|
||||
|
|
|
@ -61,7 +61,7 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
|
|||
int present_fcs_len,
|
||||
int radiotap_len)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
|
||||
return 1;
|
||||
|
@ -2123,7 +2123,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
|
|||
struct tid_ampdu_rx *tid_agg_rx;
|
||||
u16 sc;
|
||||
u16 mpdu_seq_num;
|
||||
u8 ret = 0, *qc;
|
||||
u8 ret = 0;
|
||||
int tid;
|
||||
|
||||
sta = sta_info_get(local, hdr->addr2);
|
||||
|
@ -2135,8 +2135,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
|
|||
if (!ieee80211_is_data_qos(hdr->frame_control))
|
||||
goto end_reorder;
|
||||
|
||||
qc = ieee80211_get_qos_ctl(hdr);
|
||||
tid = qc[0] & QOS_CONTROL_TID_MASK;
|
||||
tid = *ieee80211_get_qos_ctl(hdr) & QOS_CONTROL_TID_MASK;
|
||||
|
||||
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
|
||||
goto end_reorder;
|
||||
|
|
|
@ -235,6 +235,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||
return NULL;
|
||||
|
||||
spin_lock_init(&sta->lock);
|
||||
spin_lock_init(&sta->flaglock);
|
||||
|
||||
memcpy(sta->addr, addr, ETH_ALEN);
|
||||
sta->local = local;
|
||||
|
|
|
@ -164,6 +164,7 @@ struct sta_ampdu_mlme {
|
|||
* @aid: STA's unique AID (1..2007, 0 = not assigned yet),
|
||||
* only used in AP (and IBSS?) mode
|
||||
* @flags: STA flags, see &enum ieee80211_sta_info_flags
|
||||
* @flaglock: spinlock for flags accesses
|
||||
* @ps_tx_buf: buffer of frames to transmit to this station
|
||||
* when it leaves power saving state
|
||||
* @tx_filtered: buffer of frames we already tried to transmit
|
||||
|
@ -186,6 +187,7 @@ struct sta_info {
|
|||
struct rate_control_ref *rate_ctrl;
|
||||
void *rate_ctrl_priv;
|
||||
spinlock_t lock;
|
||||
spinlock_t flaglock;
|
||||
struct ieee80211_ht_info ht_info;
|
||||
u64 supp_rates[IEEE80211_NUM_BANDS];
|
||||
u8 addr[ETH_ALEN];
|
||||
|
@ -198,7 +200,10 @@ struct sta_info {
|
|||
*/
|
||||
u8 pin_status;
|
||||
|
||||
/* frequently updated information, locked with lock spinlock */
|
||||
/*
|
||||
* frequently updated, locked with own spinlock (flaglock),
|
||||
* use the accessors defined below
|
||||
*/
|
||||
u32 flags;
|
||||
|
||||
/*
|
||||
|
@ -293,34 +298,41 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta)
|
|||
|
||||
static inline void set_sta_flags(struct sta_info *sta, const u32 flags)
|
||||
{
|
||||
spin_lock_bh(&sta->lock);
|
||||
unsigned long irqfl;
|
||||
|
||||
spin_lock_irqsave(&sta->flaglock, irqfl);
|
||||
sta->flags |= flags;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_irqrestore(&sta->flaglock, irqfl);
|
||||
}
|
||||
|
||||
static inline void clear_sta_flags(struct sta_info *sta, const u32 flags)
|
||||
{
|
||||
spin_lock_bh(&sta->lock);
|
||||
unsigned long irqfl;
|
||||
|
||||
spin_lock_irqsave(&sta->flaglock, irqfl);
|
||||
sta->flags &= ~flags;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_irqrestore(&sta->flaglock, irqfl);
|
||||
}
|
||||
|
||||
static inline void set_and_clear_sta_flags(struct sta_info *sta,
|
||||
const u32 set, const u32 clear)
|
||||
{
|
||||
spin_lock_bh(&sta->lock);
|
||||
unsigned long irqfl;
|
||||
|
||||
spin_lock_irqsave(&sta->flaglock, irqfl);
|
||||
sta->flags |= set;
|
||||
sta->flags &= ~clear;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_irqrestore(&sta->flaglock, irqfl);
|
||||
}
|
||||
|
||||
static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags)
|
||||
{
|
||||
u32 ret;
|
||||
unsigned long irqfl;
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock_irqsave(&sta->flaglock, irqfl);
|
||||
ret = sta->flags & flags;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_irqrestore(&sta->flaglock, irqfl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -329,11 +341,12 @@ static inline u32 test_and_clear_sta_flags(struct sta_info *sta,
|
|||
const u32 flags)
|
||||
{
|
||||
u32 ret;
|
||||
unsigned long irqfl;
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock_irqsave(&sta->flaglock, irqfl);
|
||||
ret = sta->flags & flags;
|
||||
sta->flags &= ~flags;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_irqrestore(&sta->flaglock, irqfl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -341,10 +354,11 @@ static inline u32 test_and_clear_sta_flags(struct sta_info *sta,
|
|||
static inline u32 get_sta_flags(struct sta_info *sta)
|
||||
{
|
||||
u32 ret;
|
||||
unsigned long irqfl;
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock_irqsave(&sta->flaglock, irqfl);
|
||||
ret = sta->flags;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_irqrestore(&sta->flaglock, irqfl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -164,10 +164,10 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
|
|||
iv16 = data[2] | (data[0] << 8);
|
||||
iv32 = get_unaligned_le32(&data[4]);
|
||||
|
||||
tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
|
||||
tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
|
||||
ctx = &key->u.tkip.tx;
|
||||
|
||||
#ifdef CONFIG_TKIP_DEBUG
|
||||
#ifdef CONFIG_MAC80211_TKIP_DEBUG
|
||||
printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
|
||||
iv16, iv32);
|
||||
|
||||
|
@ -177,7 +177,7 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
|
|||
printk(KERN_DEBUG "Wrap around of iv16 in the middle of a "
|
||||
"fragmented packet\n");
|
||||
}
|
||||
#endif /* CONFIG_TKIP_DEBUG */
|
||||
#endif
|
||||
|
||||
/* Update the p1k only when the iv16 in the packet wraps around, this
|
||||
* might occur after the wrap around of iv16 in the key in case of
|
||||
|
@ -205,7 +205,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
|
|||
{
|
||||
u8 rc4key[16];
|
||||
struct tkip_ctx *ctx = &key->u.tkip.tx;
|
||||
const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
|
||||
const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
|
||||
|
||||
/* Calculate per-packet key */
|
||||
if (ctx->iv16 == 0 || !ctx->initialized)
|
||||
|
@ -231,7 +231,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
|
|||
u32 iv16;
|
||||
u8 rc4key[16], keyid, *pos = payload;
|
||||
int res;
|
||||
const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
|
||||
const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
|
||||
|
||||
if (payload_len < 12)
|
||||
return -1;
|
||||
|
@ -240,7 +240,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
|
|||
keyid = pos[3];
|
||||
iv32 = get_unaligned_le32(pos + 4);
|
||||
pos += 8;
|
||||
#ifdef CONFIG_TKIP_DEBUG
|
||||
#ifdef CONFIG_MAC80211_TKIP_DEBUG
|
||||
{
|
||||
int i;
|
||||
printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len);
|
||||
|
@ -250,7 +250,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
|
|||
printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n",
|
||||
iv16, iv32);
|
||||
}
|
||||
#endif /* CONFIG_TKIP_DEBUG */
|
||||
#endif
|
||||
|
||||
if (!(keyid & (1 << 5)))
|
||||
return TKIP_DECRYPT_NO_EXT_IV;
|
||||
|
@ -262,14 +262,14 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
|
|||
(iv32 < key->u.tkip.rx[queue].iv32 ||
|
||||
(iv32 == key->u.tkip.rx[queue].iv32 &&
|
||||
iv16 <= key->u.tkip.rx[queue].iv16))) {
|
||||
#ifdef CONFIG_TKIP_DEBUG
|
||||
#ifdef CONFIG_MAC80211_TKIP_DEBUG
|
||||
DECLARE_MAC_BUF(mac);
|
||||
printk(KERN_DEBUG "TKIP replay detected for RX frame from "
|
||||
"%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
|
||||
print_mac(mac, ta),
|
||||
iv32, iv16, key->u.tkip.rx[queue].iv32,
|
||||
key->u.tkip.rx[queue].iv16);
|
||||
#endif /* CONFIG_TKIP_DEBUG */
|
||||
#endif
|
||||
return TKIP_DECRYPT_REPLAY;
|
||||
}
|
||||
|
||||
|
@ -283,23 +283,23 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
|
|||
key->u.tkip.rx[queue].iv32 != iv32) {
|
||||
/* IV16 wrapped around - perform TKIP phase 1 */
|
||||
tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
|
||||
#ifdef CONFIG_TKIP_DEBUG
|
||||
#ifdef CONFIG_MAC80211_TKIP_DEBUG
|
||||
{
|
||||
int i;
|
||||
u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s"
|
||||
" TK=", print_mac(mac, ta));
|
||||
for (i = 0; i < 16; i++)
|
||||
printk("%02x ",
|
||||
key->conf.key[
|
||||
ALG_TKIP_TEMP_ENCR_KEY + i]);
|
||||
key->conf.key[key_offset + i]);
|
||||
printk("\n");
|
||||
printk(KERN_DEBUG "TKIP decrypt: P1K=");
|
||||
for (i = 0; i < 5; i++)
|
||||
printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
|
||||
printk("\n");
|
||||
}
|
||||
#endif /* CONFIG_TKIP_DEBUG */
|
||||
#endif
|
||||
if (key->local->ops->update_tkip_key &&
|
||||
key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
|
||||
u8 bcast[ETH_ALEN] =
|
||||
|
@ -316,7 +316,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
|
|||
}
|
||||
|
||||
tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
|
||||
#ifdef CONFIG_TKIP_DEBUG
|
||||
#ifdef CONFIG_MAC80211_TKIP_DEBUG
|
||||
{
|
||||
int i;
|
||||
printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key=");
|
||||
|
@ -324,7 +324,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
|
|||
printk("%02x ", rc4key[i]);
|
||||
printk("\n");
|
||||
}
|
||||
#endif /* CONFIG_TKIP_DEBUG */
|
||||
#endif
|
||||
|
||||
res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
|
||||
done:
|
||||
|
|
|
@ -52,9 +52,8 @@ static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdat
|
|||
static void ieee80211_dump_frame(const char *ifname, const char *title,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 fc;
|
||||
int hdrlen;
|
||||
const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
unsigned int hdrlen;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
|
||||
|
@ -63,13 +62,12 @@ static void ieee80211_dump_frame(const char *ifname, const char *title,
|
|||
return;
|
||||
}
|
||||
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
hdrlen = ieee80211_get_hdrlen(fc);
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
if (hdrlen > skb->len)
|
||||
hdrlen = skb->len;
|
||||
if (hdrlen >= 4)
|
||||
printk(" FC=0x%04x DUR=0x%04x",
|
||||
fc, le16_to_cpu(hdr->duration_id));
|
||||
le16_to_cpu(hdr->frame_control), le16_to_cpu(hdr->duration_id));
|
||||
if (hdrlen >= 10)
|
||||
printk(" A1=%s", print_mac(mac, hdr->addr1));
|
||||
if (hdrlen >= 16)
|
||||
|
@ -87,8 +85,8 @@ static inline void ieee80211_dump_frame(const char *ifname, const char *title,
|
|||
}
|
||||
#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
|
||||
|
||||
static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
|
||||
int next_frag_len)
|
||||
static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
|
||||
int next_frag_len)
|
||||
{
|
||||
int rate, mrate, erp, dur, i;
|
||||
struct ieee80211_rate *txrate;
|
||||
|
@ -140,7 +138,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
|
|||
|
||||
/* data/mgmt */
|
||||
if (0 /* FIX: data/mgmt during CFP */)
|
||||
return 32768;
|
||||
return cpu_to_le16(32768);
|
||||
|
||||
if (group_addr) /* Group address as the destination - no ACK */
|
||||
return 0;
|
||||
|
@ -210,7 +208,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
|
|||
tx->sdata->bss_conf.use_short_preamble);
|
||||
}
|
||||
|
||||
return dur;
|
||||
return cpu_to_le16(dur);
|
||||
}
|
||||
|
||||
static int inline is_ieee80211_device(struct net_device *dev,
|
||||
|
@ -281,7 +279,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
|
|||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
|
||||
if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
|
||||
if (ieee80211_hdrlen(hdr->frame_control) >= 24)
|
||||
ieee80211_include_sequence(tx->sdata, hdr);
|
||||
|
||||
return TX_CONTINUE;
|
||||
|
@ -542,9 +540,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
|||
static ieee80211_tx_result
|
||||
ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
|
||||
u16 fc = le16_to_cpu(hdr->frame_control);
|
||||
u16 dur;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
|
@ -595,21 +591,13 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
|
|||
/* Transmit data frames using short preambles if the driver supports
|
||||
* short preambles at the selected rate and short preambles are
|
||||
* available on the network at the current point in time. */
|
||||
if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
|
||||
if (ieee80211_is_data(hdr->frame_control) &&
|
||||
(sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
|
||||
tx->sdata->bss_conf.use_short_preamble &&
|
||||
(!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
|
||||
info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
|
||||
}
|
||||
|
||||
/* Setup duration field for the first fragment of the frame. Duration
|
||||
* for remaining fragments will be updated when they are being sent
|
||||
* to low-level driver in ieee80211_tx(). */
|
||||
dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
|
||||
(tx->flags & IEEE80211_TX_FRAGMENTED) ?
|
||||
tx->extra_frag[0]->len : 0);
|
||||
hdr->duration_id = cpu_to_le16(dur);
|
||||
|
||||
if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
|
||||
(info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
|
||||
struct ieee80211_rate *rate;
|
||||
|
@ -647,7 +635,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
|
|||
static ieee80211_tx_result
|
||||
ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
size_t hdrlen, per_fragm, num_fragm, payload_len, left;
|
||||
struct sk_buff **frags, *first, *frag;
|
||||
int i;
|
||||
|
@ -670,7 +658,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
|||
|
||||
first = tx->skb;
|
||||
|
||||
hdrlen = ieee80211_get_hdrlen(tx->fc);
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
payload_len = first->len - hdrlen;
|
||||
per_fragm = frag_threshold - hdrlen - FCS_LEN;
|
||||
num_fragm = DIV_ROUND_UP(payload_len, per_fragm);
|
||||
|
@ -711,6 +699,8 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
|||
fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
|
||||
copylen = left > per_fragm ? per_fragm : left;
|
||||
memcpy(skb_put(frag, copylen), pos, copylen);
|
||||
memcpy(frag->cb, first->cb, sizeof(frag->cb));
|
||||
skb_copy_queue_mapping(frag, first);
|
||||
|
||||
pos += copylen;
|
||||
left -= copylen;
|
||||
|
@ -754,6 +744,36 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
|
|||
return TX_DROP;
|
||||
}
|
||||
|
||||
static ieee80211_tx_result
|
||||
ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
int next_len, i;
|
||||
int group_addr = is_multicast_ether_addr(hdr->addr1);
|
||||
|
||||
if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) {
|
||||
hdr->duration_id = ieee80211_duration(tx, group_addr, 0);
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
hdr->duration_id = ieee80211_duration(tx, group_addr,
|
||||
tx->extra_frag[0]->len);
|
||||
|
||||
for (i = 0; i < tx->num_extra_frag; i++) {
|
||||
if (i + 1 < tx->num_extra_frag) {
|
||||
next_len = tx->extra_frag[i + 1]->len;
|
||||
} else {
|
||||
next_len = 0;
|
||||
tx->rate_idx = tx->last_frag_rate_idx;
|
||||
}
|
||||
|
||||
hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data;
|
||||
hdr->duration_id = ieee80211_duration(tx, 0, next_len);
|
||||
}
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static ieee80211_tx_result
|
||||
ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
|
@ -788,6 +808,7 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] =
|
|||
ieee80211_tx_h_fragment,
|
||||
/* handlers after fragment must be aware of tx info fragmentation! */
|
||||
ieee80211_tx_h_encrypt,
|
||||
ieee80211_tx_h_calculate_duration,
|
||||
ieee80211_tx_h_stats,
|
||||
NULL
|
||||
};
|
||||
|
@ -1083,13 +1104,46 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
|
|||
return IEEE80211_TX_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke TX handlers, return 0 on success and non-zero if the
|
||||
* frame was dropped or queued.
|
||||
*/
|
||||
static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_local *local = tx->local;
|
||||
struct sk_buff *skb = tx->skb;
|
||||
ieee80211_tx_handler *handler;
|
||||
ieee80211_tx_result res = TX_DROP;
|
||||
int i;
|
||||
|
||||
for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
|
||||
res = (*handler)(tx);
|
||||
if (res != TX_CONTINUE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(res == TX_DROP)) {
|
||||
I802_DEBUG_INC(local->tx_handlers_drop);
|
||||
dev_kfree_skb(skb);
|
||||
for (i = 0; i < tx->num_extra_frag; i++)
|
||||
if (tx->extra_frag[i])
|
||||
dev_kfree_skb(tx->extra_frag[i]);
|
||||
kfree(tx->extra_frag);
|
||||
return -1;
|
||||
} else if (unlikely(res == TX_QUEUED)) {
|
||||
I802_DEBUG_INC(local->tx_handlers_queued);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct sta_info *sta;
|
||||
ieee80211_tx_handler *handler;
|
||||
struct ieee80211_tx_data tx;
|
||||
ieee80211_tx_result res = TX_DROP, res_prepare;
|
||||
ieee80211_tx_result res_prepare;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
int ret, i;
|
||||
u16 queue;
|
||||
|
@ -1118,44 +1172,8 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
|
|||
tx.channel = local->hw.conf.channel;
|
||||
info->band = tx.channel->band;
|
||||
|
||||
for (handler = ieee80211_tx_handlers; *handler != NULL;
|
||||
handler++) {
|
||||
res = (*handler)(&tx);
|
||||
if (res != TX_CONTINUE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (WARN_ON(tx.skb != skb))
|
||||
goto drop;
|
||||
|
||||
if (unlikely(res == TX_DROP)) {
|
||||
I802_DEBUG_INC(local->tx_handlers_drop);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (unlikely(res == TX_QUEUED)) {
|
||||
I802_DEBUG_INC(local->tx_handlers_queued);
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tx.extra_frag) {
|
||||
for (i = 0; i < tx.num_extra_frag; i++) {
|
||||
int next_len, dur;
|
||||
struct ieee80211_hdr *hdr =
|
||||
(struct ieee80211_hdr *)
|
||||
tx.extra_frag[i]->data;
|
||||
|
||||
if (i + 1 < tx.num_extra_frag) {
|
||||
next_len = tx.extra_frag[i + 1]->len;
|
||||
} else {
|
||||
next_len = 0;
|
||||
tx.rate_idx = tx.last_frag_rate_idx;
|
||||
}
|
||||
dur = ieee80211_duration(&tx, 0, next_len);
|
||||
hdr->duration_id = cpu_to_le16(dur);
|
||||
}
|
||||
}
|
||||
if (invoke_tx_handlers(&tx))
|
||||
goto out;
|
||||
|
||||
retry:
|
||||
ret = __ieee80211_tx(local, skb, &tx);
|
||||
|
@ -1198,6 +1216,7 @@ retry:
|
|||
store->last_frag_rate_ctrl_probe =
|
||||
!!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
|
||||
}
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
|
||||
|
@ -1379,7 +1398,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int ret = 1, head_need;
|
||||
u16 ethertype, hdrlen, meshhdrlen = 0, fc;
|
||||
u16 ethertype, hdrlen, meshhdrlen = 0;
|
||||
__le16 fc;
|
||||
struct ieee80211_hdr hdr;
|
||||
struct ieee80211s_hdr mesh_hdr;
|
||||
const u8 *encaps_data;
|
||||
|
@ -1402,12 +1422,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
/* convert Ethernet header to proper 802.11 header (based on
|
||||
* operation mode) */
|
||||
ethertype = (skb->data[12] << 8) | skb->data[13];
|
||||
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
|
||||
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case IEEE80211_IF_TYPE_AP:
|
||||
case IEEE80211_IF_TYPE_VLAN:
|
||||
fc |= IEEE80211_FCTL_FROMDS;
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
|
||||
/* DA BSSID SA */
|
||||
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
||||
memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
|
||||
|
@ -1415,7 +1435,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
hdrlen = 24;
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_WDS:
|
||||
fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
|
||||
/* RA TA DA SA */
|
||||
memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
|
||||
memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
|
||||
|
@ -1425,7 +1445,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
break;
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case IEEE80211_IF_TYPE_MESH_POINT:
|
||||
fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
|
||||
/* RA TA DA SA */
|
||||
if (is_multicast_ether_addr(skb->data))
|
||||
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
||||
|
@ -1455,7 +1475,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
break;
|
||||
#endif
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
fc |= IEEE80211_FCTL_TODS;
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
|
||||
/* BSSID SA DA */
|
||||
memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
|
||||
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
||||
|
@ -1490,7 +1510,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
/* receiver and we are QoS enabled, use a QoS type frame */
|
||||
if (sta_flags & WLAN_STA_WME &&
|
||||
ieee80211_num_regular_queues(&local->hw) >= 4) {
|
||||
fc |= IEEE80211_STYPE_QOS_DATA;
|
||||
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||
hdrlen += 2;
|
||||
}
|
||||
|
||||
|
@ -1518,7 +1538,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
hdr.frame_control = cpu_to_le16(fc);
|
||||
hdr.frame_control = fc;
|
||||
hdr.duration_id = 0;
|
||||
hdr.seq_ctrl = 0;
|
||||
|
||||
|
@ -1587,7 +1607,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
h_pos += meshhdrlen;
|
||||
}
|
||||
|
||||
if (fc & IEEE80211_STYPE_QOS_DATA) {
|
||||
if (ieee80211_is_data_qos(fc)) {
|
||||
__le16 *qos_control;
|
||||
|
||||
qos_control = (__le16*) skb_push(skb, 2);
|
||||
|
@ -1845,8 +1865,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
mgmt = (struct ieee80211_mgmt *)
|
||||
skb_put(skb, 24 + sizeof(mgmt->u.beacon));
|
||||
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
|
||||
mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
|
||||
IEEE80211_STYPE_BEACON);
|
||||
mgmt->frame_control =
|
||||
cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
|
||||
memset(mgmt->da, 0xff, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
|
||||
/* BSSID is left zeroed, wildcard value */
|
||||
|
@ -1914,10 +1934,9 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
struct ieee80211_rts *rts)
|
||||
{
|
||||
const struct ieee80211_hdr *hdr = frame;
|
||||
u16 fctl;
|
||||
|
||||
fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
|
||||
rts->frame_control = cpu_to_le16(fctl);
|
||||
rts->frame_control =
|
||||
cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
|
||||
rts->duration = ieee80211_rts_duration(hw, vif, frame_len,
|
||||
frame_txctl);
|
||||
memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
|
||||
|
@ -1931,10 +1950,9 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
struct ieee80211_cts *cts)
|
||||
{
|
||||
const struct ieee80211_hdr *hdr = frame;
|
||||
u16 fctl;
|
||||
|
||||
fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;
|
||||
cts->frame_control = cpu_to_le16(fctl);
|
||||
cts->frame_control =
|
||||
cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
|
||||
cts->duration = ieee80211_ctstoself_duration(hw, vif,
|
||||
frame_len, frame_txctl);
|
||||
memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
|
||||
|
@ -1948,9 +1966,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
|
|||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sk_buff *skb = NULL;
|
||||
struct sta_info *sta;
|
||||
ieee80211_tx_handler *handler;
|
||||
struct ieee80211_tx_data tx;
|
||||
ieee80211_tx_result res = TX_DROP;
|
||||
struct net_device *bdev;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_if_ap *bss = NULL;
|
||||
|
@ -2001,25 +2017,9 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
|
|||
tx.channel = local->hw.conf.channel;
|
||||
info->band = tx.channel->band;
|
||||
|
||||
for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
|
||||
res = (*handler)(&tx);
|
||||
if (res == TX_DROP || res == TX_QUEUED)
|
||||
break;
|
||||
}
|
||||
|
||||
if (WARN_ON(tx.skb != skb))
|
||||
res = TX_DROP;
|
||||
|
||||
if (res == TX_DROP) {
|
||||
I802_DEBUG_INC(local->tx_handlers_drop);
|
||||
dev_kfree_skb(skb);
|
||||
if (invoke_tx_handlers(&tx))
|
||||
skb = NULL;
|
||||
} else if (res == TX_QUEUED) {
|
||||
I802_DEBUG_INC(local->tx_handlers_queued);
|
||||
skb = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
||||
return skb;
|
||||
|
|
|
@ -84,20 +84,17 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
|
|||
struct sk_buff *skb,
|
||||
struct ieee80211_key *key)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 fc;
|
||||
int hdrlen;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
unsigned int hdrlen;
|
||||
u8 *newhdr;
|
||||
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
fc |= IEEE80211_FCTL_PROTECTED;
|
||||
hdr->frame_control = cpu_to_le16(fc);
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
|
||||
if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN ||
|
||||
skb_headroom(skb) < WEP_IV_LEN))
|
||||
return NULL;
|
||||
|
||||
hdrlen = ieee80211_get_hdrlen(fc);
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
newhdr = skb_push(skb, WEP_IV_LEN);
|
||||
memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
|
||||
ieee80211_wep_get_iv(local, key, newhdr + hdrlen);
|
||||
|
@ -109,12 +106,10 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local,
|
|||
struct sk_buff *skb,
|
||||
struct ieee80211_key *key)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 fc;
|
||||
int hdrlen;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
unsigned int hdrlen;
|
||||
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
hdrlen = ieee80211_get_hdrlen(fc);
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen);
|
||||
skb_pull(skb, WEP_IV_LEN);
|
||||
}
|
||||
|
@ -224,17 +219,15 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
|
|||
u32 klen;
|
||||
u8 *rc4key;
|
||||
u8 keyidx;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 fc;
|
||||
int hdrlen;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
unsigned int hdrlen;
|
||||
size_t len;
|
||||
int ret = 0;
|
||||
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
if (!(fc & IEEE80211_FCTL_PROTECTED))
|
||||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
return -1;
|
||||
|
||||
hdrlen = ieee80211_get_hdrlen(fc);
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
if (skb->len < 8 + hdrlen)
|
||||
return -1;
|
||||
|
@ -281,17 +274,15 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
|
|||
|
||||
u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 fc;
|
||||
int hdrlen;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
unsigned int hdrlen;
|
||||
u8 *ivpos;
|
||||
u32 iv;
|
||||
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
if (!(fc & IEEE80211_FCTL_PROTECTED))
|
||||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
return NULL;
|
||||
|
||||
hdrlen = ieee80211_get_hdrlen(fc);
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
ivpos = skb->data + hdrlen;
|
||||
iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
|
||||
|
||||
|
|
|
@ -135,7 +135,39 @@ static int ieee80211_ioctl_giwname(struct net_device *dev,
|
|||
struct iw_request_info *info,
|
||||
char *name, char *extra)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_supported_band *sband;
|
||||
u8 is_ht = 0, is_a = 0, is_b = 0, is_g = 0;
|
||||
|
||||
|
||||
sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ];
|
||||
if (sband) {
|
||||
is_a = 1;
|
||||
is_ht |= sband->ht_info.ht_supported;
|
||||
}
|
||||
|
||||
sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ];
|
||||
if (sband) {
|
||||
int i;
|
||||
/* Check for mandatory rates */
|
||||
for (i = 0; i < sband->n_bitrates; i++) {
|
||||
if (sband->bitrates[i].bitrate == 10)
|
||||
is_b = 1;
|
||||
if (sband->bitrates[i].bitrate == 60)
|
||||
is_g = 1;
|
||||
}
|
||||
is_ht |= sband->ht_info.ht_supported;
|
||||
}
|
||||
|
||||
strcpy(name, "IEEE 802.11");
|
||||
if (is_a)
|
||||
strcat(name, "a");
|
||||
if (is_b)
|
||||
strcat(name, "b");
|
||||
if (is_g)
|
||||
strcat(name, "g");
|
||||
if (is_ht)
|
||||
strcat(name, "n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -567,7 +599,7 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
|
|||
if (local->sta_sw_scanning || local->sta_hw_scanning)
|
||||
return -EAGAIN;
|
||||
|
||||
res = ieee80211_sta_scan_results(dev, extra, data->length);
|
||||
res = ieee80211_sta_scan_results(dev, info, extra, data->length);
|
||||
if (res >= 0) {
|
||||
data->length = res;
|
||||
return 0;
|
||||
|
@ -721,6 +753,9 @@ static int ieee80211_ioctl_siwrts(struct net_device *dev,
|
|||
|
||||
if (rts->disabled)
|
||||
local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
|
||||
else if (!rts->fixed)
|
||||
/* if the rts value is not fixed, then take default */
|
||||
local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
|
||||
else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
|
||||
return -EINVAL;
|
||||
else
|
||||
|
@ -949,6 +984,19 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
|
|||
erq->length = sdata->keys[idx]->conf.keylen;
|
||||
erq->flags |= IW_ENCODE_ENABLED;
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
|
||||
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
|
||||
switch (ifsta->auth_alg) {
|
||||
case WLAN_AUTH_OPEN:
|
||||
case WLAN_AUTH_LEAP:
|
||||
erq->flags |= IW_ENCODE_OPEN;
|
||||
break;
|
||||
case WLAN_AUTH_SHARED_KEY:
|
||||
erq->flags |= IW_ENCODE_RESTRICTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
|
|||
ieee80211_tx_result
|
||||
ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
u8 *data, *sa, *da, *key, *mic, qos_tid;
|
||||
u8 *data, *sa, *da, *key, *mic, qos_tid, key_offset;
|
||||
size_t data_len;
|
||||
u16 fc;
|
||||
struct sk_buff *skb = tx->skb;
|
||||
|
@ -88,8 +88,12 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
|
|||
#else
|
||||
authenticator = 1;
|
||||
#endif
|
||||
key = &tx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY :
|
||||
ALG_TKIP_TEMP_AUTH_RX_MIC_KEY];
|
||||
/* At this point we know we're using ALG_TKIP. To get the MIC key
|
||||
* we now will rely on the offset from the ieee80211_key_conf::key */
|
||||
key_offset = authenticator ?
|
||||
NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY :
|
||||
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
|
||||
key = &tx->key->conf.key[key_offset];
|
||||
mic = skb_put(skb, MICHAEL_MIC_LEN);
|
||||
michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
|
||||
|
||||
|
@ -100,7 +104,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
|
|||
ieee80211_rx_result
|
||||
ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
u8 *data, *sa, *da, *key = NULL, qos_tid;
|
||||
u8 *data, *sa, *da, *key = NULL, qos_tid, key_offset;
|
||||
size_t data_len;
|
||||
u16 fc;
|
||||
u8 mic[MICHAEL_MIC_LEN];
|
||||
|
@ -131,8 +135,12 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
|||
#else
|
||||
authenticator = 1;
|
||||
#endif
|
||||
key = &rx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY :
|
||||
ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
|
||||
/* At this point we know we're using ALG_TKIP. To get the MIC key
|
||||
* we now will rely on the offset from the ieee80211_key_conf::key */
|
||||
key_offset = authenticator ?
|
||||
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY :
|
||||
NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
|
||||
key = &rx->key->conf.key[key_offset];
|
||||
michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
|
||||
if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
|
||||
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
||||
|
|
|
@ -30,39 +30,43 @@ struct rfkill_task {
|
|||
spinlock_t lock; /* for accessing last and desired state */
|
||||
unsigned long last; /* last schedule */
|
||||
enum rfkill_state desired_state; /* on/off */
|
||||
enum rfkill_state current_state; /* on/off */
|
||||
};
|
||||
|
||||
static void rfkill_task_handler(struct work_struct *work)
|
||||
{
|
||||
struct rfkill_task *task = container_of(work, struct rfkill_task, work);
|
||||
enum rfkill_state state;
|
||||
|
||||
mutex_lock(&task->mutex);
|
||||
|
||||
/*
|
||||
* Use temp variable to fetch desired state to keep it
|
||||
* consistent even if rfkill_schedule_toggle() runs in
|
||||
* another thread or interrupts us.
|
||||
*/
|
||||
state = task->desired_state;
|
||||
|
||||
if (state != task->current_state) {
|
||||
rfkill_switch_all(task->type, state);
|
||||
task->current_state = state;
|
||||
}
|
||||
rfkill_switch_all(task->type, task->desired_state);
|
||||
|
||||
mutex_unlock(&task->mutex);
|
||||
}
|
||||
|
||||
static void rfkill_schedule_toggle(struct rfkill_task *task)
|
||||
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 = !task->desired_state;
|
||||
task->desired_state = desired_state;
|
||||
task->last = jiffies;
|
||||
schedule_work(&task->work);
|
||||
}
|
||||
|
@ -70,26 +74,45 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
|
|||
spin_unlock_irqrestore(&task->lock, flags);
|
||||
}
|
||||
|
||||
#define DEFINE_RFKILL_TASK(n, t) \
|
||||
struct rfkill_task n = { \
|
||||
.work = __WORK_INITIALIZER(n.work, \
|
||||
rfkill_task_handler), \
|
||||
.type = t, \
|
||||
.mutex = __MUTEX_INITIALIZER(n.mutex), \
|
||||
.lock = __SPIN_LOCK_UNLOCKED(n.lock), \
|
||||
.desired_state = RFKILL_STATE_ON, \
|
||||
.current_state = RFKILL_STATE_ON, \
|
||||
static void rfkill_schedule_toggle(struct rfkill_task *task)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(work_pending(&epo_work)))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&task->lock, flags);
|
||||
|
||||
if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
|
||||
task->desired_state =
|
||||
rfkill_state_complement(task->desired_state);
|
||||
task->last = jiffies;
|
||||
schedule_work(&task->work);
|
||||
}
|
||||
|
||||
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_UNBLOCKED, \
|
||||
}
|
||||
|
||||
static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
|
||||
static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
|
||||
static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
|
||||
static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
|
||||
static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
|
||||
|
||||
static void rfkill_event(struct input_handle *handle, unsigned int type,
|
||||
unsigned int code, int down)
|
||||
unsigned int code, int data)
|
||||
{
|
||||
if (type == EV_KEY && down == 1) {
|
||||
if (type == EV_KEY && data == 1) {
|
||||
switch (code) {
|
||||
case KEY_WLAN:
|
||||
rfkill_schedule_toggle(&rfkill_wlan);
|
||||
|
@ -106,6 +129,28 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
} else if (type == EV_SW) {
|
||||
switch (code) {
|
||||
case SW_RFKILL_ALL:
|
||||
/* EVERY radio type. data != 0 means radios ON */
|
||||
/* handle EPO (emergency power off) through shortcut */
|
||||
if (data) {
|
||||
rfkill_schedule_set(&rfkill_wwan,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
rfkill_schedule_set(&rfkill_wimax,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
rfkill_schedule_set(&rfkill_uwb,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
rfkill_schedule_set(&rfkill_bt,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
rfkill_schedule_set(&rfkill_wlan,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
} else
|
||||
rfkill_schedule_epo();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,6 +213,11 @@ static const struct input_device_id rfkill_ids[] = {
|
|||
.evbit = { BIT_MASK(EV_KEY) },
|
||||
.keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
|
||||
},
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT,
|
||||
.evbit = { BIT(EV_SW) },
|
||||
.swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) },
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
#define __RFKILL_INPUT_H
|
||||
|
||||
void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
|
||||
void rfkill_epo(void);
|
||||
|
||||
#endif /* __RFKILL_INPUT_H */
|
||||
|
|
|
@ -39,8 +39,56 @@ MODULE_LICENSE("GPL");
|
|||
static LIST_HEAD(rfkill_list); /* list of registered rf switches */
|
||||
static DEFINE_MUTEX(rfkill_mutex);
|
||||
|
||||
static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED;
|
||||
module_param_named(default_state, rfkill_default_state, uint, 0444);
|
||||
MODULE_PARM_DESC(default_state,
|
||||
"Default initial state for all radio types, 0 = radio off");
|
||||
|
||||
static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX];
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list);
|
||||
|
||||
|
||||
/**
|
||||
* register_rfkill_notifier - Add notifier to rfkill notifier chain
|
||||
* @nb: pointer to the new entry to add to the chain
|
||||
*
|
||||
* See blocking_notifier_chain_register() for return value and further
|
||||
* observations.
|
||||
*
|
||||
* Adds a notifier to the rfkill notifier chain. The chain will be
|
||||
* called with a pointer to the relevant rfkill structure as a parameter,
|
||||
* refer to include/linux/rfkill.h for the possible events.
|
||||
*
|
||||
* Notifiers added to this chain are to always return NOTIFY_DONE. This
|
||||
* chain is a blocking notifier chain: notifiers can sleep.
|
||||
*
|
||||
* Calls to this chain may have been done through a workqueue. One must
|
||||
* assume unordered asynchronous behaviour, there is no way to know if
|
||||
* actions related to the event that generated the notification have been
|
||||
* carried out already.
|
||||
*/
|
||||
int register_rfkill_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&rfkill_notifier_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_rfkill_notifier);
|
||||
|
||||
/**
|
||||
* unregister_rfkill_notifier - remove notifier from rfkill notifier chain
|
||||
* @nb: pointer to the entry to remove from the chain
|
||||
*
|
||||
* See blocking_notifier_chain_unregister() for return value and further
|
||||
* observations.
|
||||
*
|
||||
* Removes a notifier from the rfkill notifier chain.
|
||||
*/
|
||||
int unregister_rfkill_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_rfkill_notifier);
|
||||
|
||||
|
||||
static void rfkill_led_trigger(struct rfkill *rfkill,
|
||||
enum rfkill_state state)
|
||||
|
@ -50,24 +98,99 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
|
|||
|
||||
if (!led->name)
|
||||
return;
|
||||
if (state == RFKILL_STATE_OFF)
|
||||
if (state != RFKILL_STATE_UNBLOCKED)
|
||||
led_trigger_event(led, LED_OFF);
|
||||
else
|
||||
led_trigger_event(led, LED_FULL);
|
||||
#endif /* CONFIG_RFKILL_LEDS */
|
||||
}
|
||||
|
||||
static void notify_rfkill_state_change(struct rfkill *rfkill)
|
||||
{
|
||||
blocking_notifier_call_chain(&rfkill_notifier_list,
|
||||
RFKILL_STATE_CHANGED,
|
||||
rfkill);
|
||||
}
|
||||
|
||||
static void update_rfkill_state(struct rfkill *rfkill)
|
||||
{
|
||||
enum rfkill_state newstate, oldstate;
|
||||
|
||||
if (rfkill->get_state) {
|
||||
mutex_lock(&rfkill->mutex);
|
||||
if (!rfkill->get_state(rfkill->data, &newstate)) {
|
||||
oldstate = rfkill->state;
|
||||
rfkill->state = newstate;
|
||||
if (oldstate != newstate)
|
||||
notify_rfkill_state_change(rfkill);
|
||||
}
|
||||
mutex_unlock(&rfkill->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rfkill_toggle_radio - wrapper for toggle_radio hook
|
||||
* calls toggle_radio taking into account a lot of "small"
|
||||
* details.
|
||||
* @rfkill: the rfkill struct to use
|
||||
* @force: calls toggle_radio even if cache says it is not needed,
|
||||
* and also makes sure notifications of the state will be
|
||||
* sent even if it didn't change
|
||||
* @state: the new state to call toggle_radio() with
|
||||
*
|
||||
* This wrappen protects and enforces the API for toggle_radio
|
||||
* calls. Note that @force cannot override a (possibly cached)
|
||||
* state of RFKILL_STATE_HARD_BLOCKED. Any device making use of
|
||||
* RFKILL_STATE_HARD_BLOCKED implements either get_state() or
|
||||
* rfkill_force_state(), so the cache either is bypassed or valid.
|
||||
*
|
||||
* Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED
|
||||
* even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to
|
||||
* give the driver a hint that it should double-BLOCK the transmitter.
|
||||
*
|
||||
* Caller must have aquired rfkill_mutex.
|
||||
*/
|
||||
static int rfkill_toggle_radio(struct rfkill *rfkill,
|
||||
enum rfkill_state state)
|
||||
enum rfkill_state state,
|
||||
int force)
|
||||
{
|
||||
int retval = 0;
|
||||
enum rfkill_state oldstate, newstate;
|
||||
|
||||
if (state != rfkill->state) {
|
||||
oldstate = rfkill->state;
|
||||
|
||||
if (rfkill->get_state && !force &&
|
||||
!rfkill->get_state(rfkill->data, &newstate))
|
||||
rfkill->state = newstate;
|
||||
|
||||
switch (state) {
|
||||
case RFKILL_STATE_HARD_BLOCKED:
|
||||
/* typically happens when refreshing hardware state,
|
||||
* such as on resume */
|
||||
state = RFKILL_STATE_SOFT_BLOCKED;
|
||||
break;
|
||||
case RFKILL_STATE_UNBLOCKED:
|
||||
/* force can't override this, only rfkill_force_state() can */
|
||||
if (rfkill->state == RFKILL_STATE_HARD_BLOCKED)
|
||||
return -EPERM;
|
||||
break;
|
||||
case RFKILL_STATE_SOFT_BLOCKED:
|
||||
/* nothing to do, we want to give drivers the hint to double
|
||||
* BLOCK even a transmitter that is already in state
|
||||
* RFKILL_STATE_HARD_BLOCKED */
|
||||
break;
|
||||
}
|
||||
|
||||
if (force || state != rfkill->state) {
|
||||
retval = rfkill->toggle_radio(rfkill->data, state);
|
||||
if (!retval) {
|
||||
/* never allow a HARD->SOFT downgrade! */
|
||||
if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED)
|
||||
rfkill->state = state;
|
||||
rfkill_led_trigger(rfkill, state);
|
||||
}
|
||||
}
|
||||
|
||||
if (force || rfkill->state != oldstate) {
|
||||
rfkill_led_trigger(rfkill, rfkill->state);
|
||||
notify_rfkill_state_change(rfkill);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
@ -82,7 +205,6 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
|
|||
* a specific switch is claimed by userspace in which case it is
|
||||
* left alone.
|
||||
*/
|
||||
|
||||
void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
|
||||
{
|
||||
struct rfkill *rfkill;
|
||||
|
@ -93,13 +215,66 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
|
|||
|
||||
list_for_each_entry(rfkill, &rfkill_list, node) {
|
||||
if ((!rfkill->user_claim) && (rfkill->type == type))
|
||||
rfkill_toggle_radio(rfkill, state);
|
||||
rfkill_toggle_radio(rfkill, state, 0);
|
||||
}
|
||||
|
||||
mutex_unlock(&rfkill_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(rfkill_switch_all);
|
||||
|
||||
/**
|
||||
* rfkill_epo - emergency power off all transmitters
|
||||
*
|
||||
* This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring
|
||||
* everything in its path but rfkill_mutex.
|
||||
*/
|
||||
void rfkill_epo(void)
|
||||
{
|
||||
struct rfkill *rfkill;
|
||||
|
||||
mutex_lock(&rfkill_mutex);
|
||||
list_for_each_entry(rfkill, &rfkill_list, node) {
|
||||
rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
|
||||
}
|
||||
mutex_unlock(&rfkill_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rfkill_epo);
|
||||
|
||||
/**
|
||||
* rfkill_force_state - Force the internal rfkill radio state
|
||||
* @rfkill: pointer to the rfkill class to modify.
|
||||
* @state: the current radio state the class should be forced to.
|
||||
*
|
||||
* This function updates the internal state of the radio cached
|
||||
* by the rfkill class. It should be used when the driver gets
|
||||
* a notification by the firmware/hardware of the current *real*
|
||||
* state of the radio rfkill switch.
|
||||
*
|
||||
* It may not be called from an atomic context.
|
||||
*/
|
||||
int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
|
||||
{
|
||||
enum rfkill_state oldstate;
|
||||
|
||||
if (state != RFKILL_STATE_SOFT_BLOCKED &&
|
||||
state != RFKILL_STATE_UNBLOCKED &&
|
||||
state != RFKILL_STATE_HARD_BLOCKED)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&rfkill->mutex);
|
||||
|
||||
oldstate = rfkill->state;
|
||||
rfkill->state = state;
|
||||
|
||||
if (state != oldstate)
|
||||
notify_rfkill_state_change(rfkill);
|
||||
|
||||
mutex_unlock(&rfkill->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rfkill_force_state);
|
||||
|
||||
static ssize_t rfkill_name_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
@ -109,31 +284,31 @@ static ssize_t rfkill_name_show(struct device *dev,
|
|||
return sprintf(buf, "%s\n", rfkill->name);
|
||||
}
|
||||
|
||||
static const char *rfkill_get_type_str(enum rfkill_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case RFKILL_TYPE_WLAN:
|
||||
return "wlan";
|
||||
case RFKILL_TYPE_BLUETOOTH:
|
||||
return "bluetooth";
|
||||
case RFKILL_TYPE_UWB:
|
||||
return "ultrawideband";
|
||||
case RFKILL_TYPE_WIMAX:
|
||||
return "wimax";
|
||||
case RFKILL_TYPE_WWAN:
|
||||
return "wwan";
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t rfkill_type_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct rfkill *rfkill = to_rfkill(dev);
|
||||
const char *type;
|
||||
|
||||
switch (rfkill->type) {
|
||||
case RFKILL_TYPE_WLAN:
|
||||
type = "wlan";
|
||||
break;
|
||||
case RFKILL_TYPE_BLUETOOTH:
|
||||
type = "bluetooth";
|
||||
break;
|
||||
case RFKILL_TYPE_UWB:
|
||||
type = "ultrawideband";
|
||||
break;
|
||||
case RFKILL_TYPE_WIMAX:
|
||||
type = "wimax";
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return sprintf(buf, "%s\n", type);
|
||||
return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type));
|
||||
}
|
||||
|
||||
static ssize_t rfkill_state_show(struct device *dev,
|
||||
|
@ -142,6 +317,7 @@ static ssize_t rfkill_state_show(struct device *dev,
|
|||
{
|
||||
struct rfkill *rfkill = to_rfkill(dev);
|
||||
|
||||
update_rfkill_state(rfkill);
|
||||
return sprintf(buf, "%d\n", rfkill->state);
|
||||
}
|
||||
|
||||
|
@ -156,10 +332,14 @@ static ssize_t rfkill_state_store(struct device *dev,
|
|||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
/* RFKILL_STATE_HARD_BLOCKED is illegal here... */
|
||||
if (state != RFKILL_STATE_UNBLOCKED &&
|
||||
state != RFKILL_STATE_SOFT_BLOCKED)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&rfkill->mutex))
|
||||
return -ERESTARTSYS;
|
||||
error = rfkill_toggle_radio(rfkill,
|
||||
state ? RFKILL_STATE_ON : RFKILL_STATE_OFF);
|
||||
error = rfkill_toggle_radio(rfkill, state, 0);
|
||||
mutex_unlock(&rfkill->mutex);
|
||||
|
||||
return error ? error : count;
|
||||
|
@ -200,7 +380,8 @@ static ssize_t rfkill_claim_store(struct device *dev,
|
|||
if (rfkill->user_claim != claim) {
|
||||
if (!claim)
|
||||
rfkill_toggle_radio(rfkill,
|
||||
rfkill_states[rfkill->type]);
|
||||
rfkill_states[rfkill->type],
|
||||
0);
|
||||
rfkill->user_claim = claim;
|
||||
}
|
||||
|
||||
|
@ -233,12 +414,12 @@ static int rfkill_suspend(struct device *dev, pm_message_t state)
|
|||
|
||||
if (dev->power.power_state.event != state.event) {
|
||||
if (state.event & PM_EVENT_SLEEP) {
|
||||
/* Stop transmitter, keep state, no notifies */
|
||||
update_rfkill_state(rfkill);
|
||||
|
||||
mutex_lock(&rfkill->mutex);
|
||||
|
||||
if (rfkill->state == RFKILL_STATE_ON)
|
||||
rfkill->toggle_radio(rfkill->data,
|
||||
RFKILL_STATE_OFF);
|
||||
|
||||
rfkill->toggle_radio(rfkill->data,
|
||||
RFKILL_STATE_SOFT_BLOCKED);
|
||||
mutex_unlock(&rfkill->mutex);
|
||||
}
|
||||
|
||||
|
@ -255,8 +436,8 @@ static int rfkill_resume(struct device *dev)
|
|||
if (dev->power.power_state.event != PM_EVENT_ON) {
|
||||
mutex_lock(&rfkill->mutex);
|
||||
|
||||
if (rfkill->state == RFKILL_STATE_ON)
|
||||
rfkill->toggle_radio(rfkill->data, RFKILL_STATE_ON);
|
||||
/* restore radio state AND notify everybody */
|
||||
rfkill_toggle_radio(rfkill, rfkill->state, 1);
|
||||
|
||||
mutex_unlock(&rfkill->mutex);
|
||||
}
|
||||
|
@ -269,12 +450,51 @@ static int rfkill_resume(struct device *dev)
|
|||
#define rfkill_resume NULL
|
||||
#endif
|
||||
|
||||
static int rfkill_blocking_uevent_notifier(struct notifier_block *nb,
|
||||
unsigned long eventid,
|
||||
void *data)
|
||||
{
|
||||
struct rfkill *rfkill = (struct rfkill *)data;
|
||||
|
||||
switch (eventid) {
|
||||
case RFKILL_STATE_CHANGED:
|
||||
kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block rfkill_blocking_uevent_nb = {
|
||||
.notifier_call = rfkill_blocking_uevent_notifier,
|
||||
.priority = 0,
|
||||
};
|
||||
|
||||
static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct rfkill *rfkill = to_rfkill(dev);
|
||||
int error;
|
||||
|
||||
error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name);
|
||||
if (error)
|
||||
return error;
|
||||
error = add_uevent_var(env, "RFKILL_TYPE=%s",
|
||||
rfkill_get_type_str(rfkill->type));
|
||||
if (error)
|
||||
return error;
|
||||
error = add_uevent_var(env, "RFKILL_STATE=%d", rfkill->state);
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct class rfkill_class = {
|
||||
.name = "rfkill",
|
||||
.dev_release = rfkill_release,
|
||||
.dev_attrs = rfkill_dev_attrs,
|
||||
.suspend = rfkill_suspend,
|
||||
.resume = rfkill_resume,
|
||||
.dev_uevent = rfkill_dev_uevent,
|
||||
};
|
||||
|
||||
static int rfkill_add_switch(struct rfkill *rfkill)
|
||||
|
@ -283,7 +503,7 @@ static int rfkill_add_switch(struct rfkill *rfkill)
|
|||
|
||||
mutex_lock(&rfkill_mutex);
|
||||
|
||||
error = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type]);
|
||||
error = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type], 0);
|
||||
if (!error)
|
||||
list_add_tail(&rfkill->node, &rfkill_list);
|
||||
|
||||
|
@ -296,7 +516,7 @@ static void rfkill_remove_switch(struct rfkill *rfkill)
|
|||
{
|
||||
mutex_lock(&rfkill_mutex);
|
||||
list_del_init(&rfkill->node);
|
||||
rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF);
|
||||
rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
|
||||
mutex_unlock(&rfkill_mutex);
|
||||
}
|
||||
|
||||
|
@ -412,7 +632,7 @@ int rfkill_register(struct rfkill *rfkill)
|
|||
EXPORT_SYMBOL(rfkill_register);
|
||||
|
||||
/**
|
||||
* rfkill_unregister - Uegister a rfkill structure.
|
||||
* rfkill_unregister - Unregister a rfkill structure.
|
||||
* @rfkill: rfkill structure to be unregistered
|
||||
*
|
||||
* This function should be called by the network driver during device
|
||||
|
@ -436,8 +656,13 @@ static int __init rfkill_init(void)
|
|||
int error;
|
||||
int i;
|
||||
|
||||
/* RFKILL_STATE_HARD_BLOCKED is illegal here... */
|
||||
if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED &&
|
||||
rfkill_default_state != RFKILL_STATE_UNBLOCKED)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rfkill_states); i++)
|
||||
rfkill_states[i] = RFKILL_STATE_ON;
|
||||
rfkill_states[i] = rfkill_default_state;
|
||||
|
||||
error = class_register(&rfkill_class);
|
||||
if (error) {
|
||||
|
@ -445,11 +670,14 @@ static int __init rfkill_init(void)
|
|||
return error;
|
||||
}
|
||||
|
||||
register_rfkill_notifier(&rfkill_blocking_uevent_nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rfkill_exit(void)
|
||||
{
|
||||
unregister_rfkill_notifier(&rfkill_blocking_uevent_nb);
|
||||
class_unregister(&rfkill_class);
|
||||
}
|
||||
|
||||
|
|
10
net/socket.c
10
net/socket.c
|
@ -90,6 +90,7 @@
|
|||
#include <asm/unistd.h>
|
||||
|
||||
#include <net/compat.h>
|
||||
#include <net/wext.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
#include <linux/netfilter.h>
|
||||
|
@ -2210,10 +2211,19 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd,
|
|||
{
|
||||
struct socket *sock = file->private_data;
|
||||
int ret = -ENOIOCTLCMD;
|
||||
struct sock *sk;
|
||||
struct net *net;
|
||||
|
||||
sk = sock->sk;
|
||||
net = sock_net(sk);
|
||||
|
||||
if (sock->ops->compat_ioctl)
|
||||
ret = sock->ops->compat_ioctl(sock, cmd, arg);
|
||||
|
||||
if (ret == -ENOIOCTLCMD &&
|
||||
(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST))
|
||||
ret = compat_wext_handle_ioctl(net, cmd, arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -500,7 +500,7 @@ static int call_commit_handler(struct net_device *dev)
|
|||
/*
|
||||
* Calculate size of private arguments
|
||||
*/
|
||||
static inline int get_priv_size(__u16 args)
|
||||
static int get_priv_size(__u16 args)
|
||||
{
|
||||
int num = args & IW_PRIV_SIZE_MASK;
|
||||
int type = (args & IW_PRIV_TYPE_MASK) >> 12;
|
||||
|
@ -512,10 +512,9 @@ static inline int get_priv_size(__u16 args)
|
|||
/*
|
||||
* Re-calculate the size of private arguments
|
||||
*/
|
||||
static inline int adjust_priv_size(__u16 args,
|
||||
union iwreq_data * wrqu)
|
||||
static int adjust_priv_size(__u16 args, struct iw_point *iwp)
|
||||
{
|
||||
int num = wrqu->data.length;
|
||||
int num = iwp->length;
|
||||
int max = args & IW_PRIV_SIZE_MASK;
|
||||
int type = (args & IW_PRIV_TYPE_MASK) >> 12;
|
||||
|
||||
|
@ -695,19 +694,150 @@ void wext_proc_exit(struct net *net)
|
|||
*/
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
|
||||
const struct iw_ioctl_description *descr,
|
||||
iw_handler handler, struct net_device *dev,
|
||||
struct iw_request_info *info)
|
||||
{
|
||||
int err, extra_size, user_length = 0, essid_compat = 0;
|
||||
char *extra;
|
||||
|
||||
/* Calculate space needed by arguments. Always allocate
|
||||
* for max space.
|
||||
*/
|
||||
extra_size = descr->max_tokens * descr->token_size;
|
||||
|
||||
/* Check need for ESSID compatibility for WE < 21 */
|
||||
switch (cmd) {
|
||||
case SIOCSIWESSID:
|
||||
case SIOCGIWESSID:
|
||||
case SIOCSIWNICKN:
|
||||
case SIOCGIWNICKN:
|
||||
if (iwp->length == descr->max_tokens + 1)
|
||||
essid_compat = 1;
|
||||
else if (IW_IS_SET(cmd) && (iwp->length != 0)) {
|
||||
char essid[IW_ESSID_MAX_SIZE + 1];
|
||||
|
||||
err = copy_from_user(essid, iwp->pointer,
|
||||
iwp->length *
|
||||
descr->token_size);
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
|
||||
if (essid[iwp->length - 1] == '\0')
|
||||
essid_compat = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
iwp->length -= essid_compat;
|
||||
|
||||
/* Check what user space is giving us */
|
||||
if (IW_IS_SET(cmd)) {
|
||||
/* Check NULL pointer */
|
||||
if (!iwp->pointer && iwp->length != 0)
|
||||
return -EFAULT;
|
||||
/* Check if number of token fits within bounds */
|
||||
if (iwp->length > descr->max_tokens)
|
||||
return -E2BIG;
|
||||
if (iwp->length < descr->min_tokens)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
/* Check NULL pointer */
|
||||
if (!iwp->pointer)
|
||||
return -EFAULT;
|
||||
/* Save user space buffer size for checking */
|
||||
user_length = iwp->length;
|
||||
|
||||
/* Don't check if user_length > max to allow forward
|
||||
* compatibility. The test user_length < min is
|
||||
* implied by the test at the end.
|
||||
*/
|
||||
|
||||
/* Support for very large requests */
|
||||
if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
|
||||
(user_length > descr->max_tokens)) {
|
||||
/* Allow userspace to GET more than max so
|
||||
* we can support any size GET requests.
|
||||
* There is still a limit : -ENOMEM.
|
||||
*/
|
||||
extra_size = user_length * descr->token_size;
|
||||
|
||||
/* Note : user_length is originally a __u16,
|
||||
* and token_size is controlled by us,
|
||||
* so extra_size won't get negative and
|
||||
* won't overflow...
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/* kzalloc() ensures NULL-termination for essid_compat. */
|
||||
extra = kzalloc(extra_size, GFP_KERNEL);
|
||||
if (!extra)
|
||||
return -ENOMEM;
|
||||
|
||||
/* If it is a SET, get all the extra data in here */
|
||||
if (IW_IS_SET(cmd) && (iwp->length != 0)) {
|
||||
if (copy_from_user(extra, iwp->pointer,
|
||||
iwp->length *
|
||||
descr->token_size)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
err = handler(dev, info, (union iwreq_data *) iwp, extra);
|
||||
|
||||
iwp->length += essid_compat;
|
||||
|
||||
/* If we have something to return to the user */
|
||||
if (!err && IW_IS_GET(cmd)) {
|
||||
/* Check if there is enough buffer up there */
|
||||
if (user_length < iwp->length) {
|
||||
err = -E2BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (copy_to_user(iwp->pointer, extra,
|
||||
iwp->length *
|
||||
descr->token_size)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate an event to notify listeners of the change */
|
||||
if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) {
|
||||
union iwreq_data *data = (union iwreq_data *) iwp;
|
||||
|
||||
if (descr->flags & IW_DESCR_FLAG_RESTRICT)
|
||||
/* If the event is restricted, don't
|
||||
* export the payload.
|
||||
*/
|
||||
wireless_send_event(dev, cmd, data, NULL);
|
||||
else
|
||||
wireless_send_event(dev, cmd, data, extra);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(extra);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper to call a standard Wireless Extension handler.
|
||||
* We do various checks and also take care of moving data between
|
||||
* user space and kernel space.
|
||||
*/
|
||||
static int ioctl_standard_call(struct net_device * dev,
|
||||
struct ifreq * ifr,
|
||||
struct iwreq *iwr,
|
||||
unsigned int cmd,
|
||||
struct iw_request_info *info,
|
||||
iw_handler handler)
|
||||
{
|
||||
struct iwreq * iwr = (struct iwreq *) ifr;
|
||||
const struct iw_ioctl_description * descr;
|
||||
struct iw_request_info info;
|
||||
int ret = -EINVAL;
|
||||
|
||||
/* Get the description of the IOCTL */
|
||||
|
@ -715,145 +845,19 @@ static int ioctl_standard_call(struct net_device * dev,
|
|||
return -EOPNOTSUPP;
|
||||
descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
|
||||
|
||||
/* Prepare the call */
|
||||
info.cmd = cmd;
|
||||
info.flags = 0;
|
||||
|
||||
/* Check if we have a pointer to user space data or not */
|
||||
if (descr->header_type != IW_HEADER_TYPE_POINT) {
|
||||
|
||||
/* No extra arguments. Trivial to handle */
|
||||
ret = handler(dev, &info, &(iwr->u), NULL);
|
||||
ret = handler(dev, info, &(iwr->u), NULL);
|
||||
|
||||
/* Generate an event to notify listeners of the change */
|
||||
if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
|
||||
((ret == 0) || (ret == -EIWCOMMIT)))
|
||||
wireless_send_event(dev, cmd, &(iwr->u), NULL);
|
||||
} else {
|
||||
char * extra;
|
||||
int extra_size;
|
||||
int user_length = 0;
|
||||
int err;
|
||||
int essid_compat = 0;
|
||||
|
||||
/* Calculate space needed by arguments. Always allocate
|
||||
* for max space. Easier, and won't last long... */
|
||||
extra_size = descr->max_tokens * descr->token_size;
|
||||
|
||||
/* Check need for ESSID compatibility for WE < 21 */
|
||||
switch (cmd) {
|
||||
case SIOCSIWESSID:
|
||||
case SIOCGIWESSID:
|
||||
case SIOCSIWNICKN:
|
||||
case SIOCGIWNICKN:
|
||||
if (iwr->u.data.length == descr->max_tokens + 1)
|
||||
essid_compat = 1;
|
||||
else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
|
||||
char essid[IW_ESSID_MAX_SIZE + 1];
|
||||
|
||||
err = copy_from_user(essid, iwr->u.data.pointer,
|
||||
iwr->u.data.length *
|
||||
descr->token_size);
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
|
||||
if (essid[iwr->u.data.length - 1] == '\0')
|
||||
essid_compat = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
iwr->u.data.length -= essid_compat;
|
||||
|
||||
/* Check what user space is giving us */
|
||||
if (IW_IS_SET(cmd)) {
|
||||
/* Check NULL pointer */
|
||||
if ((iwr->u.data.pointer == NULL) &&
|
||||
(iwr->u.data.length != 0))
|
||||
return -EFAULT;
|
||||
/* Check if number of token fits within bounds */
|
||||
if (iwr->u.data.length > descr->max_tokens)
|
||||
return -E2BIG;
|
||||
if (iwr->u.data.length < descr->min_tokens)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
/* Check NULL pointer */
|
||||
if (iwr->u.data.pointer == NULL)
|
||||
return -EFAULT;
|
||||
/* Save user space buffer size for checking */
|
||||
user_length = iwr->u.data.length;
|
||||
|
||||
/* Don't check if user_length > max to allow forward
|
||||
* compatibility. The test user_length < min is
|
||||
* implied by the test at the end. */
|
||||
|
||||
/* Support for very large requests */
|
||||
if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
|
||||
(user_length > descr->max_tokens)) {
|
||||
/* Allow userspace to GET more than max so
|
||||
* we can support any size GET requests.
|
||||
* There is still a limit : -ENOMEM. */
|
||||
extra_size = user_length * descr->token_size;
|
||||
/* Note : user_length is originally a __u16,
|
||||
* and token_size is controlled by us,
|
||||
* so extra_size won't get negative and
|
||||
* won't overflow... */
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the kernel buffer */
|
||||
/* kzalloc ensures NULL-termination for essid_compat */
|
||||
extra = kzalloc(extra_size, GFP_KERNEL);
|
||||
if (extra == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* If it is a SET, get all the extra data in here */
|
||||
if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
|
||||
err = copy_from_user(extra, iwr->u.data.pointer,
|
||||
iwr->u.data.length *
|
||||
descr->token_size);
|
||||
if (err) {
|
||||
kfree(extra);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the handler */
|
||||
ret = handler(dev, &info, &(iwr->u), extra);
|
||||
|
||||
iwr->u.data.length += essid_compat;
|
||||
|
||||
/* If we have something to return to the user */
|
||||
if (!ret && IW_IS_GET(cmd)) {
|
||||
/* Check if there is enough buffer up there */
|
||||
if (user_length < iwr->u.data.length) {
|
||||
kfree(extra);
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
err = copy_to_user(iwr->u.data.pointer, extra,
|
||||
iwr->u.data.length *
|
||||
descr->token_size);
|
||||
if (err)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
/* Generate an event to notify listeners of the change */
|
||||
if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
|
||||
((ret == 0) || (ret == -EIWCOMMIT))) {
|
||||
if (descr->flags & IW_DESCR_FLAG_RESTRICT)
|
||||
/* If the event is restricted, don't
|
||||
* export the payload */
|
||||
wireless_send_event(dev, cmd, &(iwr->u), NULL);
|
||||
else
|
||||
wireless_send_event(dev, cmd, &(iwr->u),
|
||||
extra);
|
||||
}
|
||||
|
||||
/* Cleanup - I told you it wasn't that long ;-) */
|
||||
kfree(extra);
|
||||
ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
|
||||
handler, dev, info);
|
||||
}
|
||||
|
||||
/* Call commit handler if needed and defined */
|
||||
|
@ -881,25 +885,22 @@ static int ioctl_standard_call(struct net_device * dev,
|
|||
* a iw_handler but process it in your ioctl handler (i.e. use the
|
||||
* old driver API).
|
||||
*/
|
||||
static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
|
||||
unsigned int cmd, iw_handler handler)
|
||||
static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
|
||||
const struct iw_priv_args **descrp)
|
||||
{
|
||||
struct iwreq * iwr = (struct iwreq *) ifr;
|
||||
const struct iw_priv_args * descr = NULL;
|
||||
struct iw_request_info info;
|
||||
int extra_size = 0;
|
||||
int i;
|
||||
int ret = -EINVAL;
|
||||
const struct iw_priv_args *descr;
|
||||
int i, extra_size;
|
||||
|
||||
/* Get the description of the IOCTL */
|
||||
for (i = 0; i < dev->wireless_handlers->num_private_args; i++)
|
||||
descr = NULL;
|
||||
for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
|
||||
if (cmd == dev->wireless_handlers->private_args[i].cmd) {
|
||||
descr = &(dev->wireless_handlers->private_args[i]);
|
||||
descr = &dev->wireless_handlers->private_args[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute the size of the set/get arguments */
|
||||
if (descr != NULL) {
|
||||
extra_size = 0;
|
||||
if (descr) {
|
||||
if (IW_IS_SET(cmd)) {
|
||||
int offset = 0; /* For sub-ioctls */
|
||||
/* Check for sub-ioctl handler */
|
||||
|
@ -924,73 +925,78 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
|
|||
extra_size = 0;
|
||||
}
|
||||
}
|
||||
*descrp = descr;
|
||||
return extra_size;
|
||||
}
|
||||
|
||||
/* Prepare the call */
|
||||
info.cmd = cmd;
|
||||
info.flags = 0;
|
||||
static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
|
||||
const struct iw_priv_args *descr,
|
||||
iw_handler handler, struct net_device *dev,
|
||||
struct iw_request_info *info, int extra_size)
|
||||
{
|
||||
char *extra;
|
||||
int err;
|
||||
|
||||
/* Check what user space is giving us */
|
||||
if (IW_IS_SET(cmd)) {
|
||||
if (!iwp->pointer && iwp->length != 0)
|
||||
return -EFAULT;
|
||||
|
||||
if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
|
||||
return -E2BIG;
|
||||
} else if (!iwp->pointer)
|
||||
return -EFAULT;
|
||||
|
||||
extra = kmalloc(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, extra_size)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the handler */
|
||||
err = handler(dev, info, (union iwreq_data *) iwp, extra);
|
||||
|
||||
/* 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);
|
||||
|
||||
if (copy_to_user(iwp->pointer, extra, extra_size))
|
||||
err = -EFAULT;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(extra);
|
||||
return err;
|
||||
}
|
||||
|
||||
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));
|
||||
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)) {
|
||||
/* Check NULL pointer */
|
||||
if ((iwr->u.data.pointer == NULL) &&
|
||||
(iwr->u.data.length != 0))
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the handler */
|
||||
ret = handler(dev, &info, &(iwr->u), extra);
|
||||
|
||||
/* If we have something to return to the user */
|
||||
if (!ret && 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,
|
||||
&(iwr->u));
|
||||
}
|
||||
|
||||
err = copy_to_user(iwr->u.data.pointer, extra,
|
||||
extra_size);
|
||||
if (err)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
/* Cleanup - I told you it wasn't that long ;-) */
|
||||
kfree(extra);
|
||||
ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
|
||||
handler, dev, info, extra_size);
|
||||
}
|
||||
|
||||
|
||||
/* Call commit handler if needed and defined */
|
||||
if (ret == -EIWCOMMIT)
|
||||
ret = call_commit_handler(dev);
|
||||
|
@ -999,12 +1005,21 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
|
|||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
|
||||
unsigned int, struct iw_request_info *,
|
||||
iw_handler);
|
||||
|
||||
/*
|
||||
* Main IOCTl dispatcher.
|
||||
* Check the type of IOCTL and call the appropriate wrapper...
|
||||
*/
|
||||
static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd)
|
||||
static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
|
||||
unsigned int cmd,
|
||||
struct iw_request_info *info,
|
||||
wext_ioctl_func standard,
|
||||
wext_ioctl_func private)
|
||||
{
|
||||
struct iwreq *iwr = (struct iwreq *) ifr;
|
||||
struct net_device *dev;
|
||||
iw_handler handler;
|
||||
|
||||
|
@ -1019,12 +1034,12 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
|
|||
* Note that 'cmd' is already filtered in dev_ioctl() with
|
||||
* (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
|
||||
if (cmd == SIOCGIWSTATS)
|
||||
return ioctl_standard_call(dev, ifr, cmd,
|
||||
&iw_handler_get_iwstats);
|
||||
return standard(dev, iwr, cmd, info,
|
||||
&iw_handler_get_iwstats);
|
||||
|
||||
if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
|
||||
return ioctl_standard_call(dev, ifr, cmd,
|
||||
&iw_handler_get_private);
|
||||
return standard(dev, iwr, cmd, info,
|
||||
&iw_handler_get_private);
|
||||
|
||||
/* Basic check */
|
||||
if (!netif_device_present(dev))
|
||||
|
@ -1035,9 +1050,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
|
|||
if (handler) {
|
||||
/* Standard and private are not the same */
|
||||
if (cmd < SIOCIWFIRSTPRIV)
|
||||
return ioctl_standard_call(dev, ifr, cmd, handler);
|
||||
return standard(dev, iwr, cmd, info, handler);
|
||||
else
|
||||
return ioctl_private_call(dev, ifr, cmd, handler);
|
||||
return private(dev, iwr, cmd, info, handler);
|
||||
}
|
||||
/* Old driver API : call driver ioctl handler */
|
||||
if (dev->do_ioctl)
|
||||
|
@ -1045,28 +1060,155 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* entry point from dev ioctl */
|
||||
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
|
||||
void __user *arg)
|
||||
/* If command is `set a parameter', or `get the encoding parameters',
|
||||
* check if the user has the right to do it.
|
||||
*/
|
||||
static int wext_permission_check(unsigned int cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* If command is `set a parameter', or
|
||||
* `get the encoding parameters', check if
|
||||
* the user has the right to do it */
|
||||
if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
|
||||
&& !capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* entry point from dev ioctl */
|
||||
static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
|
||||
unsigned int cmd, struct iw_request_info *info,
|
||||
wext_ioctl_func standard,
|
||||
wext_ioctl_func private)
|
||||
{
|
||||
int ret = wext_permission_check(cmd);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_load(net, ifr->ifr_name);
|
||||
rtnl_lock();
|
||||
ret = wireless_process_ioctl(net, ifr, cmd);
|
||||
ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
|
||||
rtnl_unlock();
|
||||
if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq)))
|
||||
return -EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
|
||||
void __user *arg)
|
||||
{
|
||||
struct iw_request_info info = { .cmd = cmd, .flags = 0 };
|
||||
int ret;
|
||||
|
||||
ret = wext_ioctl_dispatch(net, ifr, cmd, &info,
|
||||
ioctl_standard_call,
|
||||
ioctl_private_call);
|
||||
if (ret >= 0 &&
|
||||
IW_IS_GET(cmd) &&
|
||||
copy_to_user(arg, ifr, sizeof(struct iwreq)))
|
||||
return -EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static int compat_standard_call(struct net_device *dev,
|
||||
struct iwreq *iwr,
|
||||
unsigned int cmd,
|
||||
struct iw_request_info *info,
|
||||
iw_handler handler)
|
||||
{
|
||||
const struct iw_ioctl_description *descr;
|
||||
struct compat_iw_point *iwp_compat;
|
||||
struct iw_point iwp;
|
||||
int err;
|
||||
|
||||
descr = standard_ioctl + (cmd - SIOCIWFIRST);
|
||||
|
||||
if (descr->header_type != IW_HEADER_TYPE_POINT)
|
||||
return ioctl_standard_call(dev, iwr, cmd, info, handler);
|
||||
|
||||
iwp_compat = (struct compat_iw_point *) &iwr->u.data;
|
||||
iwp.pointer = compat_ptr(iwp_compat->pointer);
|
||||
iwp.length = iwp_compat->length;
|
||||
iwp.flags = iwp_compat->flags;
|
||||
|
||||
err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info);
|
||||
|
||||
iwp_compat->pointer = ptr_to_compat(iwp.pointer);
|
||||
iwp_compat->length = iwp.length;
|
||||
iwp_compat->flags = iwp.flags;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
|
||||
unsigned int cmd, struct iw_request_info *info,
|
||||
iw_handler handler)
|
||||
{
|
||||
const struct iw_priv_args *descr;
|
||||
int ret, extra_size;
|
||||
|
||||
extra_size = get_priv_descr_and_size(dev, cmd, &descr);
|
||||
|
||||
/* Check if we have a pointer to user space data or not. */
|
||||
if (extra_size == 0) {
|
||||
/* No extra arguments. Trivial to handle */
|
||||
ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
|
||||
} else {
|
||||
struct compat_iw_point *iwp_compat;
|
||||
struct iw_point iwp;
|
||||
|
||||
iwp_compat = (struct compat_iw_point *) &iwr->u.data;
|
||||
iwp.pointer = compat_ptr(iwp_compat->pointer);
|
||||
iwp.length = iwp_compat->length;
|
||||
iwp.flags = iwp_compat->flags;
|
||||
|
||||
ret = ioctl_private_iw_point(&iwp, cmd, descr,
|
||||
handler, dev, info, extra_size);
|
||||
|
||||
iwp_compat->pointer = ptr_to_compat(iwp.pointer);
|
||||
iwp_compat->length = iwp.length;
|
||||
iwp_compat->flags = iwp.flags;
|
||||
}
|
||||
|
||||
/* Call commit handler if needed and defined */
|
||||
if (ret == -EIWCOMMIT)
|
||||
ret = call_commit_handler(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
struct iw_request_info info;
|
||||
struct iwreq iwr;
|
||||
char *colon;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&iwr, argp, sizeof(struct iwreq)))
|
||||
return -EFAULT;
|
||||
|
||||
iwr.ifr_name[IFNAMSIZ-1] = 0;
|
||||
colon = strchr(iwr.ifr_name, ':');
|
||||
if (colon)
|
||||
*colon = 0;
|
||||
|
||||
info.cmd = cmd;
|
||||
info.flags = IW_REQUEST_FLAG_COMPAT;
|
||||
|
||||
ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info,
|
||||
compat_standard_call,
|
||||
compat_private_call);
|
||||
|
||||
if (ret >= 0 &&
|
||||
IW_IS_GET(cmd) &&
|
||||
copy_to_user(argp, &iwr, sizeof(struct iwreq)))
|
||||
return -EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************* EVENT PROCESSING *************************/
|
||||
/*
|
||||
* Process events generated by the wireless layer or the driver.
|
||||
|
|
Loading…
Reference in a new issue