diff options
-rw-r--r-- | include/net/mac80211.h | 10 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 39 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 31 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 33 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/status.c | 4 |
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 | */ |
1803 | struct ieee80211_ops { | 1808 | struct 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 | ||
498 | static 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 | |||
516 | static 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 | ||
887 | TRACE_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 | |||
915 | DEFINE_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); |