aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h10
-rw-r--r--net/mac80211/cfg.c39
-rw-r--r--net/mac80211/driver-ops.h31
-rw-r--r--net/mac80211/driver-trace.h33
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/status.c4
6 files changed, 118 insertions, 0 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 96cc7ed35169..2b072fa99399 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1799,6 +1799,11 @@ enum ieee80211_ampdu_mlme_action {
1799 * ieee80211_remain_on_channel_expired(). This callback may sleep. 1799 * ieee80211_remain_on_channel_expired(). This callback may sleep.
1800 * @cancel_remain_on_channel: Requests that an ongoing off-channel period is 1800 * @cancel_remain_on_channel: Requests that an ongoing off-channel period is
1801 * aborted before it expires. This callback may sleep. 1801 * aborted before it expires. This callback may sleep.
1802 * @offchannel_tx: Transmit frame on another channel, wait for a response
1803 * and return. Reliable TX status must be reported for the frame. If the
1804 * return value is 1, then the @remain_on_channel will be used with a
1805 * regular transmission (if supported.)
1806 * @offchannel_tx_cancel_wait: cancel wait associated with offchannel TX
1802 */ 1807 */
1803struct ieee80211_ops { 1808struct ieee80211_ops {
1804 void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); 1809 void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1878,6 +1883,11 @@ struct ieee80211_ops {
1878 enum nl80211_channel_type channel_type, 1883 enum nl80211_channel_type channel_type,
1879 int duration); 1884 int duration);
1880 int (*cancel_remain_on_channel)(struct ieee80211_hw *hw); 1885 int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
1886 int (*offchannel_tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
1887 struct ieee80211_channel *chan,
1888 enum nl80211_channel_type channel_type,
1889 unsigned int wait);
1890 int (*offchannel_tx_cancel_wait)(struct ieee80211_hw *hw);
1881}; 1891};
1882 1892
1883/** 1893/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 140503d4c97a..8b436c768c4e 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,
1800 1800
1801 *cookie = (unsigned long) skb; 1801 *cookie = (unsigned long) skb;
1802 1802
1803 if (is_offchan && local->ops->offchannel_tx) {
1804 int ret;
1805
1806 IEEE80211_SKB_CB(skb)->band = chan->band;
1807
1808 mutex_lock(&local->mtx);
1809
1810 if (local->hw_offchan_tx_cookie) {
1811 mutex_unlock(&local->mtx);
1812 return -EBUSY;
1813 }
1814
1815 /* TODO: bitrate control, TX processing? */
1816 ret = drv_offchannel_tx(local, skb, chan, channel_type, wait);
1817
1818 if (ret == 0)
1819 local->hw_offchan_tx_cookie = *cookie;
1820 mutex_unlock(&local->mtx);
1821
1822 /*
1823 * Allow driver to return 1 to indicate it wants to have the
1824 * frame transmitted with a remain_on_channel + regular TX.
1825 */
1826 if (ret != 1)
1827 return ret;
1828 }
1829
1803 if (is_offchan && local->ops->remain_on_channel) { 1830 if (is_offchan && local->ops->remain_on_channel) {
1804 unsigned int duration; 1831 unsigned int duration;
1805 int ret; 1832 int ret;
@@ -1886,6 +1913,18 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
1886 1913
1887 mutex_lock(&local->mtx); 1914 mutex_lock(&local->mtx);
1888 1915
1916 if (local->ops->offchannel_tx_cancel_wait &&
1917 local->hw_offchan_tx_cookie == cookie) {
1918 ret = drv_offchannel_tx_cancel_wait(local);
1919
1920 if (!ret)
1921 local->hw_offchan_tx_cookie = 0;
1922
1923 mutex_unlock(&local->mtx);
1924
1925 return ret;
1926 }
1927
1889 if (local->ops->cancel_remain_on_channel) { 1928 if (local->ops->cancel_remain_on_channel) {
1890 cookie ^= 2; 1929 cookie ^= 2;
1891 ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); 1930 ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 32f05c1abbaf..3729296f6f95 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -495,4 +495,35 @@ static inline int drv_cancel_remain_on_channel(struct ieee80211_local *local)
495 return ret; 495 return ret;
496} 496}
497 497
498static inline int drv_offchannel_tx(struct ieee80211_local *local,
499 struct sk_buff *skb,
500 struct ieee80211_channel *chan,
501 enum nl80211_channel_type channel_type,
502 unsigned int wait)
503{
504 int ret;
505
506 might_sleep();
507
508 trace_drv_offchannel_tx(local, skb, chan, channel_type, wait);
509 ret = local->ops->offchannel_tx(&local->hw, skb, chan,
510 channel_type, wait);
511 trace_drv_return_int(local, ret);
512
513 return ret;
514}
515
516static inline int drv_offchannel_tx_cancel_wait(struct ieee80211_local *local)
517{
518 int ret;
519
520 might_sleep();
521
522 trace_drv_offchannel_tx_cancel_wait(local);
523 ret = local->ops->offchannel_tx_cancel_wait(&local->hw);
524 trace_drv_return_int(local, ret);
525
526 return ret;
527}
528
498#endif /* __MAC80211_DRIVER_OPS */ 529#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index e5cce19a7d65..520fe2444893 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -884,6 +884,39 @@ DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel,
884 TP_ARGS(local) 884 TP_ARGS(local)
885); 885);
886 886
887TRACE_EVENT(drv_offchannel_tx,
888 TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb,
889 struct ieee80211_channel *chan,
890 enum nl80211_channel_type channel_type,
891 unsigned int wait),
892
893 TP_ARGS(local, skb, chan, channel_type, wait),
894
895 TP_STRUCT__entry(
896 LOCAL_ENTRY
897 __field(int, center_freq)
898 __field(int, channel_type)
899 __field(unsigned int, wait)
900 ),
901
902 TP_fast_assign(
903 LOCAL_ASSIGN;
904 __entry->center_freq = chan->center_freq;
905 __entry->channel_type = channel_type;
906 __entry->wait = wait;
907 ),
908
909 TP_printk(
910 LOCAL_PR_FMT " freq:%dMHz, wait:%dms",
911 LOCAL_PR_ARG, __entry->center_freq, __entry->wait
912 )
913);
914
915DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
916 TP_PROTO(struct ieee80211_local *local),
917 TP_ARGS(local)
918);
919
887/* 920/*
888 * Tracing for API calls that drivers call. 921 * Tracing for API calls that drivers call.
889 */ 922 */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 0a570a111a84..a40401701424 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -957,6 +957,7 @@ struct ieee80211_local {
957 unsigned int hw_roc_duration; 957 unsigned int hw_roc_duration;
958 u32 hw_roc_cookie; 958 u32 hw_roc_cookie;
959 bool hw_roc_for_tx; 959 bool hw_roc_for_tx;
960 unsigned long hw_offchan_tx_cookie;
960 961
961 /* dummy netdev for use w/ NAPI */ 962 /* dummy netdev for use w/ NAPI */
962 struct net_device napi_dev; 963 struct net_device napi_dev;
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 865185127f51..b936dd29e92b 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -341,6 +341,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
341 cookie = local->hw_roc_cookie ^ 2; 341 cookie = local->hw_roc_cookie ^ 2;
342 local->hw_roc_skb_for_status = NULL; 342 local->hw_roc_skb_for_status = NULL;
343 } 343 }
344
345 if (cookie == local->hw_offchan_tx_cookie)
346 local->hw_offchan_tx_cookie = 0;
347
344 cfg80211_mgmt_tx_status( 348 cfg80211_mgmt_tx_status(
345 skb->dev, cookie, skb->data, skb->len, 349 skb->dev, cookie, skb->data, skb->len,
346 !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); 350 !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);