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

This commit is contained in:
David S. Miller 2008-06-28 22:57:58 -07:00
commit 28f49d8fec
84 changed files with 3421 additions and 4644 deletions

View file

@ -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.

View file

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

View file

@ -148,9 +148,9 @@ static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
unsigned long offset,
enum dma_data_direction dir)
{
dma_sync_single_range_for_device(sdev->dma_dev, dma_base,
offset & dma_desc_align_mask,
dma_desc_sync_size, dir);
ssb_dma_sync_single_range_for_device(sdev, dma_base,
offset & dma_desc_align_mask,
dma_desc_sync_size, dir);
}
static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
@ -158,9 +158,9 @@ static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
unsigned long offset,
enum dma_data_direction dir)
{
dma_sync_single_range_for_cpu(sdev->dma_dev, dma_base,
offset & dma_desc_align_mask,
dma_desc_sync_size, dir);
ssb_dma_sync_single_range_for_cpu(sdev, dma_base,
offset & dma_desc_align_mask,
dma_desc_sync_size, dir);
}
static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
@ -613,10 +613,10 @@ static void b44_tx(struct b44 *bp)
BUG_ON(skb == NULL);
dma_unmap_single(bp->sdev->dma_dev,
rp->mapping,
skb->len,
DMA_TO_DEVICE);
ssb_dma_unmap_single(bp->sdev,
rp->mapping,
skb->len,
DMA_TO_DEVICE);
rp->skb = NULL;
dev_kfree_skb_irq(skb);
}
@ -653,29 +653,29 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
if (skb == NULL)
return -ENOMEM;
mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
mapping = ssb_dma_map_single(bp->sdev, skb->data,
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
/* Hardware bug work-around, the chip is unable to do PCI DMA
to/from anything above 1GB :-( */
if (dma_mapping_error(mapping) ||
if (ssb_dma_mapping_error(bp->sdev, mapping) ||
mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
/* Sigh... */
if (!dma_mapping_error(mapping))
dma_unmap_single(bp->sdev->dma_dev, mapping,
RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
if (!ssb_dma_mapping_error(bp->sdev, mapping))
ssb_dma_unmap_single(bp->sdev, mapping,
RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
if (skb == NULL)
return -ENOMEM;
mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
if (dma_mapping_error(mapping) ||
mapping = ssb_dma_map_single(bp->sdev, skb->data,
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
if (ssb_dma_mapping_error(bp->sdev, mapping) ||
mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
if (!dma_mapping_error(mapping))
dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
if (!ssb_dma_mapping_error(bp->sdev, mapping))
ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
return -ENOMEM;
}
@ -750,9 +750,9 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dest_idx * sizeof(dest_desc),
DMA_BIDIRECTIONAL);
dma_sync_single_for_device(bp->sdev->dma_dev, le32_to_cpu(src_desc->addr),
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
ssb_dma_sync_single_for_device(bp->sdev, le32_to_cpu(src_desc->addr),
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
}
static int b44_rx(struct b44 *bp, int budget)
@ -772,7 +772,7 @@ static int b44_rx(struct b44 *bp, int budget)
struct rx_header *rh;
u16 len;
dma_sync_single_for_cpu(bp->sdev->dma_dev, map,
ssb_dma_sync_single_for_cpu(bp->sdev, map,
RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
rh = (struct rx_header *) skb->data;
@ -806,8 +806,8 @@ static int b44_rx(struct b44 *bp, int budget)
skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
if (skb_size < 0)
goto drop_it;
dma_unmap_single(bp->sdev->dma_dev, map,
skb_size, DMA_FROM_DEVICE);
ssb_dma_unmap_single(bp->sdev, map,
skb_size, DMA_FROM_DEVICE);
/* Leave out rx_header */
skb_put(skb, len + RX_PKT_OFFSET);
skb_pull(skb, RX_PKT_OFFSET);
@ -966,25 +966,25 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto err_out;
}
mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE);
if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE);
if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_30BIT_MASK) {
struct sk_buff *bounce_skb;
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
if (!dma_mapping_error(mapping))
dma_unmap_single(bp->sdev->dma_dev, mapping, len,
DMA_TO_DEVICE);
if (!ssb_dma_mapping_error(bp->sdev, mapping))
ssb_dma_unmap_single(bp->sdev, mapping, len,
DMA_TO_DEVICE);
bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb)
goto err_out;
mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data,
len, DMA_TO_DEVICE);
if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
if (!dma_mapping_error(mapping))
dma_unmap_single(bp->sdev->dma_dev, mapping,
len, DMA_TO_DEVICE);
mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data,
len, DMA_TO_DEVICE);
if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_30BIT_MASK) {
if (!ssb_dma_mapping_error(bp->sdev, mapping))
ssb_dma_unmap_single(bp->sdev, mapping,
len, DMA_TO_DEVICE);
dev_kfree_skb_any(bounce_skb);
goto err_out;
}
@ -1082,8 +1082,8 @@ static void b44_free_rings(struct b44 *bp)
if (rp->skb == NULL)
continue;
dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ,
DMA_FROM_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
}
@ -1094,8 +1094,8 @@ static void b44_free_rings(struct b44 *bp)
if (rp->skb == NULL)
continue;
dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len,
DMA_TO_DEVICE);
ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len,
DMA_TO_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
}
@ -1117,14 +1117,14 @@ static void b44_init_rings(struct b44 *bp)
memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
if (bp->flags & B44_FLAG_RX_RING_HACK)
dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma,
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);
ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma,
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);
if (bp->flags & B44_FLAG_TX_RING_HACK)
dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma,
DMA_TABLE_BYTES,
DMA_TO_DEVICE);
ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma,
DMA_TABLE_BYTES,
DMA_TO_DEVICE);
for (i = 0; i < bp->rx_pending; i++) {
if (b44_alloc_rx_skb(bp, -1, i) < 0)
@ -1144,25 +1144,27 @@ static void b44_free_consistent(struct b44 *bp)
bp->tx_buffers = NULL;
if (bp->rx_ring) {
if (bp->flags & B44_FLAG_RX_RING_HACK) {
dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma,
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);
ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma,
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);
kfree(bp->rx_ring);
} else
dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
bp->rx_ring, bp->rx_ring_dma);
ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
bp->rx_ring, bp->rx_ring_dma,
GFP_KERNEL);
bp->rx_ring = NULL;
bp->flags &= ~B44_FLAG_RX_RING_HACK;
}
if (bp->tx_ring) {
if (bp->flags & B44_FLAG_TX_RING_HACK) {
dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma,
DMA_TABLE_BYTES,
DMA_TO_DEVICE);
ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma,
DMA_TABLE_BYTES,
DMA_TO_DEVICE);
kfree(bp->tx_ring);
} else
dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
bp->tx_ring, bp->tx_ring_dma);
ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
bp->tx_ring, bp->tx_ring_dma,
GFP_KERNEL);
bp->tx_ring = NULL;
bp->flags &= ~B44_FLAG_TX_RING_HACK;
}
@ -1187,7 +1189,7 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
goto out_err;
size = DMA_TABLE_BYTES;
bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->rx_ring_dma, gfp);
bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp);
if (!bp->rx_ring) {
/* Allocation may have failed due to pci_alloc_consistent
insisting on use of GFP_DMA, which is more restrictive
@ -1199,11 +1201,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
if (!rx_ring)
goto out_err;
rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring,
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);
rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring,
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(rx_ring_dma) ||
if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) ||
rx_ring_dma + size > DMA_30BIT_MASK) {
kfree(rx_ring);
goto out_err;
@ -1214,9 +1216,9 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
bp->flags |= B44_FLAG_RX_RING_HACK;
}
bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->tx_ring_dma, gfp);
bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp);
if (!bp->tx_ring) {
/* Allocation may have failed due to dma_alloc_coherent
/* Allocation may have failed due to ssb_dma_alloc_consistent
insisting on use of GFP_DMA, which is more restrictive
than necessary... */
struct dma_desc *tx_ring;
@ -1226,11 +1228,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
if (!tx_ring)
goto out_err;
tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring,
tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring,
DMA_TABLE_BYTES,
DMA_TO_DEVICE);
if (dma_mapping_error(tx_ring_dma) ||
if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) ||
tx_ring_dma + size > DMA_30BIT_MASK) {
kfree(tx_ring);
goto out_err;

View file

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

View file

@ -14,30 +14,6 @@ config WLAN_PRE80211
This option does not affect the kernel build, it only
lets you choose drivers.
config STRIP
tristate "STRIP (Metricom starmode radio IP)"
depends on INET && WLAN_PRE80211
select WIRELESS_EXT
---help---
Say Y if you have a Metricom radio and intend to use Starmode Radio
IP. STRIP is a radio protocol developed for the MosquitoNet project
(on the WWW at <http://mosquitonet.stanford.edu/>) to send Internet
traffic using Metricom radios. Metricom radios are small, battery
powered, 100kbit/sec packet radio transceivers, about the size and
weight of a cellular telephone. (You may also have heard them called
"Metricom modems" but we avoid the term "modem" because it misleads
many people into thinking that you can plug a Metricom modem into a
phone line and use it as a modem.)
You can use STRIP on any Linux machine with a serial port, although
it is obviously most useful for people with laptop computers. If you
think you might get a Metricom radio in the future, there is no harm
in saying Y to STRIP now, except that it makes the kernel a bit
bigger.
To compile this as a module, choose M here: the module will be
called strip.
config ARLAN
tristate "Aironet Arlan 655 & IC2200 DS support"
depends on ISA && !64BIT && WLAN_PRE80211

View file

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

View file

@ -1685,7 +1685,6 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct adm8211_tx_hdr *txhdr;
u16 fc;
size_t payload_len, hdrlen;
int plcp, dur, len, plcp_signal, short_preamble;
struct ieee80211_hdr *hdr;
@ -1696,8 +1695,7 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
plcp_signal = txrate->bitrate;
hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
hdrlen = ieee80211_get_hdrlen(fc);
hdrlen = ieee80211_hdrlen(hdr->frame_control);
memcpy(skb->cb, skb->data, hdrlen);
hdr = (struct ieee80211_hdr *)skb->cb;
skb_pull(skb, hdrlen);
@ -1711,8 +1709,6 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
txhdr->frame_control = hdr->frame_control;
len = hdrlen + payload_len + FCS_LEN;
if (fc & IEEE80211_FCTL_PROTECTED)
len += 8;
txhdr->frag = cpu_to_le16(0x0FFF);
adm8211_calc_durations(&dur, &plcp, payload_len,
@ -1730,9 +1726,6 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
if (fc & IEEE80211_FCTL_PROTECTED)
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
txhdr->retry_limit = info->control.retry_limit;
adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);

View file

@ -85,10 +85,10 @@ static struct pci_driver airo_driver = {
/* Include Wireless Extension definition and check version - Jean II */
#include <linux/wireless.h>
#define WIRELESS_SPY // enable iwspy support
#include <net/iw_handler.h> // New driver API
#define WIRELESS_SPY /* enable iwspy support */
#include <net/iw_handler.h> /* New driver API */
#define CISCO_EXT // enable Cisco extensions
#define CISCO_EXT /* enable Cisco extensions */
#ifdef CISCO_EXT
#include <linux/delay.h>
#endif
@ -281,7 +281,7 @@ MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc");
/* This is a kind of sloppy hack to get this information to OUT4500 and
IN4500. I would be extremely interested in the situation where this
doesn't work though!!! */
static int do8bitIO = 0;
static int do8bitIO /* = 0 */;
/* Return codes */
#define SUCCESS 0
@ -398,8 +398,8 @@ static int do8bitIO = 0;
#define MAXTXQ 64
/* BAP selectors */
#define BAP0 0 // Used for receiving packets
#define BAP1 2 // Used for xmiting packets and working with RIDS
#define BAP0 0 /* Used for receiving packets */
#define BAP1 2 /* Used for xmiting packets and working with RIDS */
/* Flags */
#define COMMAND_BUSY 0x8000
@ -5522,11 +5522,13 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
Cmd cmd;
Resp rsp;
if ((ai->APList == NULL) &&
(ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL)
if (!ai->APList)
ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL);
if (!ai->APList)
return -ENOMEM;
if ((ai->SSID == NULL) &&
(ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL)
if (!ai->SSID)
ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL);
if (!ai->SSID)
return -ENOMEM;
readAPListRid(ai, ai->APList);
readSsidRid(ai, ai->SSID);
@ -5537,7 +5539,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
disable_MAC(ai, 0);
netif_device_detach(dev);
ai->power = state;
cmd.cmd=HOSTSLEEP;
cmd.cmd = HOSTSLEEP;
issuecommand(ai, &cmd, &rsp);
pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
@ -5567,7 +5569,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
msleep(100);
}
set_bit (FLAG_COMMIT, &ai->flags);
set_bit(FLAG_COMMIT, &ai->flags);
disable_MAC(ai, 0);
msleep(200);
if (ai->SSID) {
@ -5594,9 +5596,6 @@ static int airo_pci_resume(struct pci_dev *pdev)
static int __init airo_init_module( void )
{
int i;
#if 0
int have_isa_dev = 0;
#endif
airo_entry = create_proc_entry("driver/aironet",
S_IFDIR | airo_perm,
@ -5607,15 +5606,11 @@ static int __init airo_init_module( void )
airo_entry->gid = proc_gid;
}
for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
for (i = 0; i < 4 && io[i] && irq[i]; i++) {
airo_print_info("", "Trying to configure ISA adapter at irq=%d "
"io=0x%x", irq[i], io[i] );
if (init_airo_card( irq[i], io[i], 0, NULL ))
#if 0
have_isa_dev = 1;
#else
/* do nothing */ ;
#endif
}
#ifdef CONFIG_PCI
@ -5661,7 +5656,7 @@ static void __exit airo_cleanup_module( void )
static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
{
if( !rssi_rid )
if (!rssi_rid)
return 0;
return (0x100 - rssi_rid[rssi].rssidBm);
@ -5671,10 +5666,10 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
{
int i;
if( !rssi_rid )
if (!rssi_rid)
return 0;
for( i = 0; i < 256; i++ )
for (i = 0; i < 256; i++)
if (rssi_rid[i].rssidBm == dbm)
return rssi_rid[i].rssipct;
@ -7156,6 +7151,7 @@ static int airo_set_scan(struct net_device *dev,
* 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);

View file

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

View file

@ -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 @@ ath5k_tasklet_rx(unsigned long data)
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");

View file

@ -45,6 +45,7 @@
#include <linux/list.h>
#include <linux/wireless.h>
#include <linux/if_ether.h>
#include <linux/leds.h>
#include "ath5k.h"
#include "debug.h"
@ -79,6 +80,19 @@ struct ath5k_txq {
bool setup;
};
#define ATH5K_LED_MAX_NAME_LEN 31
/*
* State for LED triggers
*/
struct ath5k_led
{
char name[ATH5K_LED_MAX_NAME_LEN + 1]; /* name of the LED in sysfs */
struct ath5k_softc *sc; /* driver state */
struct led_classdev led_dev; /* led classdev */
};
#if CHAN_DEBUG
#define ATH_CHAN_MAX (26+26+26+200+200)
#else
@ -118,13 +132,11 @@ struct ath5k_softc {
size_t desc_len; /* size of TX/RX descriptors */
u16 cachelsz; /* cache line size */
DECLARE_BITMAP(status, 6);
DECLARE_BITMAP(status, 4);
#define ATH_STAT_INVALID 0 /* disable hardware accesses */
#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */
#define ATH_STAT_PROMISC 2
#define ATH_STAT_LEDBLINKING 3 /* LED blink operation active */
#define ATH_STAT_LEDENDBLINK 4 /* finish LED blink operation */
#define ATH_STAT_LEDSOFT 5 /* enable LED gpio status */
#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */
unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
unsigned int curmode; /* current phy mode */
@ -132,13 +144,6 @@ struct ath5k_softc {
struct ieee80211_vif *vif;
struct {
u8 rxflags; /* radiotap rx flags */
u8 txflags; /* radiotap tx flags */
u16 ledon; /* softled on time */
u16 ledoff; /* softled off time */
} hwmap[32]; /* h/w rate ix mappings */
enum ath5k_int imask; /* interrupt mask copy */
DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */
@ -148,9 +153,6 @@ struct ath5k_softc {
unsigned int led_pin, /* GPIO pin for driving LED */
led_on, /* pin setting for LED on */
led_off; /* off time for current blink */
struct timer_list led_tim; /* led off timer */
u8 led_rxrate; /* current rx rate for LED */
u8 led_txrate; /* current tx rate for LED */
struct tasklet_struct restq; /* reset tasklet */
@ -159,6 +161,7 @@ struct ath5k_softc {
spinlock_t rxbuflock;
u32 *rxlink; /* link ptr in last RX desc */
struct tasklet_struct rxtq; /* rx intr tasklet */
struct ath5k_led rx_led; /* rx led */
struct list_head txbuf; /* transmit buffer */
spinlock_t txbuflock;
@ -167,6 +170,7 @@ struct ath5k_softc {
struct ath5k_txq *txq; /* beacon and tx*/
struct tasklet_struct txtq; /* tx intr tasklet */
struct ath5k_led tx_led; /* tx led */
struct ath5k_buf *bbuf; /* beacon buffer */
unsigned int bhalq, /* SW q for outgoing beacons */

View file

@ -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 *,

View file

@ -2310,30 +2310,40 @@ static int atmel_get_scan(struct net_device *dev,
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6);
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN);
current_ev = iwe_stream_add_event(info, current_ev,
extra + IW_SCAN_MAX_DATA,
&iwe, IW_EV_ADDR_LEN);
iwe.u.data.length = priv->BSSinfo[i].SSIDsize;
if (iwe.u.data.length > 32)
iwe.u.data.length = 32;
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, priv->BSSinfo[i].SSID);
current_ev = iwe_stream_add_point(info, current_ev,
extra + IW_SCAN_MAX_DATA,
&iwe, priv->BSSinfo[i].SSID);
iwe.cmd = SIOCGIWMODE;
iwe.u.mode = priv->BSSinfo[i].BSStype;
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN);
current_ev = iwe_stream_add_event(info, current_ev,
extra + IW_SCAN_MAX_DATA,
&iwe, IW_EV_UINT_LEN);
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = priv->BSSinfo[i].channel;
iwe.u.freq.e = 0;
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN);
current_ev = iwe_stream_add_event(info, current_ev,
extra + IW_SCAN_MAX_DATA,
&iwe, IW_EV_FREQ_LEN);
/* Add quality statistics */
iwe.cmd = IWEVQUAL;
iwe.u.qual.level = priv->BSSinfo[i].RSSI;
iwe.u.qual.qual = iwe.u.qual.level;
/* iwe.u.qual.noise = SOMETHING */
current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA , &iwe, IW_EV_QUAL_LEN);
current_ev = iwe_stream_add_event(info, current_ev,
extra + IW_SCAN_MAX_DATA,
&iwe, IW_EV_QUAL_LEN);
iwe.cmd = SIOCGIWENCODE;
@ -2342,7 +2352,9 @@ static int atmel_get_scan(struct net_device *dev,
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL);
current_ev = iwe_stream_add_point(info, current_ev,
extra + IW_SCAN_MAX_DATA,
&iwe, NULL);
}
/* Length of data */

View file

@ -441,6 +441,8 @@ enum {
#define B43_FWPANIC_DIE 0 /* Firmware died. Don't auto-restart it. */
#define B43_FWPANIC_RESTART 1 /* Firmware died. Schedule a controller reset. */
/* The firmware register that contains the watchdog counter. */
#define B43_WATCHDOG_REG 1
/* Device specific rate values.
* The actual values defined here are (rate_in_mbps * 2).

View file

@ -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 @@ static ssize_t b43_debugfs_write(struct file *file,
.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);

View file

@ -11,6 +11,7 @@ enum b43_dyndbg { /* Dynamic debugging features */
B43_DBG_PWORK_FAST,
B43_DBG_PWORK_STOP,
B43_DBG_LO,
B43_DBG_FIRMWARE,
__B43_NR_DYNDBG,
};
@ -36,9 +37,15 @@ struct b43_dfsentry {
struct b43_wldev *dev;
struct dentry *subdir;
struct b43_dfs_file file_shm16read;
struct b43_dfs_file file_shm16write;
struct b43_dfs_file file_shm32read;
struct b43_dfs_file file_shm32write;
struct b43_dfs_file file_mmio16read;
struct b43_dfs_file file_mmio16write;
struct b43_dfs_file file_mmio32read;
struct b43_dfs_file file_mmio32write;
struct b43_dfs_file file_tsf;
struct b43_dfs_file file_ucode_regs;
struct b43_dfs_file file_shm;
struct b43_dfs_file file_txstat;
struct b43_dfs_file file_txpower_g;
struct b43_dfs_file file_restart;
@ -46,6 +53,18 @@ struct b43_dfsentry {
struct b43_txstatus_log txstatlog;
/* The cached address for the next mmio16read file read */
u16 mmio16read_next;
/* The cached address for the next mmio32read file read */
u16 mmio32read_next;
/* The cached address for the next shm16read file read */
u32 shm16read_routing_next;
u32 shm16read_addr_next;
/* The cached address for the next shm32read file read */
u32 shm32read_routing_next;
u32 shm32read_addr_next;
/* Enabled/Disabled list for the dynamic debugging features. */
u32 dyn_debug[__B43_NR_DYNDBG];
/* Dentries for the dynamic debugging entries. */

View file

@ -328,11 +328,11 @@ static inline
dma_addr_t dmaaddr;
if (tx) {
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len, DMA_TO_DEVICE);
dmaaddr = ssb_dma_map_single(ring->dev->dev,
buf, len, DMA_TO_DEVICE);
} else {
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len, DMA_FROM_DEVICE);
dmaaddr = ssb_dma_map_single(ring->dev->dev,
buf, len, DMA_FROM_DEVICE);
}
return dmaaddr;
@ -343,11 +343,11 @@ static inline
dma_addr_t addr, size_t len, int tx)
{
if (tx) {
dma_unmap_single(ring->dev->dev->dma_dev,
addr, len, DMA_TO_DEVICE);
ssb_dma_unmap_single(ring->dev->dev,
addr, len, DMA_TO_DEVICE);
} else {
dma_unmap_single(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
ssb_dma_unmap_single(ring->dev->dev,
addr, len, DMA_FROM_DEVICE);
}
}
@ -356,8 +356,8 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
ssb_dma_sync_single_for_cpu(ring->dev->dev,
addr, len, DMA_FROM_DEVICE);
}
static inline
@ -365,8 +365,8 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
dma_sync_single_for_device(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
ssb_dma_sync_single_for_device(ring->dev->dev,
addr, len, DMA_FROM_DEVICE);
}
static inline
@ -381,7 +381,6 @@ static inline
static int alloc_ringmemory(struct b43_dmaring *ring)
{
struct device *dma_dev = ring->dev->dev->dma_dev;
gfp_t flags = GFP_KERNEL;
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
@ -392,11 +391,14 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
* For unknown reasons - possibly a hardware error - the BCM4311 rev
* 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
* which accounts for the GFP_DMA flag below.
*
* The flags here must match the flags in free_ringmemory below!
*/
if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
ring->descbase = dma_alloc_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
&(ring->dmabase), flags);
ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
B43_DMA_RINGMEMSIZE,
&(ring->dmabase), flags);
if (!ring->descbase) {
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
return -ENOMEM;
@ -408,10 +410,13 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
static void free_ringmemory(struct b43_dmaring *ring)
{
struct device *dma_dev = ring->dev->dev->dma_dev;
gfp_t flags = GFP_KERNEL;
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);

View file

@ -373,13 +373,10 @@ static inline void b43_shm_control_word(struct b43_wldev *dev,
b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
}
u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
{
struct b43_wl *wl = dev->wl;
unsigned long flags;
u32 ret;
spin_lock_irqsave(&wl->shm_lock, flags);
if (routing == B43_SHM_SHARED) {
B43_WARN_ON(offset & 0x0001);
if (offset & 0x0003) {
@ -397,18 +394,26 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
b43_shm_control_word(dev, routing, offset);
ret = b43_read32(dev, B43_MMIO_SHM_DATA);
out:
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

View file

@ -95,9 +95,13 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
u64 b43_hf_read(struct b43_wldev *dev);
void b43_hf_write(struct b43_wldev *dev, u64 value);

View file

@ -586,7 +586,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
spin_lock(&q->lock); /* IRQs are already disabled. */
info = (void *)pack->skb;
info = IEEE80211_SKB_CB(pack->skb);
memset(&info->status, 0, sizeof(info->status));
b43_fill_txstatus_report(info, status);

View file

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

View file

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

View file

@ -393,13 +393,13 @@ dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
dma_addr_t dmaaddr;
if (tx)
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len,
DMA_TO_DEVICE);
dmaaddr = ssb_dma_map_single(ring->dev->dev,
buf, len,
DMA_TO_DEVICE);
else
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len,
DMA_FROM_DEVICE);
dmaaddr = ssb_dma_map_single(ring->dev->dev,
buf, len,
DMA_FROM_DEVICE);
return dmaaddr;
}
@ -411,13 +411,13 @@ void unmap_descbuffer(struct b43legacy_dmaring *ring,
int tx)
{
if (tx)
dma_unmap_single(ring->dev->dev->dma_dev,
addr, len,
DMA_TO_DEVICE);
ssb_dma_unmap_single(ring->dev->dev,
addr, len,
DMA_TO_DEVICE);
else
dma_unmap_single(ring->dev->dev->dma_dev,
addr, len,
DMA_FROM_DEVICE);
ssb_dma_unmap_single(ring->dev->dev,
addr, len,
DMA_FROM_DEVICE);
}
static inline
@ -427,8 +427,8 @@ void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
{
B43legacy_WARN_ON(ring->tx);
dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
ssb_dma_sync_single_for_cpu(ring->dev->dev,
addr, len, DMA_FROM_DEVICE);
}
static inline
@ -438,8 +438,8 @@ void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
{
B43legacy_WARN_ON(ring->tx);
dma_sync_single_for_device(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
ssb_dma_sync_single_for_device(ring->dev->dev,
addr, len, DMA_FROM_DEVICE);
}
static inline
@ -458,10 +458,11 @@ void free_descriptor_buffer(struct b43legacy_dmaring *ring,
static int alloc_ringmemory(struct b43legacy_dmaring *ring)
{
struct device *dma_dev = ring->dev->dev->dma_dev;
ring->descbase = dma_alloc_coherent(dma_dev, B43legacy_DMA_RINGMEMSIZE,
&(ring->dmabase), GFP_KERNEL);
/* GFP flags must match the flags in free_ringmemory()! */
ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
B43legacy_DMA_RINGMEMSIZE,
&(ring->dmabase),
GFP_KERNEL);
if (!ring->descbase) {
b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
" failed\n");
@ -474,10 +475,8 @@ static int alloc_ringmemory(struct b43legacy_dmaring *ring)
static void free_ringmemory(struct b43legacy_dmaring *ring)
{
struct device *dma_dev = ring->dev->dev->dma_dev;
dma_free_coherent(dma_dev, B43legacy_DMA_RINGMEMSIZE,
ring->descbase, ring->dmabase);
ssb_dma_free_consistent(ring->dev->dev, B43legacy_DMA_RINGMEMSIZE,
ring->descbase, ring->dmabase, GFP_KERNEL);
}
/* Reset the RX DMA channel */
@ -589,7 +588,7 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
size_t buffersize,
bool dma_to_device)
{
if (unlikely(dma_mapping_error(addr)))
if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
return 1;
switch (ring->type) {
@ -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;

View file

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

View file

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

View file

@ -67,7 +67,8 @@ void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
struct iw_quality qual[], int buf_size,
int aplist);
int prism2_ap_translate_scan(struct net_device *dev, char *buffer);
int prism2_ap_translate_scan(struct net_device *dev,
struct iw_request_info *info, char *buffer);
int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param);

View file

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

View file

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

View file

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

View file

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

View file

@ -776,8 +776,9 @@ int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid,
#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;

View file

@ -430,15 +430,16 @@ static int __init init_mac80211_hwsim(void)
hwsim_radios[i] = hw;
data = hw->priv;
data->dev = device_create(hwsim_class, NULL, 0, "hwsim%d", i);
data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw,
"hwsim%d", i);
if (IS_ERR(data->dev)) {
printk(KERN_DEBUG "mac80211_hwsim: device_create "
printk(KERN_DEBUG
"mac80211_hwsim: device_create_drvdata "
"failed (%ld)\n", PTR_ERR(data->dev));
err = -ENOMEM;
goto failed;
}
data->dev->driver = &mac80211_hwsim_driver;
dev_set_drvdata(data->dev, hw);
SET_IEEE80211_DEV(hw, data->dev);
addr[3] = i >> 8;

View file

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

View file

@ -571,8 +571,9 @@ prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
*/
static char *
prism54_translate_bss(struct net_device *ndev, char *current_ev,
char *end_buf, struct obj_bss *bss, char noise)
prism54_translate_bss(struct net_device *ndev, struct iw_request_info *info,
char *current_ev, char *end_buf, struct obj_bss *bss,
char noise)
{
struct iw_event iwe; /* Temporary buffer */
short cap;
@ -584,8 +585,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
iwe.cmd = SIOCGIWAP;
current_ev =
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
&iwe, IW_EV_ADDR_LEN);
/* The following entries will be displayed in the same order we give them */
@ -593,7 +594,7 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
iwe.u.data.length = bss->ssid.length;
iwe.u.data.flags = 1;
iwe.cmd = SIOCGIWESSID;
current_ev = iwe_stream_add_point(current_ev, end_buf,
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, bss->ssid.octets);
/* Capabilities */
@ -610,9 +611,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
iwe.u.mode = IW_MODE_ADHOC;
iwe.cmd = SIOCGIWMODE;
if (iwe.u.mode)
current_ev =
iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_UINT_LEN);
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
&iwe, IW_EV_UINT_LEN);
/* Encryption capability */
if (cap & CAP_CRYPT)
@ -621,14 +621,15 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
iwe.cmd = SIOCGIWENCODE;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, NULL);
/* Add frequency. (short) bss->channel is the frequency in MHz */
iwe.u.freq.m = bss->channel;
iwe.u.freq.e = 6;
iwe.cmd = SIOCGIWFREQ;
current_ev =
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
&iwe, IW_EV_FREQ_LEN);
/* Add quality statistics */
iwe.u.qual.level = bss->rssi;
@ -636,20 +637,20 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
/* do a simple SNR for quality */
iwe.u.qual.qual = bss->rssi - noise;
iwe.cmd = IWEVQUAL;
current_ev =
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
&iwe, IW_EV_QUAL_LEN);
/* Add WPA/RSN Information Element, if any */
wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
if (wpa_ie_len > 0) {
iwe.cmd = IWEVGENIE;
iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
current_ev = iwe_stream_add_point(current_ev, end_buf,
&iwe, wpa_ie);
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, wpa_ie);
}
/* Do the bitrates */
{
char * current_val = current_ev + IW_EV_LCP_LEN;
char *current_val = current_ev + iwe_stream_lcp_len(info);
int i;
int mask;
@ -662,14 +663,14 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
for(i = 0; i < sizeof(scan_rate_list); i++) {
if(bss->rates & mask) {
iwe.u.bitrate.value = (scan_rate_list[i] * 500000);
current_val = iwe_stream_add_value(current_ev, current_val,
end_buf, &iwe,
IW_EV_PARAM_LEN);
current_val = iwe_stream_add_value(
info, current_ev, current_val,
end_buf, &iwe, IW_EV_PARAM_LEN);
}
mask <<= 1;
}
/* Check if we added any event */
if ((current_val - current_ev) > IW_EV_LCP_LEN)
if ((current_val - current_ev) > iwe_stream_lcp_len(info))
current_ev = current_val;
}
@ -710,7 +711,7 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
/* ok now, scan the list and translate its info */
for (i = 0; i < (int) bsslist->nr; i++) {
current_ev = prism54_translate_bss(ndev, current_ev,
current_ev = prism54_translate_bss(ndev, info, current_ev,
extra + dwrq->length,
&(bsslist->bsslist[i]),
noise);
@ -2704,6 +2705,7 @@ prism2_ioctl_scan_req(struct net_device *ndev,
struct prism2_hostapd_param *param)
{
islpci_private *priv = netdev_priv(ndev);
struct iw_request_info info;
int i, rvalue;
struct obj_bsslist *bsslist;
u32 noise = 0;
@ -2727,9 +2729,12 @@ prism2_ioctl_scan_req(struct net_device *ndev,
rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
bsslist = r.ptr;
info.cmd = PRISM54_HOSTAPD;
info.flags = 0;
/* ok now, scan the list and translate its info */
for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
current_ev = prism54_translate_bss(ndev, current_ev,
current_ev = prism54_translate_bss(ndev, &info, current_ev,
extra + IW_SCAN_MAX_DATA,
&(bsslist->bsslist[i]),
noise);

View file

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

View file

@ -632,15 +632,15 @@ static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
rt2x00_desc_read(entry_priv->desc, 2, &word);
rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
entry->queue->data_size);
rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len);
rt2x00_desc_write(entry_priv->desc, 2, word);
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(entry_priv->desc, 0, &word);
@ -1012,7 +1012,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
* Start writing the descriptor words.
*/
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(txd, 2, &word);
@ -1154,7 +1154,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
}
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
rt2x00lib_txdone(entry, &txdesc);
}
}
@ -1366,7 +1366,7 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
EEPROM_MAC_ADDR_0));
@ -1412,9 +1412,10 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
rt2400pci_probe_hw_mode(rt2x00dev);
/*
* This device requires the atim queue
* This device requires the atim queue and DMA-mapped skbs.
*/
__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
/*
* Set the rssi offset.
@ -1526,7 +1527,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
* Write entire beacon with descriptor to register,
* and kick the beacon generator.
*/
memcpy(entry_priv->data, skb->data, skb->len);
rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);

View file

@ -727,10 +727,11 @@ static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(entry_priv->desc, 0, &word);
@ -1171,7 +1172,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
* Start writing the descriptor words.
*/
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(txd, 2, &word);
@ -1311,7 +1312,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
}
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
rt2x00lib_txdone(entry, &txdesc);
}
}
@ -1688,7 +1689,7 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->extra_tx_headroom = 0;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
EEPROM_MAC_ADDR_0));
@ -1752,9 +1753,10 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
rt2500pci_probe_hw_mode(rt2x00dev);
/*
* This device requires the atim queue
* This device requires the atim queue and DMA-mapped skbs.
*/
__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
/*
* Set the rssi offset.
@ -1842,7 +1844,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
* Write entire beacon with descriptor to register,
* and kick the beacon generator.
*/
memcpy(entry_priv->data, skb->data, skb->len);
rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);

View file

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

View file

@ -44,7 +44,7 @@
/*
* Module information.
*/
#define DRV_VERSION "2.1.7"
#define DRV_VERSION "2.1.8"
#define DRV_PROJECT "http://rt2x00.serialmonkey.com"
/*
@ -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.

View file

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

View file

@ -98,10 +98,57 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf, const int force_config);
/*
* Queue handlers.
/**
* DOC: Queue handlers
*/
/**
* rt2x00queue_alloc_rxskb - allocate a skb for RX purposes.
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @queue: The queue for which the skb will be applicable.
*/
struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry);
/**
* rt2x00queue_unmap_skb - Unmap a skb from DMA.
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to unmap.
*/
void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
* rt2x00queue_free_skb - free a skb
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to free.
*/
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
* rt2x00queue_free_skb - free a skb
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to free.
*/
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
* rt2x00queue_write_tx_frame - Write TX frame to hardware
* @queue: Queue over which the frame should be send
* @skb: The skb to send
*/
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb);
/**
* rt2x00queue_index_inc - Index incrementation function
* @queue: Queue (&struct data_queue) to perform the action on.
* @index: Index type (&enum queue_index) to perform the action on.
*
* This function will increase the requested index on the queue,
* it will grab the appropriate locks and handle queue overflow events by
* resetting the index to the start of the queue.
*/
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev);
void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev);
int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);

View file

@ -60,12 +60,8 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry)
* Fill in skb descriptor
*/
skbdesc = get_skb_frame_desc(entry->skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = entry->queue->desc_size;
skbdesc->entry = entry;
memcpy(entry_priv->data, entry->skb->data, entry->skb->len);
return 0;
}
@ -80,7 +76,6 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
struct queue_entry *entry;
struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc;
struct rxdone_entry_desc rxdesc;
u32 word;
while (1) {
@ -91,110 +86,27 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
break;
memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
/*
* Allocate the sk_buffer and copy all data into it.
*/
entry->skb = rt2x00queue_alloc_rxskb(queue);
if (!entry->skb)
return;
memcpy(entry->skb->data, entry_priv->data, rxdesc.size);
skb_trim(entry->skb, rxdesc.size);
/*
* Fill in skb descriptor
* Fill in desc fields of the skb descriptor
*/
skbdesc = get_skb_frame_desc(entry->skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = queue->desc_size;
skbdesc->entry = entry;
skbdesc->desc_len = entry->queue->desc_size;
/*
* Send the frame to rt2x00lib for further processing.
*/
rt2x00lib_rxdone(entry, &rxdesc);
if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) {
rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
rt2x00_desc_write(entry_priv->desc, 0, word);
}
rt2x00queue_index_inc(queue, Q_INDEX);
rt2x00lib_rxdone(rt2x00dev, entry);
}
}
EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
struct txdone_entry_desc *txdesc)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
u32 word;
rt2x00lib_txdone(entry, txdesc);
/*
* Make this entry available for reuse.
*/
entry->flags = 0;
rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0);
rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0);
rt2x00_desc_write(entry_priv->desc, 0, word);
__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
/*
* If the data queue was below the threshold before the txdone
* handler we must make sure the packet queue in the mac80211 stack
* is reenabled when the txdone handler has finished.
*/
if (!rt2x00queue_threshold(entry->queue))
ieee80211_wake_queue(rt2x00dev->hw, qid);
}
EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
/*
* Device initialization handlers.
*/
#define desc_size(__queue) \
({ \
((__queue)->limit * (__queue)->desc_size);\
})
#define data_size(__queue) \
({ \
((__queue)->limit * (__queue)->data_size);\
})
#define dma_size(__queue) \
({ \
data_size(__queue) + desc_size(__queue);\
})
#define desc_offset(__queue, __base, __i) \
({ \
(__base) + data_size(__queue) + \
((__i) * (__queue)->desc_size); \
})
#define data_offset(__queue, __base, __i) \
({ \
(__base) + \
((__i) * (__queue)->data_size); \
})
static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
struct queue_entry_priv_pci *entry_priv;
void *addr;
dma_addr_t dma;
@ -203,21 +115,21 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
/*
* Allocate DMA memory for descriptor and buffer.
*/
addr = pci_alloc_consistent(pci_dev, dma_size(queue), &dma);
addr = dma_alloc_coherent(rt2x00dev->dev,
queue->limit * queue->desc_size,
&dma, GFP_KERNEL | GFP_DMA);
if (!addr)
return -ENOMEM;
memset(addr, 0, dma_size(queue));
memset(addr, 0, queue->limit * queue->desc_size);
/*
* Initialize all queue entries to contain valid addresses.
*/
for (i = 0; i < queue->limit; i++) {
entry_priv = queue->entries[i].priv_data;
entry_priv->desc = desc_offset(queue, addr, i);
entry_priv->desc_dma = desc_offset(queue, dma, i);
entry_priv->data = data_offset(queue, addr, i);
entry_priv->data_dma = data_offset(queue, dma, i);
entry_priv->desc = addr + i * queue->desc_size;
entry_priv->desc_dma = dma + i * queue->desc_size;
}
return 0;
@ -226,19 +138,19 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
struct queue_entry_priv_pci *entry_priv =
queue->entries[0].priv_data;
if (entry_priv->data)
pci_free_consistent(pci_dev, dma_size(queue),
entry_priv->data, entry_priv->data_dma);
entry_priv->data = NULL;
if (entry_priv->desc)
dma_free_coherent(rt2x00dev->dev,
queue->limit * queue->desc_size,
entry_priv->desc, entry_priv->desc_dma);
entry_priv->desc = NULL;
}
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
{
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
struct data_queue *queue;
int status;
@ -279,7 +191,7 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
/*
* Free irq line.
*/
free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev);
free_irq(to_pci_dev(rt2x00dev->dev)->irq, rt2x00dev);
/*
* Free DMA
@ -308,7 +220,7 @@ static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
{
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0),
pci_resource_len(pci_dev, 0));
@ -357,7 +269,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
if (pci_set_mwi(pci_dev))
ERROR_PROBE("MWI not available.\n");
if (pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
if (dma_set_mask(&pci_dev->dev, DMA_32BIT_MASK)) {
ERROR_PROBE("PCI DMA not supported.\n");
retval = -EIO;
goto exit_disable_device;
@ -373,7 +285,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
pci_set_drvdata(pci_dev, hw);
rt2x00dev = hw->priv;
rt2x00dev->dev = pci_dev;
rt2x00dev->dev = &pci_dev->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;

View file

@ -107,9 +107,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry);
struct queue_entry_priv_pci {
__le32 *desc;
dma_addr_t desc_dma;
void *data;
dma_addr_t data_dma;
};
/**
@ -118,15 +115,6 @@ struct queue_entry_priv_pci {
*/
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00pci_txdone - Handle TX done events
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @entry: Entry which has completed the transmission of a frame.
* @desc: TX done descriptor
*/
void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
struct txdone_entry_desc *desc);
/*
* Device initialization handlers.
*/

View file

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

View file

@ -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;
};

View file

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

View file

@ -40,7 +40,7 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
void *buffer, const u16 buffer_length,
const int timeout)
{
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
int status;
unsigned int i;
unsigned int pipe =
@ -130,10 +130,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct txdone_entry_desc txdesc;
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
@ -157,26 +156,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
txdesc.retry = 0;
rt2x00lib_txdone(entry, &txdesc);
/*
* Make this entry available for reuse.
*/
entry->flags = 0;
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
/*
* If the data queue was below the threshold before the txdone
* handler we must make sure the packet queue in the mac80211 stack
* is reenabled when the txdone handler has finished.
*/
if (!rt2x00queue_threshold(entry->queue))
ieee80211_wake_queue(rt2x00dev->hw, qid);
}
int rt2x00usb_write_tx_data(struct queue_entry *entry)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc;
u32 length;
@ -191,10 +176,8 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
* Fill in skb descriptor
*/
skbdesc = get_skb_frame_desc(entry->skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->desc = entry->skb->data;
skbdesc->desc_len = entry->queue->desc_size;
skbdesc->entry = entry;
/*
* USB devices cannot blindly pass the skb->len as the
@ -264,13 +247,11 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct sk_buff *skb;
struct skb_frame_desc *skbdesc;
struct rxdone_entry_desc rxdesc;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u8 rxd[32];
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
@ -278,50 +259,22 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
* to be actually valid, or if the urb is signaling
* a problem.
*/
if (urb->actual_length < entry->queue->desc_size || urb->status)
goto skip_entry;
if (urb->actual_length < entry->queue->desc_size || urb->status) {
__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(urb, GFP_ATOMIC);
return;
}
/*
* Fill in skb descriptor
* Fill in desc fields of the skb descriptor
*/
skbdesc = get_skb_frame_desc(entry->skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;
skbdesc->desc = rxd;
skbdesc->desc_len = entry->queue->desc_size;
memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
/*
* Allocate a new sk buffer to replace the current one.
* If allocation fails, we should drop the current frame
* so we can recycle the existing sk buffer for the new frame.
*/
skb = rt2x00queue_alloc_rxskb(entry->queue);
if (!skb)
goto skip_entry;
/*
* Send the frame to rt2x00lib for further processing.
*/
rt2x00lib_rxdone(entry, &rxdesc);
/*
* Replace current entry's skb with the newly allocated one,
* and reinitialize the urb.
*/
entry->skb = skb;
urb->transfer_buffer = entry->skb->data;
urb->transfer_buffer_length = entry->skb->len;
skip_entry:
if (test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) {
__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(urb, GFP_ATOMIC);
}
rt2x00queue_index_inc(entry->queue, Q_INDEX);
rt2x00lib_rxdone(rt2x00dev, entry);
}
/*
@ -331,6 +284,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_bcn *bcn_priv;
struct data_queue *queue;
unsigned int i;
rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
@ -339,9 +293,11 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Cancel all queues.
*/
for (i = 0; i < rt2x00dev->rx->limit; i++) {
entry_priv = rt2x00dev->rx->entries[i].priv_data;
usb_kill_urb(entry_priv->urb);
queue_for_each(rt2x00dev, queue) {
for (i = 0; i < queue->limit; i++) {
entry_priv = queue->entries[i].priv_data;
usb_kill_urb(entry_priv->urb);
}
}
/*
@ -364,7 +320,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
usb_fill_bulk_urb(entry_priv->urb, usb_dev,
@ -431,8 +387,6 @@ static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
entry_priv = queue->entries[i].priv_data;
usb_kill_urb(entry_priv->urb);
usb_free_urb(entry_priv->urb);
if (queue->entries[i].skb)
kfree_skb(queue->entries[i].skb);
}
/*
@ -454,10 +408,7 @@ static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
struct sk_buff *skb;
unsigned int entry_size;
unsigned int i;
int uninitialized_var(status);
int status;
/*
* Allocate DMA
@ -468,18 +419,6 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
goto exit;
}
/*
* For the RX queue, skb's should be allocated.
*/
entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size;
for (i = 0; i < rt2x00dev->rx->limit; i++) {
skb = rt2x00queue_alloc_rxskb(rt2x00dev->rx);
if (!skb)
goto exit;
rt2x00dev->rx->entries[i].skb = skb;
}
return 0;
exit:
@ -558,7 +497,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
usb_set_intfdata(usb_intf, hw);
rt2x00dev = hw->priv;
rt2x00dev->dev = usb_intf;
rt2x00dev->dev = &usb_intf->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
mutex_init(&rt2x00dev->usb_cache_mutex);

View file

@ -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.

View file

@ -1030,11 +1030,12 @@ static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
rt2x00_desc_read(entry_priv->desc, 5, &word);
rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
entry_priv->data_dma);
skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 5, word);
rt2x00_desc_read(entry_priv->desc, 0, &word);
@ -1522,7 +1523,6 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
__le32 *txd = skbdesc->desc;
u32 word;
@ -1557,7 +1557,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_read(txd, 6, &word);
rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
entry_priv->data_dma);
skbdesc->skb_dma);
rt2x00_desc_write(txd, 6, word);
if (skbdesc->desc_len > TXINFO_SIZE) {
@ -1767,7 +1767,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
txdesc.retry = 0;
rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc);
rt2x00lib_txdone(entry_done, &txdesc);
entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
}
@ -1787,7 +1787,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
}
txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
rt2x00lib_txdone(entry, &txdesc);
}
}
@ -1973,7 +1973,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* To determine the RT chip we have to read the
* PCI header of the device.
*/
pci_read_config_word(rt2x00dev_pci(rt2x00dev),
pci_read_config_word(to_pci_dev(rt2x00dev->dev),
PCI_CONFIG_HEADER_DEVICE, &device);
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
@ -2239,7 +2239,7 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
EEPROM_MAC_ADDR_0));
@ -2302,9 +2302,10 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
rt61pci_probe_hw_mode(rt2x00dev);
/*
* This device requires firmware.
* This device requires firmware and DMA mapped skbs.
*/
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
/*
* Set the rssi offset.
@ -2402,6 +2403,12 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
skb->data, skb->len);
rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON);
/*
* Clean up beacon skb.
*/
dev_kfree_skb_any(skb);
intf->beacon->skb = NULL;
return 0;
}

View file

@ -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

View file

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

View file

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

View file

@ -376,8 +376,6 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
struct ieee80211_hdr *header, u32 flags)
{
u16 fctl = le16_to_cpu(header->frame_control);
/*
* CONTROL TODO:
* - if backoff needed, enable bit 0
@ -395,8 +393,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
cs->control |= ZD_CS_MULTICAST;
/* PS-POLL */
if ((fctl & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) ==
(IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL))
if (ieee80211_is_pspoll(header->frame_control))
cs->control |= ZD_CS_PS_POLL_FRAME;
if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
@ -550,13 +547,11 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
struct ieee80211_rx_status *stats)
{
u16 fc = le16_to_cpu(rx_hdr->frame_control);
struct sk_buff *skb;
struct sk_buff_head *q;
unsigned long flags;
if ((fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) !=
(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK))
if (!ieee80211_is_ack(rx_hdr->frame_control))
return 0;
q = &zd_hw_mac(hw)->ack_wait_queue;
@ -584,8 +579,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
const struct rx_status *status;
struct sk_buff *skb;
int bad_frame = 0;
u16 fc;
bool is_qos, is_4addr, need_padding;
__le16 fc;
int need_padding;
int i;
u8 rate;
@ -644,13 +639,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
&& !mac->pass_ctrl)
return 0;
fc = le16_to_cpu(*((__le16 *) buffer));
is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
(fc & IEEE80211_STYPE_QOS_DATA);
is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
need_padding = is_qos ^ is_4addr;
fc = *(__le16 *)buffer;
need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc);
skb = dev_alloc_skb(length + (need_padding ? 2 : 0));
if (skb == NULL)

View file

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

View file

@ -462,18 +462,15 @@ static int ssb_devices_register(struct ssb_bus *bus)
#ifdef CONFIG_SSB_PCIHOST
sdev->irq = bus->host_pci->irq;
dev->parent = &bus->host_pci->dev;
sdev->dma_dev = &bus->host_pci->dev;
#endif
break;
case SSB_BUSTYPE_PCMCIA:
#ifdef CONFIG_SSB_PCMCIAHOST
sdev->irq = bus->host_pcmcia->irq.AssignedIRQ;
dev->parent = &bus->host_pcmcia->dev;
sdev->dma_dev = &bus->host_pcmcia->dev;
#endif
break;
case SSB_BUSTYPE_SSB:
sdev->dma_dev = dev;
break;
}
@ -1156,36 +1153,82 @@ u32 ssb_dma_translation(struct ssb_device *dev)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_SSB:
case SSB_BUSTYPE_PCMCIA:
return 0;
case SSB_BUSTYPE_PCI:
return SSB_PCI_DMA;
default:
__ssb_dma_not_implemented(dev);
}
return 0;
}
EXPORT_SYMBOL(ssb_dma_translation);
int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)
int ssb_dma_set_mask(struct ssb_device *dev, u64 mask)
{
struct device *dma_dev = ssb_dev->dma_dev;
int err = 0;
int err;
#ifdef CONFIG_SSB_PCIHOST
if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI) {
err = pci_set_dma_mask(ssb_dev->bus->host_pci, mask);
switch (dev->bus->bustype) {
case SSB_BUSTYPE_PCI:
err = pci_set_dma_mask(dev->bus->host_pci, mask);
if (err)
return err;
err = pci_set_consistent_dma_mask(ssb_dev->bus->host_pci, mask);
err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask);
return err;
case SSB_BUSTYPE_SSB:
return dma_set_mask(dev->dev, mask);
default:
__ssb_dma_not_implemented(dev);
}
#endif
dma_dev->coherent_dma_mask = mask;
dma_dev->dma_mask = &dma_dev->coherent_dma_mask;
return err;
return -ENOSYS;
}
EXPORT_SYMBOL(ssb_dma_set_mask);
void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp_flags)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_PCI:
if (gfp_flags & GFP_DMA) {
/* Workaround: The PCI API does not support passing
* a GFP flag. */
return dma_alloc_coherent(&dev->bus->host_pci->dev,
size, dma_handle, gfp_flags);
}
return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle);
case SSB_BUSTYPE_SSB:
return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags);
default:
__ssb_dma_not_implemented(dev);
}
return NULL;
}
EXPORT_SYMBOL(ssb_dma_alloc_consistent);
void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle,
gfp_t gfp_flags)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_PCI:
if (gfp_flags & GFP_DMA) {
/* Workaround: The PCI API does not support passing
* a GFP flag. */
dma_free_coherent(&dev->bus->host_pci->dev,
size, vaddr, dma_handle);
return;
}
pci_free_consistent(dev->bus->host_pci, size,
vaddr, dma_handle);
return;
case SSB_BUSTYPE_SSB:
dma_free_coherent(dev->dev, size, vaddr, dma_handle);
return;
default:
__ssb_dma_not_implemented(dev);
}
}
EXPORT_SYMBOL(ssb_dma_free_consistent);
int ssb_bus_may_powerdown(struct ssb_bus *bus)
{
struct ssb_chipcommon *cc;

View file

@ -58,7 +58,6 @@
#include <linux/syscalls.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/wireless.h>
#include <linux/atalk.h>
#include <linux/loop.h>
@ -1757,64 +1756,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a
return sys_ioctl(fd, cmd, (unsigned long)tdata);
}
struct compat_iw_point {
compat_caddr_t pointer;
__u16 length;
__u16 flags;
};
static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct iwreq __user *iwr;
struct iwreq __user *iwr_u;
struct iw_point __user *iwp;
struct compat_iw_point __user *iwp_u;
compat_caddr_t pointer_u;
void __user *pointer;
__u16 length, flags;
int ret;
iwr_u = compat_ptr(arg);
iwp_u = (struct compat_iw_point __user *) &iwr_u->u.data;
iwr = compat_alloc_user_space(sizeof(*iwr));
if (iwr == NULL)
return -ENOMEM;
iwp = &iwr->u.data;
if (!access_ok(VERIFY_WRITE, iwr, sizeof(*iwr)))
return -EFAULT;
if (__copy_in_user(&iwr->ifr_ifrn.ifrn_name[0],
&iwr_u->ifr_ifrn.ifrn_name[0],
sizeof(iwr->ifr_ifrn.ifrn_name)))
return -EFAULT;
if (__get_user(pointer_u, &iwp_u->pointer) ||
__get_user(length, &iwp_u->length) ||
__get_user(flags, &iwp_u->flags))
return -EFAULT;
if (__put_user(compat_ptr(pointer_u), &iwp->pointer) ||
__put_user(length, &iwp->length) ||
__put_user(flags, &iwp->flags))
return -EFAULT;
ret = sys_ioctl(fd, cmd, (unsigned long) iwr);
if (__get_user(pointer, &iwp->pointer) ||
__get_user(length, &iwp->length) ||
__get_user(flags, &iwp->flags))
return -EFAULT;
if (__put_user(ptr_to_compat(pointer), &iwp_u->pointer) ||
__put_user(length, &iwp_u->length) ||
__put_user(flags, &iwp_u->flags))
return -EFAULT;
return ret;
}
/* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
* for some operations; this forces use of the newer bridge-utils that
* use compatiable ioctls
@ -2495,36 +2436,6 @@ COMPATIBLE_IOCTL(I2C_TENBIT)
COMPATIBLE_IOCTL(I2C_PEC)
COMPATIBLE_IOCTL(I2C_RETRIES)
COMPATIBLE_IOCTL(I2C_TIMEOUT)
/* wireless */
COMPATIBLE_IOCTL(SIOCSIWCOMMIT)
COMPATIBLE_IOCTL(SIOCGIWNAME)
COMPATIBLE_IOCTL(SIOCSIWNWID)
COMPATIBLE_IOCTL(SIOCGIWNWID)
COMPATIBLE_IOCTL(SIOCSIWFREQ)
COMPATIBLE_IOCTL(SIOCGIWFREQ)
COMPATIBLE_IOCTL(SIOCSIWMODE)
COMPATIBLE_IOCTL(SIOCGIWMODE)
COMPATIBLE_IOCTL(SIOCSIWSENS)
COMPATIBLE_IOCTL(SIOCGIWSENS)
COMPATIBLE_IOCTL(SIOCSIWRANGE)
COMPATIBLE_IOCTL(SIOCSIWPRIV)
COMPATIBLE_IOCTL(SIOCSIWSTATS)
COMPATIBLE_IOCTL(SIOCSIWAP)
COMPATIBLE_IOCTL(SIOCGIWAP)
COMPATIBLE_IOCTL(SIOCSIWRATE)
COMPATIBLE_IOCTL(SIOCGIWRATE)
COMPATIBLE_IOCTL(SIOCSIWRTS)
COMPATIBLE_IOCTL(SIOCGIWRTS)
COMPATIBLE_IOCTL(SIOCSIWFRAG)
COMPATIBLE_IOCTL(SIOCGIWFRAG)
COMPATIBLE_IOCTL(SIOCSIWTXPOW)
COMPATIBLE_IOCTL(SIOCGIWTXPOW)
COMPATIBLE_IOCTL(SIOCSIWRETRY)
COMPATIBLE_IOCTL(SIOCGIWRETRY)
COMPATIBLE_IOCTL(SIOCSIWPOWER)
COMPATIBLE_IOCTL(SIOCGIWPOWER)
COMPATIBLE_IOCTL(SIOCSIWAUTH)
COMPATIBLE_IOCTL(SIOCGIWAUTH)
/* hiddev */
COMPATIBLE_IOCTL(HIDIOCGVERSION)
COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
@ -2755,29 +2666,7 @@ COMPATIBLE_IOCTL(USBDEVFS_IOCTL32)
HANDLE_IOCTL(I2C_FUNCS, w_long)
HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl)
/* wireless */
HANDLE_IOCTL(SIOCGIWRANGE, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWPRIV, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWSTATS, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWSPY, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWSPY, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWTHRSPY, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWTHRSPY, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWMLME, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWAPLIST, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWSCAN, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWSCAN, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWESSID, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWESSID, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWNICKN, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWNICKN, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWENCODE, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWENCODE, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWGENIE, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWGENIE, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWENCODEEXT, do_wireless_ioctl)
HANDLE_IOCTL(SIOCGIWENCODEEXT, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWPMKSA, do_wireless_ioctl)
/* bridge */
HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl)
HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
/* Not implemented in the native kernel */

View file

@ -469,6 +469,40 @@ struct ieee80211s_hdr {
u8 eaddr3[6];
} __attribute__ ((packed));
/**
* struct ieee80211_quiet_ie
*
* This structure refers to "Quiet information element"
*/
struct ieee80211_quiet_ie {
u8 count;
u8 period;
__le16 duration;
__le16 offset;
} __attribute__ ((packed));
/**
* struct ieee80211_msrment_ie
*
* This structure refers to "Measurement Request/Report information element"
*/
struct ieee80211_msrment_ie {
u8 token;
u8 mode;
u8 type;
u8 request[0];
} __attribute__ ((packed));
/**
* struct ieee80211_channel_sw_ie
*
* This structure refers to "Channel Switch Announcement information element"
*/
struct ieee80211_channel_sw_ie {
u8 mode;
u8 new_ch_num;
u8 count;
} __attribute__ ((packed));
struct ieee80211_mgmt {
__le16 frame_control;
@ -544,10 +578,15 @@ struct ieee80211_mgmt {
u8 action_code;
u8 element_id;
u8 length;
u8 switch_mode;
u8 new_chan;
u8 switch_count;
struct ieee80211_channel_sw_ie sw_elem;
} __attribute__((packed)) chan_switch;
struct{
u8 action_code;
u8 dialog_token;
u8 element_id;
u8 length;
struct ieee80211_msrment_ie msr_elem;
} __attribute__((packed)) measurement;
struct{
u8 action_code;
u8 dialog_token;
@ -700,11 +739,21 @@ struct ieee80211_ht_addt_info {
#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
#define WLAN_CAPABILITY_PBCC (1<<6)
#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
/* 802.11h */
#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
#define WLAN_CAPABILITY_QOS (1<<9)
#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
#define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
/* measurement */
#define IEEE80211_SPCT_MSR_RPRT_MODE_LATE (1<<0)
#define IEEE80211_SPCT_MSR_RPRT_MODE_INCAPABLE (1<<1)
#define IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED (1<<2)
#define IEEE80211_SPCT_MSR_RPRT_TYPE_BASIC 0
#define IEEE80211_SPCT_MSR_RPRT_TYPE_CCA 1
#define IEEE80211_SPCT_MSR_RPRT_TYPE_RPI 2
/* 802.11g ERP information element */
#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
@ -875,6 +924,15 @@ enum ieee80211_category {
WLAN_CATEGORY_WMM = 17,
};
/* SPECTRUM_MGMT action code */
enum ieee80211_spectrum_mgmt_actioncode {
WLAN_ACTION_SPCT_MSR_REQ = 0,
WLAN_ACTION_SPCT_MSR_RPRT = 1,
WLAN_ACTION_SPCT_TPC_REQ = 2,
WLAN_ACTION_SPCT_TPC_RPRT = 3,
WLAN_ACTION_SPCT_CHL_SWITCH = 4,
};
/* BACK action code */
enum ieee80211_back_actioncode {
WLAN_ACTION_ADDBA_REQ = 0,

View file

@ -241,7 +241,10 @@ enum nl80211_attrs {
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
};
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
/**
* enum nl80211_iftype - (virtual) interface types

View file

@ -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 */

View file

@ -137,9 +137,6 @@ struct ssb_device {
const struct ssb_bus_ops *ops;
struct device *dev;
/* Pointer to the device that has to be used for
* any DMA related operation. */
struct device *dma_dev;
struct ssb_bus *bus;
struct ssb_device_id id;
@ -399,13 +396,151 @@ static inline void ssb_block_write(struct ssb_device *dev, const void *buffer,
#endif /* CONFIG_SSB_BLOCKIO */
/* The SSB DMA API. Use this API for any DMA operation on the device.
* This API basically is a wrapper that calls the correct DMA API for
* the host device type the SSB device is attached to. */
/* Translation (routing) bits that need to be ORed to DMA
* addresses before they are given to a device. */
extern u32 ssb_dma_translation(struct ssb_device *dev);
#define SSB_DMA_TRANSLATION_MASK 0xC0000000
#define SSB_DMA_TRANSLATION_SHIFT 30
extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask);
extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask);
extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp_flags);
extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle,
gfp_t gfp_flags);
static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
{
#ifdef CONFIG_SSB_DEBUG
printk(KERN_ERR "SSB: BUG! Calling DMA API for "
"unsupported bustype %d\n", dev->bus->bustype);
#endif /* DEBUG */
}
static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_PCI:
return pci_dma_mapping_error(addr);
case SSB_BUSTYPE_SSB:
return dma_mapping_error(addr);
default:
__ssb_dma_not_implemented(dev);
}
return -ENOSYS;
}
static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p,
size_t size, enum dma_data_direction dir)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_PCI:
return pci_map_single(dev->bus->host_pci, p, size, dir);
case SSB_BUSTYPE_SSB:
return dma_map_single(dev->dev, p, size, dir);
default:
__ssb_dma_not_implemented(dev);
}
return 0;
}
static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr,
size_t size, enum dma_data_direction dir)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_PCI:
pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir);
return;
case SSB_BUSTYPE_SSB:
dma_unmap_single(dev->dev, dma_addr, size, dir);
return;
default:
__ssb_dma_not_implemented(dev);
}
}
static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev,
dma_addr_t dma_addr,
size_t size,
enum dma_data_direction dir)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_PCI:
pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
size, dir);
return;
case SSB_BUSTYPE_SSB:
dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir);
return;
default:
__ssb_dma_not_implemented(dev);
}
}
static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev,
dma_addr_t dma_addr,
size_t size,
enum dma_data_direction dir)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_PCI:
pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
size, dir);
return;
case SSB_BUSTYPE_SSB:
dma_sync_single_for_device(dev->dev, dma_addr, size, dir);
return;
default:
__ssb_dma_not_implemented(dev);
}
}
static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev,
dma_addr_t dma_addr,
unsigned long offset,
size_t size,
enum dma_data_direction dir)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_PCI:
/* Just sync everything. That's all the PCI API can do. */
pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
offset + size, dir);
return;
case SSB_BUSTYPE_SSB:
dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset,
size, dir);
return;
default:
__ssb_dma_not_implemented(dev);
}
}
static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev,
dma_addr_t dma_addr,
unsigned long offset,
size_t size,
enum dma_data_direction dir)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_PCI:
/* Just sync everything. That's all the PCI API can do. */
pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
offset + size, dir);
return;
case SSB_BUSTYPE_SSB:
dma_sync_single_range_for_device(dev->dev, dma_addr, offset,
size, dir);
return;
default:
__ssb_dma_not_implemented(dev);
}
}
#ifdef CONFIG_SSB_PCIHOST

View file

@ -677,6 +677,19 @@ struct iw_point
__u16 flags; /* Optional params */
};
#ifdef __KERNEL__
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
struct compat_iw_point {
compat_caddr_t pointer;
__u16 length;
__u16 flags;
};
#endif
#endif
/*
* A frequency
* For numbers lower than 10^9, we encode the number in 'm' and
@ -1100,6 +1113,21 @@ struct iw_event
#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \
IW_EV_POINT_OFF)
#ifdef __KERNEL__
#ifdef CONFIG_COMPAT
struct __compat_iw_event {
__u16 len; /* Real length of this stuff */
__u16 cmd; /* Wireless IOCTL */
compat_caddr_t pointer;
};
#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer)
#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length)
#define IW_EV_COMPAT_POINT_LEN \
(IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \
IW_EV_COMPAT_POINT_OFF)
#endif
#endif
/* Size of the Event prefix when packed in stream */
#define IW_EV_LCP_PK_LEN (4)
/* Size of the various events when packed in stream */

View file

@ -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 */

View file

@ -595,7 +595,12 @@ enum ieee80211_key_flags {
* @flags: key flags, see &enum ieee80211_key_flags.
* @keyidx: the key index (0-3)
* @keylen: key material length
* @key: key material
* @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte)
* data block:
* - Temporal Encryption Key (128 bits)
* - Temporal Authenticator Tx MIC Key (64 bits)
* - Temporal Authenticator Rx MIC Key (64 bits)
*
*/
struct ieee80211_key_conf {
enum ieee80211_key_alg alg;
@ -733,8 +738,11 @@ enum ieee80211_hw_flags {
* @conf: &struct ieee80211_conf, device configuration, don't use.
*
* @workqueue: single threaded workqueue available for driver use,
* allocated by mac80211 on registration and flushed on
* unregistration.
* allocated by mac80211 on registration and flushed when an
* interface is removed.
* NOTICE: All work performed on this workqueue should NEVER
* acquire the RTNL lock (i.e. Don't use the function
* ieee80211_iterate_active_interfaces())
*
* @priv: pointer to private area that was allocated for driver use
* along with this structure.

View file

@ -12,6 +12,8 @@ extern int wext_proc_init(struct net *net);
extern void wext_proc_exit(struct net *net);
extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg);
extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg);
#else
static inline int wext_proc_init(struct net *net)
{
@ -26,6 +28,11 @@ static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned
{
return -EINVAL;
}
static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg)
{
return -EINVAL;
}
#endif
#endif /* __NET_WEXT_H */

View file

@ -43,8 +43,9 @@ static const char *ieee80211_modes[] = {
#define MAX_CUSTOM_LEN 64
static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
char *start, char *stop,
struct ieee80211_network *network)
char *start, char *stop,
struct ieee80211_network *network,
struct iw_request_info *info)
{
char custom[MAX_CUSTOM_LEN];
char *p;
@ -57,7 +58,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
/* Remaining entries will be displayed in the order we provide them */
@ -66,17 +67,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
iwe.u.data.flags = 1;
if (network->flags & NETWORK_EMPTY_ESSID) {
iwe.u.data.length = sizeof("<hidden>");
start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
start = iwe_stream_add_point(info, start, stop,
&iwe, "<hidden>");
} else {
iwe.u.data.length = min(network->ssid_len, (u8) 32);
start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
start = iwe_stream_add_point(info, start, stop,
&iwe, network->ssid);
}
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
ieee80211_modes[network->mode]);
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
/* Add mode */
iwe.cmd = SIOCGIWMODE;
@ -86,7 +89,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
else
iwe.u.mode = IW_MODE_ADHOC;
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
start = iwe_stream_add_event(info, start, stop,
&iwe, IW_EV_UINT_LEN);
}
/* Add channel and frequency */
@ -95,7 +99,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
iwe.u.freq.e = 6;
iwe.u.freq.i = 0;
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
/* Add encryption capability */
iwe.cmd = SIOCGIWENCODE;
@ -104,12 +108,13 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
start = iwe_stream_add_point(info, start, stop,
&iwe, network->ssid);
/* Add basic and extended rates */
/* Rate : stuffing multiple values in a single event require a bit
* more of magic - Jean II */
current_val = start + IW_EV_LCP_LEN;
current_val = start + iwe_stream_lcp_len(info);
iwe.cmd = SIOCGIWRATE;
/* Those two flags are ignored... */
iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
@ -124,17 +129,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
/* Bit rate given in 500 kb/s units (+ 0x80) */
iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
/* Add new value to event */
current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
current_val = iwe_stream_add_value(info, start, current_val,
stop, &iwe, IW_EV_PARAM_LEN);
}
for (; j < network->rates_ex_len; j++) {
rate = network->rates_ex[j] & 0x7F;
/* Bit rate given in 500 kb/s units (+ 0x80) */
iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
/* Add new value to event */
current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
current_val = iwe_stream_add_value(info, start, current_val,
stop, &iwe, IW_EV_PARAM_LEN);
}
/* Check if we added any rate */
if((current_val - start) > IW_EV_LCP_LEN)
if ((current_val - start) > iwe_stream_lcp_len(info))
start = current_val;
/* Add quality statistics */
@ -181,14 +188,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
iwe.u.qual.level = network->stats.signal;
}
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
iwe.cmd = IWEVCUSTOM;
p = custom;
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
start = iwe_stream_add_point(start, stop, &iwe, custom);
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
memset(&iwe, 0, sizeof(iwe));
if (network->wpa_ie_len) {
@ -196,7 +203,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
memcpy(buf, network->wpa_ie, network->wpa_ie_len);
iwe.cmd = IWEVGENIE;
iwe.u.data.length = network->wpa_ie_len;
start = iwe_stream_add_point(start, stop, &iwe, buf);
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
}
memset(&iwe, 0, sizeof(iwe));
@ -205,7 +212,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
memcpy(buf, network->rsn_ie, network->rsn_ie_len);
iwe.cmd = IWEVGENIE;
iwe.u.data.length = network->rsn_ie_len;
start = iwe_stream_add_point(start, stop, &iwe, buf);
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
}
/* Add EXTRA: Age to display seconds since last beacon/probe response
@ -217,7 +224,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
jiffies_to_msecs(jiffies - network->last_scanned));
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
start = iwe_stream_add_point(start, stop, &iwe, custom);
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
/* Add spectrum management information */
iwe.cmd = -1;
@ -238,7 +245,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
if (iwe.cmd == IWEVCUSTOM) {
iwe.u.data.length = p - custom;
start = iwe_stream_add_point(start, stop, &iwe, custom);
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
}
return start;
@ -272,7 +279,8 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
if (ieee->scan_age == 0 ||
time_after(network->last_scanned + ieee->scan_age, jiffies))
ev = ieee80211_translate_scan(ieee, ev, stop, network);
ev = ieee80211_translate_scan(ieee, ev, stop, network,
info);
else
IEEE80211_DEBUG_SCAN("Not showing network '%s ("
"%s)' due to age (%dms).\n",

View file

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

View file

@ -24,6 +24,7 @@
#include <linux/spinlock.h>
#include <linux/etherdevice.h>
#include <net/wireless.h>
#include <net/iw_handler.h>
#include "key.h"
#include "sta_info.h"
@ -790,6 +791,10 @@ struct ieee802_11_elems {
u8 *preq;
u8 *prep;
u8 *perr;
u8 *ch_switch_elem;
u8 *country_elem;
u8 *pwr_constr_elem;
u8 *quiet_elem; /* first quite element */
/* length of them, respectively */
u8 ssid_len;
@ -814,6 +819,11 @@ struct ieee802_11_elems {
u8 preq_len;
u8 prep_len;
u8 perr_len;
u8 ch_switch_elem_len;
u8 country_elem_len;
u8 pwr_constr_elem_len;
u8 quiet_elem_len;
u8 num_of_quiet_elem; /* can be more the one */
};
static inline struct ieee80211_local *hw_to_local(
@ -867,7 +877,9 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid);
int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
void ieee80211_sta_req_auth(struct net_device *dev,
struct ieee80211_if_sta *ifsta);
int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
int ieee80211_sta_scan_results(struct net_device *dev,
struct iw_request_info *info,
char *buf, size_t len);
ieee80211_rx_result ieee80211_sta_rx_scan(
struct net_device *dev, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status);

View file

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

View file

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

View file

@ -204,6 +204,25 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
elems->perr = pos;
elems->perr_len = elen;
break;
case WLAN_EID_CHANNEL_SWITCH:
elems->ch_switch_elem = pos;
elems->ch_switch_elem_len = elen;
break;
case WLAN_EID_QUIET:
if (!elems->quiet_elem) {
elems->quiet_elem = pos;
elems->quiet_elem_len = elen;
}
elems->num_of_quiet_elem++;
break;
case WLAN_EID_COUNTRY:
elems->country_elem = pos;
elems->country_elem_len = elen;
break;
case WLAN_EID_PWR_CONSTRAINT:
elems->pwr_constr_elem = pos;
elems->pwr_constr_elem_len = elen;
break;
default:
break;
}
@ -1701,6 +1720,71 @@ void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr)
}
}
static void ieee80211_send_refuse_measurement_request(struct net_device *dev,
struct ieee80211_msrment_ie *request_ie,
const u8 *da, const u8 *bssid,
u8 dialog_token)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sk_buff *skb;
struct ieee80211_mgmt *msr_report;
skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
sizeof(struct ieee80211_msrment_ie));
if (!skb) {
printk(KERN_ERR "%s: failed to allocate buffer for "
"measurement report frame\n", dev->name);
return;
}
skb_reserve(skb, local->hw.extra_tx_headroom);
msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
memset(msr_report, 0, 24);
memcpy(msr_report->da, da, ETH_ALEN);
memcpy(msr_report->sa, dev->dev_addr, ETH_ALEN);
memcpy(msr_report->bssid, bssid, ETH_ALEN);
msr_report->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
IEEE80211_STYPE_ACTION);
skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement));
msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
msr_report->u.action.u.measurement.action_code =
WLAN_ACTION_SPCT_MSR_RPRT;
msr_report->u.action.u.measurement.dialog_token = dialog_token;
msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT;
msr_report->u.action.u.measurement.length =
sizeof(struct ieee80211_msrment_ie);
memset(&msr_report->u.action.u.measurement.msr_elem, 0,
sizeof(struct ieee80211_msrment_ie));
msr_report->u.action.u.measurement.msr_elem.token = request_ie->token;
msr_report->u.action.u.measurement.msr_elem.mode |=
IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
ieee80211_sta_tx(dev, skb, 0);
}
static void ieee80211_sta_process_measurement_req(struct net_device *dev,
struct ieee80211_mgmt *mgmt,
size_t len)
{
/*
* Ignoring measurement request is spec violation.
* Mandatory measurements must be reported optional
* measurements might be refused or reported incapable
* For now just refuse
* TODO: Answer basic measurement as unmeasured
*/
ieee80211_send_refuse_measurement_request(dev,
&mgmt->u.action.u.measurement.msr_elem,
mgmt->sa, mgmt->bssid,
mgmt->u.action.u.measurement.dialog_token);
}
static void ieee80211_rx_mgmt_auth(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
@ -1753,11 +1837,12 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
auth_transaction, status_code);
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
/* IEEE 802.11 standard does not require authentication in IBSS
/*
* IEEE 802.11 standard does not require authentication in IBSS
* networks and most implementations do not seem to use it.
* However, try to reply to authentication attempts if someone
* has actually implemented this.
* TODO: Could implement shared key authentication. */
*/
if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
printk(KERN_DEBUG "%s: unexpected IBSS authentication "
"frame (alg=%d transaction=%d)\n",
@ -3025,11 +3110,24 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev,
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
if (len < IEEE80211_MIN_ACTION_SIZE)
return;
switch (mgmt->u.action.category) {
case WLAN_CATEGORY_SPECTRUM_MGMT:
if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
break;
switch (mgmt->u.action.u.chan_switch.action_code) {
case WLAN_ACTION_SPCT_MSR_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.measurement)))
break;
ieee80211_sta_process_measurement_req(dev, mgmt, len);
break;
}
break;
case WLAN_CATEGORY_BACK:
switch (mgmt->u.action.u.addba_req.action_code) {
case WLAN_ACTION_ADDBA_REQ:
@ -3173,33 +3271,32 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_mgmt *mgmt;
u16 fc;
__le16 fc;
if (skb->len < 2)
return RX_DROP_UNUSABLE;
mgmt = (struct ieee80211_mgmt *) skb->data;
fc = le16_to_cpu(mgmt->frame_control);
fc = mgmt->frame_control;
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
if (ieee80211_is_ctl(fc))
return RX_CONTINUE;
if (skb->len < 24)
return RX_DROP_MONITOR;
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
ieee80211_rx_mgmt_probe_resp(dev, mgmt,
skb->len, rx_status);
dev_kfree_skb(skb);
return RX_QUEUED;
} else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
rx_status);
dev_kfree_skb(skb);
return RX_QUEUED;
}
if (ieee80211_is_probe_resp(fc)) {
ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status);
dev_kfree_skb(skb);
return RX_QUEUED;
}
if (ieee80211_is_beacon(fc)) {
ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
dev_kfree_skb(skb);
return RX_QUEUED;
}
return RX_CONTINUE;
}
@ -3777,7 +3874,7 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
{
struct sk_buff *skb;
struct ieee80211_hdr *nullfunc;
u16 fc;
__le16 fc;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
if (!skb) {
@ -3789,11 +3886,11 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
memset(nullfunc, 0, 24);
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
IEEE80211_FCTL_TODS;
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
IEEE80211_FCTL_TODS);
if (powersave)
fc |= IEEE80211_FCTL_PM;
nullfunc->frame_control = cpu_to_le16(fc);
fc |= cpu_to_le16(IEEE80211_FCTL_PM);
nullfunc->frame_control = fc;
memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
@ -4087,6 +4184,7 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
static char *
ieee80211_sta_scan_result(struct net_device *dev,
struct iw_request_info *info,
struct ieee80211_sta_bss *bss,
char *current_ev, char *end_buf)
{
@ -4101,7 +4199,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
IW_EV_ADDR_LEN);
memset(&iwe, 0, sizeof(iwe));
@ -4109,13 +4207,13 @@ ieee80211_sta_scan_result(struct net_device *dev,
if (bss_mesh_cfg(bss)) {
iwe.u.data.length = bss_mesh_id_len(bss);
iwe.u.data.flags = 1;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
bss_mesh_id(bss));
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, bss_mesh_id(bss));
} else {
iwe.u.data.length = bss->ssid_len;
iwe.u.data.flags = 1;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
bss->ssid);
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, bss->ssid);
}
if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
@ -4128,22 +4226,22 @@ ieee80211_sta_scan_result(struct net_device *dev,
iwe.u.mode = IW_MODE_MASTER;
else
iwe.u.mode = IW_MODE_ADHOC;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_UINT_LEN);
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
&iwe, IW_EV_UINT_LEN);
}
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
iwe.u.freq.e = 0;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
IW_EV_FREQ_LEN);
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = bss->freq;
iwe.u.freq.e = 6;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
IW_EV_FREQ_LEN);
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVQUAL;
@ -4151,7 +4249,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
iwe.u.qual.level = bss->signal;
iwe.u.qual.noise = bss->noise;
iwe.u.qual.updated = local->wstats_flags;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
IW_EV_QUAL_LEN);
memset(&iwe, 0, sizeof(iwe));
@ -4161,35 +4259,36 @@ ieee80211_sta_scan_result(struct net_device *dev,
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, "");
if (bss && bss->wpa_ie) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = bss->wpa_ie_len;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
bss->wpa_ie);
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, bss->wpa_ie);
}
if (bss && bss->rsn_ie) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = bss->rsn_ie_len;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
bss->rsn_ie);
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, bss->rsn_ie);
}
if (bss && bss->ht_ie) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = bss->ht_ie_len;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
bss->ht_ie);
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, bss->ht_ie);
}
if (bss && bss->supp_rates_len > 0) {
/* display all supported rates in readable format */
char *p = current_ev + IW_EV_LCP_LEN;
char *p = current_ev + iwe_stream_lcp_len(info);
int i;
memset(&iwe, 0, sizeof(iwe));
@ -4200,7 +4299,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
for (i = 0; i < bss->supp_rates_len; i++) {
iwe.u.bitrate.value = ((bss->supp_rates[i] &
0x7f) * 500000);
p = iwe_stream_add_value(current_ev, p,
p = iwe_stream_add_value(info, current_ev, p,
end_buf, &iwe, IW_EV_PARAM_LEN);
}
current_ev = p;
@ -4214,7 +4313,8 @@ ieee80211_sta_scan_result(struct net_device *dev,
iwe.cmd = IWEVCUSTOM;
sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
iwe.u.data.length = strlen(buf);
current_ev = iwe_stream_add_point(current_ev, end_buf,
current_ev = iwe_stream_add_point(info, current_ev,
end_buf,
&iwe, buf);
kfree(buf);
}
@ -4229,31 +4329,36 @@ ieee80211_sta_scan_result(struct net_device *dev,
iwe.cmd = IWEVCUSTOM;
sprintf(buf, "Mesh network (version %d)", cfg[0]);
iwe.u.data.length = strlen(buf);
current_ev = iwe_stream_add_point(current_ev, end_buf,
current_ev = iwe_stream_add_point(info, current_ev,
end_buf,
&iwe, buf);
sprintf(buf, "Path Selection Protocol ID: "
"0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
cfg[4]);
iwe.u.data.length = strlen(buf);
current_ev = iwe_stream_add_point(current_ev, end_buf,
current_ev = iwe_stream_add_point(info, current_ev,
end_buf,
&iwe, buf);
sprintf(buf, "Path Selection Metric ID: "
"0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
cfg[8]);
iwe.u.data.length = strlen(buf);
current_ev = iwe_stream_add_point(current_ev, end_buf,
current_ev = iwe_stream_add_point(info, current_ev,
end_buf,
&iwe, buf);
sprintf(buf, "Congestion Control Mode ID: "
"0x%02X%02X%02X%02X", cfg[9], cfg[10],
cfg[11], cfg[12]);
iwe.u.data.length = strlen(buf);
current_ev = iwe_stream_add_point(current_ev, end_buf,
current_ev = iwe_stream_add_point(info, current_ev,
end_buf,
&iwe, buf);
sprintf(buf, "Channel Precedence: "
"0x%02X%02X%02X%02X", cfg[13], cfg[14],
cfg[15], cfg[16]);
iwe.u.data.length = strlen(buf);
current_ev = iwe_stream_add_point(current_ev, end_buf,
current_ev = iwe_stream_add_point(info, current_ev,
end_buf,
&iwe, buf);
kfree(buf);
}
@ -4263,7 +4368,9 @@ ieee80211_sta_scan_result(struct net_device *dev,
}
int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
int ieee80211_sta_scan_results(struct net_device *dev,
struct iw_request_info *info,
char *buf, size_t len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
char *current_ev = buf;
@ -4276,8 +4383,8 @@ int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
spin_unlock_bh(&local->sta_bss_lock);
return -E2BIG;
}
current_ev = ieee80211_sta_scan_result(dev, bss, current_ev,
end_buf);
current_ev = ieee80211_sta_scan_result(dev, info, bss,
current_ev, end_buf);
}
spin_unlock_bh(&local->sta_bss_lock);
return current_ev - buf;

View file

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

View file

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

View file

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

View file

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

View file

@ -52,9 +52,8 @@ static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdat
static void ieee80211_dump_frame(const char *ifname, const char *title,
const struct sk_buff *skb)
{
const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 fc;
int hdrlen;
const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
unsigned int hdrlen;
DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
@ -63,13 +62,12 @@ static void ieee80211_dump_frame(const char *ifname, const char *title,
return;
}
fc = le16_to_cpu(hdr->frame_control);
hdrlen = ieee80211_get_hdrlen(fc);
hdrlen = ieee80211_hdrlen(hdr->frame_control);
if (hdrlen > skb->len)
hdrlen = skb->len;
if (hdrlen >= 4)
printk(" FC=0x%04x DUR=0x%04x",
fc, le16_to_cpu(hdr->duration_id));
le16_to_cpu(hdr->frame_control), le16_to_cpu(hdr->duration_id));
if (hdrlen >= 10)
printk(" A1=%s", print_mac(mac, hdr->addr1));
if (hdrlen >= 16)
@ -87,8 +85,8 @@ static inline void ieee80211_dump_frame(const char *ifname, const char *title,
}
#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
int next_frag_len)
static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
int next_frag_len)
{
int rate, mrate, erp, dur, i;
struct ieee80211_rate *txrate;
@ -140,7 +138,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
/* data/mgmt */
if (0 /* FIX: data/mgmt during CFP */)
return 32768;
return cpu_to_le16(32768);
if (group_addr) /* Group address as the destination - no ACK */
return 0;
@ -210,7 +208,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
tx->sdata->bss_conf.use_short_preamble);
}
return dur;
return cpu_to_le16(dur);
}
static int inline is_ieee80211_device(struct net_device *dev,
@ -281,7 +279,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
if (ieee80211_hdrlen(hdr->frame_control) >= 24)
ieee80211_include_sequence(tx->sdata, hdr);
return TX_CONTINUE;
@ -542,9 +540,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
static ieee80211_tx_result
ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
u16 fc = le16_to_cpu(hdr->frame_control);
u16 dur;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
struct ieee80211_supported_band *sband;
@ -595,21 +591,13 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
/* Transmit data frames using short preambles if the driver supports
* short preambles at the selected rate and short preambles are
* available on the network at the current point in time. */
if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
if (ieee80211_is_data(hdr->frame_control) &&
(sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
tx->sdata->bss_conf.use_short_preamble &&
(!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
}
/* Setup duration field for the first fragment of the frame. Duration
* for remaining fragments will be updated when they are being sent
* to low-level driver in ieee80211_tx(). */
dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
(tx->flags & IEEE80211_TX_FRAGMENTED) ?
tx->extra_frag[0]->len : 0);
hdr->duration_id = cpu_to_le16(dur);
if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
(info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
struct ieee80211_rate *rate;
@ -647,7 +635,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
static ieee80211_tx_result
ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
size_t hdrlen, per_fragm, num_fragm, payload_len, left;
struct sk_buff **frags, *first, *frag;
int i;
@ -670,7 +658,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
first = tx->skb;
hdrlen = ieee80211_get_hdrlen(tx->fc);
hdrlen = ieee80211_hdrlen(hdr->frame_control);
payload_len = first->len - hdrlen;
per_fragm = frag_threshold - hdrlen - FCS_LEN;
num_fragm = DIV_ROUND_UP(payload_len, per_fragm);
@ -711,6 +699,8 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
copylen = left > per_fragm ? per_fragm : left;
memcpy(skb_put(frag, copylen), pos, copylen);
memcpy(frag->cb, first->cb, sizeof(frag->cb));
skb_copy_queue_mapping(frag, first);
pos += copylen;
left -= copylen;
@ -754,6 +744,36 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
return TX_DROP;
}
static ieee80211_tx_result
ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
int next_len, i;
int group_addr = is_multicast_ether_addr(hdr->addr1);
if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) {
hdr->duration_id = ieee80211_duration(tx, group_addr, 0);
return TX_CONTINUE;
}
hdr->duration_id = ieee80211_duration(tx, group_addr,
tx->extra_frag[0]->len);
for (i = 0; i < tx->num_extra_frag; i++) {
if (i + 1 < tx->num_extra_frag) {
next_len = tx->extra_frag[i + 1]->len;
} else {
next_len = 0;
tx->rate_idx = tx->last_frag_rate_idx;
}
hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data;
hdr->duration_id = ieee80211_duration(tx, 0, next_len);
}
return TX_CONTINUE;
}
static ieee80211_tx_result
ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
{
@ -788,6 +808,7 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] =
ieee80211_tx_h_fragment,
/* handlers after fragment must be aware of tx info fragmentation! */
ieee80211_tx_h_encrypt,
ieee80211_tx_h_calculate_duration,
ieee80211_tx_h_stats,
NULL
};
@ -1083,13 +1104,46 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
return IEEE80211_TX_OK;
}
/*
* Invoke TX handlers, return 0 on success and non-zero if the
* frame was dropped or queued.
*/
static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
{
struct ieee80211_local *local = tx->local;
struct sk_buff *skb = tx->skb;
ieee80211_tx_handler *handler;
ieee80211_tx_result res = TX_DROP;
int i;
for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
res = (*handler)(tx);
if (res != TX_CONTINUE)
break;
}
if (unlikely(res == TX_DROP)) {
I802_DEBUG_INC(local->tx_handlers_drop);
dev_kfree_skb(skb);
for (i = 0; i < tx->num_extra_frag; i++)
if (tx->extra_frag[i])
dev_kfree_skb(tx->extra_frag[i]);
kfree(tx->extra_frag);
return -1;
} else if (unlikely(res == TX_QUEUED)) {
I802_DEBUG_INC(local->tx_handlers_queued);
return -1;
}
return 0;
}
static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
ieee80211_tx_handler *handler;
struct ieee80211_tx_data tx;
ieee80211_tx_result res = TX_DROP, res_prepare;
ieee80211_tx_result res_prepare;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret, i;
u16 queue;
@ -1118,44 +1172,8 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
tx.channel = local->hw.conf.channel;
info->band = tx.channel->band;
for (handler = ieee80211_tx_handlers; *handler != NULL;
handler++) {
res = (*handler)(&tx);
if (res != TX_CONTINUE)
break;
}
if (WARN_ON(tx.skb != skb))
goto drop;
if (unlikely(res == TX_DROP)) {
I802_DEBUG_INC(local->tx_handlers_drop);
goto drop;
}
if (unlikely(res == TX_QUEUED)) {
I802_DEBUG_INC(local->tx_handlers_queued);
rcu_read_unlock();
return 0;
}
if (tx.extra_frag) {
for (i = 0; i < tx.num_extra_frag; i++) {
int next_len, dur;
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *)
tx.extra_frag[i]->data;
if (i + 1 < tx.num_extra_frag) {
next_len = tx.extra_frag[i + 1]->len;
} else {
next_len = 0;
tx.rate_idx = tx.last_frag_rate_idx;
}
dur = ieee80211_duration(&tx, 0, next_len);
hdr->duration_id = cpu_to_le16(dur);
}
}
if (invoke_tx_handlers(&tx))
goto out;
retry:
ret = __ieee80211_tx(local, skb, &tx);
@ -1198,6 +1216,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
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;

View file

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

View file

@ -135,7 +135,39 @@ static int ieee80211_ioctl_giwname(struct net_device *dev,
struct iw_request_info *info,
char *name, char *extra)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_supported_band *sband;
u8 is_ht = 0, is_a = 0, is_b = 0, is_g = 0;
sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ];
if (sband) {
is_a = 1;
is_ht |= sband->ht_info.ht_supported;
}
sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ];
if (sband) {
int i;
/* Check for mandatory rates */
for (i = 0; i < sband->n_bitrates; i++) {
if (sband->bitrates[i].bitrate == 10)
is_b = 1;
if (sband->bitrates[i].bitrate == 60)
is_g = 1;
}
is_ht |= sband->ht_info.ht_supported;
}
strcpy(name, "IEEE 802.11");
if (is_a)
strcat(name, "a");
if (is_b)
strcat(name, "b");
if (is_g)
strcat(name, "g");
if (is_ht)
strcat(name, "n");
return 0;
}
@ -567,7 +599,7 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
if (local->sta_sw_scanning || local->sta_hw_scanning)
return -EAGAIN;
res = ieee80211_sta_scan_results(dev, extra, data->length);
res = ieee80211_sta_scan_results(dev, info, extra, data->length);
if (res >= 0) {
data->length = res;
return 0;
@ -721,6 +753,9 @@ static int ieee80211_ioctl_siwrts(struct net_device *dev,
if (rts->disabled)
local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
else if (!rts->fixed)
/* if the rts value is not fixed, then take default */
local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
return -EINVAL;
else
@ -949,6 +984,19 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
erq->length = sdata->keys[idx]->conf.keylen;
erq->flags |= IW_ENCODE_ENABLED;
if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
switch (ifsta->auth_alg) {
case WLAN_AUTH_OPEN:
case WLAN_AUTH_LEAP:
erq->flags |= IW_ENCODE_OPEN;
break;
case WLAN_AUTH_SHARED_KEY:
erq->flags |= IW_ENCODE_RESTRICTED;
break;
}
}
return 0;
}

View file

@ -49,7 +49,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
ieee80211_tx_result
ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
{
u8 *data, *sa, *da, *key, *mic, qos_tid;
u8 *data, *sa, *da, *key, *mic, qos_tid, key_offset;
size_t data_len;
u16 fc;
struct sk_buff *skb = tx->skb;
@ -88,8 +88,12 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
#else
authenticator = 1;
#endif
key = &tx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY :
ALG_TKIP_TEMP_AUTH_RX_MIC_KEY];
/* At this point we know we're using ALG_TKIP. To get the MIC key
* we now will rely on the offset from the ieee80211_key_conf::key */
key_offset = authenticator ?
NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY :
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
key = &tx->key->conf.key[key_offset];
mic = skb_put(skb, MICHAEL_MIC_LEN);
michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
@ -100,7 +104,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
ieee80211_rx_result
ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
{
u8 *data, *sa, *da, *key = NULL, qos_tid;
u8 *data, *sa, *da, *key = NULL, qos_tid, key_offset;
size_t data_len;
u16 fc;
u8 mic[MICHAEL_MIC_LEN];
@ -131,8 +135,12 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
#else
authenticator = 1;
#endif
key = &rx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY :
ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
/* At this point we know we're using ALG_TKIP. To get the MIC key
* we now will rely on the offset from the ieee80211_key_conf::key */
key_offset = authenticator ?
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY :
NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
key = &rx->key->conf.key[key_offset];
michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
if (!(rx->flags & IEEE80211_RX_RA_MATCH))

View file

@ -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) },
},
{ }
};

View file

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

View file

@ -39,8 +39,56 @@ MODULE_LICENSE("GPL");
static LIST_HEAD(rfkill_list); /* list of registered rf switches */
static DEFINE_MUTEX(rfkill_mutex);
static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED;
module_param_named(default_state, rfkill_default_state, uint, 0444);
MODULE_PARM_DESC(default_state,
"Default initial state for all radio types, 0 = radio off");
static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX];
static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list);
/**
* register_rfkill_notifier - Add notifier to rfkill notifier chain
* @nb: pointer to the new entry to add to the chain
*
* See blocking_notifier_chain_register() for return value and further
* observations.
*
* Adds a notifier to the rfkill notifier chain. The chain will be
* called with a pointer to the relevant rfkill structure as a parameter,
* refer to include/linux/rfkill.h for the possible events.
*
* Notifiers added to this chain are to always return NOTIFY_DONE. This
* chain is a blocking notifier chain: notifiers can sleep.
*
* Calls to this chain may have been done through a workqueue. One must
* assume unordered asynchronous behaviour, there is no way to know if
* actions related to the event that generated the notification have been
* carried out already.
*/
int register_rfkill_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&rfkill_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(register_rfkill_notifier);
/**
* unregister_rfkill_notifier - remove notifier from rfkill notifier chain
* @nb: pointer to the entry to remove from the chain
*
* See blocking_notifier_chain_unregister() for return value and further
* observations.
*
* Removes a notifier from the rfkill notifier chain.
*/
int unregister_rfkill_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(unregister_rfkill_notifier);
static void rfkill_led_trigger(struct rfkill *rfkill,
enum rfkill_state state)
@ -50,24 +98,99 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
if (!led->name)
return;
if (state == RFKILL_STATE_OFF)
if (state != RFKILL_STATE_UNBLOCKED)
led_trigger_event(led, LED_OFF);
else
led_trigger_event(led, LED_FULL);
#endif /* CONFIG_RFKILL_LEDS */
}
static void notify_rfkill_state_change(struct rfkill *rfkill)
{
blocking_notifier_call_chain(&rfkill_notifier_list,
RFKILL_STATE_CHANGED,
rfkill);
}
static void update_rfkill_state(struct rfkill *rfkill)
{
enum rfkill_state newstate, oldstate;
if (rfkill->get_state) {
mutex_lock(&rfkill->mutex);
if (!rfkill->get_state(rfkill->data, &newstate)) {
oldstate = rfkill->state;
rfkill->state = newstate;
if (oldstate != newstate)
notify_rfkill_state_change(rfkill);
}
mutex_unlock(&rfkill->mutex);
}
}
/**
* rfkill_toggle_radio - wrapper for toggle_radio hook
* calls toggle_radio taking into account a lot of "small"
* details.
* @rfkill: the rfkill struct to use
* @force: calls toggle_radio even if cache says it is not needed,
* and also makes sure notifications of the state will be
* sent even if it didn't change
* @state: the new state to call toggle_radio() with
*
* This wrappen protects and enforces the API for toggle_radio
* calls. Note that @force cannot override a (possibly cached)
* state of RFKILL_STATE_HARD_BLOCKED. Any device making use of
* RFKILL_STATE_HARD_BLOCKED implements either get_state() or
* rfkill_force_state(), so the cache either is bypassed or valid.
*
* Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED
* even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to
* give the driver a hint that it should double-BLOCK the transmitter.
*
* Caller must have aquired rfkill_mutex.
*/
static int rfkill_toggle_radio(struct rfkill *rfkill,
enum rfkill_state state)
enum rfkill_state state,
int force)
{
int retval = 0;
enum rfkill_state oldstate, newstate;
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);
}

View file

@ -90,6 +90,7 @@
#include <asm/unistd.h>
#include <net/compat.h>
#include <net/wext.h>
#include <net/sock.h>
#include <linux/netfilter.h>
@ -2210,10 +2211,19 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd,
{
struct socket *sock = file->private_data;
int ret = -ENOIOCTLCMD;
struct sock *sk;
struct net *net;
sk = sock->sk;
net = sock_net(sk);
if (sock->ops->compat_ioctl)
ret = sock->ops->compat_ioctl(sock, cmd, arg);
if (ret == -ENOIOCTLCMD &&
(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST))
ret = compat_wext_handle_ioctl(net, cmd, arg);
return ret;
}
#endif

View file

@ -500,7 +500,7 @@ static int call_commit_handler(struct net_device *dev)
/*
* Calculate size of private arguments
*/
static inline int get_priv_size(__u16 args)
static int get_priv_size(__u16 args)
{
int num = args & IW_PRIV_SIZE_MASK;
int type = (args & IW_PRIV_TYPE_MASK) >> 12;
@ -512,10 +512,9 @@ static inline int get_priv_size(__u16 args)
/*
* Re-calculate the size of private arguments
*/
static inline int adjust_priv_size(__u16 args,
union iwreq_data * wrqu)
static int adjust_priv_size(__u16 args, struct iw_point *iwp)
{
int num = wrqu->data.length;
int num = iwp->length;
int max = args & IW_PRIV_SIZE_MASK;
int type = (args & IW_PRIV_TYPE_MASK) >> 12;
@ -695,19 +694,150 @@ void wext_proc_exit(struct net *net)
*/
/* ---------------------------------------------------------------- */
static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
const struct iw_ioctl_description *descr,
iw_handler handler, struct net_device *dev,
struct iw_request_info *info)
{
int err, extra_size, user_length = 0, essid_compat = 0;
char *extra;
/* Calculate space needed by arguments. Always allocate
* for max space.
*/
extra_size = descr->max_tokens * descr->token_size;
/* Check need for ESSID compatibility for WE < 21 */
switch (cmd) {
case SIOCSIWESSID:
case SIOCGIWESSID:
case SIOCSIWNICKN:
case SIOCGIWNICKN:
if (iwp->length == descr->max_tokens + 1)
essid_compat = 1;
else if (IW_IS_SET(cmd) && (iwp->length != 0)) {
char essid[IW_ESSID_MAX_SIZE + 1];
err = copy_from_user(essid, iwp->pointer,
iwp->length *
descr->token_size);
if (err)
return -EFAULT;
if (essid[iwp->length - 1] == '\0')
essid_compat = 1;
}
break;
default:
break;
}
iwp->length -= essid_compat;
/* Check what user space is giving us */
if (IW_IS_SET(cmd)) {
/* Check NULL pointer */
if (!iwp->pointer && iwp->length != 0)
return -EFAULT;
/* Check if number of token fits within bounds */
if (iwp->length > descr->max_tokens)
return -E2BIG;
if (iwp->length < descr->min_tokens)
return -EINVAL;
} else {
/* Check NULL pointer */
if (!iwp->pointer)
return -EFAULT;
/* Save user space buffer size for checking */
user_length = iwp->length;
/* Don't check if user_length > max to allow forward
* compatibility. The test user_length < min is
* implied by the test at the end.
*/
/* Support for very large requests */
if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
(user_length > descr->max_tokens)) {
/* Allow userspace to GET more than max so
* we can support any size GET requests.
* There is still a limit : -ENOMEM.
*/
extra_size = user_length * descr->token_size;
/* Note : user_length is originally a __u16,
* and token_size is controlled by us,
* so extra_size won't get negative and
* won't overflow...
*/
}
}
/* kzalloc() ensures NULL-termination for essid_compat. */
extra = kzalloc(extra_size, GFP_KERNEL);
if (!extra)
return -ENOMEM;
/* If it is a SET, get all the extra data in here */
if (IW_IS_SET(cmd) && (iwp->length != 0)) {
if (copy_from_user(extra, iwp->pointer,
iwp->length *
descr->token_size)) {
err = -EFAULT;
goto out;
}
}
err = handler(dev, info, (union iwreq_data *) iwp, extra);
iwp->length += essid_compat;
/* If we have something to return to the user */
if (!err && IW_IS_GET(cmd)) {
/* Check if there is enough buffer up there */
if (user_length < iwp->length) {
err = -E2BIG;
goto out;
}
if (copy_to_user(iwp->pointer, extra,
iwp->length *
descr->token_size)) {
err = -EFAULT;
goto out;
}
}
/* Generate an event to notify listeners of the change */
if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) {
union iwreq_data *data = (union iwreq_data *) iwp;
if (descr->flags & IW_DESCR_FLAG_RESTRICT)
/* If the event is restricted, don't
* export the payload.
*/
wireless_send_event(dev, cmd, data, NULL);
else
wireless_send_event(dev, cmd, data, extra);
}
out:
kfree(extra);
return err;
}
/*
* Wrapper to call a standard Wireless Extension handler.
* We do various checks and also take care of moving data between
* user space and kernel space.
*/
static int ioctl_standard_call(struct net_device * dev,
struct ifreq * ifr,
struct iwreq *iwr,
unsigned int cmd,
struct iw_request_info *info,
iw_handler handler)
{
struct iwreq * iwr = (struct iwreq *) ifr;
const struct iw_ioctl_description * descr;
struct iw_request_info info;
int ret = -EINVAL;
/* Get the description of the IOCTL */
@ -715,145 +845,19 @@ static int ioctl_standard_call(struct net_device * dev,
return -EOPNOTSUPP;
descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
/* Prepare the call */
info.cmd = cmd;
info.flags = 0;
/* Check if we have a pointer to user space data or not */
if (descr->header_type != IW_HEADER_TYPE_POINT) {
/* No extra arguments. Trivial to handle */
ret = handler(dev, &info, &(iwr->u), NULL);
ret = handler(dev, info, &(iwr->u), NULL);
/* Generate an event to notify listeners of the change */
if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
((ret == 0) || (ret == -EIWCOMMIT)))
wireless_send_event(dev, cmd, &(iwr->u), NULL);
} else {
char * extra;
int extra_size;
int user_length = 0;
int err;
int essid_compat = 0;
/* Calculate space needed by arguments. Always allocate
* for max space. Easier, and won't last long... */
extra_size = descr->max_tokens * descr->token_size;
/* Check need for ESSID compatibility for WE < 21 */
switch (cmd) {
case SIOCSIWESSID:
case SIOCGIWESSID:
case SIOCSIWNICKN:
case SIOCGIWNICKN:
if (iwr->u.data.length == descr->max_tokens + 1)
essid_compat = 1;
else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
char essid[IW_ESSID_MAX_SIZE + 1];
err = copy_from_user(essid, iwr->u.data.pointer,
iwr->u.data.length *
descr->token_size);
if (err)
return -EFAULT;
if (essid[iwr->u.data.length - 1] == '\0')
essid_compat = 1;
}
break;
default:
break;
}
iwr->u.data.length -= essid_compat;
/* Check what user space is giving us */
if (IW_IS_SET(cmd)) {
/* Check NULL pointer */
if ((iwr->u.data.pointer == NULL) &&
(iwr->u.data.length != 0))
return -EFAULT;
/* Check if number of token fits within bounds */
if (iwr->u.data.length > descr->max_tokens)
return -E2BIG;
if (iwr->u.data.length < descr->min_tokens)
return -EINVAL;
} else {
/* Check NULL pointer */
if (iwr->u.data.pointer == NULL)
return -EFAULT;
/* Save user space buffer size for checking */
user_length = iwr->u.data.length;
/* Don't check if user_length > max to allow forward
* compatibility. The test user_length < min is
* implied by the test at the end. */
/* Support for very large requests */
if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
(user_length > descr->max_tokens)) {
/* Allow userspace to GET more than max so
* we can support any size GET requests.
* There is still a limit : -ENOMEM. */
extra_size = user_length * descr->token_size;
/* Note : user_length is originally a __u16,
* and token_size is controlled by us,
* so extra_size won't get negative and
* won't overflow... */
}
}
/* Create the kernel buffer */
/* kzalloc ensures NULL-termination for essid_compat */
extra = kzalloc(extra_size, GFP_KERNEL);
if (extra == NULL)
return -ENOMEM;
/* If it is a SET, get all the extra data in here */
if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
err = copy_from_user(extra, iwr->u.data.pointer,
iwr->u.data.length *
descr->token_size);
if (err) {
kfree(extra);
return -EFAULT;
}
}
/* Call the handler */
ret = handler(dev, &info, &(iwr->u), extra);
iwr->u.data.length += essid_compat;
/* If we have something to return to the user */
if (!ret && IW_IS_GET(cmd)) {
/* Check if there is enough buffer up there */
if (user_length < iwr->u.data.length) {
kfree(extra);
return -E2BIG;
}
err = copy_to_user(iwr->u.data.pointer, extra,
iwr->u.data.length *
descr->token_size);
if (err)
ret = -EFAULT;
}
/* Generate an event to notify listeners of the change */
if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
((ret == 0) || (ret == -EIWCOMMIT))) {
if (descr->flags & IW_DESCR_FLAG_RESTRICT)
/* If the event is restricted, don't
* export the payload */
wireless_send_event(dev, cmd, &(iwr->u), NULL);
else
wireless_send_event(dev, cmd, &(iwr->u),
extra);
}
/* Cleanup - I told you it wasn't that long ;-) */
kfree(extra);
ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
handler, dev, info);
}
/* Call commit handler if needed and defined */
@ -881,25 +885,22 @@ static int ioctl_standard_call(struct net_device * dev,
* a iw_handler but process it in your ioctl handler (i.e. use the
* old driver API).
*/
static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
unsigned int cmd, iw_handler handler)
static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
const struct iw_priv_args **descrp)
{
struct iwreq * iwr = (struct iwreq *) ifr;
const struct iw_priv_args * descr = NULL;
struct iw_request_info info;
int extra_size = 0;
int i;
int ret = -EINVAL;
const struct iw_priv_args *descr;
int i, extra_size;
/* Get the description of the IOCTL */
for (i = 0; i < dev->wireless_handlers->num_private_args; i++)
descr = NULL;
for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
if (cmd == dev->wireless_handlers->private_args[i].cmd) {
descr = &(dev->wireless_handlers->private_args[i]);
descr = &dev->wireless_handlers->private_args[i];
break;
}
}
/* Compute the size of the set/get arguments */
if (descr != NULL) {
extra_size = 0;
if (descr) {
if (IW_IS_SET(cmd)) {
int offset = 0; /* For sub-ioctls */
/* Check for sub-ioctl handler */
@ -924,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.