^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Off-channel operation helpers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright 2004, Instant802 Networks, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright 2005, Devicescape Software, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Copyright (C) 2019 Intel Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <net/mac80211.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "ieee80211_i.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "driver-ops.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * Tell our hardware to disable PS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * Optionally inform AP that we will go to sleep so that it will buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * the frames while we are doing off-channel work. This is optional
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * because we *may* be doing work on-operating channel, and want our
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * hardware unconditionally awake, but still let the AP send us normal frames.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct ieee80211_local *local = sdata->local;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) bool offchannel_ps_enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* FIXME: what to do when local->pspolling is true? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) del_timer_sync(&local->dynamic_ps_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) del_timer_sync(&ifmgd->bcn_mon_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) del_timer_sync(&ifmgd->conn_mon_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) cancel_work_sync(&local->dynamic_ps_enable_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (local->hw.conf.flags & IEEE80211_CONF_PS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) offchannel_ps_enabled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) local->hw.conf.flags &= ~IEEE80211_CONF_PS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (!offchannel_ps_enabled ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) !ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * If power save was enabled, no need to send a nullfunc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * frame because AP knows that we are sleeping. But if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * hardware is creating the nullfunc frame for power save
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * enabled) and power save was enabled, the firmware just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * sent a null frame with power save disabled. So we need
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * to send a new nullfunc frame to inform the AP that we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * are again sleeping.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) ieee80211_send_nullfunc(local, sdata, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /* inform AP that we are awake again */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct ieee80211_local *local = sdata->local;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (!local->ps_sdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) ieee80211_send_nullfunc(local, sdata, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) else if (local->hw.conf.dynamic_ps_timeout > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * the dynamic_ps_timer had been running before leaving the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * operating channel, restart the timer now and send a nullfunc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * frame to inform the AP that we are awake so that AP sends
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * the buffered packets (if any).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ieee80211_send_nullfunc(local, sdata, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) mod_timer(&local->dynamic_ps_timer, jiffies +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ieee80211_sta_reset_beacon_monitor(sdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) ieee80211_sta_reset_conn_monitor(sdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct ieee80211_sub_if_data *sdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (WARN_ON(local->use_chanctx))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * notify the AP about us leaving the channel and stop all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * STA interfaces.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * Stop queues and transmit all frames queued by the driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * before sending nullfunc to enable powersave at the AP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) ieee80211_flush_queues(local, NULL, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) mutex_lock(&local->iflist_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) list_for_each_entry(sdata, &local->interfaces, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (!ieee80211_sdata_running(sdata))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) sdata->vif.type == NL80211_IFTYPE_NAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Check to see if we should disable beaconing. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (sdata->vif.bss_conf.enable_beacon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) set_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) &sdata->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) sdata->vif.bss_conf.enable_beacon = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ieee80211_bss_info_change_notify(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) sdata, BSS_CHANGED_BEACON_ENABLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (sdata->vif.type == NL80211_IFTYPE_STATION &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) sdata->u.mgd.associated)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ieee80211_offchannel_ps_enable(sdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) mutex_unlock(&local->iflist_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) void ieee80211_offchannel_return(struct ieee80211_local *local)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct ieee80211_sub_if_data *sdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (WARN_ON(local->use_chanctx))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) mutex_lock(&local->iflist_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) list_for_each_entry(sdata, &local->interfaces, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (!ieee80211_sdata_running(sdata))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* Tell AP we're back */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (sdata->vif.type == NL80211_IFTYPE_STATION &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) sdata->u.mgd.associated)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) ieee80211_offchannel_ps_disable(sdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) &sdata->state)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) sdata->vif.bss_conf.enable_beacon = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) ieee80211_bss_info_change_notify(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) sdata, BSS_CHANGED_BEACON_ENABLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) mutex_unlock(&local->iflist_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* was never transmitted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (roc->frame) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) cfg80211_mgmt_tx_status(&roc->sdata->wdev, roc->mgmt_tx_cookie,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) roc->frame->data, roc->frame->len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) false, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) ieee80211_free_txskb(&roc->sdata->local->hw, roc->frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (!roc->mgmt_tx_cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) cfg80211_remain_on_channel_expired(&roc->sdata->wdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) roc->cookie, roc->chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) cfg80211_tx_mgmt_expired(&roc->sdata->wdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) roc->mgmt_tx_cookie,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) roc->chan, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) list_del(&roc->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) kfree(roc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static unsigned long ieee80211_end_finished_rocs(struct ieee80211_local *local,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) unsigned long now)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) struct ieee80211_roc_work *roc, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) long remaining_dur_min = LONG_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) lockdep_assert_held(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) long remaining;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (!roc->started)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) remaining = roc->start_time +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) msecs_to_jiffies(roc->duration) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /* In case of HW ROC, it is possible that the HW finished the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * ROC session before the actual requested time. In such a case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * end the ROC session (disregarding the remaining time).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (roc->abort || roc->hw_begun || remaining <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) ieee80211_roc_notify_destroy(roc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) remaining_dur_min = min(remaining_dur_min, remaining);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return remaining_dur_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) static bool ieee80211_recalc_sw_work(struct ieee80211_local *local,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) unsigned long now)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) long dur = ieee80211_end_finished_rocs(local, now);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (dur == LONG_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) mod_delayed_work(local->workqueue, &local->roc_work, dur);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) unsigned long start_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (WARN_ON(roc->notified))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) roc->start_time = start_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) roc->started = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (roc->mgmt_tx_cookie) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (!WARN_ON(!roc->frame)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) ieee80211_tx_skb_tid_band(roc->sdata, roc->frame, 7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) roc->chan->band);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) roc->frame = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) roc->chan, roc->req_duration,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) roc->notified = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static void ieee80211_hw_roc_start(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) struct ieee80211_local *local =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) container_of(work, struct ieee80211_local, hw_roc_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) struct ieee80211_roc_work *roc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) mutex_lock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) list_for_each_entry(roc, &local->roc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (!roc->started)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) roc->hw_begun = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) ieee80211_handle_roc_started(roc, local->hw_roc_start_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) mutex_unlock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) void ieee80211_ready_on_channel(struct ieee80211_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) struct ieee80211_local *local = hw_to_local(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) local->hw_roc_start_time = jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) trace_api_ready_on_channel(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) ieee80211_queue_work(hw, &local->hw_roc_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static void _ieee80211_start_next_roc(struct ieee80211_local *local)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) struct ieee80211_roc_work *roc, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) enum ieee80211_roc_type type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) u32 min_dur, max_dur;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) lockdep_assert_held(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (WARN_ON(list_empty(&local->roc_list)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (WARN_ON(roc->started))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) min_dur = roc->duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) max_dur = roc->duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) type = roc->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) list_for_each_entry(tmp, &local->roc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (tmp == roc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (tmp->sdata != roc->sdata || tmp->chan != roc->chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) max_dur = max(tmp->duration, max_dur);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) min_dur = min(tmp->duration, min_dur);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) type = max(tmp->type, type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (local->ops->remain_on_channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) int ret = drv_remain_on_channel(local, roc->sdata, roc->chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) max_dur, type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) wiphy_warn(local->hw.wiphy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) "failed to start next HW ROC (%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) * queue the work struct again to avoid recursion
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * when multiple failures occur
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) list_for_each_entry(tmp, &local->roc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (tmp->sdata != roc->sdata ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) tmp->chan != roc->chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) tmp->started = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) tmp->abort = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) ieee80211_queue_work(&local->hw, &local->hw_roc_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) /* we'll notify about the start once the HW calls back */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) list_for_each_entry(tmp, &local->roc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (tmp->sdata != roc->sdata || tmp->chan != roc->chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) tmp->started = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) /* If actually operating on the desired channel (with at least
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * 20 MHz channel width) don't stop all the operations but still
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) * treat it as though the ROC operation started properly, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * other ROC operations won't interfere with this one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) roc->on_channel = roc->chan == local->_oper_chandef.chan &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) local->_oper_chandef.width != NL80211_CHAN_WIDTH_5 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) local->_oper_chandef.width != NL80211_CHAN_WIDTH_10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) /* start this ROC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ieee80211_recalc_idle(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (!roc->on_channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) ieee80211_offchannel_stop_vifs(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) local->tmp_channel = roc->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) ieee80211_hw_config(local, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) ieee80211_queue_delayed_work(&local->hw, &local->roc_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) msecs_to_jiffies(min_dur));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) /* tell userspace or send frame(s) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) list_for_each_entry(tmp, &local->roc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (tmp->sdata != roc->sdata || tmp->chan != roc->chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) tmp->on_channel = roc->on_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) ieee80211_handle_roc_started(tmp, jiffies);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) void ieee80211_start_next_roc(struct ieee80211_local *local)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) struct ieee80211_roc_work *roc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) lockdep_assert_held(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (list_empty(&local->roc_list)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) ieee80211_run_deferred_scan(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /* defer roc if driver is not started (i.e. during reconfig) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (local->in_reconfig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (WARN_ON_ONCE(roc->started))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (local->ops->remain_on_channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) _ieee80211_start_next_roc(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) /* delay it a bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) ieee80211_queue_delayed_work(&local->hw, &local->roc_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) round_jiffies_relative(HZ/2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) static void __ieee80211_roc_work(struct ieee80211_local *local)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) struct ieee80211_roc_work *roc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) bool on_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) lockdep_assert_held(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (WARN_ON(local->ops->remain_on_channel))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) roc = list_first_entry_or_null(&local->roc_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) struct ieee80211_roc_work, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) if (!roc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (!roc->started) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) WARN_ON(local->use_chanctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) _ieee80211_start_next_roc(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) on_channel = roc->on_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (ieee80211_recalc_sw_work(local, jiffies))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) /* careful - roc pointer became invalid during recalc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (!on_channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) ieee80211_flush_queues(local, NULL, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) local->tmp_channel = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) ieee80211_hw_config(local, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) ieee80211_offchannel_return(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) ieee80211_recalc_idle(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) ieee80211_start_next_roc(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) static void ieee80211_roc_work(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) struct ieee80211_local *local =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) container_of(work, struct ieee80211_local, roc_work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) mutex_lock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) __ieee80211_roc_work(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) mutex_unlock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) static void ieee80211_hw_roc_done(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) struct ieee80211_local *local =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) container_of(work, struct ieee80211_local, hw_roc_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) mutex_lock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) ieee80211_end_finished_rocs(local, jiffies);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) /* if there's another roc, start it now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) ieee80211_start_next_roc(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) mutex_unlock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) struct ieee80211_local *local = hw_to_local(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) trace_api_remain_on_channel_expired(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) ieee80211_queue_work(hw, &local->hw_roc_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) static bool
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) ieee80211_coalesce_hw_started_roc(struct ieee80211_local *local,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) struct ieee80211_roc_work *new_roc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) struct ieee80211_roc_work *cur_roc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) unsigned long now = jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) unsigned long remaining;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (WARN_ON(!cur_roc->started))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) /* if it was scheduled in the hardware, but not started yet,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) * we can only combine if the older one had a longer duration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) if (!cur_roc->hw_begun && new_roc->duration > cur_roc->duration)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) remaining = cur_roc->start_time +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) msecs_to_jiffies(cur_roc->duration) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) /* if it doesn't fit entirely, schedule a new one */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (new_roc->duration > jiffies_to_msecs(remaining))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) /* add just after the current one so we combine their finish later */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) list_add(&new_roc->list, &cur_roc->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) /* if the existing one has already begun then let this one also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) * begin, otherwise they'll both be marked properly by the work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) * struct that runs once the driver notifies us of the beginning
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (cur_roc->hw_begun) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) new_roc->hw_begun = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) ieee80211_handle_roc_started(new_roc, now);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) static int ieee80211_start_roc_work(struct ieee80211_local *local,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) struct ieee80211_sub_if_data *sdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) struct ieee80211_channel *channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) unsigned int duration, u64 *cookie,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) struct sk_buff *txskb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) enum ieee80211_roc_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) struct ieee80211_roc_work *roc, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) bool queued = false, combine_started = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) lockdep_assert_held(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (channel->freq_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) /* this may work, but is untested */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (local->use_chanctx && !local->ops->remain_on_channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) roc = kzalloc(sizeof(*roc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (!roc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) * If the duration is zero, then the driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) * wouldn't actually do anything. Set it to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * 10 for now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * TODO: cancel the off-channel operation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * when we get the SKB's TX status and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * the wait time was zero before.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if (!duration)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) duration = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) roc->chan = channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) roc->duration = duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) roc->req_duration = duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) roc->frame = txskb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) roc->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) roc->sdata = sdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) * cookie is either the roc cookie (for normal roc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) * or the SKB (for mgmt TX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (!txskb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) roc->cookie = ieee80211_mgmt_tx_cookie(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) *cookie = roc->cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) roc->mgmt_tx_cookie = *cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) /* if there's no need to queue, handle it immediately */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) if (list_empty(&local->roc_list) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) !local->scanning && !ieee80211_is_radar_required(local)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) /* if not HW assist, just queue & schedule work */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (!local->ops->remain_on_channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) list_add_tail(&roc->list, &local->roc_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) ieee80211_queue_delayed_work(&local->hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) &local->roc_work, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) /* otherwise actually kick it off here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) * (for error handling)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) ret = drv_remain_on_channel(local, sdata, channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) duration, type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) kfree(roc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) roc->started = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) list_add_tail(&roc->list, &local->roc_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) /* otherwise handle queueing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) list_for_each_entry(tmp, &local->roc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (tmp->chan != channel || tmp->sdata != sdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) * Extend this ROC if possible: If it hasn't started, add
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) * just after the new one to combine.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) if (!tmp->started) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) list_add(&roc->list, &tmp->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) queued = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (!combine_started)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) if (!local->ops->remain_on_channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) /* If there's no hardware remain-on-channel, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) * doing so won't push us over the maximum r-o-c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) * we allow, then we can just add the new one to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * the list and mark it as having started now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * If it would push over the limit, don't try to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * combine with other started ones (that haven't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) * been running as long) but potentially sort it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) * with others that had the same fate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) unsigned long now = jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) u32 elapsed = jiffies_to_msecs(now - tmp->start_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) struct wiphy *wiphy = local->hw.wiphy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) u32 max_roc = wiphy->max_remain_on_channel_duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) if (elapsed + roc->duration > max_roc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) combine_started = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) list_add(&roc->list, &tmp->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) queued = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) roc->on_channel = tmp->on_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) ieee80211_handle_roc_started(roc, now);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) ieee80211_recalc_sw_work(local, now);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) queued = ieee80211_coalesce_hw_started_roc(local, roc, tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) if (queued)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) /* if it wasn't queued, perhaps it can be combined with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) * another that also couldn't get combined previously,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) * but no need to check for already started ones, since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * that can't work.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) combine_started = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) if (!queued)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) list_add_tail(&roc->list, &local->roc_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) int ieee80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) struct ieee80211_channel *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) unsigned int duration, u64 *cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) struct ieee80211_local *local = sdata->local;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) mutex_lock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) ret = ieee80211_start_roc_work(local, sdata, chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) duration, cookie, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) IEEE80211_ROC_TYPE_NORMAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) mutex_unlock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) static int ieee80211_cancel_roc(struct ieee80211_local *local,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) u64 cookie, bool mgmt_tx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) struct ieee80211_roc_work *roc, *tmp, *found = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) if (!cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) flush_work(&local->hw_roc_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) mutex_lock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) if (!mgmt_tx && roc->cookie != cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) else if (mgmt_tx && roc->mgmt_tx_cookie != cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) found = roc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (!found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) mutex_unlock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) if (!found->started) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) ieee80211_roc_notify_destroy(found);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) if (local->ops->remain_on_channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) ret = drv_cancel_remain_on_channel(local, roc->sdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) if (WARN_ON_ONCE(ret)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) mutex_unlock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) /* TODO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) * if multiple items were combined here then we really shouldn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) * cancel them all - we should wait for as much time as needed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) * for the longest remaining one, and only then cancel ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if (!roc->started)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if (roc == found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) found = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) ieee80211_roc_notify_destroy(roc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) /* that really must not happen - it was started */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) WARN_ON(found);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) ieee80211_start_next_roc(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) /* go through work struct to return to the operating channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) found->abort = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) mod_delayed_work(local->workqueue, &local->roc_work, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) out_unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) mutex_unlock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) struct wireless_dev *wdev, u64 cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) struct ieee80211_local *local = sdata->local;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) return ieee80211_cancel_roc(local, cookie, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) struct cfg80211_mgmt_tx_params *params, u64 *cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) struct ieee80211_local *local = sdata->local;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) struct sta_info *sta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) const struct ieee80211_mgmt *mgmt = (void *)params->buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) bool need_offchan = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) u32 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) u8 *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) if (params->dont_wait_for_ack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) flags = IEEE80211_TX_CTL_NO_ACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) IEEE80211_TX_CTL_REQ_TX_STATUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if (params->no_cck)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) switch (sdata->vif.type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) case NL80211_IFTYPE_ADHOC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) if (!sdata->vif.bss_conf.ibss_joined)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) need_offchan = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) #ifdef CONFIG_MAC80211_MESH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) case NL80211_IFTYPE_MESH_POINT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) if (ieee80211_vif_is_mesh(&sdata->vif) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) !sdata->u.mesh.mesh_id_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) need_offchan = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) case NL80211_IFTYPE_AP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) case NL80211_IFTYPE_AP_VLAN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) case NL80211_IFTYPE_P2P_GO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) !ieee80211_vif_is_mesh(&sdata->vif) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) !rcu_access_pointer(sdata->bss->beacon))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) need_offchan = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) if (!ieee80211_is_action(mgmt->frame_control) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) mgmt->u.action.category == WLAN_CATEGORY_PUBLIC ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) sta = sta_info_get_bss(sdata, mgmt->da);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) if (!sta)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) return -ENOLINK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) case NL80211_IFTYPE_STATION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) case NL80211_IFTYPE_P2P_CLIENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) sdata_lock(sdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) if (!sdata->u.mgd.associated ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) (params->offchan && params->wait &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) local->ops->remain_on_channel &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) memcmp(sdata->u.mgd.associated->bssid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) mgmt->bssid, ETH_ALEN)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) need_offchan = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) sdata_unlock(sdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) case NL80211_IFTYPE_P2P_DEVICE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) need_offchan = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) case NL80211_IFTYPE_NAN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) /* configurations requiring offchan cannot work if no channel has been
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) * specified
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) if (need_offchan && !params->chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) mutex_lock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) /* Check if the operating channel is the requested channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) if (!need_offchan) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) struct ieee80211_chanctx_conf *chanctx_conf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) if (chanctx_conf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) need_offchan = params->chan &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) (params->chan !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) chanctx_conf->def.chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) } else if (!params->chan) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) need_offchan = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (need_offchan && !params->offchan) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) skb = dev_alloc_skb(local->hw.extra_tx_headroom + params->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) if (!skb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) skb_reserve(skb, local->hw.extra_tx_headroom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) data = skb_put_data(skb, params->buf, params->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) /* Update CSA counters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) if (sdata->vif.csa_active &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) (sdata->vif.type == NL80211_IFTYPE_AP ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) sdata->vif.type == NL80211_IFTYPE_ADHOC) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) params->n_csa_offsets) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) struct beacon_data *beacon = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) if (sdata->vif.type == NL80211_IFTYPE_AP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) beacon = rcu_dereference(sdata->u.ap.beacon);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) beacon = rcu_dereference(sdata->u.ibss.presp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) else if (ieee80211_vif_is_mesh(&sdata->vif))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) beacon = rcu_dereference(sdata->u.mesh.beacon);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) if (beacon)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) for (i = 0; i < params->n_csa_offsets; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) data[params->csa_offsets[i]] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) beacon->cntdwn_current_counter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) IEEE80211_SKB_CB(skb)->flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) skb->dev = sdata->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) if (!params->dont_wait_for_ack) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) /* make a copy to preserve the frame contents
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) * in case of encryption.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) ret = ieee80211_attach_ack_skb(local, skb, cookie, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) /* Assign a dummy non-zero cookie, it's not sent to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) * userspace in this case but we rely on its value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) * internally in the need_offchan case to distinguish
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) * mgmt-tx from remain-on-channel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) *cookie = 0xffffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) if (!need_offchan) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) ieee80211_tx_skb(sdata, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) IEEE80211_SKB_CB(skb)->hw_queue =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) local->hw.offchannel_tx_hw_queue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) /* This will handle all kinds of coalescing and immediate TX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) ret = ieee80211_start_roc_work(local, sdata, params->chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) params->wait, cookie, skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) IEEE80211_ROC_TYPE_MGMT_TX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) ieee80211_free_txskb(&local->hw, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) out_unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) mutex_unlock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) struct wireless_dev *wdev, u64 cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) struct ieee80211_local *local = wiphy_priv(wiphy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) return ieee80211_cancel_roc(local, cookie, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) void ieee80211_roc_setup(struct ieee80211_local *local)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) INIT_DELAYED_WORK(&local->roc_work, ieee80211_roc_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) INIT_LIST_HEAD(&local->roc_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) void ieee80211_roc_purge(struct ieee80211_local *local,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) struct ieee80211_sub_if_data *sdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) struct ieee80211_roc_work *roc, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) bool work_to_do = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) mutex_lock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) if (sdata && roc->sdata != sdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) if (roc->started) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) if (local->ops->remain_on_channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) /* can race, so ignore return value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) drv_cancel_remain_on_channel(local, sdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) ieee80211_roc_notify_destroy(roc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) roc->abort = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) work_to_do = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) ieee80211_roc_notify_destroy(roc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) if (work_to_do)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) __ieee80211_roc_work(local);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) mutex_unlock(&local->mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) }