diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-02-25 14:36:57 (GMT) |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-02-25 20:33:40 (GMT) |
commit | 5f16a43617d46cf255a66f4dc193a7f5b2540aaf (patch) | |
tree | add5e551c9d1abeee57b1fbad632a0e23bdd39b1 /net/mac80211/cfg.c | |
parent | 8628172f45c839376bf2b70bbd326d56e68dadc3 (diff) | |
download | linux-5f16a43617d46cf255a66f4dc193a7f5b2540aaf.tar.xz |
mac80211: support direct offchannel TX offload
For devices supported by iwlwifi sometimes
off-channel transmissions need to be handled
by the device completely. To support this
mac80211 needs to pass the frame directly
to the driver and not through the TX path
as the driver needs the frame and channel
information at the same time.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 140503d..8b436c7 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1800,6 +1800,33 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, *cookie = (unsigned long) skb; + if (is_offchan && local->ops->offchannel_tx) { + int ret; + + IEEE80211_SKB_CB(skb)->band = chan->band; + + mutex_lock(&local->mtx); + + if (local->hw_offchan_tx_cookie) { + mutex_unlock(&local->mtx); + return -EBUSY; + } + + /* TODO: bitrate control, TX processing? */ + ret = drv_offchannel_tx(local, skb, chan, channel_type, wait); + + if (ret == 0) + local->hw_offchan_tx_cookie = *cookie; + mutex_unlock(&local->mtx); + + /* + * Allow driver to return 1 to indicate it wants to have the + * frame transmitted with a remain_on_channel + regular TX. + */ + if (ret != 1) + return ret; + } + if (is_offchan && local->ops->remain_on_channel) { unsigned int duration; int ret; @@ -1886,6 +1913,18 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, mutex_lock(&local->mtx); + if (local->ops->offchannel_tx_cancel_wait && + local->hw_offchan_tx_cookie == cookie) { + ret = drv_offchannel_tx_cancel_wait(local); + + if (!ret) + local->hw_offchan_tx_cookie = 0; + + mutex_unlock(&local->mtx); + + return ret; + } + if (local->ops->cancel_remain_on_channel) { cookie ^= 2; ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); |