2007-07-27 21:43:22 +08:00
|
|
|
/*
|
|
|
|
* Copyright 2002-2005, Instant802 Networks, Inc.
|
|
|
|
* Copyright 2005-2006, Devicescape Software, Inc.
|
|
|
|
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
|
|
|
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Transmit and frame generation functions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/skbuff.h>
|
|
|
|
#include <linux/etherdevice.h>
|
|
|
|
#include <linux/bitmap.h>
|
[MAC80211]: fix race conditions with keys
During receive processing, we select the key long before using it and
because there's no locking it is possible that we kfree() the key
after having selected it but before using it for crypto operations.
Obviously, this is bad.
Secondly, during transmit processing, there are two possible races: We
have a similar race between select_key() and using it for encryption,
but we also have a race here between select_key() and hardware
encryption (both when a key is removed.)
This patch solves these issues by using RCU: when a key is to be freed,
we first remove the pointer from the appropriate places (sdata->keys,
sdata->default_key, sta->key) using rcu_assign_pointer() and then
synchronize_rcu(). Then, we can safely kfree() the key and remove it
from the hardware. There's a window here where the hardware may still
be using it for decryption, but we can't work around that without having
two hardware callbacks, one to disable the key for RX and one to disable
it for TX; but the worst thing that will happen is that we receive a
packet decrypted that we don't find a key for any more and then drop it.
When we add a key, we first need to upload it to the hardware and then,
using rcu_assign_pointer() again, link it into our structures.
In the code using keys (TX/RX paths) we use rcu_dereference() to get the
key and enclose the whole tx/rx section in a rcu_read_lock() ...
rcu_read_unlock() block. Because we've uploaded the key to hardware
before linking it into internal structures, we can guarantee that it is
valid once get to into tx().
One possible race condition remains, however: when we have hardware
acceleration enabled and the driver shuts down the queues, we end up
queueing the frame. If now somebody removes the key, the key will be
removed from hwaccel and then then driver will be asked to encrypt the
frame with a key index that has been removed. Hence, drivers will need
to be aware that the hw_key_index they are passed might not be under
all circumstances. Most drivers will, however, simply ignore that
condition and encrypt the frame with the selected key anyway, this
only results in a frame being encrypted with a wrong key or dropped
(rightfully) because the key was not valid. There isn't much we can
do about it unless we want to walk the pending frame queue every time
a key is removed and remove all frames that used it.
This race condition, however, will most likely be solved once we add
multiqueue support to mac80211 because then frames will be queued
further up the stack instead of after being processed.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-09-14 23:10:24 +08:00
|
|
|
#include <linux/rcupdate.h>
|
2007-09-18 02:56:21 +08:00
|
|
|
#include <net/net_namespace.h>
|
2007-07-27 21:43:22 +08:00
|
|
|
#include <net/ieee80211_radiotap.h>
|
|
|
|
#include <net/cfg80211.h>
|
|
|
|
#include <net/mac80211.h>
|
|
|
|
#include <asm/unaligned.h>
|
|
|
|
|
|
|
|
#include "ieee80211_i.h"
|
2009-04-24 00:52:52 +08:00
|
|
|
#include "driver-ops.h"
|
2008-04-09 03:14:40 +08:00
|
|
|
#include "led.h"
|
2008-02-23 22:17:10 +08:00
|
|
|
#include "mesh.h"
|
2007-07-27 21:43:22 +08:00
|
|
|
#include "wep.h"
|
|
|
|
#include "wpa.h"
|
|
|
|
#include "wme.h"
|
2008-04-09 03:14:40 +08:00
|
|
|
#include "rate.h"
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
/* misc utils */
|
|
|
|
|
2008-06-25 19:36:27 +08:00
|
|
|
static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
|
|
|
|
int next_frag_len)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
|
|
|
int rate, mrate, erp, dur, i;
|
2008-05-15 18:55:27 +08:00
|
|
|
struct ieee80211_rate *txrate;
|
2007-07-27 21:43:22 +08:00
|
|
|
struct ieee80211_local *local = tx->local;
|
2008-01-25 02:38:38 +08:00
|
|
|
struct ieee80211_supported_band *sband;
|
2008-07-16 09:44:13 +08:00
|
|
|
struct ieee80211_hdr *hdr;
|
2008-10-21 18:40:02 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
|
|
|
|
|
|
/* assume HW handles this */
|
|
|
|
if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* uh huh? */
|
|
|
|
if (WARN_ON_ONCE(info->control.rates[0].idx < 0))
|
|
|
|
return 0;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-05-15 18:55:27 +08:00
|
|
|
sband = local->hw.wiphy->bands[tx->channel->band];
|
2008-10-21 18:40:02 +08:00
|
|
|
txrate = &sband->bitrates[info->control.rates[0].idx];
|
2008-01-25 02:38:38 +08:00
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
erp = txrate->flags & IEEE80211_RATE_ERP_G;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* data and mgmt (except PS Poll):
|
|
|
|
* - during CFP: 32768
|
|
|
|
* - during contention period:
|
|
|
|
* if addr1 is group address: 0
|
|
|
|
* if more fragments = 0 and addr1 is individual address: time to
|
|
|
|
* transmit one ACK plus SIFS
|
|
|
|
* if more fragments = 1 and addr1 is individual address: time to
|
|
|
|
* transmit next fragment plus 2 x ACK plus 3 x SIFS
|
|
|
|
*
|
|
|
|
* IEEE 802.11, 9.6:
|
|
|
|
* - control response frame (CTS or ACK) shall be transmitted using the
|
|
|
|
* same rate as the immediately previous frame in the frame exchange
|
|
|
|
* sequence, if this rate belongs to the PHY mandatory rates, or else
|
|
|
|
* at the highest possible rate belonging to the PHY rates in the
|
|
|
|
* BSSBasicRateSet
|
|
|
|
*/
|
2008-07-16 09:44:13 +08:00
|
|
|
hdr = (struct ieee80211_hdr *)tx->skb->data;
|
|
|
|
if (ieee80211_is_ctl(hdr->frame_control)) {
|
2007-07-27 21:43:22 +08:00
|
|
|
/* TODO: These control frames are not currently sent by
|
2008-09-11 06:01:56 +08:00
|
|
|
* mac80211, but should they be implemented, this function
|
2007-07-27 21:43:22 +08:00
|
|
|
* needs to be updated to support duration field calculation.
|
|
|
|
*
|
|
|
|
* RTS: time needed to transmit pending data/mgmt frame plus
|
|
|
|
* one CTS frame plus one ACK frame plus 3 x SIFS
|
|
|
|
* CTS: duration of immediately previous RTS minus time
|
|
|
|
* required to transmit CTS and its SIFS
|
|
|
|
* ACK: 0 if immediately previous directed data/mgmt had
|
|
|
|
* more=0, with more=1 duration in ACK frame is duration
|
|
|
|
* from previous frame minus time needed to transmit ACK
|
|
|
|
* and its SIFS
|
|
|
|
* PS Poll: BIT(15) | BIT(14) | aid
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* data/mgmt */
|
|
|
|
if (0 /* FIX: data/mgmt during CFP */)
|
2008-06-25 19:36:27 +08:00
|
|
|
return cpu_to_le16(32768);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
if (group_addr) /* Group address as the destination - no ACK */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Individual destination address:
|
|
|
|
* IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes)
|
|
|
|
* CTS and ACK frames shall be transmitted using the highest rate in
|
|
|
|
* basic rate set that is less than or equal to the rate of the
|
|
|
|
* immediately previous frame and that is using the same modulation
|
|
|
|
* (CCK or OFDM). If no basic rate set matches with these requirements,
|
|
|
|
* the highest mandatory rate of the PHY that is less than or equal to
|
|
|
|
* the rate of the previous frame is used.
|
|
|
|
* Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps
|
|
|
|
*/
|
|
|
|
rate = -1;
|
2008-01-25 02:38:38 +08:00
|
|
|
/* use lowest available if everything fails */
|
|
|
|
mrate = sband->bitrates[0].bitrate;
|
|
|
|
for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
|
struct ieee80211_rate *r = &sband->bitrates[i];
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-01-25 02:38:38 +08:00
|
|
|
if (r->bitrate > txrate->bitrate)
|
|
|
|
break;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-10-11 07:51:51 +08:00
|
|
|
if (tx->sdata->vif.bss_conf.basic_rates & BIT(i))
|
2008-01-25 02:38:38 +08:00
|
|
|
rate = r->bitrate;
|
|
|
|
|
|
|
|
switch (sband->band) {
|
|
|
|
case IEEE80211_BAND_2GHZ: {
|
|
|
|
u32 flag;
|
|
|
|
if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
|
|
|
|
flag = IEEE80211_RATE_MANDATORY_G;
|
|
|
|
else
|
|
|
|
flag = IEEE80211_RATE_MANDATORY_B;
|
|
|
|
if (r->flags & flag)
|
|
|
|
mrate = r->bitrate;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IEEE80211_BAND_5GHZ:
|
|
|
|
if (r->flags & IEEE80211_RATE_MANDATORY_A)
|
|
|
|
mrate = r->bitrate;
|
|
|
|
break;
|
|
|
|
case IEEE80211_NUM_BANDS:
|
|
|
|
WARN_ON(1);
|
|
|
|
break;
|
|
|
|
}
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
if (rate == -1) {
|
|
|
|
/* No matching basic rate found; use highest suitable mandatory
|
|
|
|
* PHY rate */
|
|
|
|
rate = mrate;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Time needed to transmit ACK
|
|
|
|
* (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
|
|
|
|
* to closest integer */
|
|
|
|
|
|
|
|
dur = ieee80211_frame_duration(local, 10, rate, erp,
|
2008-10-11 07:51:51 +08:00
|
|
|
tx->sdata->vif.bss_conf.use_short_preamble);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
if (next_frag_len) {
|
|
|
|
/* Frame is fragmented: duration increases with time needed to
|
|
|
|
* transmit next fragment plus ACK and 2 x SIFS. */
|
|
|
|
dur *= 2; /* ACK + SIFS */
|
|
|
|
/* next fragment */
|
|
|
|
dur += ieee80211_frame_duration(local, next_frag_len,
|
2008-01-25 02:38:38 +08:00
|
|
|
txrate->bitrate, erp,
|
2008-10-11 07:51:51 +08:00
|
|
|
tx->sdata->vif.bss_conf.use_short_preamble);
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-06-25 19:36:27 +08:00
|
|
|
return cpu_to_le16(dur);
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2011-01-17 07:09:38 +08:00
|
|
|
static inline int is_ieee80211_device(struct ieee80211_local *local,
|
2008-09-16 20:18:59 +08:00
|
|
|
struct net_device *dev)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2008-09-16 20:18:59 +08:00
|
|
|
return local == wdev_priv(dev->ieee80211_ptr);
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* tx handlers */
|
2010-01-12 16:42:46 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
|
|
|
ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
|
|
|
|
{
|
|
|
|
struct ieee80211_local *local = tx->local;
|
mac80211: check uapsd state for dynamic power save
To make U-APSD client mode effective, we must not wake up from dynamic power
save when transmitting frames. So if dynamic power save is enabled, it needs
check the queue the transmitted packet is in and decide if we need to wake
up or not.
In a perfect world, where all packets would have correct QoS tags, U-APSD
enabled queues should not trigger wakeup from power save. But in the real
world, where very few packets have correct QoS tags, this won't work. For
example, if only voip class has U-APSD enabled and we send a packet in voip
class, but the packets we receive are in best effort class, we would receive
the packets with the legacy power save method. And that would increase
latencies too much from a voip application point of view.
The workaround is to enable U-APSD for all qeueus and still use dynamic ps
wakeup for all other queues except voip. That way we can still save power
with a voip application and not sacrifice latency. Normal traffic (in
background, best effort or video class) would still trigger wakeup from
dynamic power save.
Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2010-01-12 16:42:53 +08:00
|
|
|
struct ieee80211_if_managed *ifmgd;
|
2010-01-12 16:42:46 +08:00
|
|
|
|
|
|
|
/* driver doesn't support power save */
|
|
|
|
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
|
|
|
/* hardware does dynamic power save */
|
|
|
|
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
|
|
|
/* dynamic power save disabled */
|
|
|
|
if (local->hw.conf.dynamic_ps_timeout <= 0)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
|
|
|
/* we are scanning, don't enable power save */
|
|
|
|
if (local->scanning)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
|
|
|
if (!local->ps_sdata)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
|
|
|
/* No point if we're going to suspend */
|
|
|
|
if (local->quiescing)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
mac80211: check uapsd state for dynamic power save
To make U-APSD client mode effective, we must not wake up from dynamic power
save when transmitting frames. So if dynamic power save is enabled, it needs
check the queue the transmitted packet is in and decide if we need to wake
up or not.
In a perfect world, where all packets would have correct QoS tags, U-APSD
enabled queues should not trigger wakeup from power save. But in the real
world, where very few packets have correct QoS tags, this won't work. For
example, if only voip class has U-APSD enabled and we send a packet in voip
class, but the packets we receive are in best effort class, we would receive
the packets with the legacy power save method. And that would increase
latencies too much from a voip application point of view.
The workaround is to enable U-APSD for all qeueus and still use dynamic ps
wakeup for all other queues except voip. That way we can still save power
with a voip application and not sacrifice latency. Normal traffic (in
background, best effort or video class) would still trigger wakeup from
dynamic power save.
Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2010-01-12 16:42:53 +08:00
|
|
|
/* dynamic ps is supported only in managed mode */
|
|
|
|
if (tx->sdata->vif.type != NL80211_IFTYPE_STATION)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
|
|
|
ifmgd = &tx->sdata->u.mgd;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't wakeup from power save if u-apsd is enabled, voip ac has
|
|
|
|
* u-apsd enabled and the frame is in voip class. This effectively
|
|
|
|
* means that even if all access categories have u-apsd enabled, in
|
|
|
|
* practise u-apsd is only used with the voip ac. This is a
|
|
|
|
* workaround for the case when received voip class packets do not
|
|
|
|
* have correct qos tag for some reason, due the network or the
|
|
|
|
* peer application.
|
|
|
|
*
|
|
|
|
* Note: local->uapsd_queues access is racy here. If the value is
|
|
|
|
* changed via debugfs, user needs to reassociate manually to have
|
|
|
|
* everything in sync.
|
|
|
|
*/
|
|
|
|
if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
|
|
|
|
&& (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
|
|
|
|
&& skb_get_queue_mapping(tx->skb) == 0)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
2010-01-12 16:42:46 +08:00
|
|
|
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
|
|
|
ieee80211_stop_queues_by_reason(&local->hw,
|
|
|
|
IEEE80211_QUEUE_STOP_REASON_PS);
|
2011-02-18 19:48:03 +08:00
|
|
|
ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
|
2010-01-12 16:42:46 +08:00
|
|
|
ieee80211_queue_work(&local->hw,
|
|
|
|
&local->dynamic_ps_disable_work);
|
|
|
|
}
|
|
|
|
|
|
|
|
mod_timer(&local->dynamic_ps_timer, jiffies +
|
|
|
|
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
|
|
|
|
|
|
|
|
return TX_CONTINUE;
|
|
|
|
}
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-06-30 21:10:44 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
2008-02-25 23:27:43 +08:00
|
|
|
ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2008-07-16 09:44:13 +08:00
|
|
|
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
2007-07-27 21:43:22 +08:00
|
|
|
u32 sta_flags;
|
|
|
|
|
2008-05-15 18:55:29 +08:00
|
|
|
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-09-26 23:53:18 +08:00
|
|
|
|
mac80211: Optimize scans on current operating channel.
This should decrease un-necessary flushes, on/off channel work,
and channel changes in cases where the only scanned channel is
the current operating channel.
* Removes SCAN_OFF_CHANNEL flag, uses SDATA_STATE_OFFCHANNEL
and is-scanning flags instead.
* Add helper method to determine if we are currently configured
for the operating channel.
* Do no blindly go off/on channel in work.c Instead, only call
appropriate on/off code when we really need to change channels.
Always enable offchannel-ps mode when starting work,
and disable it when we are done.
* Consolidate ieee80211_offchannel_stop_station and
ieee80211_offchannel_stop_beaconing, call it
ieee80211_offchannel_stop_vifs instead.
* Accept non-beacon frames when scanning on operating channel.
* Scan state machine optimized to minimize on/off channel
transitions. Also, when going on-channel, go ahead and
re-enable beaconing. We're going to be there for 200ms,
so seems like some useful beaconing could happen.
Always enable offchannel-ps mode when starting software
scan, and disable it when we are done.
* Grab local->mtx earlier in __ieee80211_scan_completed_finish
so that we are protected when calling hw_config(), etc.
* Pass probe-responses up the stack if scanning on local
channel, so that mlme can take a look.
Signed-off-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2011-02-05 03:54:17 +08:00
|
|
|
if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) &&
|
|
|
|
test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) &&
|
2009-03-18 20:06:44 +08:00
|
|
|
!ieee80211_is_probe_req(hdr->frame_control) &&
|
|
|
|
!ieee80211_is_nullfunc(hdr->frame_control))
|
|
|
|
/*
|
|
|
|
* When software scanning only nullfunc frames (to notify
|
|
|
|
* the sleep state to the AP) and probe requests (for the
|
|
|
|
* active scan) are allowed, all other frames should not be
|
|
|
|
* sent and we should not get here, but if we do
|
|
|
|
* nonetheless, drop them to avoid sending them
|
|
|
|
* off-channel. See the link below and
|
|
|
|
* ieee80211_start_scan() for more.
|
|
|
|
*
|
|
|
|
* http://article.gmane.org/gmane.linux.kernel.wireless.general/30089
|
|
|
|
*/
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_DROP;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2010-10-01 23:20:41 +08:00
|
|
|
if (tx->sdata->vif.type == NL80211_IFTYPE_WDS)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
2008-09-11 06:01:58 +08:00
|
|
|
if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
2008-02-23 22:17:10 +08:00
|
|
|
return TX_CONTINUE;
|
|
|
|
|
2008-02-25 23:27:43 +08:00
|
|
|
if (tx->flags & IEEE80211_TX_PS_BUFFERED)
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-05-03 07:02:02 +08:00
|
|
|
sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-02-25 23:27:43 +08:00
|
|
|
if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
|
2007-07-27 21:43:22 +08:00
|
|
|
if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
|
2008-09-11 06:01:58 +08:00
|
|
|
tx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
2008-07-16 09:44:13 +08:00
|
|
|
ieee80211_is_data(hdr->frame_control))) {
|
2007-07-27 21:43:22 +08:00
|
|
|
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
|
|
|
printk(KERN_DEBUG "%s: dropped data frame to not "
|
2008-10-28 06:56:10 +08:00
|
|
|
"associated station %pM\n",
|
2009-11-26 00:46:19 +08:00
|
|
|
tx->sdata->name, hdr->addr1);
|
2007-07-27 21:43:22 +08:00
|
|
|
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
|
|
|
I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_DROP;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
} else {
|
2008-07-16 09:44:13 +08:00
|
|
|
if (unlikely(ieee80211_is_data(hdr->frame_control) &&
|
2007-07-27 21:43:22 +08:00
|
|
|
tx->local->num_sta == 0 &&
|
2008-09-11 06:01:58 +08:00
|
|
|
tx->sdata->vif.type != NL80211_IFTYPE_ADHOC)) {
|
2007-07-27 21:43:22 +08:00
|
|
|
/*
|
|
|
|
* No associated STAs - no need to send multicast
|
|
|
|
* frames.
|
|
|
|
*/
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_DROP;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This function is called whenever the AP is about to exceed the maximum limit
|
|
|
|
* of buffered frames for power saving STAs. This situation should not really
|
|
|
|
* happen often during normal operation, so dropping the oldest buffered packet
|
|
|
|
* from each queue should be OK to make some room for new frames. */
|
|
|
|
static void purge_old_ps_buffers(struct ieee80211_local *local)
|
|
|
|
{
|
|
|
|
int total = 0, purged = 0;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
struct ieee80211_sub_if_data *sdata;
|
|
|
|
struct sta_info *sta;
|
|
|
|
|
2007-09-19 05:29:21 +08:00
|
|
|
/*
|
|
|
|
* virtual interfaces are protected by RCU
|
|
|
|
*/
|
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
2007-07-27 21:43:22 +08:00
|
|
|
struct ieee80211_if_ap *ap;
|
2008-09-11 06:01:58 +08:00
|
|
|
if (sdata->vif.type != NL80211_IFTYPE_AP)
|
2007-07-27 21:43:22 +08:00
|
|
|
continue;
|
|
|
|
ap = &sdata->u.ap;
|
|
|
|
skb = skb_dequeue(&ap->ps_bc_buf);
|
|
|
|
if (skb) {
|
|
|
|
purged++;
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
}
|
|
|
|
total += skb_queue_len(&ap->ps_bc_buf);
|
|
|
|
}
|
|
|
|
|
2008-02-25 23:27:46 +08:00
|
|
|
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
2007-07-27 21:43:22 +08:00
|
|
|
skb = skb_dequeue(&sta->ps_tx_buf);
|
|
|
|
if (skb) {
|
|
|
|
purged++;
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
}
|
|
|
|
total += skb_queue_len(&sta->ps_tx_buf);
|
|
|
|
}
|
2008-02-25 23:27:46 +08:00
|
|
|
|
|
|
|
rcu_read_unlock();
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
local->total_ps_buffered = total;
|
2008-07-24 15:40:37 +08:00
|
|
|
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
2010-08-21 07:25:38 +08:00
|
|
|
wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n",
|
|
|
|
purged);
|
2008-06-30 21:10:46 +08:00
|
|
|
#endif
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-02-01 02:48:20 +08:00
|
|
|
static ieee80211_tx_result
|
2008-02-25 23:27:43 +08:00
|
|
|
ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
2008-07-16 09:44:13 +08:00
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
2008-05-15 18:55:29 +08:00
|
|
|
|
2007-12-19 08:31:25 +08:00
|
|
|
/*
|
|
|
|
* broadcast/multicast frame
|
|
|
|
*
|
|
|
|
* If any of the associated stations is in power save mode,
|
|
|
|
* the frame is buffered to be sent after DTIM beacon frame.
|
|
|
|
* This is done either by the hardware or us.
|
|
|
|
*/
|
|
|
|
|
mac80211: make master netdev handling sane
Currently, almost every interface type has a 'bss' pointer
pointing to BSS information. This BSS information, however,
is for a _local_ BSS, not for the BSS we joined, so having
it on a STA mode interface makes little sense, but now they
have it pointing to the master device, which is an AP mode
virtual interface. However, except for some bitrate control
data, this pointer is only used in AP/VLAN modes (for power
saving stations.)
Overall, it is not necessary to even have the master netdev
be a valid virtual interface, and it doesn't have to be on
the list of interfaces either.
This patch changes the master netdev to be special, it now
- no longer is on the list of virtual interfaces, which
lets me remove a lot of tests for that
- no longer has sub_if_data attached, since that isn't used
Additionally, this patch changes some vlan/ap mode handling
that is related to these 'bss' pointers described above (but
in the VLAN case they actually make sense because there they
point to the AP they belong to); it also adds some debugging
code to IEEE80211_DEV_TO_SUB_IF to validate it is not called
on the master netdev any more.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2008-07-09 20:40:34 +08:00
|
|
|
/* powersaving STAs only in AP/VLAN mode */
|
|
|
|
if (!tx->sdata->bss)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
|
|
|
/* no buffering for ordered frames */
|
2008-07-16 09:44:13 +08:00
|
|
|
if (ieee80211_has_order(hdr->frame_control))
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-12-19 08:31:25 +08:00
|
|
|
|
|
|
|
/* no stations in PS mode */
|
|
|
|
if (!atomic_read(&tx->sdata->bss->num_sta_ps))
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-12-19 08:31:25 +08:00
|
|
|
|
2009-10-29 19:19:21 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
|
2009-08-10 22:04:15 +08:00
|
|
|
|
2009-10-29 19:19:21 +08:00
|
|
|
/* device releases frame after DTIM beacon */
|
|
|
|
if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING))
|
2009-08-10 22:04:15 +08:00
|
|
|
return TX_CONTINUE;
|
|
|
|
|
2007-12-19 08:31:25 +08:00
|
|
|
/* buffered in mac80211 */
|
2009-08-10 22:04:15 +08:00
|
|
|
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
|
|
|
|
purge_old_ps_buffers(tx->local);
|
|
|
|
|
|
|
|
if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) {
|
2008-07-24 15:40:37 +08:00
|
|
|
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
2009-08-10 22:04:15 +08:00
|
|
|
if (net_ratelimit())
|
|
|
|
printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n",
|
2009-11-26 00:46:19 +08:00
|
|
|
tx->sdata->name);
|
2008-06-30 21:10:46 +08:00
|
|
|
#endif
|
2009-08-10 22:04:15 +08:00
|
|
|
dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
|
|
|
|
} else
|
|
|
|
tx->local->total_ps_buffered++;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-08-10 22:04:15 +08:00
|
|
|
skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
|
2007-12-19 08:31:25 +08:00
|
|
|
|
2009-08-10 22:04:15 +08:00
|
|
|
return TX_QUEUED;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2009-01-08 19:32:00 +08:00
|
|
|
static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
if (!ieee80211_is_mgmt(fc))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (sta == NULL || !test_sta_flags(sta, WLAN_STA_MFP))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *)
|
|
|
|
skb->data))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-02-01 02:48:20 +08:00
|
|
|
static ieee80211_tx_result
|
2008-02-25 23:27:43 +08:00
|
|
|
ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
|
|
|
struct sta_info *sta = tx->sta;
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
2008-07-16 09:44:13 +08:00
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
2010-04-19 15:12:52 +08:00
|
|
|
struct ieee80211_local *local = tx->local;
|
2008-05-03 07:02:02 +08:00
|
|
|
u32 staflags;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-11-30 08:55:45 +08:00
|
|
|
if (unlikely(!sta ||
|
|
|
|
ieee80211_is_probe_resp(hdr->frame_control) ||
|
|
|
|
ieee80211_is_auth(hdr->frame_control) ||
|
|
|
|
ieee80211_is_assoc_resp(hdr->frame_control) ||
|
|
|
|
ieee80211_is_reassoc_resp(hdr->frame_control)))
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-05-03 07:02:02 +08:00
|
|
|
staflags = get_sta_flags(sta);
|
|
|
|
|
mac80211: async station powersave handling
Some devices require that all frames to a station
are flushed when that station goes into powersave
mode before being able to send frames to that
station again when it wakes up or polls -- all in
order to avoid reordering and too many or too few
frames being sent to the station when it polls.
Normally, this is the case unless the station
goes to sleep and wakes up very quickly again.
But in that case, frames for it may be pending
on the hardware queues, and thus races could
happen in the case of multiple hardware queues
used for QoS/WMM. Normally this isn't a problem,
but with the iwlwifi mechanism we need to make
sure the race doesn't happen.
This makes mac80211 able to cope with the race
with driver help by a new WLAN_STA_PS_DRIVER
per-station flag that can be controlled by the
driver and tells mac80211 whether it can transmit
frames or not. This flag must be set according to
very specific rules outlined in the documentation
for the function that controls it.
When we buffer new frames for the station, we
normally set the TIM bit right away, but while
the driver has blocked transmission to that sta
we need to avoid that as well since we cannot
respond to the station if it wakes up due to the
TIM bit. Once the driver unblocks, we can set
the TIM bit.
Similarly, when the station just wakes up, we
need to wait until all other frames are flushed
before we can transmit frames to that station,
so the same applies here, we need to wait for
the driver to give the OK.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 18:35:50 +08:00
|
|
|
if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) &&
|
2009-07-24 19:23:09 +08:00
|
|
|
!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
|
2007-07-27 21:43:22 +08:00
|
|
|
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
2008-10-28 06:56:10 +08:00
|
|
|
printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
|
2007-07-27 21:43:22 +08:00
|
|
|
"before %d)\n",
|
2008-10-28 06:56:10 +08:00
|
|
|
sta->sta.addr, sta->sta.aid,
|
2007-07-27 21:43:22 +08:00
|
|
|
skb_queue_len(&sta->ps_tx_buf));
|
|
|
|
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
|
|
|
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
|
|
|
|
purge_old_ps_buffers(tx->local);
|
|
|
|
if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
|
|
|
|
struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);
|
2008-07-24 15:40:37 +08:00
|
|
|
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
2007-07-27 21:43:22 +08:00
|
|
|
if (net_ratelimit()) {
|
2008-10-28 06:56:10 +08:00
|
|
|
printk(KERN_DEBUG "%s: STA %pM TX "
|
2007-07-27 21:43:22 +08:00
|
|
|
"buffer full - dropping oldest frame\n",
|
2009-11-26 00:46:19 +08:00
|
|
|
tx->sdata->name, sta->sta.addr);
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
2008-06-30 21:10:46 +08:00
|
|
|
#endif
|
2007-07-27 21:43:22 +08:00
|
|
|
dev_kfree_skb(old);
|
|
|
|
} else
|
|
|
|
tx->local->total_ps_buffered++;
|
2008-02-20 18:21:35 +08:00
|
|
|
|
mac80211: async station powersave handling
Some devices require that all frames to a station
are flushed when that station goes into powersave
mode before being able to send frames to that
station again when it wakes up or polls -- all in
order to avoid reordering and too many or too few
frames being sent to the station when it polls.
Normally, this is the case unless the station
goes to sleep and wakes up very quickly again.
But in that case, frames for it may be pending
on the hardware queues, and thus races could
happen in the case of multiple hardware queues
used for QoS/WMM. Normally this isn't a problem,
but with the iwlwifi mechanism we need to make
sure the race doesn't happen.
This makes mac80211 able to cope with the race
with driver help by a new WLAN_STA_PS_DRIVER
per-station flag that can be controlled by the
driver and tells mac80211 whether it can transmit
frames or not. This flag must be set according to
very specific rules outlined in the documentation
for the function that controls it.
When we buffer new frames for the station, we
normally set the TIM bit right away, but while
the driver has blocked transmission to that sta
we need to avoid that as well since we cannot
respond to the station if it wakes up due to the
TIM bit. Once the driver unblocks, we can set
the TIM bit.
Similarly, when the station just wakes up, we
need to wait until all other frames are flushed
before we can transmit frames to that station,
so the same applies here, we need to wait for
the driver to give the OK.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 18:35:50 +08:00
|
|
|
/*
|
|
|
|
* Queue frame to be sent after STA wakes up/polls,
|
|
|
|
* but don't set the TIM bit if the driver is blocking
|
|
|
|
* wakeup or poll response transmissions anyway.
|
|
|
|
*/
|
|
|
|
if (skb_queue_empty(&sta->ps_tx_buf) &&
|
|
|
|
!(staflags & WLAN_STA_PS_DRIVER))
|
2008-02-20 18:21:35 +08:00
|
|
|
sta_info_set_tim_bit(sta);
|
|
|
|
|
2008-05-15 18:55:29 +08:00
|
|
|
info->control.jiffies = jiffies;
|
2009-07-14 06:33:34 +08:00
|
|
|
info->control.vif = &tx->sdata->vif;
|
2009-06-08 03:58:37 +08:00
|
|
|
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
2007-07-27 21:43:22 +08:00
|
|
|
skb_queue_tail(&sta->ps_tx_buf, tx->skb);
|
2010-04-19 15:12:52 +08:00
|
|
|
|
|
|
|
if (!timer_pending(&local->sta_cleanup))
|
|
|
|
mod_timer(&local->sta_cleanup,
|
|
|
|
round_jiffies(jiffies +
|
|
|
|
STA_INFO_CLEANUP_INTERVAL));
|
|
|
|
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_QUEUED;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
mac80211: async station powersave handling
Some devices require that all frames to a station
are flushed when that station goes into powersave
mode before being able to send frames to that
station again when it wakes up or polls -- all in
order to avoid reordering and too many or too few
frames being sent to the station when it polls.
Normally, this is the case unless the station
goes to sleep and wakes up very quickly again.
But in that case, frames for it may be pending
on the hardware queues, and thus races could
happen in the case of multiple hardware queues
used for QoS/WMM. Normally this isn't a problem,
but with the iwlwifi mechanism we need to make
sure the race doesn't happen.
This makes mac80211 able to cope with the race
with driver help by a new WLAN_STA_PS_DRIVER
per-station flag that can be controlled by the
driver and tells mac80211 whether it can transmit
frames or not. This flag must be set according to
very specific rules outlined in the documentation
for the function that controls it.
When we buffer new frames for the station, we
normally set the TIM bit right away, but while
the driver has blocked transmission to that sta
we need to avoid that as well since we cannot
respond to the station if it wakes up due to the
TIM bit. Once the driver unblocks, we can set
the TIM bit.
Similarly, when the station just wakes up, we
need to wait until all other frames are flushed
before we can transmit frames to that station,
so the same applies here, we need to wait for
the driver to give the OK.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 18:35:50 +08:00
|
|
|
else if (unlikely(staflags & WLAN_STA_PS_STA)) {
|
2008-10-28 06:56:10 +08:00
|
|
|
printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll "
|
2009-11-26 00:46:19 +08:00
|
|
|
"set -> send frame\n", tx->sdata->name,
|
2008-10-28 06:56:10 +08:00
|
|
|
sta->sta.addr);
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
|
|
|
|
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-06-30 21:10:44 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
2008-02-25 23:27:43 +08:00
|
|
|
ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2008-02-25 23:27:43 +08:00
|
|
|
if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED))
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-02-25 23:27:43 +08:00
|
|
|
if (tx->flags & IEEE80211_TX_UNICAST)
|
2007-07-27 21:43:22 +08:00
|
|
|
return ieee80211_tx_h_unicast_ps_buf(tx);
|
|
|
|
else
|
|
|
|
return ieee80211_tx_h_multicast_ps_buf(tx);
|
|
|
|
}
|
|
|
|
|
2010-08-27 19:26:54 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
|
|
|
ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
|
|
|
|
{
|
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
|
|
|
|
|
|
if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol &&
|
|
|
|
tx->sdata->control_port_no_encrypt))
|
|
|
|
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
|
|
|
|
|
|
|
return TX_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2008-06-30 21:10:44 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
2008-02-25 23:27:43 +08:00
|
|
|
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2009-04-25 03:35:42 +08:00
|
|
|
struct ieee80211_key *key = NULL;
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
2008-07-16 09:44:13 +08:00
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
[MAC80211]: fix race conditions with keys
During receive processing, we select the key long before using it and
because there's no locking it is possible that we kfree() the key
after having selected it but before using it for crypto operations.
Obviously, this is bad.
Secondly, during transmit processing, there are two possible races: We
have a similar race between select_key() and using it for encryption,
but we also have a race here between select_key() and hardware
encryption (both when a key is removed.)
This patch solves these issues by using RCU: when a key is to be freed,
we first remove the pointer from the appropriate places (sdata->keys,
sdata->default_key, sta->key) using rcu_assign_pointer() and then
synchronize_rcu(). Then, we can safely kfree() the key and remove it
from the hardware. There's a window here where the hardware may still
be using it for decryption, but we can't work around that without having
two hardware callbacks, one to disable the key for RX and one to disable
it for TX; but the worst thing that will happen is that we receive a
packet decrypted that we don't find a key for any more and then drop it.
When we add a key, we first need to upload it to the hardware and then,
using rcu_assign_pointer() again, link it into our structures.
In the code using keys (TX/RX paths) we use rcu_dereference() to get the
key and enclose the whole tx/rx section in a rcu_read_lock() ...
rcu_read_unlock() block. Because we've uploaded the key to hardware
before linking it into internal structures, we can guarantee that it is
valid once get to into tx().
One possible race condition remains, however: when we have hardware
acceleration enabled and the driver shuts down the queues, we end up
queueing the frame. If now somebody removes the key, the key will be
removed from hwaccel and then then driver will be asked to encrypt the
frame with a key index that has been removed. Hence, drivers will need
to be aware that the hw_key_index they are passed might not be under
all circumstances. Most drivers will, however, simply ignore that
condition and encrypt the frame with the selected key anyway, this
only results in a frame being encrypted with a wrong key or dropped
(rightfully) because the key was not valid. There isn't much we can
do about it unless we want to walk the pending frame queue every time
a key is removed and remove all frames that used it.
This race condition, however, will most likely be solved once we add
multiqueue support to mac80211 because then frames will be queued
further up the stack instead of after being processed.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-09-14 23:10:24 +08:00
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
|
2007-07-27 21:43:22 +08:00
|
|
|
tx->key = NULL;
|
2010-10-06 01:39:30 +08:00
|
|
|
else if (tx->sta && (key = rcu_dereference(tx->sta->ptk)))
|
[MAC80211]: fix race conditions with keys
During receive processing, we select the key long before using it and
because there's no locking it is possible that we kfree() the key
after having selected it but before using it for crypto operations.
Obviously, this is bad.
Secondly, during transmit processing, there are two possible races: We
have a similar race between select_key() and using it for encryption,
but we also have a race here between select_key() and hardware
encryption (both when a key is removed.)
This patch solves these issues by using RCU: when a key is to be freed,
we first remove the pointer from the appropriate places (sdata->keys,
sdata->default_key, sta->key) using rcu_assign_pointer() and then
synchronize_rcu(). Then, we can safely kfree() the key and remove it
from the hardware. There's a window here where the hardware may still
be using it for decryption, but we can't work around that without having
two hardware callbacks, one to disable the key for RX and one to disable
it for TX; but the worst thing that will happen is that we receive a
packet decrypted that we don't find a key for any more and then drop it.
When we add a key, we first need to upload it to the hardware and then,
using rcu_assign_pointer() again, link it into our structures.
In the code using keys (TX/RX paths) we use rcu_dereference() to get the
key and enclose the whole tx/rx section in a rcu_read_lock() ...
rcu_read_unlock() block. Because we've uploaded the key to hardware
before linking it into internal structures, we can guarantee that it is
valid once get to into tx().
One possible race condition remains, however: when we have hardware
acceleration enabled and the driver shuts down the queues, we end up
queueing the frame. If now somebody removes the key, the key will be
removed from hwaccel and then then driver will be asked to encrypt the
frame with a key index that has been removed. Hence, drivers will need
to be aware that the hw_key_index they are passed might not be under
all circumstances. Most drivers will, however, simply ignore that
condition and encrypt the frame with the selected key anyway, this
only results in a frame being encrypted with a wrong key or dropped
(rightfully) because the key was not valid. There isn't much we can
do about it unless we want to walk the pending frame queue every time
a key is removed and remove all frames that used it.
This race condition, however, will most likely be solved once we add
multiqueue support to mac80211 because then frames will be queued
further up the stack instead of after being processed.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-09-14 23:10:24 +08:00
|
|
|
tx->key = key;
|
2009-01-08 19:32:02 +08:00
|
|
|
else if (ieee80211_is_mgmt(hdr->frame_control) &&
|
2010-03-30 14:35:23 +08:00
|
|
|
is_multicast_ether_addr(hdr->addr1) &&
|
|
|
|
ieee80211_is_robust_mgmt_frame(hdr) &&
|
2009-01-08 19:32:02 +08:00
|
|
|
(key = rcu_dereference(tx->sdata->default_mgmt_key)))
|
|
|
|
tx->key = key;
|
2010-12-10 02:49:02 +08:00
|
|
|
else if (is_multicast_ether_addr(hdr->addr1) &&
|
|
|
|
(key = rcu_dereference(tx->sdata->default_multicast_key)))
|
|
|
|
tx->key = key;
|
|
|
|
else if (!is_multicast_ether_addr(hdr->addr1) &&
|
|
|
|
(key = rcu_dereference(tx->sdata->default_unicast_key)))
|
[MAC80211]: fix race conditions with keys
During receive processing, we select the key long before using it and
because there's no locking it is possible that we kfree() the key
after having selected it but before using it for crypto operations.
Obviously, this is bad.
Secondly, during transmit processing, there are two possible races: We
have a similar race between select_key() and using it for encryption,
but we also have a race here between select_key() and hardware
encryption (both when a key is removed.)
This patch solves these issues by using RCU: when a key is to be freed,
we first remove the pointer from the appropriate places (sdata->keys,
sdata->default_key, sta->key) using rcu_assign_pointer() and then
synchronize_rcu(). Then, we can safely kfree() the key and remove it
from the hardware. There's a window here where the hardware may still
be using it for decryption, but we can't work around that without having
two hardware callbacks, one to disable the key for RX and one to disable
it for TX; but the worst thing that will happen is that we receive a
packet decrypted that we don't find a key for any more and then drop it.
When we add a key, we first need to upload it to the hardware and then,
using rcu_assign_pointer() again, link it into our structures.
In the code using keys (TX/RX paths) we use rcu_dereference() to get the
key and enclose the whole tx/rx section in a rcu_read_lock() ...
rcu_read_unlock() block. Because we've uploaded the key to hardware
before linking it into internal structures, we can guarantee that it is
valid once get to into tx().
One possible race condition remains, however: when we have hardware
acceleration enabled and the driver shuts down the queues, we end up
queueing the frame. If now somebody removes the key, the key will be
removed from hwaccel and then then driver will be asked to encrypt the
frame with a key index that has been removed. Hence, drivers will need
to be aware that the hw_key_index they are passed might not be under
all circumstances. Most drivers will, however, simply ignore that
condition and encrypt the frame with the selected key anyway, this
only results in a frame being encrypted with a wrong key or dropped
(rightfully) because the key was not valid. There isn't much we can
do about it unless we want to walk the pending frame queue every time
a key is removed and remove all frames that used it.
This race condition, however, will most likely be solved once we add
multiqueue support to mac80211 because then frames will be queued
further up the stack instead of after being processed.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-09-14 23:10:24 +08:00
|
|
|
tx->key = key;
|
2007-07-27 21:43:22 +08:00
|
|
|
else if (tx->sdata->drop_unencrypted &&
|
2010-08-27 19:26:54 +08:00
|
|
|
(tx->skb->protocol != tx->sdata->control_port_protocol) &&
|
2009-01-19 22:52:00 +08:00
|
|
|
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
|
|
|
|
(!ieee80211_is_robust_mgmt_frame(hdr) ||
|
|
|
|
(ieee80211_is_action(hdr->frame_control) &&
|
|
|
|
tx->sta && test_sta_flags(tx->sta, WLAN_STA_MFP)))) {
|
2007-07-27 21:43:22 +08:00
|
|
|
I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_DROP;
|
2007-12-18 22:27:47 +08:00
|
|
|
} else
|
2007-07-27 21:43:22 +08:00
|
|
|
tx->key = NULL;
|
|
|
|
|
|
|
|
if (tx->key) {
|
2010-01-17 08:47:58 +08:00
|
|
|
bool skip_hw = false;
|
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
tx->key->tx_rx_count++;
|
2007-09-17 13:29:25 +08:00
|
|
|
/* TODO: add threshold stuff again */
|
2007-12-18 22:27:47 +08:00
|
|
|
|
2010-08-10 15:46:38 +08:00
|
|
|
switch (tx->key->conf.cipher) {
|
|
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
2008-07-16 09:44:13 +08:00
|
|
|
if (ieee80211_is_auth(hdr->frame_control))
|
2007-12-18 22:27:47 +08:00
|
|
|
break;
|
2010-08-10 15:46:38 +08:00
|
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
2008-07-16 09:44:13 +08:00
|
|
|
if (!ieee80211_is_data_present(hdr->frame_control))
|
2007-12-18 22:27:47 +08:00
|
|
|
tx->key = NULL;
|
|
|
|
break;
|
2010-08-10 15:46:38 +08:00
|
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
2009-01-08 19:32:00 +08:00
|
|
|
if (!ieee80211_is_data_present(hdr->frame_control) &&
|
|
|
|
!ieee80211_use_mfp(hdr->frame_control, tx->sta,
|
|
|
|
tx->skb))
|
|
|
|
tx->key = NULL;
|
2010-01-24 02:27:14 +08:00
|
|
|
else
|
|
|
|
skip_hw = (tx->key->conf.flags &
|
|
|
|
IEEE80211_KEY_FLAG_SW_MGMT) &&
|
|
|
|
ieee80211_is_mgmt(hdr->frame_control);
|
2009-01-08 19:32:00 +08:00
|
|
|
break;
|
2010-08-10 15:46:38 +08:00
|
|
|
case WLAN_CIPHER_SUITE_AES_CMAC:
|
2009-01-08 19:32:02 +08:00
|
|
|
if (!ieee80211_is_mgmt(hdr->frame_control))
|
|
|
|
tx->key = NULL;
|
|
|
|
break;
|
2007-12-18 22:27:47 +08:00
|
|
|
}
|
2010-01-17 08:47:58 +08:00
|
|
|
|
2010-01-23 05:07:59 +08:00
|
|
|
if (!skip_hw && tx->key &&
|
2010-01-25 18:36:16 +08:00
|
|
|
tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
|
2010-01-17 08:47:58 +08:00
|
|
|
info->control.hw_key = &tx->key->conf;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-06-30 21:10:44 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
2008-02-25 23:27:43 +08:00
|
|
|
ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
2008-10-21 18:40:02 +08:00
|
|
|
struct ieee80211_hdr *hdr = (void *)tx->skb->data;
|
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
|
struct ieee80211_rate *rate;
|
2010-04-28 02:15:12 +08:00
|
|
|
int i;
|
|
|
|
u32 len;
|
2008-10-21 18:40:02 +08:00
|
|
|
bool inval = false, rts = false, short_preamble = false;
|
|
|
|
struct ieee80211_tx_rate_control txrc;
|
2009-07-17 01:15:09 +08:00
|
|
|
u32 sta_flags;
|
2008-01-25 02:38:38 +08:00
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
memset(&txrc, 0, sizeof(txrc));
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
sband = tx->local->hw.wiphy->bands[tx->channel->band];
|
2007-09-26 23:53:18 +08:00
|
|
|
|
2010-04-28 02:15:12 +08:00
|
|
|
len = min_t(u32, tx->skb->len + FCS_LEN,
|
2009-04-21 00:39:05 +08:00
|
|
|
tx->local->hw.wiphy->frag_threshold);
|
2008-10-21 18:40:02 +08:00
|
|
|
|
|
|
|
/* set up the tx rate control struct we give the RC algo */
|
|
|
|
txrc.hw = local_to_hw(tx->local);
|
|
|
|
txrc.sband = sband;
|
|
|
|
txrc.bss_conf = &tx->sdata->vif.bss_conf;
|
|
|
|
txrc.skb = tx->skb;
|
|
|
|
txrc.reported_rate.idx = -1;
|
2010-01-06 19:09:08 +08:00
|
|
|
txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band];
|
|
|
|
if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
|
|
|
|
txrc.max_rate_idx = -1;
|
|
|
|
else
|
|
|
|
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
|
2010-11-11 22:07:23 +08:00
|
|
|
txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
|
|
|
|
tx->sdata->vif.type == NL80211_IFTYPE_ADHOC);
|
2008-10-21 18:40:02 +08:00
|
|
|
|
|
|
|
/* set up RTS protection if desired */
|
2009-04-21 00:39:05 +08:00
|
|
|
if (len > tx->local->hw.wiphy->rts_threshold) {
|
2008-10-21 18:40:02 +08:00
|
|
|
txrc.rts = rts = true;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
/*
|
|
|
|
* Use short preamble if the BSS can handle it, but not for
|
|
|
|
* management frames unless we know the receiver can handle
|
|
|
|
* that -- the management frame might be to a station that
|
|
|
|
* just wants a probe response.
|
|
|
|
*/
|
|
|
|
if (tx->sdata->vif.bss_conf.use_short_preamble &&
|
|
|
|
(ieee80211_is_data(hdr->frame_control) ||
|
|
|
|
(tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
|
|
|
|
txrc.short_preamble = short_preamble = true;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-07-17 01:15:09 +08:00
|
|
|
sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lets not bother rate control if we're associated and cannot
|
|
|
|
* talk to the sta. This should not happen.
|
|
|
|
*/
|
2009-07-23 18:14:04 +08:00
|
|
|
if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) &&
|
2009-07-17 01:15:09 +08:00
|
|
|
(sta_flags & WLAN_STA_ASSOC) &&
|
|
|
|
!rate_usable_index_exists(sband, &tx->sta->sta),
|
|
|
|
"%s: Dropped data frame as no usable bitrate found while "
|
|
|
|
"scanning and associated. Target station: "
|
|
|
|
"%pM on %d GHz band\n",
|
2009-11-26 00:46:19 +08:00
|
|
|
tx->sdata->name, hdr->addr1,
|
2009-07-17 01:15:09 +08:00
|
|
|
tx->channel->band ? 5 : 2))
|
|
|
|
return TX_DROP;
|
2008-05-15 18:55:27 +08:00
|
|
|
|
2009-07-17 01:15:09 +08:00
|
|
|
/*
|
|
|
|
* If we're associated with the sta at this point we know we can at
|
|
|
|
* least send the frame at the lowest bit rate.
|
|
|
|
*/
|
2008-10-21 18:40:02 +08:00
|
|
|
rate_control_get_rate(tx->sdata, tx->sta, &txrc);
|
|
|
|
|
|
|
|
if (unlikely(info->control.rates[0].idx < 0))
|
|
|
|
return TX_DROP;
|
|
|
|
|
2010-12-01 23:34:45 +08:00
|
|
|
if (txrc.reported_rate.idx < 0) {
|
2008-10-21 18:40:02 +08:00
|
|
|
txrc.reported_rate = info->control.rates[0];
|
2010-12-01 23:34:45 +08:00
|
|
|
if (tx->sta && ieee80211_is_data(hdr->frame_control))
|
|
|
|
tx->sta->last_tx_rate = txrc.reported_rate;
|
|
|
|
} else if (tx->sta)
|
2008-10-21 18:40:02 +08:00
|
|
|
tx->sta->last_tx_rate = txrc.reported_rate;
|
2008-05-15 18:55:29 +08:00
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
if (unlikely(!info->control.rates[0].count))
|
|
|
|
info->control.rates[0].count = 1;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-04-24 01:36:14 +08:00
|
|
|
if (WARN_ON_ONCE((info->control.rates[0].count > 1) &&
|
|
|
|
(info->flags & IEEE80211_TX_CTL_NO_ACK)))
|
|
|
|
info->control.rates[0].count = 1;
|
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
if (is_multicast_ether_addr(hdr->addr1)) {
|
|
|
|
/*
|
|
|
|
* XXX: verify the rate is in the basic rateset
|
|
|
|
*/
|
|
|
|
return TX_CONTINUE;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
/*
|
|
|
|
* set up the RTS/CTS rate as the fastest basic rate
|
|
|
|
* that is not faster than the data rate
|
|
|
|
*
|
|
|
|
* XXX: Should this check all retry rates?
|
|
|
|
*/
|
|
|
|
if (!(info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
|
|
|
|
s8 baserate = 0;
|
|
|
|
|
|
|
|
rate = &sband->bitrates[info->control.rates[0].idx];
|
|
|
|
|
|
|
|
for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
|
/* must be a basic rate */
|
|
|
|
if (!(tx->sdata->vif.bss_conf.basic_rates & BIT(i)))
|
|
|
|
continue;
|
|
|
|
/* must not be faster than the data rate */
|
|
|
|
if (sband->bitrates[i].bitrate > rate->bitrate)
|
|
|
|
continue;
|
|
|
|
/* maximum */
|
|
|
|
if (sband->bitrates[baserate].bitrate <
|
|
|
|
sband->bitrates[i].bitrate)
|
|
|
|
baserate = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->control.rts_cts_rate_idx = baserate;
|
2007-07-27 21:43:24 +08:00
|
|
|
}
|
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
|
|
|
/*
|
|
|
|
* make sure there's no valid rate following
|
|
|
|
* an invalid one, just in case drivers don't
|
|
|
|
* take the API seriously to stop at -1.
|
|
|
|
*/
|
|
|
|
if (inval) {
|
|
|
|
info->control.rates[i].idx = -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (info->control.rates[i].idx < 0) {
|
|
|
|
inval = true;
|
|
|
|
continue;
|
|
|
|
}
|
2008-01-25 02:38:38 +08:00
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
/*
|
|
|
|
* For now assume MCS is already set up correctly, this
|
|
|
|
* needs to be fixed.
|
|
|
|
*/
|
|
|
|
if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) {
|
|
|
|
WARN_ON(info->control.rates[i].idx > 76);
|
|
|
|
continue;
|
|
|
|
}
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
/* set up RTS protection if desired */
|
|
|
|
if (rts)
|
|
|
|
info->control.rates[i].flags |=
|
|
|
|
IEEE80211_TX_RC_USE_RTS_CTS;
|
2008-01-25 02:38:38 +08:00
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
/* RC is busted */
|
2008-10-23 14:44:02 +08:00
|
|
|
if (WARN_ON_ONCE(info->control.rates[i].idx >=
|
|
|
|
sband->n_bitrates)) {
|
2008-10-21 18:40:02 +08:00
|
|
|
info->control.rates[i].idx = -1;
|
|
|
|
continue;
|
2008-01-25 02:38:38 +08:00
|
|
|
}
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
rate = &sband->bitrates[info->control.rates[i].idx];
|
|
|
|
|
|
|
|
/* set up short preamble */
|
|
|
|
if (short_preamble &&
|
|
|
|
rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
|
|
|
|
info->control.rates[i].flags |=
|
|
|
|
IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
|
|
|
|
|
|
|
|
/* set up G protection */
|
|
|
|
if (!rts && tx->sdata->vif.bss_conf.use_cts_prot &&
|
|
|
|
rate->flags & IEEE80211_RATE_ERP_G)
|
|
|
|
info->control.rates[i].flags |=
|
|
|
|
IEEE80211_TX_RC_USE_CTS_PROTECT;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-10-21 18:40:02 +08:00
|
|
|
return TX_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2008-07-10 17:21:26 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
|
|
|
ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
|
|
|
|
{
|
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
|
|
|
u16 *seq;
|
|
|
|
u8 *qc;
|
|
|
|
int tid;
|
|
|
|
|
2008-09-13 04:52:47 +08:00
|
|
|
/*
|
|
|
|
* Packet injection may want to control the sequence
|
|
|
|
* number, if we have no matching interface then we
|
|
|
|
* neither assign one ourselves nor ask the driver to.
|
|
|
|
*/
|
2009-07-14 06:33:34 +08:00
|
|
|
if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR))
|
2008-09-13 04:52:47 +08:00
|
|
|
return TX_CONTINUE;
|
|
|
|
|
2008-07-10 17:21:26 +08:00
|
|
|
if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
|
|
|
if (ieee80211_hdrlen(hdr->frame_control) < 24)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
2008-10-10 19:21:59 +08:00
|
|
|
/*
|
|
|
|
* Anything but QoS data that has a sequence number field
|
|
|
|
* (is long enough) gets a sequence number from the global
|
|
|
|
* counter.
|
|
|
|
*/
|
2008-07-10 17:21:26 +08:00
|
|
|
if (!ieee80211_is_data_qos(hdr->frame_control)) {
|
2008-10-10 19:21:59 +08:00
|
|
|
/* driver should assign sequence number */
|
2008-07-10 17:21:26 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
2008-10-10 19:21:59 +08:00
|
|
|
/* for pure STA mode without beacons, we can do it */
|
|
|
|
hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number);
|
|
|
|
tx->sdata->sequence_number += 0x10;
|
2008-07-10 17:21:26 +08:00
|
|
|
return TX_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This should be true for injected/management frames only, for
|
|
|
|
* management frames we have set the IEEE80211_TX_CTL_ASSIGN_SEQ
|
|
|
|
* above since they are not QoS-data frames.
|
|
|
|
*/
|
|
|
|
if (!tx->sta)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
|
|
|
/* include per-STA, per-TID sequence counter */
|
|
|
|
|
|
|
|
qc = ieee80211_get_qos_ctl(hdr);
|
|
|
|
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
|
|
|
|
seq = &tx->sta->tid_seq[tid];
|
|
|
|
|
|
|
|
hdr->seq_ctrl = cpu_to_le16(*seq);
|
|
|
|
|
|
|
|
/* Increase the sequence number. */
|
|
|
|
*seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ;
|
|
|
|
|
|
|
|
return TX_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2009-03-24 00:28:35 +08:00
|
|
|
static int ieee80211_fragment(struct ieee80211_local *local,
|
|
|
|
struct sk_buff *skb, int hdrlen,
|
|
|
|
int frag_threshold)
|
|
|
|
{
|
|
|
|
struct sk_buff *tail = skb, *tmp;
|
|
|
|
int per_fragm = frag_threshold - hdrlen - FCS_LEN;
|
|
|
|
int pos = hdrlen + per_fragm;
|
|
|
|
int rem = skb->len - hdrlen - per_fragm;
|
|
|
|
|
|
|
|
if (WARN_ON(rem < 0))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
while (rem) {
|
|
|
|
int fraglen = per_fragm;
|
|
|
|
|
|
|
|
if (fraglen > rem)
|
|
|
|
fraglen = rem;
|
|
|
|
rem -= fraglen;
|
|
|
|
tmp = dev_alloc_skb(local->tx_headroom +
|
|
|
|
frag_threshold +
|
|
|
|
IEEE80211_ENCRYPT_HEADROOM +
|
|
|
|
IEEE80211_ENCRYPT_TAILROOM);
|
|
|
|
if (!tmp)
|
|
|
|
return -ENOMEM;
|
|
|
|
tail->next = tmp;
|
|
|
|
tail = tmp;
|
|
|
|
skb_reserve(tmp, local->tx_headroom +
|
|
|
|
IEEE80211_ENCRYPT_HEADROOM);
|
|
|
|
/* copy control information */
|
|
|
|
memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
|
|
|
|
skb_copy_queue_mapping(tmp, skb);
|
|
|
|
tmp->priority = skb->priority;
|
|
|
|
tmp->dev = skb->dev;
|
|
|
|
|
|
|
|
/* copy header and data */
|
|
|
|
memcpy(skb_put(tmp, hdrlen), skb->data, hdrlen);
|
|
|
|
memcpy(skb_put(tmp, fraglen), skb->data + pos, fraglen);
|
|
|
|
|
|
|
|
pos += fraglen;
|
|
|
|
}
|
|
|
|
|
|
|
|
skb->len = hdrlen + per_fragm;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-30 21:10:44 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
2008-05-15 18:55:28 +08:00
|
|
|
ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
|
|
|
{
|
2009-03-24 00:28:35 +08:00
|
|
|
struct sk_buff *skb = tx->skb;
|
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
|
struct ieee80211_hdr *hdr = (void *)skb->data;
|
2009-04-21 00:39:05 +08:00
|
|
|
int frag_threshold = tx->local->hw.wiphy->frag_threshold;
|
2009-03-24 00:28:35 +08:00
|
|
|
int hdrlen;
|
|
|
|
int fragnum;
|
2008-05-15 18:55:28 +08:00
|
|
|
|
|
|
|
if (!(tx->flags & IEEE80211_TX_FRAGMENTED))
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
2008-05-17 06:57:13 +08:00
|
|
|
/*
|
|
|
|
* Warn when submitting a fragmented A-MPDU frame and drop it.
|
2009-06-17 23:43:56 +08:00
|
|
|
* This scenario is handled in ieee80211_tx_prepare but extra
|
2008-06-12 20:42:29 +08:00
|
|
|
* caution taken here as fragmented ampdu may cause Tx stop.
|
2008-05-17 06:57:13 +08:00
|
|
|
*/
|
2008-10-24 12:25:27 +08:00
|
|
|
if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
|
2008-05-17 06:57:13 +08:00
|
|
|
return TX_DROP;
|
|
|
|
|
2008-06-23 07:45:27 +08:00
|
|
|
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
2008-05-15 18:55:28 +08:00
|
|
|
|
2009-03-24 00:28:35 +08:00
|
|
|
/* internal error, why is TX_FRAGMENTED set? */
|
2009-04-30 05:35:56 +08:00
|
|
|
if (WARN_ON(skb->len + FCS_LEN <= frag_threshold))
|
2009-03-24 00:28:35 +08:00
|
|
|
return TX_DROP;
|
2008-10-21 18:40:02 +08:00
|
|
|
|
2009-03-24 00:28:35 +08:00
|
|
|
/*
|
|
|
|
* Now fragment the frame. This will allocate all the fragments and
|
|
|
|
* chain them (using skb as the first fragment) to skb->next.
|
|
|
|
* During transmission, we will remove the successfully transmitted
|
|
|
|
* fragments from this list. When the low-level driver rejects one
|
|
|
|
* of the fragments then we will simply pretend to accept the skb
|
|
|
|
* but store it away as pending.
|
|
|
|
*/
|
|
|
|
if (ieee80211_fragment(tx->local, skb, hdrlen, frag_threshold))
|
|
|
|
return TX_DROP;
|
2008-10-21 18:40:02 +08:00
|
|
|
|
2009-03-24 00:28:35 +08:00
|
|
|
/* update duration/seq/flags of fragments */
|
|
|
|
fragnum = 0;
|
|
|
|
do {
|
|
|
|
int next_len;
|
|
|
|
const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
|
2008-10-21 18:40:02 +08:00
|
|
|
|
2009-03-24 00:28:35 +08:00
|
|
|
hdr = (void *)skb->data;
|
|
|
|
info = IEEE80211_SKB_CB(skb);
|
2008-10-21 18:40:02 +08:00
|
|
|
|
2009-03-24 00:28:35 +08:00
|
|
|
if (skb->next) {
|
|
|
|
hdr->frame_control |= morefrags;
|
|
|
|
next_len = skb->next->len;
|
2008-10-21 18:40:02 +08:00
|
|
|
/*
|
|
|
|
* No multi-rate retries for fragmented frames, that
|
|
|
|
* would completely throw off the NAV at other STAs.
|
|
|
|
*/
|
|
|
|
info->control.rates[1].idx = -1;
|
|
|
|
info->control.rates[2].idx = -1;
|
|
|
|
info->control.rates[3].idx = -1;
|
|
|
|
info->control.rates[4].idx = -1;
|
|
|
|
BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
|
|
|
|
info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
2009-03-24 00:28:35 +08:00
|
|
|
} else {
|
|
|
|
hdr->frame_control &= ~morefrags;
|
|
|
|
next_len = 0;
|
2008-10-21 18:40:02 +08:00
|
|
|
}
|
2009-03-24 00:28:35 +08:00
|
|
|
hdr->duration_id = ieee80211_duration(tx, 0, next_len);
|
|
|
|
hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG);
|
|
|
|
fragnum++;
|
|
|
|
} while ((skb = skb->next));
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2009-08-10 22:01:54 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
|
|
|
ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
|
|
|
|
{
|
|
|
|
struct sk_buff *skb = tx->skb;
|
|
|
|
|
|
|
|
if (!tx->sta)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
|
|
|
tx->sta->tx_packets++;
|
|
|
|
do {
|
|
|
|
tx->sta->tx_fragments++;
|
|
|
|
tx->sta->tx_bytes += skb->len;
|
|
|
|
} while ((skb = skb->next));
|
|
|
|
|
|
|
|
return TX_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2008-06-30 21:10:44 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
2008-05-15 18:55:28 +08:00
|
|
|
ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
|
|
|
|
{
|
2010-08-27 19:26:52 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
|
|
|
2008-05-15 18:55:28 +08:00
|
|
|
if (!tx->key)
|
|
|
|
return TX_CONTINUE;
|
|
|
|
|
2010-08-10 15:46:38 +08:00
|
|
|
switch (tx->key->conf.cipher) {
|
|
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
2008-05-15 18:55:28 +08:00
|
|
|
return ieee80211_crypto_wep_encrypt(tx);
|
2010-08-10 15:46:38 +08:00
|
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
2008-05-15 18:55:28 +08:00
|
|
|
return ieee80211_crypto_tkip_encrypt(tx);
|
2010-08-10 15:46:38 +08:00
|
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
2008-05-15 18:55:28 +08:00
|
|
|
return ieee80211_crypto_ccmp_encrypt(tx);
|
2010-08-10 15:46:38 +08:00
|
|
|
case WLAN_CIPHER_SUITE_AES_CMAC:
|
2009-01-08 19:32:02 +08:00
|
|
|
return ieee80211_crypto_aes_cmac_encrypt(tx);
|
2010-08-27 19:26:52 +08:00
|
|
|
default:
|
|
|
|
/* handle hw-only algorithm */
|
|
|
|
if (info->control.hw_key) {
|
|
|
|
ieee80211_tx_set_protected(tx);
|
|
|
|
return TX_CONTINUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-05-15 18:55:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return TX_DROP;
|
|
|
|
}
|
|
|
|
|
2008-06-30 21:10:44 +08:00
|
|
|
static ieee80211_tx_result debug_noinline
|
2008-06-25 19:36:27 +08:00
|
|
|
ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
|
|
|
|
{
|
2009-03-24 00:28:35 +08:00
|
|
|
struct sk_buff *skb = tx->skb;
|
|
|
|
struct ieee80211_hdr *hdr;
|
|
|
|
int next_len;
|
|
|
|
bool group_addr;
|
2008-06-25 19:36:27 +08:00
|
|
|
|
2009-03-24 00:28:35 +08:00
|
|
|
do {
|
|
|
|
hdr = (void *) skb->data;
|
2009-05-20 00:25:58 +08:00
|
|
|
if (unlikely(ieee80211_is_pspoll(hdr->frame_control)))
|
|
|
|
break; /* must not overwrite AID */
|
2009-03-24 00:28:35 +08:00
|
|
|
next_len = skb->next ? skb->next->len : 0;
|
|
|
|
group_addr = is_multicast_ether_addr(hdr->addr1);
|
2008-06-25 19:36:27 +08:00
|
|
|
|
2009-03-24 00:28:35 +08:00
|
|
|
hdr->duration_id =
|
|
|
|
ieee80211_duration(tx, group_addr, next_len);
|
|
|
|
} while ((skb = skb->next));
|
2008-06-25 19:36:27 +08:00
|
|
|
|
|
|
|
return TX_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
/* actual transmit path */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* deal with packet injection down monitor interface
|
|
|
|
* with Radiotap Header -- only called for monitor mode interface
|
|
|
|
*/
|
2009-06-10 01:48:25 +08:00
|
|
|
static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
|
|
|
|
struct sk_buff *skb)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* this is the moment to interpret and discard the radiotap header that
|
|
|
|
* must be at the start of the packet injected in Monitor mode
|
|
|
|
*
|
|
|
|
* Need to take some care with endian-ness since radiotap
|
|
|
|
* args are little-endian
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct ieee80211_radiotap_iterator iterator;
|
|
|
|
struct ieee80211_radiotap_header *rthdr =
|
|
|
|
(struct ieee80211_radiotap_header *) skb->data;
|
2010-11-08 17:51:06 +08:00
|
|
|
bool hw_frag;
|
2009-06-17 23:43:56 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
2010-02-03 17:24:30 +08:00
|
|
|
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
|
|
|
|
NULL);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
2008-02-25 23:27:43 +08:00
|
|
|
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2010-11-08 17:51:06 +08:00
|
|
|
/* packet is fragmented in HW if we have a non-NULL driver callback */
|
|
|
|
hw_frag = (tx->local->ops->set_frag_threshold != NULL);
|
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
/*
|
|
|
|
* for every radiotap entry that is present
|
|
|
|
* (ieee80211_radiotap_iterator_next returns -ENOENT when no more
|
|
|
|
* entries present, or -EINVAL on error)
|
|
|
|
*/
|
|
|
|
|
|
|
|
while (!ret) {
|
|
|
|
ret = ieee80211_radiotap_iterator_next(&iterator);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* see if this argument is something we can use */
|
|
|
|
switch (iterator.this_arg_index) {
|
|
|
|
/*
|
|
|
|
* You must take care when dereferencing iterator.this_arg
|
|
|
|
* for multibyte types... the pointer is not aligned. Use
|
|
|
|
* get_unaligned((type *)iterator.this_arg) to dereference
|
|
|
|
* iterator.this_arg for type "type" safely on all arches.
|
|
|
|
*/
|
|
|
|
case IEEE80211_RADIOTAP_FLAGS:
|
|
|
|
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
|
|
|
|
/*
|
|
|
|
* this indicates that the skb we have been
|
|
|
|
* handed has the 32-bit FCS CRC at the end...
|
|
|
|
* we should react to that by snipping it off
|
|
|
|
* because it will be recomputed and added
|
|
|
|
* on transmission
|
|
|
|
*/
|
2010-02-03 17:24:30 +08:00
|
|
|
if (skb->len < (iterator._max_length + FCS_LEN))
|
2009-06-10 01:48:25 +08:00
|
|
|
return false;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
skb_trim(skb, skb->len - FCS_LEN);
|
|
|
|
}
|
2007-09-26 23:53:18 +08:00
|
|
|
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
|
2009-06-17 23:43:56 +08:00
|
|
|
info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
2010-11-08 17:51:06 +08:00
|
|
|
if ((*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) &&
|
|
|
|
!hw_frag)
|
2008-02-25 23:27:43 +08:00
|
|
|
tx->flags |= IEEE80211_TX_FRAGMENTED;
|
2007-07-27 21:43:22 +08:00
|
|
|
break;
|
|
|
|
|
2007-09-26 23:53:18 +08:00
|
|
|
/*
|
|
|
|
* Please update the file
|
|
|
|
* Documentation/networking/mac80211-injection.txt
|
|
|
|
* when parsing new fields here.
|
|
|
|
*/
|
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
|
2009-06-10 01:48:25 +08:00
|
|
|
return false;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* remove the radiotap header
|
2010-02-03 17:24:30 +08:00
|
|
|
* iterator->_max_length was sanity-checked against
|
2007-07-27 21:43:22 +08:00
|
|
|
* skb->len by iterator init
|
|
|
|
*/
|
2010-02-03 17:24:30 +08:00
|
|
|
skb_pull(skb, iterator._max_length);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-06-10 01:48:25 +08:00
|
|
|
return true;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2010-06-10 16:21:39 +08:00
|
|
|
static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
|
|
|
|
struct sk_buff *skb,
|
|
|
|
struct ieee80211_tx_info *info,
|
|
|
|
struct tid_ampdu_tx *tid_tx,
|
|
|
|
int tid)
|
|
|
|
{
|
|
|
|
bool queued = false;
|
|
|
|
|
|
|
|
if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
|
|
|
|
info->flags |= IEEE80211_TX_CTL_AMPDU;
|
2010-06-10 16:21:42 +08:00
|
|
|
} else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
|
|
|
|
/*
|
|
|
|
* nothing -- this aggregation session is being started
|
|
|
|
* but that might still fail with the driver
|
|
|
|
*/
|
2010-06-10 16:21:39 +08:00
|
|
|
} else {
|
|
|
|
spin_lock(&tx->sta->lock);
|
|
|
|
/*
|
|
|
|
* Need to re-check now, because we may get here
|
|
|
|
*
|
|
|
|
* 1) in the window during which the setup is actually
|
|
|
|
* already done, but not marked yet because not all
|
|
|
|
* packets are spliced over to the driver pending
|
|
|
|
* queue yet -- if this happened we acquire the lock
|
|
|
|
* either before or after the splice happens, but
|
|
|
|
* need to recheck which of these cases happened.
|
|
|
|
*
|
|
|
|
* 2) during session teardown, if the OPERATIONAL bit
|
|
|
|
* was cleared due to the teardown but the pointer
|
|
|
|
* hasn't been assigned NULL yet (or we loaded it
|
|
|
|
* before it was assigned) -- in this case it may
|
|
|
|
* now be NULL which means we should just let the
|
|
|
|
* packet pass through because splicing the frames
|
|
|
|
* back is already done.
|
|
|
|
*/
|
|
|
|
tid_tx = tx->sta->ampdu_mlme.tid_tx[tid];
|
|
|
|
|
|
|
|
if (!tid_tx) {
|
|
|
|
/* do nothing, let packet pass through */
|
|
|
|
} else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
|
|
|
|
info->flags |= IEEE80211_TX_CTL_AMPDU;
|
|
|
|
} else {
|
|
|
|
queued = true;
|
|
|
|
info->control.vif = &tx->sdata->vif;
|
|
|
|
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
|
|
|
__skb_queue_tail(&tid_tx->pending, skb);
|
|
|
|
}
|
|
|
|
spin_unlock(&tx->sta->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
return queued;
|
|
|
|
}
|
|
|
|
|
2007-09-26 23:53:18 +08:00
|
|
|
/*
|
|
|
|
* initialises @tx
|
|
|
|
*/
|
2008-02-01 02:48:20 +08:00
|
|
|
static ieee80211_tx_result
|
2009-06-17 23:43:56 +08:00
|
|
|
ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
|
|
|
struct ieee80211_tx_data *tx,
|
|
|
|
struct sk_buff *skb)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2009-06-17 23:43:56 +08:00
|
|
|
struct ieee80211_local *local = sdata->local;
|
2007-09-26 23:53:18 +08:00
|
|
|
struct ieee80211_hdr *hdr;
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
2008-10-24 12:25:27 +08:00
|
|
|
int hdrlen, tid;
|
2010-06-10 16:21:39 +08:00
|
|
|
u8 *qc;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
memset(tx, 0, sizeof(*tx));
|
|
|
|
tx->skb = skb;
|
|
|
|
tx->local = local;
|
2009-06-17 23:43:56 +08:00
|
|
|
tx->sdata = sdata;
|
2008-05-15 18:55:29 +08:00
|
|
|
tx->channel = local->hw.conf.channel;
|
2007-07-27 21:43:22 +08:00
|
|
|
/*
|
2007-09-26 23:53:18 +08:00
|
|
|
* Set this flag (used below to indicate "automatic fragmentation"),
|
|
|
|
* it will be cleared/left by radiotap as desired.
|
2010-11-08 17:51:06 +08:00
|
|
|
* Only valid when fragmentation is done by the stack.
|
2007-07-27 21:43:22 +08:00
|
|
|
*/
|
2010-11-08 17:51:06 +08:00
|
|
|
if (!local->ops->set_frag_threshold)
|
|
|
|
tx->flags |= IEEE80211_TX_FRAGMENTED;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
/* process and remove the injection radiotap header */
|
2010-02-01 04:56:25 +08:00
|
|
|
if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) {
|
2009-06-10 01:48:25 +08:00
|
|
|
if (!__ieee80211_parse_tx_radiotap(tx, skb))
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_DROP;
|
2007-09-26 23:53:18 +08:00
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
/*
|
2007-09-26 23:53:18 +08:00
|
|
|
* __ieee80211_parse_tx_radiotap has now removed
|
|
|
|
* the radiotap header that was present and pre-filled
|
|
|
|
* 'tx' with tx control information.
|
2007-07-27 21:43:22 +08:00
|
|
|
*/
|
2010-02-01 04:56:25 +08:00
|
|
|
info->flags &= ~IEEE80211_TX_INTFL_HAS_RADIOTAP;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2009-03-24 00:28:41 +08:00
|
|
|
/*
|
|
|
|
* If this flag is set to true anywhere, and we get here,
|
|
|
|
* we are doing the needed processing, so remove the flag
|
|
|
|
* now.
|
|
|
|
*/
|
|
|
|
info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
|
|
|
|
2007-09-26 23:53:18 +08:00
|
|
|
hdr = (struct ieee80211_hdr *) skb->data;
|
|
|
|
|
2010-01-09 01:15:13 +08:00
|
|
|
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
2009-11-11 03:10:05 +08:00
|
|
|
tx->sta = rcu_dereference(sdata->u.vlan.sta);
|
2010-01-09 01:15:13 +08:00
|
|
|
if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
|
|
|
|
return TX_DROP;
|
2010-02-01 06:25:24 +08:00
|
|
|
} else if (info->flags & IEEE80211_TX_CTL_INJECTED) {
|
|
|
|
tx->sta = sta_info_get_bss(sdata, hdr->addr1);
|
2010-01-09 01:15:13 +08:00
|
|
|
}
|
2009-11-11 03:10:05 +08:00
|
|
|
if (!tx->sta)
|
2009-11-26 00:46:18 +08:00
|
|
|
tx->sta = sta_info_get(sdata, hdr->addr1);
|
2007-09-26 23:53:18 +08:00
|
|
|
|
2009-03-24 00:28:41 +08:00
|
|
|
if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
|
|
|
|
(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
|
|
|
|
struct tid_ampdu_tx *tid_tx;
|
|
|
|
|
2008-10-24 12:25:27 +08:00
|
|
|
qc = ieee80211_get_qos_ctl(hdr);
|
|
|
|
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
|
|
|
|
|
2010-06-10 16:21:39 +08:00
|
|
|
tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
|
|
|
|
if (tid_tx) {
|
|
|
|
bool queued;
|
2009-03-24 00:28:41 +08:00
|
|
|
|
2010-06-10 16:21:39 +08:00
|
|
|
queued = ieee80211_tx_prep_agg(tx, skb, info,
|
|
|
|
tid_tx, tid);
|
|
|
|
|
|
|
|
if (unlikely(queued))
|
|
|
|
return TX_QUEUED;
|
|
|
|
}
|
2008-10-24 12:25:27 +08:00
|
|
|
}
|
|
|
|
|
2007-08-29 05:01:54 +08:00
|
|
|
if (is_multicast_ether_addr(hdr->addr1)) {
|
2008-02-25 23:27:43 +08:00
|
|
|
tx->flags &= ~IEEE80211_TX_UNICAST;
|
2008-05-15 18:55:29 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
2007-08-29 05:01:54 +08:00
|
|
|
} else {
|
2008-02-25 23:27:43 +08:00
|
|
|
tx->flags |= IEEE80211_TX_UNICAST;
|
2009-05-13 04:05:40 +08:00
|
|
|
if (unlikely(local->wifi_wme_noack_test))
|
|
|
|
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
|
|
|
else
|
|
|
|
info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
|
2007-08-29 05:01:54 +08:00
|
|
|
}
|
2007-09-26 23:53:18 +08:00
|
|
|
|
2008-02-25 23:27:43 +08:00
|
|
|
if (tx->flags & IEEE80211_TX_FRAGMENTED) {
|
|
|
|
if ((tx->flags & IEEE80211_TX_UNICAST) &&
|
2009-04-21 00:39:05 +08:00
|
|
|
skb->len + FCS_LEN > local->hw.wiphy->frag_threshold &&
|
2008-06-12 20:42:29 +08:00
|
|
|
!(info->flags & IEEE80211_TX_CTL_AMPDU))
|
2008-02-25 23:27:43 +08:00
|
|
|
tx->flags |= IEEE80211_TX_FRAGMENTED;
|
2007-09-26 23:53:18 +08:00
|
|
|
else
|
2008-02-25 23:27:43 +08:00
|
|
|
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
|
2007-09-26 23:53:18 +08:00
|
|
|
}
|
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
if (!tx->sta)
|
2008-05-15 18:55:29 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
|
2008-05-03 07:02:02 +08:00
|
|
|
else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT))
|
2008-05-15 18:55:29 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
|
2007-09-26 23:53:18 +08:00
|
|
|
|
2008-07-16 09:44:12 +08:00
|
|
|
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
2007-07-27 21:43:22 +08:00
|
|
|
if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
|
|
|
|
u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
|
|
|
|
tx->ethertype = (pos[0] << 8) | pos[1];
|
|
|
|
}
|
2008-05-15 18:55:29 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-02-01 02:48:20 +08:00
|
|
|
return TX_CONTINUE;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 21:42:06 +08:00
|
|
|
/*
|
|
|
|
* Returns false if the frame couldn't be transmitted but was queued instead.
|
|
|
|
*/
|
|
|
|
static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp,
|
|
|
|
struct sta_info *sta, bool txpending)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2009-03-24 00:28:38 +08:00
|
|
|
struct sk_buff *skb = *skbp, *next;
|
2008-07-24 23:46:44 +08:00
|
|
|
struct ieee80211_tx_info *info;
|
2009-07-14 06:33:34 +08:00
|
|
|
struct ieee80211_sub_if_data *sdata;
|
2009-06-17 23:43:56 +08:00
|
|
|
unsigned long flags;
|
2011-02-24 21:42:06 +08:00
|
|
|
int len;
|
2009-03-24 00:28:35 +08:00
|
|
|
bool fragm = false;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-03-24 00:28:35 +08:00
|
|
|
while (skb) {
|
2009-06-17 23:43:56 +08:00
|
|
|
int q = skb_get_queue_mapping(skb);
|
2010-11-30 15:58:45 +08:00
|
|
|
__le16 fc;
|
2009-06-17 23:43:56 +08:00
|
|
|
|
|
|
|
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
|
|
|
if (local->queue_stop_reasons[q] ||
|
2011-02-24 21:42:06 +08:00
|
|
|
(!txpending && !skb_queue_empty(&local->pending[q]))) {
|
|
|
|
/*
|
|
|
|
* Since queue is stopped, queue up frames for later
|
|
|
|
* transmission from the tx-pending tasklet when the
|
|
|
|
* queue is woken again.
|
|
|
|
*/
|
|
|
|
|
|
|
|
do {
|
|
|
|
next = skb->next;
|
|
|
|
skb->next = NULL;
|
|
|
|
/*
|
|
|
|
* NB: If txpending is true, next must already
|
|
|
|
* be NULL since we must've gone through this
|
|
|
|
* loop before already; therefore we can just
|
|
|
|
* queue the frame to the head without worrying
|
|
|
|
* about reordering of fragments.
|
|
|
|
*/
|
|
|
|
if (unlikely(txpending))
|
|
|
|
__skb_queue_head(&local->pending[q],
|
|
|
|
skb);
|
|
|
|
else
|
|
|
|
__skb_queue_tail(&local->pending[q],
|
|
|
|
skb);
|
|
|
|
} while ((skb = next));
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
|
|
|
|
flags);
|
|
|
|
return false;
|
|
|
|
}
|
2009-06-17 23:43:56 +08:00
|
|
|
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
2008-07-24 23:46:44 +08:00
|
|
|
|
2009-03-24 00:28:36 +08:00
|
|
|
info = IEEE80211_SKB_CB(skb);
|
|
|
|
|
|
|
|
if (fragm)
|
2008-10-21 18:40:02 +08:00
|
|
|
info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
|
2008-05-15 18:55:29 +08:00
|
|
|
IEEE80211_TX_CTL_FIRST_FRAGMENT);
|
2009-03-24 00:28:36 +08:00
|
|
|
|
2009-03-24 00:28:35 +08:00
|
|
|
next = skb->next;
|
2009-03-24 00:28:40 +08:00
|
|
|
len = skb->len;
|
2009-07-14 06:33:34 +08:00
|
|
|
|
2009-08-07 22:42:15 +08:00
|
|
|
if (next)
|
|
|
|
info->flags |= IEEE80211_TX_CTL_MORE_FRAMES;
|
|
|
|
|
2009-07-14 06:33:34 +08:00
|
|
|
sdata = vif_to_sdata(info->control.vif);
|
|
|
|
|
|
|
|
switch (sdata->vif.type) {
|
|
|
|
case NL80211_IFTYPE_MONITOR:
|
|
|
|
info->control.vif = NULL;
|
|
|
|
break;
|
|
|
|
case NL80211_IFTYPE_AP_VLAN:
|
|
|
|
info->control.vif = &container_of(sdata->bss,
|
|
|
|
struct ieee80211_sub_if_data, u.ap)->vif;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* keep */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-07-22 23:11:28 +08:00
|
|
|
if (sta && sta->uploaded)
|
|
|
|
info->control.sta = &sta->sta;
|
|
|
|
else
|
|
|
|
info->control.sta = NULL;
|
|
|
|
|
2010-11-30 15:58:45 +08:00
|
|
|
fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
|
2011-02-24 21:42:06 +08:00
|
|
|
drv_tx(local, skb);
|
2009-07-25 07:57:25 +08:00
|
|
|
|
2010-11-30 15:58:45 +08:00
|
|
|
ieee80211_tpt_led_trig_tx(local, fc, len);
|
2009-03-24 00:28:38 +08:00
|
|
|
*skbp = skb = next;
|
2009-03-24 00:28:35 +08:00
|
|
|
ieee80211_led_tx(local, 1);
|
|
|
|
fragm = true;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
2009-03-24 00:28:35 +08:00
|
|
|
|
2011-02-24 21:42:06 +08:00
|
|
|
return true;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-06-20 07:22:30 +08:00
|
|
|
/*
|
|
|
|
* 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 sk_buff *skb = tx->skb;
|
2010-01-17 08:47:59 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
2008-06-20 07:22:30 +08:00
|
|
|
ieee80211_tx_result res = TX_DROP;
|
|
|
|
|
2009-10-29 15:43:48 +08:00
|
|
|
#define CALL_TXH(txh) \
|
|
|
|
do { \
|
|
|
|
res = txh(tx); \
|
|
|
|
if (res != TX_CONTINUE) \
|
|
|
|
goto txh_done; \
|
|
|
|
} while (0)
|
|
|
|
|
2010-01-12 16:42:46 +08:00
|
|
|
CALL_TXH(ieee80211_tx_h_dynamic_ps);
|
2009-10-29 15:43:48 +08:00
|
|
|
CALL_TXH(ieee80211_tx_h_check_assoc);
|
|
|
|
CALL_TXH(ieee80211_tx_h_ps_buf);
|
2010-08-27 19:26:54 +08:00
|
|
|
CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
|
2009-10-29 15:43:48 +08:00
|
|
|
CALL_TXH(ieee80211_tx_h_select_key);
|
2009-11-18 01:18:36 +08:00
|
|
|
if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
|
|
|
|
CALL_TXH(ieee80211_tx_h_rate_ctrl);
|
2010-01-17 08:47:59 +08:00
|
|
|
|
|
|
|
if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION))
|
|
|
|
goto txh_done;
|
|
|
|
|
|
|
|
CALL_TXH(ieee80211_tx_h_michael_mic_add);
|
2009-10-29 15:43:48 +08:00
|
|
|
CALL_TXH(ieee80211_tx_h_sequence);
|
|
|
|
CALL_TXH(ieee80211_tx_h_fragment);
|
2008-06-30 21:10:44 +08:00
|
|
|
/* handlers after fragment must be aware of tx info fragmentation! */
|
2009-10-29 15:43:48 +08:00
|
|
|
CALL_TXH(ieee80211_tx_h_stats);
|
|
|
|
CALL_TXH(ieee80211_tx_h_encrypt);
|
2011-02-01 04:29:12 +08:00
|
|
|
if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
|
|
|
|
CALL_TXH(ieee80211_tx_h_calculate_duration);
|
2008-06-30 21:10:44 +08:00
|
|
|
#undef CALL_TXH
|
2008-06-20 07:22:30 +08:00
|
|
|
|
2008-06-30 21:10:44 +08:00
|
|
|
txh_done:
|
2008-06-20 07:22:30 +08:00
|
|
|
if (unlikely(res == TX_DROP)) {
|
2008-06-28 08:15:03 +08:00
|
|
|
I802_DEBUG_INC(tx->local->tx_handlers_drop);
|
2009-03-24 00:28:35 +08:00
|
|
|
while (skb) {
|
|
|
|
struct sk_buff *next;
|
|
|
|
|
|
|
|
next = skb->next;
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
skb = next;
|
|
|
|
}
|
2008-06-20 07:22:30 +08:00
|
|
|
return -1;
|
|
|
|
} else if (unlikely(res == TX_QUEUED)) {
|
2008-06-28 08:15:03 +08:00
|
|
|
I802_DEBUG_INC(tx->local->tx_handlers_queued);
|
2008-06-20 07:22:30 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-02-24 21:42:06 +08:00
|
|
|
/*
|
|
|
|
* Returns false if the frame couldn't be transmitted but was queued instead.
|
|
|
|
*/
|
|
|
|
static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
2009-06-17 23:43:56 +08:00
|
|
|
struct sk_buff *skb, bool txpending)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2009-06-17 23:43:56 +08:00
|
|
|
struct ieee80211_local *local = sdata->local;
|
2008-02-25 23:27:43 +08:00
|
|
|
struct ieee80211_tx_data tx;
|
2008-06-20 07:22:30 +08:00
|
|
|
ieee80211_tx_result res_prepare;
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
2011-02-24 21:42:06 +08:00
|
|
|
bool result = true;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
if (unlikely(skb->len < 10)) {
|
|
|
|
dev_kfree_skb(skb);
|
2011-02-24 21:42:06 +08:00
|
|
|
return true;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-02-25 23:27:46 +08:00
|
|
|
rcu_read_lock();
|
|
|
|
|
2007-09-26 23:53:18 +08:00
|
|
|
/* initialises tx */
|
2009-06-17 23:43:56 +08:00
|
|
|
res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-03-24 00:28:41 +08:00
|
|
|
if (unlikely(res_prepare == TX_DROP)) {
|
2007-07-27 21:43:22 +08:00
|
|
|
dev_kfree_skb(skb);
|
2011-02-24 21:42:06 +08:00
|
|
|
goto out;
|
2009-03-24 00:28:41 +08:00
|
|
|
} else if (unlikely(res_prepare == TX_QUEUED)) {
|
2011-02-24 21:42:06 +08:00
|
|
|
goto out;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-02-25 23:27:43 +08:00
|
|
|
tx.channel = local->hw.conf.channel;
|
2008-05-15 18:55:29 +08:00
|
|
|
info->band = tx.channel->band;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2011-02-24 21:42:06 +08:00
|
|
|
if (!invoke_tx_handlers(&tx))
|
|
|
|
result = __ieee80211_tx(local, &tx.skb, tx.sta, txpending);
|
2008-06-20 07:22:30 +08:00
|
|
|
out:
|
[MAC80211]: fix race conditions with keys
During receive processing, we select the key long before using it and
because there's no locking it is possible that we kfree() the key
after having selected it but before using it for crypto operations.
Obviously, this is bad.
Secondly, during transmit processing, there are two possible races: We
have a similar race between select_key() and using it for encryption,
but we also have a race here between select_key() and hardware
encryption (both when a key is removed.)
This patch solves these issues by using RCU: when a key is to be freed,
we first remove the pointer from the appropriate places (sdata->keys,
sdata->default_key, sta->key) using rcu_assign_pointer() and then
synchronize_rcu(). Then, we can safely kfree() the key and remove it
from the hardware. There's a window here where the hardware may still
be using it for decryption, but we can't work around that without having
two hardware callbacks, one to disable the key for RX and one to disable
it for TX; but the worst thing that will happen is that we receive a
packet decrypted that we don't find a key for any more and then drop it.
When we add a key, we first need to upload it to the hardware and then,
using rcu_assign_pointer() again, link it into our structures.
In the code using keys (TX/RX paths) we use rcu_dereference() to get the
key and enclose the whole tx/rx section in a rcu_read_lock() ...
rcu_read_unlock() block. Because we've uploaded the key to hardware
before linking it into internal structures, we can guarantee that it is
valid once get to into tx().
One possible race condition remains, however: when we have hardware
acceleration enabled and the driver shuts down the queues, we end up
queueing the frame. If now somebody removes the key, the key will be
removed from hwaccel and then then driver will be asked to encrypt the
frame with a key index that has been removed. Hence, drivers will need
to be aware that the hw_key_index they are passed might not be under
all circumstances. Most drivers will, however, simply ignore that
condition and encrypt the frame with the selected key anyway, this
only results in a frame being encrypted with a wrong key or dropped
(rightfully) because the key was not valid. There isn't much we can
do about it unless we want to walk the pending frame queue every time
a key is removed and remove all frames that used it.
This race condition, however, will most likely be solved once we add
multiqueue support to mac80211 because then frames will be queued
further up the stack instead of after being processed.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-09-14 23:10:24 +08:00
|
|
|
rcu_read_unlock();
|
2011-02-24 21:42:06 +08:00
|
|
|
return result;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* device xmit handlers */
|
|
|
|
|
2008-05-29 16:38:53 +08:00
|
|
|
static int ieee80211_skb_resize(struct ieee80211_local *local,
|
|
|
|
struct sk_buff *skb,
|
|
|
|
int head_need, bool may_encrypt)
|
|
|
|
{
|
|
|
|
int tail_need = 0;
|
|
|
|
|
2011-04-27 21:10:29 +08:00
|
|
|
if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) {
|
2008-05-29 16:38:53 +08:00
|
|
|
tail_need = IEEE80211_ENCRYPT_TAILROOM;
|
|
|
|
tail_need -= skb_tailroom(skb);
|
|
|
|
tail_need = max_t(int, tail_need, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (head_need || tail_need) {
|
|
|
|
/* Sorry. Can't account for this any more */
|
|
|
|
skb_orphan(skb);
|
|
|
|
}
|
|
|
|
|
2011-02-07 19:05:00 +08:00
|
|
|
if (skb_cloned(skb))
|
2008-05-29 16:38:53 +08:00
|
|
|
I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
|
2010-12-19 02:30:49 +08:00
|
|
|
else if (head_need || tail_need)
|
2008-05-29 16:38:53 +08:00
|
|
|
I802_DEBUG_INC(local->tx_expand_skb_head);
|
2010-12-19 02:30:49 +08:00
|
|
|
else
|
|
|
|
return 0;
|
2008-05-29 16:38:53 +08:00
|
|
|
|
|
|
|
if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
|
2010-08-21 07:25:38 +08:00
|
|
|
wiphy_debug(local->hw.wiphy,
|
|
|
|
"failed to reallocate TX buffer\n");
|
2008-05-29 16:38:53 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update truesize too */
|
|
|
|
skb->truesize += head_need + tail_need;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
|
|
|
struct sk_buff *skb)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2009-06-17 23:43:56 +08:00
|
|
|
struct ieee80211_local *local = sdata->local;
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
2008-08-06 01:34:52 +08:00
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
2009-06-17 23:43:56 +08:00
|
|
|
struct ieee80211_sub_if_data *tmp_sdata;
|
2007-07-27 21:43:22 +08:00
|
|
|
int headroom;
|
2008-05-29 16:38:53 +08:00
|
|
|
bool may_encrypt;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-11-17 06:20:41 +08:00
|
|
|
rcu_read_lock();
|
|
|
|
|
2009-08-11 08:29:29 +08:00
|
|
|
if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
|
2008-09-13 04:52:47 +08:00
|
|
|
int hdrlen;
|
|
|
|
u16 len_rthdr;
|
|
|
|
|
2010-02-01 04:56:25 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_INJECTED |
|
|
|
|
IEEE80211_TX_INTFL_HAS_RADIOTAP;
|
2008-09-13 04:52:47 +08:00
|
|
|
|
|
|
|
len_rthdr = ieee80211_get_radiotap_len(skb->data);
|
2009-07-11 04:42:29 +08:00
|
|
|
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
|
2008-09-13 04:52:47 +08:00
|
|
|
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
|
|
|
|
|
|
|
/* check the header is complete in the frame */
|
|
|
|
if (likely(skb->len >= len_rthdr + hdrlen)) {
|
|
|
|
/*
|
|
|
|
* We process outgoing injected frames that have a
|
|
|
|
* local address we handle as though they are our
|
|
|
|
* own frames.
|
|
|
|
* This code here isn't entirely correct, the local
|
|
|
|
* MAC address is not necessarily enough to find
|
|
|
|
* the interface to use; for that proper VLAN/WDS
|
|
|
|
* support we will need a different mechanism.
|
|
|
|
*/
|
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
|
2008-09-13 04:52:47 +08:00
|
|
|
list) {
|
2009-12-23 20:15:31 +08:00
|
|
|
if (!ieee80211_sdata_running(tmp_sdata))
|
2008-09-13 04:52:47 +08:00
|
|
|
continue;
|
2010-11-27 02:41:55 +08:00
|
|
|
if (tmp_sdata->vif.type ==
|
|
|
|
NL80211_IFTYPE_MONITOR ||
|
|
|
|
tmp_sdata->vif.type ==
|
|
|
|
NL80211_IFTYPE_AP_VLAN ||
|
|
|
|
tmp_sdata->vif.type ==
|
|
|
|
NL80211_IFTYPE_WDS)
|
2009-02-06 07:27:32 +08:00
|
|
|
continue;
|
2009-11-26 00:46:19 +08:00
|
|
|
if (compare_ether_addr(tmp_sdata->vif.addr,
|
2009-10-25 02:55:09 +08:00
|
|
|
hdr->addr2) == 0) {
|
2009-06-17 23:43:56 +08:00
|
|
|
sdata = tmp_sdata;
|
2008-09-13 04:52:47 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-08-06 01:34:52 +08:00
|
|
|
}
|
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT);
|
2008-05-29 16:38:53 +08:00
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
headroom = local->tx_headroom;
|
2008-05-29 16:38:53 +08:00
|
|
|
if (may_encrypt)
|
|
|
|
headroom += IEEE80211_ENCRYPT_HEADROOM;
|
|
|
|
headroom -= skb_headroom(skb);
|
|
|
|
headroom = max_t(int, 0, headroom);
|
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) {
|
2008-05-29 16:38:53 +08:00
|
|
|
dev_kfree_skb(skb);
|
2009-11-17 06:20:41 +08:00
|
|
|
rcu_read_unlock();
|
2009-06-17 23:43:56 +08:00
|
|
|
return;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2010-09-12 11:01:31 +08:00
|
|
|
hdr = (struct ieee80211_hdr *) skb->data;
|
2009-07-14 06:33:34 +08:00
|
|
|
info->control.vif = &sdata->vif;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-08-11 08:29:29 +08:00
|
|
|
if (ieee80211_vif_is_mesh(&sdata->vif) &&
|
|
|
|
ieee80211_is_data(hdr->frame_control) &&
|
|
|
|
!is_multicast_ether_addr(hdr->addr1))
|
|
|
|
if (mesh_nexthop_lookup(skb, sdata)) {
|
|
|
|
/* skb queued: don't free */
|
2009-11-17 06:20:41 +08:00
|
|
|
rcu_read_unlock();
|
2009-08-11 08:29:29 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-01-06 01:00:58 +08:00
|
|
|
ieee80211_set_qos_hdr(local, skb);
|
2009-06-17 23:43:56 +08:00
|
|
|
ieee80211_tx(sdata, skb, false);
|
2009-11-17 06:20:41 +08:00
|
|
|
rcu_read_unlock();
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2009-09-01 03:50:57 +08:00
|
|
|
netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
|
|
|
struct net_device *dev)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
|
|
|
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
2009-01-31 01:08:29 +08:00
|
|
|
struct ieee80211_channel *chan = local->hw.conf.channel;
|
2007-07-27 21:43:22 +08:00
|
|
|
struct ieee80211_radiotap_header *prthdr =
|
|
|
|
(struct ieee80211_radiotap_header *)skb->data;
|
2009-06-17 23:43:56 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
2007-07-27 21:43:24 +08:00
|
|
|
u16 len_rthdr;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-01-31 01:08:29 +08:00
|
|
|
/*
|
|
|
|
* Frame injection is not allowed if beaconing is not allowed
|
|
|
|
* or if we need radar detection. Beaconing is usually not allowed when
|
|
|
|
* the mode or operation (Adhoc, AP, Mesh) does not support DFS.
|
|
|
|
* Passive scan is also used in world regulatory domains where
|
|
|
|
* your country is not known and as such it should be treated as
|
|
|
|
* NO TX unless the channel is explicitly allowed in which case
|
|
|
|
* your current regulatory domain would not have the passive scan
|
|
|
|
* flag.
|
|
|
|
*
|
|
|
|
* Since AP mode uses monitor interfaces to inject/TX management
|
|
|
|
* frames we can make AP mode the exception to this rule once it
|
|
|
|
* supports radar detection as its implementation can deal with
|
|
|
|
* radar detection by itself. We can do that later by adding a
|
|
|
|
* monitor flag interfaces used for AP support.
|
|
|
|
*/
|
|
|
|
if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
|
|
|
|
IEEE80211_CHAN_PASSIVE_SCAN)))
|
|
|
|
goto fail;
|
|
|
|
|
2007-07-27 21:43:24 +08:00
|
|
|
/* check for not even having the fixed radiotap header part */
|
|
|
|
if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
|
|
|
|
goto fail; /* too short to be possibly valid */
|
|
|
|
|
|
|
|
/* is it a header version we can trust to find length from? */
|
|
|
|
if (unlikely(prthdr->it_version))
|
|
|
|
goto fail; /* only version 0 is supported */
|
|
|
|
|
|
|
|
/* then there must be a radiotap header with a length we can use */
|
|
|
|
len_rthdr = ieee80211_get_radiotap_len(skb->data);
|
|
|
|
|
|
|
|
/* does the skb contain enough to deliver on the alleged length? */
|
|
|
|
if (unlikely(skb->len < len_rthdr))
|
|
|
|
goto fail; /* skb too short for claimed rt header extent */
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* fix up the pointers accounting for the radiotap
|
|
|
|
* header still being in there. We are being given
|
|
|
|
* a precooked IEEE80211 header so no need for
|
|
|
|
* normal processing
|
|
|
|
*/
|
2007-07-27 21:43:24 +08:00
|
|
|
skb_set_mac_header(skb, len_rthdr);
|
2007-07-27 21:43:22 +08:00
|
|
|
/*
|
2007-07-27 21:43:24 +08:00
|
|
|
* these are just fixed to the end of the rt area since we
|
|
|
|
* don't have any better information and at this point, nobody cares
|
2007-07-27 21:43:22 +08:00
|
|
|
*/
|
2007-07-27 21:43:24 +08:00
|
|
|
skb_set_network_header(skb, len_rthdr);
|
|
|
|
skb_set_transport_header(skb, len_rthdr);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
|
2009-11-19 08:08:30 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
/* pass the radiotap header up to xmit */
|
|
|
|
ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb);
|
2007-07-27 21:43:22 +08:00
|
|
|
return NETDEV_TX_OK;
|
2007-07-27 21:43:24 +08:00
|
|
|
|
|
|
|
fail:
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
return NETDEV_TX_OK; /* meaning, we dealt with the skb */
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
|
|
|
|
* subinterfaces (wlan#, WDS, and VLAN interfaces)
|
|
|
|
* @skb: packet to be sent
|
|
|
|
* @dev: incoming interface
|
|
|
|
*
|
|
|
|
* Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will
|
|
|
|
* not be freed, and caller is responsible for either retrying later or freeing
|
|
|
|
* skb).
|
|
|
|
*
|
|
|
|
* This function takes in an Ethernet header and encapsulates it with suitable
|
|
|
|
* IEEE 802.11 header based on which interface the packet is coming in. The
|
|
|
|
* encapsulated packet will then be passed to master interface, wlan#.11, for
|
|
|
|
* transmission (through low-level driver).
|
|
|
|
*/
|
2009-09-01 03:50:57 +08:00
|
|
|
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|
|
|
struct net_device *dev)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
2008-09-16 20:18:59 +08:00
|
|
|
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
|
|
struct ieee80211_local *local = sdata->local;
|
2010-12-19 02:30:48 +08:00
|
|
|
struct ieee80211_tx_info *info;
|
2009-06-12 14:22:29 +08:00
|
|
|
int ret = NETDEV_TX_BUSY, head_need;
|
2008-06-23 07:45:27 +08:00
|
|
|
u16 ethertype, hdrlen, meshhdrlen = 0;
|
|
|
|
__le16 fc;
|
2007-07-27 21:43:22 +08:00
|
|
|
struct ieee80211_hdr hdr;
|
2010-08-21 22:23:29 +08:00
|
|
|
struct ieee80211s_hdr mesh_hdr __maybe_unused;
|
2011-01-15 00:07:56 +08:00
|
|
|
struct mesh_path __maybe_unused *mppath = NULL;
|
2007-07-27 21:43:22 +08:00
|
|
|
const u8 *encaps_data;
|
|
|
|
int encaps_len, skip_header_bytes;
|
2007-08-29 05:01:54 +08:00
|
|
|
int nh_pos, h_pos;
|
2009-11-11 03:10:05 +08:00
|
|
|
struct sta_info *sta = NULL;
|
2007-12-19 08:31:22 +08:00
|
|
|
u32 sta_flags = 0;
|
2010-12-03 01:44:09 +08:00
|
|
|
struct sk_buff *tmp_skb;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
if (unlikely(skb->len < ETH_HLEN)) {
|
2009-07-06 10:23:38 +08:00
|
|
|
ret = NETDEV_TX_OK;
|
2007-07-27 21:43:22 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* convert Ethernet header to proper 802.11 header (based on
|
|
|
|
* operation mode) */
|
|
|
|
ethertype = (skb->data[12] << 8) | skb->data[13];
|
2008-06-23 07:45:27 +08:00
|
|
|
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2007-12-19 08:31:27 +08:00
|
|
|
switch (sdata->vif.type) {
|
2008-09-11 06:01:58 +08:00
|
|
|
case NL80211_IFTYPE_AP_VLAN:
|
2009-11-11 03:10:05 +08:00
|
|
|
rcu_read_lock();
|
2009-11-19 18:55:19 +08:00
|
|
|
sta = rcu_dereference(sdata->u.vlan.sta);
|
2009-11-11 03:10:05 +08:00
|
|
|
if (sta) {
|
|
|
|
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
|
|
|
|
/* RA TA DA SA */
|
|
|
|
memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN);
|
2009-11-26 00:46:19 +08:00
|
|
|
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
|
2009-11-11 03:10:05 +08:00
|
|
|
memcpy(hdr.addr3, skb->data, ETH_ALEN);
|
|
|
|
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
|
|
|
|
hdrlen = 30;
|
|
|
|
sta_flags = get_sta_flags(sta);
|
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
|
|
if (sta)
|
|
|
|
break;
|
|
|
|
/* fall through */
|
|
|
|
case NL80211_IFTYPE_AP:
|
2008-06-23 07:45:27 +08:00
|
|
|
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
|
2007-07-27 21:43:22 +08:00
|
|
|
/* DA BSSID SA */
|
|
|
|
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
2009-11-26 00:46:19 +08:00
|
|
|
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
|
2007-07-27 21:43:22 +08:00
|
|
|
memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
|
|
|
|
hdrlen = 24;
|
2007-08-29 05:01:54 +08:00
|
|
|
break;
|
2008-09-11 06:01:58 +08:00
|
|
|
case NL80211_IFTYPE_WDS:
|
2008-06-23 07:45:27 +08:00
|
|
|
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
|
2007-07-27 21:43:22 +08:00
|
|
|
/* RA TA DA SA */
|
|
|
|
memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
|
2009-11-26 00:46:19 +08:00
|
|
|
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
|
2007-07-27 21:43:22 +08:00
|
|
|
memcpy(hdr.addr3, skb->data, ETH_ALEN);
|
|
|
|
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
|
|
|
|
hdrlen = 30;
|
2007-08-29 05:01:54 +08:00
|
|
|
break;
|
2008-02-23 22:17:10 +08:00
|
|
|
#ifdef CONFIG_MAC80211_MESH
|
2008-09-11 06:01:58 +08:00
|
|
|
case NL80211_IFTYPE_MESH_POINT:
|
2008-09-11 06:01:49 +08:00
|
|
|
if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
|
2008-08-06 01:34:52 +08:00
|
|
|
/* Do not send frames with mesh_ttl == 0 */
|
2008-09-11 06:01:49 +08:00
|
|
|
sdata->u.mesh.mshstats.dropped_frames_ttl++;
|
2009-07-06 10:23:38 +08:00
|
|
|
ret = NETDEV_TX_OK;
|
2008-08-06 01:34:52 +08:00
|
|
|
goto fail;
|
2008-02-23 22:17:10 +08:00
|
|
|
}
|
2010-12-29 09:28:11 +08:00
|
|
|
if (!is_multicast_ether_addr(skb->data))
|
|
|
|
mppath = mpp_path_lookup(skb->data, sdata);
|
2008-09-22 13:30:32 +08:00
|
|
|
|
2010-12-29 09:28:11 +08:00
|
|
|
/*
|
2011-01-10 14:44:23 +08:00
|
|
|
* Use address extension if it is a packet from
|
|
|
|
* another interface or if we know the destination
|
|
|
|
* is being proxied by a portal (i.e. portal address
|
|
|
|
* differs from proxied address)
|
2010-12-29 09:28:11 +08:00
|
|
|
*/
|
2009-11-26 00:46:19 +08:00
|
|
|
if (compare_ether_addr(sdata->vif.addr,
|
2010-12-29 09:28:11 +08:00
|
|
|
skb->data + ETH_ALEN) == 0 &&
|
2011-01-10 14:44:23 +08:00
|
|
|
!(mppath && compare_ether_addr(mppath->mpp, skb->data))) {
|
2009-08-11 03:15:48 +08:00
|
|
|
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
|
|
|
|
skb->data, skb->data + ETH_ALEN);
|
|
|
|
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
|
2010-12-17 09:23:34 +08:00
|
|
|
sdata, NULL, NULL);
|
2008-09-22 13:30:32 +08:00
|
|
|
} else {
|
2009-08-11 03:15:48 +08:00
|
|
|
int is_mesh_mcast = 1;
|
2009-11-17 20:34:04 +08:00
|
|
|
const u8 *mesh_da;
|
2008-09-22 13:30:32 +08:00
|
|
|
|
2009-08-11 03:15:48 +08:00
|
|
|
rcu_read_lock();
|
2008-09-22 13:30:32 +08:00
|
|
|
if (is_multicast_ether_addr(skb->data))
|
2009-08-11 03:15:48 +08:00
|
|
|
/* DA TA mSA AE:SA */
|
|
|
|
mesh_da = skb->data;
|
2008-09-22 13:30:32 +08:00
|
|
|
else {
|
2009-11-17 20:34:04 +08:00
|
|
|
static const u8 bcast[ETH_ALEN] =
|
|
|
|
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
2009-08-11 03:15:48 +08:00
|
|
|
if (mppath) {
|
|
|
|
/* RA TA mDA mSA AE:DA SA */
|
|
|
|
mesh_da = mppath->mpp;
|
|
|
|
is_mesh_mcast = 0;
|
2009-11-17 20:34:04 +08:00
|
|
|
} else {
|
2009-08-11 03:15:48 +08:00
|
|
|
/* DA TA mSA AE:SA */
|
2009-11-17 20:34:04 +08:00
|
|
|
mesh_da = bcast;
|
|
|
|
}
|
2008-09-22 13:30:32 +08:00
|
|
|
}
|
2009-08-11 03:15:48 +08:00
|
|
|
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
|
2009-11-26 00:46:19 +08:00
|
|
|
mesh_da, sdata->vif.addr);
|
2009-08-11 03:15:48 +08:00
|
|
|
rcu_read_unlock();
|
|
|
|
if (is_mesh_mcast)
|
|
|
|
meshhdrlen =
|
|
|
|
ieee80211_new_mesh_header(&mesh_hdr,
|
|
|
|
sdata,
|
|
|
|
skb->data + ETH_ALEN,
|
|
|
|
NULL);
|
|
|
|
else
|
|
|
|
meshhdrlen =
|
|
|
|
ieee80211_new_mesh_header(&mesh_hdr,
|
|
|
|
sdata,
|
|
|
|
skb->data,
|
|
|
|
skb->data + ETH_ALEN);
|
2008-09-22 13:30:32 +08:00
|
|
|
|
|
|
|
}
|
2008-02-23 22:17:10 +08:00
|
|
|
break;
|
|
|
|
#endif
|
2008-09-11 06:01:58 +08:00
|
|
|
case NL80211_IFTYPE_STATION:
|
2009-02-15 19:44:28 +08:00
|
|
|
memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
|
2010-08-27 19:26:54 +08:00
|
|
|
if (sdata->u.mgd.use_4addr &&
|
|
|
|
cpu_to_be16(ethertype) != sdata->control_port_protocol) {
|
2009-11-11 03:10:05 +08:00
|
|
|
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
|
|
|
|
/* RA TA DA SA */
|
2009-11-26 00:46:19 +08:00
|
|
|
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
|
2009-11-11 03:10:05 +08:00
|
|
|
memcpy(hdr.addr3, skb->data, ETH_ALEN);
|
|
|
|
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
|
|
|
|
hdrlen = 30;
|
|
|
|
} else {
|
|
|
|
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
|
|
|
|
/* BSSID SA DA */
|
|
|
|
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
|
|
|
memcpy(hdr.addr3, skb->data, ETH_ALEN);
|
|
|
|
hdrlen = 24;
|
|
|
|
}
|
2007-08-29 05:01:54 +08:00
|
|
|
break;
|
2008-09-11 06:01:58 +08:00
|
|
|
case NL80211_IFTYPE_ADHOC:
|
2007-07-27 21:43:22 +08:00
|
|
|
/* DA SA BSSID */
|
|
|
|
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
|
|
|
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
2009-02-15 19:44:28 +08:00
|
|
|
memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN);
|
2007-07-27 21:43:22 +08:00
|
|
|
hdrlen = 24;
|
2007-08-29 05:01:54 +08:00
|
|
|
break;
|
|
|
|
default:
|
2009-07-06 10:23:38 +08:00
|
|
|
ret = NETDEV_TX_OK;
|
2007-07-27 21:43:22 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2008-01-29 00:11:43 +08:00
|
|
|
/*
|
|
|
|
* There's no need to try to look up the destination
|
|
|
|
* if it is a multicast address (which can only happen
|
|
|
|
* in AP mode)
|
|
|
|
*/
|
|
|
|
if (!is_multicast_ether_addr(hdr.addr1)) {
|
2008-02-25 23:27:46 +08:00
|
|
|
rcu_read_lock();
|
2009-11-26 00:46:18 +08:00
|
|
|
sta = sta_info_get(sdata, hdr.addr1);
|
|
|
|
if (sta)
|
2008-05-03 07:02:02 +08:00
|
|
|
sta_flags = get_sta_flags(sta);
|
2008-02-25 23:27:46 +08:00
|
|
|
rcu_read_unlock();
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-05-03 06:59:37 +08:00
|
|
|
/* receiver and we are QoS enabled, use a QoS type frame */
|
2009-03-13 06:49:28 +08:00
|
|
|
if ((sta_flags & WLAN_STA_WME) && local->hw.queues >= 4) {
|
2008-06-23 07:45:27 +08:00
|
|
|
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
2007-12-19 08:31:22 +08:00
|
|
|
hdrlen += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-01-29 00:19:37 +08:00
|
|
|
* Drop unicast frames to unauthorised stations unless they are
|
|
|
|
* EAPOL frames from the local station.
|
2007-12-19 08:31:22 +08:00
|
|
|
*/
|
2008-08-06 01:34:52 +08:00
|
|
|
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
|
|
|
|
unlikely(!is_multicast_ether_addr(hdr.addr1) &&
|
2008-02-23 22:17:10 +08:00
|
|
|
!(sta_flags & WLAN_STA_AUTHORIZED) &&
|
2010-08-27 19:26:54 +08:00
|
|
|
!(cpu_to_be16(ethertype) == sdata->control_port_protocol &&
|
2009-11-26 00:46:19 +08:00
|
|
|
compare_ether_addr(sdata->vif.addr,
|
2007-12-19 08:31:22 +08:00
|
|
|
skb->data + ETH_ALEN) == 0))) {
|
|
|
|
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
|
|
|
if (net_ratelimit())
|
2008-10-28 06:56:10 +08:00
|
|
|
printk(KERN_DEBUG "%s: dropped frame to %pM"
|
2007-12-19 08:31:22 +08:00
|
|
|
" (unauthorized port)\n", dev->name,
|
2008-10-28 06:56:10 +08:00
|
|
|
hdr.addr1);
|
2007-12-19 08:31:22 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
|
|
|
|
|
2009-07-06 10:23:38 +08:00
|
|
|
ret = NETDEV_TX_OK;
|
2007-12-19 08:31:22 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2010-12-03 01:44:09 +08:00
|
|
|
/*
|
|
|
|
* If the skb is shared we need to obtain our own copy.
|
|
|
|
*/
|
|
|
|
if (skb_shared(skb)) {
|
|
|
|
tmp_skb = skb;
|
2010-12-19 02:30:50 +08:00
|
|
|
skb = skb_clone(skb, GFP_ATOMIC);
|
2010-12-03 01:44:09 +08:00
|
|
|
kfree_skb(tmp_skb);
|
|
|
|
|
|
|
|
if (!skb) {
|
|
|
|
ret = NETDEV_TX_OK;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-23 07:45:27 +08:00
|
|
|
hdr.frame_control = fc;
|
2007-07-27 21:43:22 +08:00
|
|
|
hdr.duration_id = 0;
|
|
|
|
hdr.seq_ctrl = 0;
|
|
|
|
|
|
|
|
skip_header_bytes = ETH_HLEN;
|
|
|
|
if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
|
|
|
|
encaps_data = bridge_tunnel_header;
|
|
|
|
encaps_len = sizeof(bridge_tunnel_header);
|
|
|
|
skip_header_bytes -= 2;
|
|
|
|
} else if (ethertype >= 0x600) {
|
|
|
|
encaps_data = rfc1042_header;
|
|
|
|
encaps_len = sizeof(rfc1042_header);
|
|
|
|
skip_header_bytes -= 2;
|
|
|
|
} else {
|
|
|
|
encaps_data = NULL;
|
|
|
|
encaps_len = 0;
|
|
|
|
}
|
|
|
|
|
2010-12-03 01:44:09 +08:00
|
|
|
nh_pos = skb_network_header(skb) - skb->data;
|
|
|
|
h_pos = skb_transport_header(skb) - skb->data;
|
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
skb_pull(skb, skip_header_bytes);
|
|
|
|
nh_pos -= skip_header_bytes;
|
|
|
|
h_pos -= skip_header_bytes;
|
|
|
|
|
2008-05-29 16:38:53 +08:00
|
|
|
head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-05-29 16:38:53 +08:00
|
|
|
/*
|
|
|
|
* So we need to modify the skb header and hence need a copy of
|
|
|
|
* that. The head_need variable above doesn't, so far, include
|
|
|
|
* the needed header space that we don't need right away. If we
|
|
|
|
* can, then we don't reallocate right now but only after the
|
|
|
|
* frame arrives at the master device (if it does...)
|
|
|
|
*
|
|
|
|
* If we cannot, however, then we will reallocate to include all
|
|
|
|
* the ever needed space. Also, if we need to reallocate it anyway,
|
|
|
|
* make it big enough for everything we may ever need.
|
|
|
|
*/
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-06-18 16:19:51 +08:00
|
|
|
if (head_need > 0 || skb_cloned(skb)) {
|
2008-05-29 16:38:53 +08:00
|
|
|
head_need += IEEE80211_ENCRYPT_HEADROOM;
|
|
|
|
head_need += local->tx_headroom;
|
|
|
|
head_need = max_t(int, 0, head_need);
|
|
|
|
if (ieee80211_skb_resize(local, skb, head_need, true))
|
2007-07-27 21:43:22 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (encaps_data) {
|
|
|
|
memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
|
|
|
|
nh_pos += encaps_len;
|
|
|
|
h_pos += encaps_len;
|
|
|
|
}
|
2007-09-14 23:10:24 +08:00
|
|
|
|
2010-06-29 19:08:06 +08:00
|
|
|
#ifdef CONFIG_MAC80211_MESH
|
2008-02-23 22:17:10 +08:00
|
|
|
if (meshhdrlen > 0) {
|
|
|
|
memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
|
|
|
|
nh_pos += meshhdrlen;
|
|
|
|
h_pos += meshhdrlen;
|
|
|
|
}
|
2010-06-29 19:08:06 +08:00
|
|
|
#endif
|
2008-02-23 22:17:10 +08:00
|
|
|
|
2008-06-23 07:45:27 +08:00
|
|
|
if (ieee80211_is_data_qos(fc)) {
|
2007-09-14 23:10:24 +08:00
|
|
|
__le16 *qos_control;
|
|
|
|
|
|
|
|
qos_control = (__le16*) skb_push(skb, 2);
|
|
|
|
memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);
|
|
|
|
/*
|
|
|
|
* Maybe we could actually set some fields here, for now just
|
|
|
|
* initialise to zero to indicate no special operation.
|
|
|
|
*/
|
|
|
|
*qos_control = 0;
|
|
|
|
} else
|
|
|
|
memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
|
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
nh_pos += hdrlen;
|
|
|
|
h_pos += hdrlen;
|
|
|
|
|
2007-08-25 02:29:34 +08:00
|
|
|
dev->stats.tx_packets++;
|
|
|
|
dev->stats.tx_bytes += skb->len;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
/* Update skb pointers to various headers since this modified frame
|
|
|
|
* is going to go through Linux networking code that may potentially
|
|
|
|
* need things like pointer to IP header. */
|
|
|
|
skb_set_mac_header(skb, 0);
|
|
|
|
skb_set_network_header(skb, nh_pos);
|
|
|
|
skb_set_transport_header(skb, h_pos);
|
|
|
|
|
2010-12-19 02:30:48 +08:00
|
|
|
info = IEEE80211_SKB_CB(skb);
|
2009-06-17 23:43:56 +08:00
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
dev->trans_start = jiffies;
|
2009-06-17 23:43:56 +08:00
|
|
|
ieee80211_xmit(sdata, skb);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-07-06 10:23:38 +08:00
|
|
|
return NETDEV_TX_OK;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
fail:
|
2009-07-06 10:23:38 +08:00
|
|
|
if (ret == NETDEV_TX_OK)
|
2007-07-27 21:43:22 +08:00
|
|
|
dev_kfree_skb(skb);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-05-17 06:57:14 +08:00
|
|
|
/*
|
|
|
|
* ieee80211_clear_tx_pending may not be called in a context where
|
|
|
|
* it is possible that it packets could come in again.
|
|
|
|
*/
|
2007-07-27 21:43:22 +08:00
|
|
|
void ieee80211_clear_tx_pending(struct ieee80211_local *local)
|
|
|
|
{
|
2009-03-24 00:28:35 +08:00
|
|
|
int i;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-03-24 00:28:37 +08:00
|
|
|
for (i = 0; i < local->hw.queues; i++)
|
|
|
|
skb_queue_purge(&local->pending[i]);
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 21:42:06 +08:00
|
|
|
/*
|
|
|
|
* Returns false if the frame couldn't be transmitted but was queued instead,
|
|
|
|
* which in this case means re-queued -- take as an indication to stop sending
|
|
|
|
* more pending frames.
|
|
|
|
*/
|
2009-03-24 00:28:41 +08:00
|
|
|
static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
|
struct ieee80211_sub_if_data *sdata;
|
|
|
|
struct sta_info *sta;
|
|
|
|
struct ieee80211_hdr *hdr;
|
2011-02-24 21:42:06 +08:00
|
|
|
bool result;
|
2009-03-24 00:28:41 +08:00
|
|
|
|
2009-07-14 06:33:34 +08:00
|
|
|
sdata = vif_to_sdata(info->control.vif);
|
2009-03-24 00:28:41 +08:00
|
|
|
|
|
|
|
if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
|
2011-02-24 21:42:06 +08:00
|
|
|
result = ieee80211_tx(sdata, skb, true);
|
2009-03-24 00:28:41 +08:00
|
|
|
} else {
|
|
|
|
hdr = (struct ieee80211_hdr *)skb->data;
|
2009-11-26 00:46:18 +08:00
|
|
|
sta = sta_info_get(sdata, hdr->addr1);
|
2009-03-24 00:28:41 +08:00
|
|
|
|
2011-02-24 21:42:06 +08:00
|
|
|
result = __ieee80211_tx(local, &skb, sta, true);
|
2009-03-24 00:28:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2008-05-17 06:57:14 +08:00
|
|
|
/*
|
2009-06-17 23:43:56 +08:00
|
|
|
* Transmit all pending packets. Called from tasklet.
|
2008-05-17 06:57:14 +08:00
|
|
|
*/
|
2007-07-27 21:43:22 +08:00
|
|
|
void ieee80211_tx_pending(unsigned long data)
|
|
|
|
{
|
|
|
|
struct ieee80211_local *local = (struct ieee80211_local *)data;
|
2010-03-23 04:42:43 +08:00
|
|
|
struct ieee80211_sub_if_data *sdata;
|
2009-03-24 00:28:37 +08:00
|
|
|
unsigned long flags;
|
2009-03-24 00:28:41 +08:00
|
|
|
int i;
|
2009-06-17 23:43:56 +08:00
|
|
|
bool txok;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2009-03-24 00:28:36 +08:00
|
|
|
rcu_read_lock();
|
2008-05-17 06:57:14 +08:00
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
2009-03-24 00:28:37 +08:00
|
|
|
for (i = 0; i < local->hw.queues; i++) {
|
|
|
|
/*
|
|
|
|
* If queue is stopped by something other than due to pending
|
|
|
|
* frames, or we have no pending frames, proceed to next queue.
|
|
|
|
*/
|
2009-06-17 23:43:56 +08:00
|
|
|
if (local->queue_stop_reasons[i] ||
|
2009-03-24 00:28:37 +08:00
|
|
|
skb_queue_empty(&local->pending[i]))
|
2007-07-27 21:43:22 +08:00
|
|
|
continue;
|
2008-05-17 06:57:14 +08:00
|
|
|
|
2009-03-24 00:28:37 +08:00
|
|
|
while (!skb_queue_empty(&local->pending[i])) {
|
2009-06-17 23:43:56 +08:00
|
|
|
struct sk_buff *skb = __skb_dequeue(&local->pending[i]);
|
2009-07-14 06:33:34 +08:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
|
|
2009-07-27 16:33:31 +08:00
|
|
|
if (WARN_ON(!info->control.vif)) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
|
|
|
|
flags);
|
|
|
|
|
|
|
|
txok = ieee80211_tx_pending_skb(local, skb);
|
|
|
|
spin_lock_irqsave(&local->queue_stop_reason_lock,
|
|
|
|
flags);
|
|
|
|
if (!txok)
|
2009-03-24 00:28:37 +08:00
|
|
|
break;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
2010-03-23 04:42:43 +08:00
|
|
|
|
|
|
|
if (skb_queue_empty(&local->pending[i]))
|
|
|
|
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
2010-08-27 19:36:49 +08:00
|
|
|
netif_wake_subqueue(sdata->dev, i);
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
2009-06-17 23:43:56 +08:00
|
|
|
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
2009-03-24 00:28:37 +08:00
|
|
|
|
2009-03-24 00:28:36 +08:00
|
|
|
rcu_read_unlock();
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* functions for drivers to get certain frames */
|
|
|
|
|
2008-12-01 19:56:55 +08:00
|
|
|
static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
|
2007-12-19 09:03:33 +08:00
|
|
|
struct sk_buff *skb,
|
|
|
|
struct beacon_data *beacon)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
|
|
|
u8 *pos, *tim;
|
|
|
|
int aid0 = 0;
|
|
|
|
int i, have_bits = 0, n1, n2;
|
|
|
|
|
|
|
|
/* Generate bitmap for TIM only if there are any STAs in power save
|
|
|
|
* mode. */
|
|
|
|
if (atomic_read(&bss->num_sta_ps) > 0)
|
|
|
|
/* in the hope that this is faster than
|
|
|
|
* checking byte-for-byte */
|
|
|
|
have_bits = !bitmap_empty((unsigned long*)bss->tim,
|
|
|
|
IEEE80211_MAX_AID+1);
|
|
|
|
|
|
|
|
if (bss->dtim_count == 0)
|
2007-12-19 09:03:33 +08:00
|
|
|
bss->dtim_count = beacon->dtim_period - 1;
|
2007-07-27 21:43:22 +08:00
|
|
|
else
|
|
|
|
bss->dtim_count--;
|
|
|
|
|
|
|
|
tim = pos = (u8 *) skb_put(skb, 6);
|
|
|
|
*pos++ = WLAN_EID_TIM;
|
|
|
|
*pos++ = 4;
|
|
|
|
*pos++ = bss->dtim_count;
|
2007-12-19 09:03:33 +08:00
|
|
|
*pos++ = beacon->dtim_period;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
|
|
|
|
aid0 = 1;
|
|
|
|
|
2011-02-01 02:48:44 +08:00
|
|
|
bss->dtim_bc_mc = aid0 == 1;
|
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
if (have_bits) {
|
|
|
|
/* Find largest even number N1 so that bits numbered 1 through
|
|
|
|
* (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits
|
|
|
|
* (N2 + 1) x 8 through 2007 are 0. */
|
|
|
|
n1 = 0;
|
|
|
|
for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
|
|
|
|
if (bss->tim[i]) {
|
|
|
|
n1 = i & 0xfe;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n2 = n1;
|
|
|
|
for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
|
|
|
|
if (bss->tim[i]) {
|
|
|
|
n2 = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Bitmap control */
|
|
|
|
*pos++ = n1 | aid0;
|
|
|
|
/* Part Virt Bitmap */
|
|
|
|
memcpy(pos, bss->tim + n1, n2 - n1 + 1);
|
|
|
|
|
|
|
|
tim[1] = n2 - n1 + 4;
|
|
|
|
skb_put(skb, n2 - n1);
|
|
|
|
} else {
|
|
|
|
*pos++ = aid0; /* Bitmap control */
|
|
|
|
*pos++ = 0; /* Part Virt Bitmap */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-29 15:30:35 +08:00
|
|
|
struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
|
|
|
struct ieee80211_vif *vif,
|
|
|
|
u16 *tim_offset, u16 *tim_length)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
|
|
|
struct ieee80211_local *local = hw_to_local(hw);
|
2008-07-09 20:40:37 +08:00
|
|
|
struct sk_buff *skb = NULL;
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_tx_info *info;
|
2007-07-27 21:43:22 +08:00
|
|
|
struct ieee80211_sub_if_data *sdata = NULL;
|
|
|
|
struct ieee80211_if_ap *ap = NULL;
|
2007-12-19 09:03:33 +08:00
|
|
|
struct beacon_data *beacon;
|
2008-01-25 02:38:38 +08:00
|
|
|
struct ieee80211_supported_band *sband;
|
2008-05-15 18:55:27 +08:00
|
|
|
enum ieee80211_band band = local->hw.conf.channel->band;
|
2009-12-29 18:59:19 +08:00
|
|
|
struct ieee80211_tx_rate_control txrc;
|
2008-01-25 02:38:38 +08:00
|
|
|
|
2008-05-15 18:55:27 +08:00
|
|
|
sband = local->hw.wiphy->bands[band];
|
2007-12-19 09:03:33 +08:00
|
|
|
|
|
|
|
rcu_read_lock();
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2007-12-19 08:31:26 +08:00
|
|
|
sdata = vif_to_sdata(vif);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2011-01-25 02:28:49 +08:00
|
|
|
if (!ieee80211_sdata_running(sdata))
|
|
|
|
goto out;
|
|
|
|
|
2009-10-29 15:30:35 +08:00
|
|
|
if (tim_offset)
|
|
|
|
*tim_offset = 0;
|
|
|
|
if (tim_length)
|
|
|
|
*tim_length = 0;
|
|
|
|
|
2008-09-11 06:01:58 +08:00
|
|
|
if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
2008-02-23 22:17:10 +08:00
|
|
|
ap = &sdata->u.ap;
|
|
|
|
beacon = rcu_dereference(ap->beacon);
|
2011-02-08 03:03:35 +08:00
|
|
|
if (beacon) {
|
2008-02-23 22:17:19 +08:00
|
|
|
/*
|
|
|
|
* headroom, head length,
|
|
|
|
* tail length and maximum TIM length
|
|
|
|
*/
|
|
|
|
skb = dev_alloc_skb(local->tx_headroom +
|
|
|
|
beacon->head_len +
|
|
|
|
beacon->tail_len + 256);
|
|
|
|
if (!skb)
|
|
|
|
goto out;
|
2008-02-23 22:17:10 +08:00
|
|
|
|
2008-02-23 22:17:19 +08:00
|
|
|
skb_reserve(skb, local->tx_headroom);
|
|
|
|
memcpy(skb_put(skb, beacon->head_len), beacon->head,
|
|
|
|
beacon->head_len);
|
2008-02-23 22:17:10 +08:00
|
|
|
|
2008-02-25 23:27:46 +08:00
|
|
|
/*
|
|
|
|
* Not very nice, but we want to allow the driver to call
|
|
|
|
* ieee80211_beacon_get() as a response to the set_tim()
|
|
|
|
* callback. That, however, is already invoked under the
|
|
|
|
* sta_lock to guarantee consistent and race-free update
|
|
|
|
* of the tim bitmap in mac80211 and the driver.
|
|
|
|
*/
|
|
|
|
if (local->tim_in_locked_section) {
|
2008-12-01 19:56:55 +08:00
|
|
|
ieee80211_beacon_add_tim(ap, skb, beacon);
|
2008-02-25 23:27:46 +08:00
|
|
|
} else {
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&local->sta_lock, flags);
|
2008-12-01 19:56:55 +08:00
|
|
|
ieee80211_beacon_add_tim(ap, skb, beacon);
|
2008-02-25 23:27:46 +08:00
|
|
|
spin_unlock_irqrestore(&local->sta_lock, flags);
|
|
|
|
}
|
2008-02-23 22:17:10 +08:00
|
|
|
|
2009-10-29 15:30:35 +08:00
|
|
|
if (tim_offset)
|
|
|
|
*tim_offset = beacon->head_len;
|
|
|
|
if (tim_length)
|
|
|
|
*tim_length = skb->len - beacon->head_len;
|
|
|
|
|
2008-02-23 22:17:19 +08:00
|
|
|
if (beacon->tail)
|
|
|
|
memcpy(skb_put(skb, beacon->tail_len),
|
|
|
|
beacon->tail, beacon->tail_len);
|
2008-07-09 20:40:37 +08:00
|
|
|
} else
|
|
|
|
goto out;
|
2008-09-11 06:01:58 +08:00
|
|
|
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
|
2009-02-15 19:44:28 +08:00
|
|
|
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
2008-07-09 20:40:37 +08:00
|
|
|
struct ieee80211_hdr *hdr;
|
2009-04-20 03:25:43 +08:00
|
|
|
struct sk_buff *presp = rcu_dereference(ifibss->presp);
|
2008-02-23 22:17:10 +08:00
|
|
|
|
2009-04-20 03:25:43 +08:00
|
|
|
if (!presp)
|
2008-07-09 20:40:37 +08:00
|
|
|
goto out;
|
|
|
|
|
2009-04-20 03:25:43 +08:00
|
|
|
skb = skb_copy(presp, GFP_ATOMIC);
|
2008-07-09 20:40:37 +08:00
|
|
|
if (!skb)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
hdr = (struct ieee80211_hdr *) skb->data;
|
2008-07-16 09:44:13 +08:00
|
|
|
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
|
|
|
IEEE80211_STYPE_BEACON);
|
2008-02-23 22:17:19 +08:00
|
|
|
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
2008-09-11 06:01:49 +08:00
|
|
|
struct ieee80211_mgmt *mgmt;
|
|
|
|
u8 *pos;
|
|
|
|
|
2011-01-18 20:45:32 +08:00
|
|
|
#ifdef CONFIG_MAC80211_MESH
|
|
|
|
if (!sdata->u.mesh.mesh_id_len)
|
|
|
|
goto out;
|
|
|
|
#endif
|
|
|
|
|
2008-02-23 22:17:19 +08:00
|
|
|
/* headroom, head length, tail length and maximum TIM length */
|
2010-12-17 09:37:49 +08:00
|
|
|
skb = dev_alloc_skb(local->tx_headroom + 400 +
|
2011-04-08 06:08:27 +08:00
|
|
|
sdata->u.mesh.ie_len);
|
2008-02-23 22:17:19 +08:00
|
|
|
if (!skb)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
skb_reserve(skb, local->hw.extra_tx_headroom);
|
|
|
|
mgmt = (struct ieee80211_mgmt *)
|
|
|
|
skb_put(skb, 24 + sizeof(mgmt->u.beacon));
|
|
|
|
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
|
2008-06-23 07:45:27 +08:00
|
|
|
mgmt->frame_control =
|
|
|
|
cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
|
2008-02-23 22:17:19 +08:00
|
|
|
memset(mgmt->da, 0xff, ETH_ALEN);
|
2009-11-26 00:46:19 +08:00
|
|
|
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
|
|
|
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
2008-02-23 22:17:19 +08:00
|
|
|
mgmt->u.beacon.beacon_int =
|
2009-04-23 22:10:04 +08:00
|
|
|
cpu_to_le16(sdata->vif.bss_conf.beacon_int);
|
2008-02-23 22:17:19 +08:00
|
|
|
mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
|
|
|
|
|
|
|
|
pos = skb_put(skb, 2);
|
|
|
|
*pos++ = WLAN_EID_SSID;
|
|
|
|
*pos++ = 0x0;
|
|
|
|
|
2008-08-03 08:04:37 +08:00
|
|
|
mesh_mgmt_ies_add(skb, sdata);
|
2008-07-09 20:40:37 +08:00
|
|
|
} else {
|
|
|
|
WARN_ON(1);
|
2007-12-19 09:03:33 +08:00
|
|
|
goto out;
|
2007-07-27 21:43:22 +08:00
|
|
|
}
|
|
|
|
|
2008-05-15 18:55:29 +08:00
|
|
|
info = IEEE80211_SKB_CB(skb);
|
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
2009-12-29 18:59:19 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
2008-05-15 18:55:29 +08:00
|
|
|
info->band = band;
|
2009-12-29 18:59:19 +08:00
|
|
|
|
|
|
|
memset(&txrc, 0, sizeof(txrc));
|
|
|
|
txrc.hw = hw;
|
|
|
|
txrc.sband = sband;
|
|
|
|
txrc.bss_conf = &sdata->vif.bss_conf;
|
|
|
|
txrc.skb = skb;
|
|
|
|
txrc.reported_rate.idx = -1;
|
2010-01-06 19:09:08 +08:00
|
|
|
txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
|
|
|
|
if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
|
|
|
|
txrc.max_rate_idx = -1;
|
|
|
|
else
|
|
|
|
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
|
2010-11-11 22:07:23 +08:00
|
|
|
txrc.bss = true;
|
2009-12-29 18:59:19 +08:00
|
|
|
rate_control_get_rate(sdata, NULL, &txrc);
|
2008-05-15 18:55:29 +08:00
|
|
|
|
|
|
|
info->control.vif = vif;
|
2008-07-10 17:21:26 +08:00
|
|
|
|
2010-05-07 02:45:17 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT |
|
|
|
|
IEEE80211_TX_CTL_ASSIGN_SEQ |
|
|
|
|
IEEE80211_TX_CTL_FIRST_FRAGMENT;
|
2008-10-21 18:40:02 +08:00
|
|
|
out:
|
2007-12-19 09:03:33 +08:00
|
|
|
rcu_read_unlock();
|
2007-07-27 21:43:22 +08:00
|
|
|
return skb;
|
|
|
|
}
|
2009-10-29 15:30:35 +08:00
|
|
|
EXPORT_SYMBOL(ieee80211_beacon_get_tim);
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2010-01-06 02:16:19 +08:00
|
|
|
struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
|
|
|
|
struct ieee80211_vif *vif)
|
|
|
|
{
|
|
|
|
struct ieee80211_sub_if_data *sdata;
|
|
|
|
struct ieee80211_if_managed *ifmgd;
|
|
|
|
struct ieee80211_pspoll *pspoll;
|
|
|
|
struct ieee80211_local *local;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
sdata = vif_to_sdata(vif);
|
|
|
|
ifmgd = &sdata->u.mgd;
|
|
|
|
local = sdata->local;
|
|
|
|
|
|
|
|
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
|
|
|
|
if (!skb) {
|
|
|
|
printk(KERN_DEBUG "%s: failed to allocate buffer for "
|
|
|
|
"pspoll template\n", sdata->name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
skb_reserve(skb, local->hw.extra_tx_headroom);
|
|
|
|
|
|
|
|
pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
|
|
|
|
memset(pspoll, 0, sizeof(*pspoll));
|
|
|
|
pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
|
|
|
|
IEEE80211_STYPE_PSPOLL);
|
|
|
|
pspoll->aid = cpu_to_le16(ifmgd->aid);
|
|
|
|
|
|
|
|
/* aid in PS-Poll has its two MSBs each set to 1 */
|
|
|
|
pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
|
|
|
|
|
|
|
|
memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
|
|
|
|
memcpy(pspoll->ta, vif->addr, ETH_ALEN);
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ieee80211_pspoll_get);
|
|
|
|
|
|
|
|
struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
|
|
|
|
struct ieee80211_vif *vif)
|
|
|
|
{
|
|
|
|
struct ieee80211_hdr_3addr *nullfunc;
|
|
|
|
struct ieee80211_sub_if_data *sdata;
|
|
|
|
struct ieee80211_if_managed *ifmgd;
|
|
|
|
struct ieee80211_local *local;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
sdata = vif_to_sdata(vif);
|
|
|
|
ifmgd = &sdata->u.mgd;
|
|
|
|
local = sdata->local;
|
|
|
|
|
|
|
|
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc));
|
|
|
|
if (!skb) {
|
|
|
|
printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
|
|
|
|
"template\n", sdata->name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
skb_reserve(skb, local->hw.extra_tx_headroom);
|
|
|
|
|
|
|
|
nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb,
|
|
|
|
sizeof(*nullfunc));
|
|
|
|
memset(nullfunc, 0, sizeof(*nullfunc));
|
|
|
|
nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
|
|
|
IEEE80211_STYPE_NULLFUNC |
|
|
|
|
IEEE80211_FCTL_TODS);
|
|
|
|
memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN);
|
|
|
|
memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
|
|
|
|
memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN);
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ieee80211_nullfunc_get);
|
|
|
|
|
2010-01-06 02:16:38 +08:00
|
|
|
struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
|
|
|
|
struct ieee80211_vif *vif,
|
|
|
|
const u8 *ssid, size_t ssid_len,
|
|
|
|
const u8 *ie, size_t ie_len)
|
|
|
|
{
|
|
|
|
struct ieee80211_sub_if_data *sdata;
|
|
|
|
struct ieee80211_local *local;
|
|
|
|
struct ieee80211_hdr_3addr *hdr;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
size_t ie_ssid_len;
|
|
|
|
u8 *pos;
|
|
|
|
|
|
|
|
sdata = vif_to_sdata(vif);
|
|
|
|
local = sdata->local;
|
|
|
|
ie_ssid_len = 2 + ssid_len;
|
|
|
|
|
|
|
|
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) +
|
|
|
|
ie_ssid_len + ie_len);
|
|
|
|
if (!skb) {
|
|
|
|
printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
|
|
|
|
"request template\n", sdata->name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
skb_reserve(skb, local->hw.extra_tx_headroom);
|
|
|
|
|
|
|
|
hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
|
|
|
|
memset(hdr, 0, sizeof(*hdr));
|
|
|
|
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
|
|
|
IEEE80211_STYPE_PROBE_REQ);
|
|
|
|
memset(hdr->addr1, 0xff, ETH_ALEN);
|
|
|
|
memcpy(hdr->addr2, vif->addr, ETH_ALEN);
|
|
|
|
memset(hdr->addr3, 0xff, ETH_ALEN);
|
|
|
|
|
|
|
|
pos = skb_put(skb, ie_ssid_len);
|
|
|
|
*pos++ = WLAN_EID_SSID;
|
|
|
|
*pos++ = ssid_len;
|
|
|
|
if (ssid)
|
|
|
|
memcpy(pos, ssid, ssid_len);
|
|
|
|
pos += ssid_len;
|
|
|
|
|
|
|
|
if (ie) {
|
|
|
|
pos = skb_put(skb, ie_len);
|
|
|
|
memcpy(pos, ie, ie_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ieee80211_probereq_get);
|
|
|
|
|
2007-12-19 08:31:26 +08:00
|
|
|
void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
2007-07-27 21:43:22 +08:00
|
|
|
const void *frame, size_t frame_len,
|
2008-05-15 18:55:29 +08:00
|
|
|
const struct ieee80211_tx_info *frame_txctl,
|
2007-07-27 21:43:22 +08:00
|
|
|
struct ieee80211_rts *rts)
|
|
|
|
{
|
|
|
|
const struct ieee80211_hdr *hdr = frame;
|
|
|
|
|
2008-06-23 07:45:27 +08:00
|
|
|
rts->frame_control =
|
|
|
|
cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
|
2007-12-19 08:31:26 +08:00
|
|
|
rts->duration = ieee80211_rts_duration(hw, vif, frame_len,
|
|
|
|
frame_txctl);
|
2007-07-27 21:43:22 +08:00
|
|
|
memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
|
|
|
|
memcpy(rts->ta, hdr->addr2, sizeof(rts->ta));
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ieee80211_rts_get);
|
|
|
|
|
2007-12-19 08:31:26 +08:00
|
|
|
void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
2007-07-27 21:43:22 +08:00
|
|
|
const void *frame, size_t frame_len,
|
2008-05-15 18:55:29 +08:00
|
|
|
const struct ieee80211_tx_info *frame_txctl,
|
2007-07-27 21:43:22 +08:00
|
|
|
struct ieee80211_cts *cts)
|
|
|
|
{
|
|
|
|
const struct ieee80211_hdr *hdr = frame;
|
|
|
|
|
2008-06-23 07:45:27 +08:00
|
|
|
cts->frame_control =
|
|
|
|
cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
|
2007-12-19 08:31:26 +08:00
|
|
|
cts->duration = ieee80211_ctstoself_duration(hw, vif,
|
|
|
|
frame_len, frame_txctl);
|
2007-07-27 21:43:22 +08:00
|
|
|
memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ieee80211_ctstoself_get);
|
|
|
|
|
|
|
|
struct sk_buff *
|
2007-12-19 08:31:26 +08:00
|
|
|
ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_vif *vif)
|
2007-07-27 21:43:22 +08:00
|
|
|
{
|
|
|
|
struct ieee80211_local *local = hw_to_local(hw);
|
2008-05-27 22:50:51 +08:00
|
|
|
struct sk_buff *skb = NULL;
|
2008-02-25 23:27:43 +08:00
|
|
|
struct ieee80211_tx_data tx;
|
2007-07-27 21:43:22 +08:00
|
|
|
struct ieee80211_sub_if_data *sdata;
|
|
|
|
struct ieee80211_if_ap *bss = NULL;
|
2007-12-19 09:03:33 +08:00
|
|
|
struct beacon_data *beacon;
|
2008-05-15 18:55:29 +08:00
|
|
|
struct ieee80211_tx_info *info;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2007-12-19 08:31:26 +08:00
|
|
|
sdata = vif_to_sdata(vif);
|
2008-05-27 22:50:51 +08:00
|
|
|
bss = &sdata->u.ap;
|
2007-12-19 09:03:33 +08:00
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
beacon = rcu_dereference(bss->beacon);
|
|
|
|
|
2008-09-11 06:01:58 +08:00
|
|
|
if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head)
|
2008-05-27 22:50:51 +08:00
|
|
|
goto out;
|
2007-12-19 09:03:33 +08:00
|
|
|
|
2011-02-01 02:48:44 +08:00
|
|
|
if (bss->dtim_count != 0 || !bss->dtim_bc_mc)
|
2008-05-27 22:50:51 +08:00
|
|
|
goto out; /* send buffered bc/mc only after DTIM beacon */
|
2008-05-15 18:55:29 +08:00
|
|
|
|
2007-07-27 21:43:22 +08:00
|
|
|
while (1) {
|
|
|
|
skb = skb_dequeue(&bss->ps_bc_buf);
|
|
|
|
if (!skb)
|
2008-05-27 22:50:51 +08:00
|
|
|
goto out;
|
2007-07-27 21:43:22 +08:00
|
|
|
local->total_ps_buffered--;
|
|
|
|
|
|
|
|
if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
|
|
|
|
struct ieee80211_hdr *hdr =
|
|
|
|
(struct ieee80211_hdr *) skb->data;
|
|
|
|
/* more buffered multicast/broadcast frames ==> set
|
|
|
|
* MoreData flag in IEEE 802.11 header to inform PS
|
|
|
|
* STAs */
|
|
|
|
hdr->frame_control |=
|
|
|
|
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
|
|
|
}
|
|
|
|
|
2009-06-17 23:43:56 +08:00
|
|
|
if (!ieee80211_tx_prepare(sdata, &tx, skb))
|
2007-07-27 21:43:22 +08:00
|
|
|
break;
|
|
|
|
dev_kfree_skb_any(skb);
|
|
|
|
}
|
2008-05-15 18:55:29 +08:00
|
|
|
|
|
|
|
info = IEEE80211_SKB_CB(skb);
|
|
|
|
|
2008-02-25 23:27:43 +08:00
|
|
|
tx.flags |= IEEE80211_TX_PS_BUFFERED;
|
|
|
|
tx.channel = local->hw.conf.channel;
|
2008-05-15 18:55:29 +08:00
|
|
|
info->band = tx.channel->band;
|
2007-07-27 21:43:22 +08:00
|
|
|
|
2008-06-20 07:22:30 +08:00
|
|
|
if (invoke_tx_handlers(&tx))
|
2007-07-27 21:43:22 +08:00
|
|
|
skb = NULL;
|
2008-06-20 07:22:30 +08:00
|
|
|
out:
|
2008-02-25 23:27:46 +08:00
|
|
|
rcu_read_unlock();
|
2007-07-27 21:43:22 +08:00
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ieee80211_get_buffered_bc);
|
2009-06-17 23:43:56 +08:00
|
|
|
|
2009-11-19 01:42:05 +08:00
|
|
|
void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
2009-06-17 23:43:56 +08:00
|
|
|
{
|
|
|
|
skb_set_mac_header(skb, 0);
|
|
|
|
skb_set_network_header(skb, 0);
|
|
|
|
skb_set_transport_header(skb, 0);
|
|
|
|
|
2010-01-06 01:00:58 +08:00
|
|
|
/* send all internal mgmt frames on VO */
|
|
|
|
skb_set_queue_mapping(skb, 0);
|
|
|
|
|
2009-06-18 23:25:11 +08:00
|
|
|
/*
|
|
|
|
* The other path calling ieee80211_xmit is from the tasklet,
|
|
|
|
* and while we can handle concurrent transmissions locking
|
|
|
|
* requirements are that we do not come into tx with bhs on.
|
|
|
|
*/
|
|
|
|
local_bh_disable();
|
2009-06-17 23:43:56 +08:00
|
|
|
ieee80211_xmit(sdata, skb);
|
2009-06-18 23:25:11 +08:00
|
|
|
local_bh_enable();
|
2009-06-17 23:43:56 +08:00
|
|
|
}
|