.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Off-channel operation helpers |
---|
3 | 4 | * |
---|
.. | .. |
---|
7 | 8 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
---|
8 | 9 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
---|
9 | 10 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> |
---|
10 | | - * |
---|
11 | | - * This program is free software; you can redistribute it and/or modify |
---|
12 | | - * it under the terms of the GNU General Public License version 2 as |
---|
13 | | - * published by the Free Software Foundation. |
---|
| 11 | + * Copyright (C) 2019 Intel Corporation |
---|
14 | 12 | */ |
---|
15 | 13 | #include <linux/export.h> |
---|
16 | 14 | #include <net/mac80211.h> |
---|
.. | .. |
---|
28 | 26 | { |
---|
29 | 27 | struct ieee80211_local *local = sdata->local; |
---|
30 | 28 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
31 | | - |
---|
32 | | - local->offchannel_ps_enabled = false; |
---|
| 29 | + bool offchannel_ps_enabled = false; |
---|
33 | 30 | |
---|
34 | 31 | /* FIXME: what to do when local->pspolling is true? */ |
---|
35 | 32 | |
---|
.. | .. |
---|
40 | 37 | cancel_work_sync(&local->dynamic_ps_enable_work); |
---|
41 | 38 | |
---|
42 | 39 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
---|
43 | | - local->offchannel_ps_enabled = true; |
---|
| 40 | + offchannel_ps_enabled = true; |
---|
44 | 41 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; |
---|
45 | 42 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
---|
46 | 43 | } |
---|
47 | 44 | |
---|
48 | | - if (!local->offchannel_ps_enabled || |
---|
| 45 | + if (!offchannel_ps_enabled || |
---|
49 | 46 | !ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK)) |
---|
50 | 47 | /* |
---|
51 | 48 | * If power save was enabled, no need to send a nullfunc |
---|
.. | .. |
---|
60 | 57 | ieee80211_send_nullfunc(local, sdata, true); |
---|
61 | 58 | } |
---|
62 | 59 | |
---|
63 | | -/* inform AP that we are awake again, unless power save is enabled */ |
---|
| 60 | +/* inform AP that we are awake again */ |
---|
64 | 61 | static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) |
---|
65 | 62 | { |
---|
66 | 63 | struct ieee80211_local *local = sdata->local; |
---|
67 | 64 | |
---|
68 | 65 | if (!local->ps_sdata) |
---|
69 | 66 | ieee80211_send_nullfunc(local, sdata, false); |
---|
70 | | - else if (local->offchannel_ps_enabled) { |
---|
| 67 | + else if (local->hw.conf.dynamic_ps_timeout > 0) { |
---|
71 | 68 | /* |
---|
72 | | - * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware |
---|
73 | | - * will send a nullfunc frame with the powersave bit set |
---|
74 | | - * even though the AP already knows that we are sleeping. |
---|
75 | | - * This could be avoided by sending a null frame with power |
---|
76 | | - * save bit disabled before enabling the power save, but |
---|
77 | | - * this doesn't gain anything. |
---|
78 | | - * |
---|
79 | | - * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need |
---|
80 | | - * to send a nullfunc frame because AP already knows that |
---|
81 | | - * we are sleeping, let's just enable power save mode in |
---|
82 | | - * hardware. |
---|
83 | | - */ |
---|
84 | | - /* TODO: Only set hardware if CONF_PS changed? |
---|
85 | | - * TODO: Should we set offchannel_ps_enabled to false? |
---|
86 | | - */ |
---|
87 | | - local->hw.conf.flags |= IEEE80211_CONF_PS; |
---|
88 | | - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
---|
89 | | - } else if (local->hw.conf.dynamic_ps_timeout > 0) { |
---|
90 | | - /* |
---|
91 | | - * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer |
---|
92 | | - * had been running before leaving the operating channel, |
---|
93 | | - * restart the timer now and send a nullfunc frame to inform |
---|
94 | | - * the AP that we are awake. |
---|
| 69 | + * the dynamic_ps_timer had been running before leaving the |
---|
| 70 | + * operating channel, restart the timer now and send a nullfunc |
---|
| 71 | + * frame to inform the AP that we are awake so that AP sends |
---|
| 72 | + * the buffered packets (if any). |
---|
95 | 73 | */ |
---|
96 | 74 | ieee80211_send_nullfunc(local, sdata, false); |
---|
97 | 75 | mod_timer(&local->dynamic_ps_timer, jiffies + |
---|
.. | .. |
---|
202 | 180 | cfg80211_remain_on_channel_expired(&roc->sdata->wdev, |
---|
203 | 181 | roc->cookie, roc->chan, |
---|
204 | 182 | GFP_KERNEL); |
---|
| 183 | + else |
---|
| 184 | + cfg80211_tx_mgmt_expired(&roc->sdata->wdev, |
---|
| 185 | + roc->mgmt_tx_cookie, |
---|
| 186 | + roc->chan, GFP_KERNEL); |
---|
205 | 187 | |
---|
206 | 188 | list_del(&roc->list); |
---|
207 | 189 | kfree(roc); |
---|
.. | .. |
---|
262 | 244 | if (roc->mgmt_tx_cookie) { |
---|
263 | 245 | if (!WARN_ON(!roc->frame)) { |
---|
264 | 246 | ieee80211_tx_skb_tid_band(roc->sdata, roc->frame, 7, |
---|
265 | | - roc->chan->band, 0); |
---|
| 247 | + roc->chan->band); |
---|
266 | 248 | roc->frame = NULL; |
---|
267 | 249 | } |
---|
268 | 250 | } else { |
---|
.. | .. |
---|
555 | 537 | |
---|
556 | 538 | lockdep_assert_held(&local->mtx); |
---|
557 | 539 | |
---|
| 540 | + if (channel->freq_offset) |
---|
| 541 | + /* this may work, but is untested */ |
---|
| 542 | + return -EOPNOTSUPP; |
---|
| 543 | + |
---|
558 | 544 | if (local->use_chanctx && !local->ops->remain_on_channel) |
---|
559 | 545 | return -EOPNOTSUPP; |
---|
560 | 546 | |
---|
.. | .. |
---|
731 | 717 | } |
---|
732 | 718 | |
---|
733 | 719 | if (local->ops->remain_on_channel) { |
---|
734 | | - ret = drv_cancel_remain_on_channel(local); |
---|
| 720 | + ret = drv_cancel_remain_on_channel(local, roc->sdata); |
---|
735 | 721 | if (WARN_ON_ONCE(ret)) { |
---|
736 | 722 | mutex_unlock(&local->mtx); |
---|
737 | 723 | return ret; |
---|
.. | .. |
---|
802 | 788 | if (!sdata->vif.bss_conf.ibss_joined) |
---|
803 | 789 | need_offchan = true; |
---|
804 | 790 | #ifdef CONFIG_MAC80211_MESH |
---|
805 | | - /* fall through */ |
---|
| 791 | + fallthrough; |
---|
806 | 792 | case NL80211_IFTYPE_MESH_POINT: |
---|
807 | 793 | if (ieee80211_vif_is_mesh(&sdata->vif) && |
---|
808 | 794 | !sdata->u.mesh.mesh_id_len) |
---|
809 | 795 | need_offchan = true; |
---|
810 | 796 | #endif |
---|
811 | | - /* fall through */ |
---|
| 797 | + fallthrough; |
---|
812 | 798 | case NL80211_IFTYPE_AP: |
---|
813 | 799 | case NL80211_IFTYPE_AP_VLAN: |
---|
814 | 800 | case NL80211_IFTYPE_P2P_GO: |
---|
.. | .. |
---|
910 | 896 | if (beacon) |
---|
911 | 897 | for (i = 0; i < params->n_csa_offsets; i++) |
---|
912 | 898 | data[params->csa_offsets[i]] = |
---|
913 | | - beacon->csa_current_counter; |
---|
| 899 | + beacon->cntdwn_current_counter; |
---|
914 | 900 | |
---|
915 | 901 | rcu_read_unlock(); |
---|
916 | 902 | } |
---|
.. | .. |
---|
990 | 976 | if (roc->started) { |
---|
991 | 977 | if (local->ops->remain_on_channel) { |
---|
992 | 978 | /* can race, so ignore return value */ |
---|
993 | | - drv_cancel_remain_on_channel(local); |
---|
| 979 | + drv_cancel_remain_on_channel(local, sdata); |
---|
994 | 980 | ieee80211_roc_notify_destroy(roc); |
---|
995 | 981 | } else { |
---|
996 | 982 | roc->abort = true; |
---|