You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'mac80211-next-for-davem-2015-12-07' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says: ==================== This pull request got a bit bigger than I wanted, due to needing to reshuffle and fix some bugs. I merged mac80211 to get the right base for some of these changes. * new mac80211 API for upcoming driver changes: EOSP handling, key iteration * scan abort changes allowing to cancel an ongoing scan * VHT IBSS 80+80 MHz support * re-enable full AP client state tracking after fixes * various small fixes (that weren't relevant for mac80211) * various cleanups ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -495,6 +495,9 @@ struct mac80211_hwsim_data {
|
||||
const struct ieee80211_regdomain *regd;
|
||||
|
||||
struct ieee80211_channel *tmp_chan;
|
||||
struct ieee80211_channel *roc_chan;
|
||||
u32 roc_duration;
|
||||
struct delayed_work roc_start;
|
||||
struct delayed_work roc_done;
|
||||
struct delayed_work hw_scan;
|
||||
struct cfg80211_scan_request *hw_scan_request;
|
||||
@@ -514,6 +517,7 @@ struct mac80211_hwsim_data {
|
||||
bool ps_poll_pending;
|
||||
struct dentry *debugfs;
|
||||
|
||||
uintptr_t pending_cookie;
|
||||
struct sk_buff_head pending; /* packets pending */
|
||||
/*
|
||||
* Only radios in the same group can communicate together (the
|
||||
@@ -810,6 +814,9 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb);
|
||||
struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
|
||||
|
||||
if (WARN_ON(!txrate))
|
||||
return;
|
||||
|
||||
if (!netif_running(hwsim_mon))
|
||||
return;
|
||||
|
||||
@@ -960,6 +967,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
|
||||
unsigned int hwsim_flags = 0;
|
||||
int i;
|
||||
struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES];
|
||||
uintptr_t cookie;
|
||||
|
||||
if (data->ps != PS_DISABLED)
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
@@ -1018,7 +1026,10 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
|
||||
goto nla_put_failure;
|
||||
|
||||
/* We create a cookie to identify this skb */
|
||||
if (nla_put_u64(skb, HWSIM_ATTR_COOKIE, (unsigned long) my_skb))
|
||||
data->pending_cookie++;
|
||||
cookie = data->pending_cookie;
|
||||
info->rate_driver_data[0] = (void *)cookie;
|
||||
if (nla_put_u64(skb, HWSIM_ATTR_COOKIE, cookie))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(skb, msg_head);
|
||||
@@ -1247,6 +1258,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
||||
{
|
||||
struct mac80211_hwsim_data *data = hw->priv;
|
||||
struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_channel *channel;
|
||||
bool ack;
|
||||
@@ -1292,6 +1304,22 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
||||
ARRAY_SIZE(txi->control.rates));
|
||||
|
||||
txi->rate_driver_data[0] = channel;
|
||||
|
||||
if (skb->len >= 24 + 8 &&
|
||||
ieee80211_is_probe_resp(hdr->frame_control)) {
|
||||
/* fake header transmission time */
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
struct ieee80211_rate *txrate;
|
||||
u64 ts;
|
||||
|
||||
mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
txrate = ieee80211_get_tx_rate(hw, txi);
|
||||
ts = mac80211_hwsim_get_tsf_raw();
|
||||
mgmt->u.probe_resp.timestamp =
|
||||
cpu_to_le64(ts + data->tsf_offset +
|
||||
24 * 8 * 10 / txrate->bitrate);
|
||||
}
|
||||
|
||||
mac80211_hwsim_monitor_rx(hw, skb, channel);
|
||||
|
||||
/* wmediumd mode check */
|
||||
@@ -1871,7 +1899,8 @@ static void hw_scan_work(struct work_struct *work)
|
||||
req->channels[hwsim->scan_chan_idx]->center_freq);
|
||||
|
||||
hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx];
|
||||
if (hwsim->tmp_chan->flags & IEEE80211_CHAN_NO_IR ||
|
||||
if (hwsim->tmp_chan->flags & (IEEE80211_CHAN_NO_IR |
|
||||
IEEE80211_CHAN_RADAR) ||
|
||||
!req->n_ssids) {
|
||||
dwell = 120;
|
||||
} else {
|
||||
@@ -1987,6 +2016,23 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw,
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
}
|
||||
|
||||
static void hw_roc_start(struct work_struct *work)
|
||||
{
|
||||
struct mac80211_hwsim_data *hwsim =
|
||||
container_of(work, struct mac80211_hwsim_data, roc_start.work);
|
||||
|
||||
mutex_lock(&hwsim->mutex);
|
||||
|
||||
wiphy_debug(hwsim->hw->wiphy, "hwsim ROC begins\n");
|
||||
hwsim->tmp_chan = hwsim->roc_chan;
|
||||
ieee80211_ready_on_channel(hwsim->hw);
|
||||
|
||||
ieee80211_queue_delayed_work(hwsim->hw, &hwsim->roc_done,
|
||||
msecs_to_jiffies(hwsim->roc_duration));
|
||||
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
}
|
||||
|
||||
static void hw_roc_done(struct work_struct *work)
|
||||
{
|
||||
struct mac80211_hwsim_data *hwsim =
|
||||
@@ -2014,16 +2060,14 @@ static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
hwsim->tmp_chan = chan;
|
||||
hwsim->roc_chan = chan;
|
||||
hwsim->roc_duration = duration;
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
|
||||
wiphy_debug(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n",
|
||||
chan->center_freq, duration);
|
||||
ieee80211_queue_delayed_work(hw, &hwsim->roc_start, HZ/50);
|
||||
|
||||
ieee80211_ready_on_channel(hw);
|
||||
|
||||
ieee80211_queue_delayed_work(hw, &hwsim->roc_done,
|
||||
msecs_to_jiffies(duration));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2031,6 +2075,7 @@ static int mac80211_hwsim_croc(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mac80211_hwsim_data *hwsim = hw->priv;
|
||||
|
||||
cancel_delayed_work_sync(&hwsim->roc_start);
|
||||
cancel_delayed_work_sync(&hwsim->roc_done);
|
||||
|
||||
mutex_lock(&hwsim->mutex);
|
||||
@@ -2375,6 +2420,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&data->roc_start, hw_roc_start);
|
||||
INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
|
||||
INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work);
|
||||
|
||||
@@ -2411,6 +2457,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
NL80211_FEATURE_STATIC_SMPS |
|
||||
NL80211_FEATURE_DYNAMIC_SMPS |
|
||||
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
|
||||
|
||||
/* ask mac80211 to reserve space for magic */
|
||||
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
|
||||
@@ -2710,7 +2757,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
|
||||
struct mac80211_hwsim_data *data2;
|
||||
struct ieee80211_tx_info *txi;
|
||||
struct hwsim_tx_rate *tx_attempts;
|
||||
unsigned long ret_skb_ptr;
|
||||
u64 ret_skb_cookie;
|
||||
struct sk_buff *skb, *tmp;
|
||||
const u8 *src;
|
||||
unsigned int hwsim_flags;
|
||||
@@ -2728,7 +2775,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
|
||||
|
||||
src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
|
||||
hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]);
|
||||
ret_skb_ptr = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
|
||||
ret_skb_cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
|
||||
|
||||
data2 = get_hwsim_data_ref_from_addr(src);
|
||||
if (!data2)
|
||||
@@ -2736,7 +2783,12 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
|
||||
|
||||
/* look for the skb matching the cookie passed back from user */
|
||||
skb_queue_walk_safe(&data2->pending, skb, tmp) {
|
||||
if ((unsigned long)skb == ret_skb_ptr) {
|
||||
u64 skb_cookie;
|
||||
|
||||
txi = IEEE80211_SKB_CB(skb);
|
||||
skb_cookie = (u64)(uintptr_t)txi->rate_driver_data[0];
|
||||
|
||||
if (skb_cookie == ret_skb_cookie) {
|
||||
skb_unlink(skb, &data2->pending);
|
||||
found = true;
|
||||
break;
|
||||
@@ -2827,10 +2879,25 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
||||
|
||||
/* A frame is received from user space */
|
||||
memset(&rx_status, 0, sizeof(rx_status));
|
||||
/* TODO: Check ATTR_FREQ if it exists, and maybe throw away off-channel
|
||||
* packets?
|
||||
*/
|
||||
rx_status.freq = data2->channel->center_freq;
|
||||
if (info->attrs[HWSIM_ATTR_FREQ]) {
|
||||
/* throw away off-channel packets, but allow both the temporary
|
||||
* ("hw" scan/remain-on-channel) and regular channel, since the
|
||||
* internal datapath also allows this
|
||||
*/
|
||||
mutex_lock(&data2->mutex);
|
||||
rx_status.freq = nla_get_u32(info->attrs[HWSIM_ATTR_FREQ]);
|
||||
|
||||
if (rx_status.freq != data2->channel->center_freq &&
|
||||
(!data2->tmp_chan ||
|
||||
rx_status.freq != data2->tmp_chan->center_freq)) {
|
||||
mutex_unlock(&data2->mutex);
|
||||
goto out;
|
||||
}
|
||||
mutex_unlock(&data2->mutex);
|
||||
} else {
|
||||
rx_status.freq = data2->channel->center_freq;
|
||||
}
|
||||
|
||||
rx_status.band = data2->channel->band;
|
||||
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
|
||||
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
|
||||
|
||||
@@ -2321,6 +2321,8 @@ struct cfg80211_qos_map {
|
||||
* the driver, and will be valid until passed to cfg80211_scan_done().
|
||||
* For scan results, call cfg80211_inform_bss(); you can call this outside
|
||||
* the scan/scan_done bracket too.
|
||||
* @abort_scan: Tell the driver to abort an ongoing scan. The driver shall
|
||||
* indicate the status of the scan through cfg80211_scan_done().
|
||||
*
|
||||
* @auth: Request to authenticate with the specified peer
|
||||
* (invoked with the wireless_dev mutex held)
|
||||
@@ -2593,6 +2595,7 @@ struct cfg80211_ops {
|
||||
|
||||
int (*scan)(struct wiphy *wiphy,
|
||||
struct cfg80211_scan_request *request);
|
||||
void (*abort_scan)(struct wiphy *wiphy, struct wireless_dev *wdev);
|
||||
|
||||
int (*auth)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_auth_request *req);
|
||||
@@ -5173,8 +5176,11 @@ size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
|
||||
* buffer starts, which may be @ielen if the entire (remainder)
|
||||
* of the buffer should be used.
|
||||
*/
|
||||
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
|
||||
const u8 *ids, int n_ids, size_t offset);
|
||||
static inline size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
|
||||
const u8 *ids, int n_ids, size_t offset)
|
||||
{
|
||||
return ieee80211_ie_split_ric(ies, ielen, ids, n_ids, NULL, 0, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_report_wowlan_wakeup - report wakeup from WoWLAN
|
||||
|
||||
@@ -1321,11 +1321,15 @@ struct ieee80211_channel_switch {
|
||||
* interface. This flag should be set during interface addition,
|
||||
* but may be set/cleared as late as authentication to an AP. It is
|
||||
* only valid for managed/station mode interfaces.
|
||||
* @IEEE80211_VIF_GET_NOA_UPDATE: request to handle NOA attributes
|
||||
* and send P2P_PS notification to the driver if NOA changed, even
|
||||
* this is not pure P2P vif.
|
||||
*/
|
||||
enum ieee80211_vif_flags {
|
||||
IEEE80211_VIF_BEACON_FILTER = BIT(0),
|
||||
IEEE80211_VIF_SUPPORTS_CQM_RSSI = BIT(1),
|
||||
IEEE80211_VIF_SUPPORTS_UAPSD = BIT(2),
|
||||
IEEE80211_VIF_GET_NOA_UPDATE = BIT(3),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1901,6 +1905,11 @@ struct ieee80211_txq {
|
||||
* @IEEE80211_HW_BEACON_TX_STATUS: The device/driver provides TX status
|
||||
* for sent beacons.
|
||||
*
|
||||
* @IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR: Hardware (or driver) requires that each
|
||||
* station has a unique address, i.e. each station entry can be identified
|
||||
* by just its MAC address; this prevents, for example, the same station
|
||||
* from connecting to two virtual AP interfaces at the same time.
|
||||
*
|
||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
@@ -1936,6 +1945,7 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_TDLS_WIDER_BW,
|
||||
IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
|
||||
IEEE80211_HW_BEACON_TX_STATUS,
|
||||
IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
|
||||
|
||||
/* keep last, obviously */
|
||||
NUM_IEEE80211_HW_FLAGS
|
||||
@@ -4862,6 +4872,28 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
|
||||
*/
|
||||
void ieee80211_sta_eosp(struct ieee80211_sta *pubsta);
|
||||
|
||||
/**
|
||||
* ieee80211_send_eosp_nullfunc - ask mac80211 to send NDP with EOSP
|
||||
* @pubsta: the station
|
||||
* @tid: the tid of the NDP
|
||||
*
|
||||
* Sometimes the device understands that it needs to close
|
||||
* the Service Period unexpectedly. This can happen when
|
||||
* sending frames that are filling holes in the BA window.
|
||||
* In this case, the device can ask mac80211 to send a
|
||||
* Nullfunc frame with EOSP set. When that happens, the
|
||||
* driver must have called ieee80211_sta_set_buffered() to
|
||||
* let mac80211 know that there are no buffered frames any
|
||||
* more, otherwise mac80211 will get the more_data bit wrong.
|
||||
* The low level driver must have made sure that the frame
|
||||
* will be sent despite the station being in power-save.
|
||||
* Mac80211 won't call allow_buffered_frames().
|
||||
* Note that calling this function, doesn't exempt the driver
|
||||
* from closing the EOSP properly, it will still have to call
|
||||
* ieee80211_sta_eosp when the NDP is sent.
|
||||
*/
|
||||
void ieee80211_send_eosp_nullfunc(struct ieee80211_sta *pubsta, int tid);
|
||||
|
||||
/**
|
||||
* ieee80211_iter_keys - iterate keys programmed into the device
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw()
|
||||
@@ -4889,6 +4921,30 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
|
||||
void *data),
|
||||
void *iter_data);
|
||||
|
||||
/**
|
||||
* ieee80211_iter_keys_rcu - iterate keys programmed into the device
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw()
|
||||
* @vif: virtual interface to iterate, may be %NULL for all
|
||||
* @iter: iterator function that will be called for each key
|
||||
* @iter_data: custom data to pass to the iterator function
|
||||
*
|
||||
* This function can be used to iterate all the keys known to
|
||||
* mac80211, even those that weren't previously programmed into
|
||||
* the device. Note that due to locking reasons, keys of station
|
||||
* in removal process will be skipped.
|
||||
*
|
||||
* This function requires being called in an RCU critical section,
|
||||
* and thus iter must be atomic.
|
||||
*/
|
||||
void ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
void (*iter)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key,
|
||||
void *data),
|
||||
void *iter_data);
|
||||
|
||||
/**
|
||||
* ieee80211_iter_chan_contexts_atomic - iterate channel contexts
|
||||
* @hw: pointre obtained from ieee80211_alloc_hw().
|
||||
|
||||
@@ -820,6 +820,10 @@
|
||||
* as an event to indicate changes for devices with wiphy-specific regdom
|
||||
* management.
|
||||
*
|
||||
* @NL80211_CMD_ABORT_SCAN: Stop an ongoing scan. Returns -ENOENT if a scan is
|
||||
* not running. The driver indicates the status of the scan through
|
||||
* cfg80211_scan_done().
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
@@ -1006,6 +1010,8 @@ enum nl80211_commands {
|
||||
|
||||
NL80211_CMD_WIPHY_REG_CHANGE,
|
||||
|
||||
NL80211_CMD_ABORT_SCAN,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@@ -1764,8 +1770,9 @@ enum nl80211_commands {
|
||||
* over all channels.
|
||||
*
|
||||
* @NL80211_ATTR_SCHED_SCAN_DELAY: delay before the first cycle of a
|
||||
* scheduled scan (or a WoWLAN net-detect scan) is started, u32
|
||||
* in seconds.
|
||||
* scheduled scan is started. Or the delay before a WoWLAN
|
||||
* net-detect scan is started, counting from the moment the
|
||||
* system is suspended. This value is a u32, in seconds.
|
||||
|
||||
* @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
|
||||
* is operating in an indoor environment.
|
||||
|
||||
+27
-505
File diff suppressed because it is too large
Load Diff
@@ -125,6 +125,7 @@ static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = {
|
||||
FLAG(TDLS_WIDER_BW),
|
||||
FLAG(SUPPORTS_AMSDU_IN_AMPDU),
|
||||
FLAG(BEACON_TX_STATUS),
|
||||
FLAG(NEEDS_UNIQUE_STA_ADDR),
|
||||
|
||||
/* keep last for the build bug below */
|
||||
(void *)0x1
|
||||
|
||||
@@ -428,6 +428,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
chandef.width = sdata->u.ibss.chandef.width;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
chandef = sdata->u.ibss.chandef;
|
||||
chandef.chan = cbss->channel;
|
||||
|
||||
@@ -325,19 +325,15 @@ struct mesh_preq_queue {
|
||||
|
||||
struct ieee80211_roc_work {
|
||||
struct list_head list;
|
||||
struct list_head dependents;
|
||||
|
||||
struct delayed_work work;
|
||||
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
bool started, abort, hw_begun, notified;
|
||||
bool to_be_freed;
|
||||
bool on_channel;
|
||||
|
||||
unsigned long hw_start_time;
|
||||
unsigned long start_time;
|
||||
|
||||
u32 duration, req_duration;
|
||||
struct sk_buff *frame;
|
||||
@@ -1335,6 +1331,7 @@ struct ieee80211_local {
|
||||
/*
|
||||
* Remain-on-channel support
|
||||
*/
|
||||
struct delayed_work roc_work;
|
||||
struct list_head roc_list;
|
||||
struct work_struct hw_roc_start, hw_roc_done;
|
||||
unsigned long hw_roc_start_time;
|
||||
@@ -1483,6 +1480,10 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
void ieee80211_configure_filter(struct ieee80211_local *local);
|
||||
u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
u64 ieee80211_mgmt_tx_cookie(struct ieee80211_local *local);
|
||||
int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb,
|
||||
u64 *cookie, gfp_t gfp);
|
||||
|
||||
/* STA code */
|
||||
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
||||
@@ -1577,16 +1578,22 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_local *local);
|
||||
void ieee80211_sched_scan_end(struct ieee80211_local *local);
|
||||
void ieee80211_sched_scan_stopped_work(struct work_struct *work);
|
||||
|
||||
/* off-channel helpers */
|
||||
/* off-channel/mgmt-tx */
|
||||
void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local);
|
||||
void ieee80211_offchannel_return(struct ieee80211_local *local);
|
||||
void ieee80211_roc_setup(struct ieee80211_local *local);
|
||||
void ieee80211_start_next_roc(struct ieee80211_local *local);
|
||||
void ieee80211_roc_purge(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free);
|
||||
void ieee80211_sw_roc_work(struct work_struct *work);
|
||||
void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
|
||||
int ieee80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
unsigned int duration, u64 *cookie);
|
||||
int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev, u64 cookie);
|
||||
int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params, u64 *cookie);
|
||||
int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev, u64 cookie);
|
||||
|
||||
/* channel switch handling */
|
||||
void ieee80211_csa_finalize_work(struct work_struct *work);
|
||||
|
||||
+52
-4
@@ -4,6 +4,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -320,7 +321,7 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
||||
return;
|
||||
|
||||
if (new)
|
||||
list_add_tail(&new->list, &sdata->key_list);
|
||||
list_add_tail_rcu(&new->list, &sdata->key_list);
|
||||
|
||||
WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
|
||||
|
||||
@@ -368,7 +369,7 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
if (old)
|
||||
list_del(&old->list);
|
||||
list_del_rcu(&old->list);
|
||||
}
|
||||
|
||||
struct ieee80211_key *
|
||||
@@ -592,8 +593,8 @@ static void ieee80211_key_destroy(struct ieee80211_key *key,
|
||||
return;
|
||||
|
||||
/*
|
||||
* Synchronize so the TX path can no longer be using
|
||||
* this key before we free/remove it.
|
||||
* Synchronize so the TX path and rcu key iterators
|
||||
* can no longer be using this key before we free/remove it.
|
||||
*/
|
||||
synchronize_net();
|
||||
|
||||
@@ -744,6 +745,53 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_iter_keys);
|
||||
|
||||
static void
|
||||
_ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
void (*iter)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key,
|
||||
void *data),
|
||||
void *iter_data)
|
||||
{
|
||||
struct ieee80211_key *key;
|
||||
|
||||
list_for_each_entry_rcu(key, &sdata->key_list, list) {
|
||||
/* skip keys of station in removal process */
|
||||
if (key->sta && key->sta->removed)
|
||||
continue;
|
||||
if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
|
||||
continue;
|
||||
|
||||
iter(hw, &sdata->vif,
|
||||
key->sta ? &key->sta->sta : NULL,
|
||||
&key->conf, iter_data);
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
void (*iter)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key,
|
||||
void *data),
|
||||
void *iter_data)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
if (vif) {
|
||||
sdata = vif_to_sdata(vif);
|
||||
_ieee80211_iter_keys_rcu(hw, sdata, iter, iter_data);
|
||||
} else {
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
_ieee80211_iter_keys_rcu(hw, sdata, iter, iter_data);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_iter_keys_rcu);
|
||||
|
||||
static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
|
||||
struct list_head *keys)
|
||||
{
|
||||
|
||||
+3
-1
@@ -541,7 +541,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
|
||||
NL80211_FEATURE_HT_IBSS |
|
||||
NL80211_FEATURE_VIF_TXPOWER |
|
||||
NL80211_FEATURE_MAC_ON_CREATE |
|
||||
NL80211_FEATURE_USERSPACE_MPM;
|
||||
NL80211_FEATURE_USERSPACE_MPM |
|
||||
NL80211_FEATURE_FULL_AP_CLIENT_STATE;
|
||||
|
||||
if (!ops->hw_scan)
|
||||
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
|
||||
@@ -1148,6 +1149,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
cancel_delayed_work_sync(&local->roc_work);
|
||||
cancel_work_sync(&local->restart_work);
|
||||
cancel_work_sync(&local->reconfig_filter);
|
||||
cancel_work_sync(&local->tdls_chsw_work);
|
||||
|
||||
@@ -968,8 +968,8 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
|
||||
copy = true;
|
||||
} else {
|
||||
mpath_dbg(sdata,
|
||||
"Not forwarding %p (flags %#x)\n",
|
||||
gate->mpath, gate->mpath->flags);
|
||||
"Not forwarding to %pM (flags %#x)\n",
|
||||
gate->mpath->dst, gate->mpath->flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -1930,7 +1930,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
|
||||
|
||||
if (sdata->vif.p2p) {
|
||||
if (sdata->vif.p2p ||
|
||||
sdata->vif.driver_flags & IEEE80211_VIF_GET_NOA_UPDATE) {
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
|
||||
rcu_read_lock();
|
||||
@@ -3458,7 +3459,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
|
||||
if (sdata->vif.p2p) {
|
||||
if (sdata->vif.p2p ||
|
||||
sdata->vif.driver_flags & IEEE80211_VIF_GET_NOA_UPDATE) {
|
||||
struct ieee80211_p2p_noa_attr noa = {};
|
||||
int ret;
|
||||
|
||||
|
||||
+666
-167
File diff suppressed because it is too large
Load Diff
+1
-2
@@ -661,8 +661,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
|
||||
static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
WARN_ONCE((unsigned long)rx->skb->data & 1,
|
||||
"unaligned packet at 0x%p\n", rx->skb->data);
|
||||
WARN_ON_ONCE((unsigned long)rx->skb->data & 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+118
-45
@@ -2,6 +2,7 @@
|
||||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -435,6 +436,19 @@ static int sta_info_insert_check(struct sta_info *sta)
|
||||
is_multicast_ether_addr(sta->sta.addr)))
|
||||
return -EINVAL;
|
||||
|
||||
/* Strictly speaking this isn't necessary as we hold the mutex, but
|
||||
* the rhashtable code can't really deal with that distinction. We
|
||||
* do require the mutex for correctness though.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
lockdep_assert_held(&sdata->local->sta_mtx);
|
||||
if (ieee80211_hw_check(&sdata->local->hw, NEEDS_UNIQUE_STA_ADDR) &&
|
||||
ieee80211_find_sta_by_ifaddr(&sdata->local->hw, sta->addr, NULL)) {
|
||||
rcu_read_unlock();
|
||||
return -ENOTUNIQ;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -554,14 +568,15 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
|
||||
|
||||
might_sleep();
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
err = sta_info_insert_check(sta);
|
||||
if (err) {
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
rcu_read_lock();
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
err = sta_info_insert_finish(sta);
|
||||
if (err)
|
||||
goto out_free;
|
||||
@@ -868,6 +883,7 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
|
||||
}
|
||||
|
||||
list_del_rcu(&sta->list);
|
||||
sta->removed = true;
|
||||
|
||||
drv_sta_pre_rcu_remove(local, sta->sdata, sta);
|
||||
|
||||
@@ -1230,11 +1246,11 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
}
|
||||
|
||||
static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, int tid,
|
||||
static void ieee80211_send_null_response(struct sta_info *sta, int tid,
|
||||
enum ieee80211_frame_release_type reason,
|
||||
bool call_driver)
|
||||
bool call_driver, bool more_data)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_qos_hdr *nullfunc;
|
||||
struct sk_buff *skb;
|
||||
@@ -1274,9 +1290,13 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
|
||||
if (qos) {
|
||||
nullfunc->qos_ctrl = cpu_to_le16(tid);
|
||||
|
||||
if (reason == IEEE80211_FRAME_RELEASE_UAPSD)
|
||||
if (reason == IEEE80211_FRAME_RELEASE_UAPSD) {
|
||||
nullfunc->qos_ctrl |=
|
||||
cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
|
||||
if (more_data)
|
||||
nullfunc->frame_control |=
|
||||
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||
}
|
||||
}
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
@@ -1323,22 +1343,48 @@ static int find_highest_prio_tid(unsigned long tids)
|
||||
return fls(tids) - 1;
|
||||
}
|
||||
|
||||
/* Indicates if the MORE_DATA bit should be set in the last
|
||||
* frame obtained by ieee80211_sta_ps_get_frames.
|
||||
* Note that driver_release_tids is relevant only if
|
||||
* reason = IEEE80211_FRAME_RELEASE_PSPOLL
|
||||
*/
|
||||
static bool
|
||||
ieee80211_sta_ps_more_data(struct sta_info *sta, u8 ignored_acs,
|
||||
enum ieee80211_frame_release_type reason,
|
||||
unsigned long driver_release_tids)
|
||||
{
|
||||
int ac;
|
||||
|
||||
/* If the driver has data on more than one TID then
|
||||
* certainly there's more data if we release just a
|
||||
* single frame now (from a single TID). This will
|
||||
* only happen for PS-Poll.
|
||||
*/
|
||||
if (reason == IEEE80211_FRAME_RELEASE_PSPOLL &&
|
||||
hweight16(driver_release_tids) > 1)
|
||||
return true;
|
||||
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
if (ignored_acs & BIT(ac))
|
||||
continue;
|
||||
|
||||
if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
|
||||
!skb_queue_empty(&sta->ps_tx_buf[ac]))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||
int n_frames, u8 ignored_acs,
|
||||
enum ieee80211_frame_release_type reason)
|
||||
ieee80211_sta_ps_get_frames(struct sta_info *sta, int n_frames, u8 ignored_acs,
|
||||
enum ieee80211_frame_release_type reason,
|
||||
struct sk_buff_head *frames,
|
||||
unsigned long *driver_release_tids)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
bool more_data = false;
|
||||
int ac;
|
||||
unsigned long driver_release_tids = 0;
|
||||
struct sk_buff_head frames;
|
||||
|
||||
/* Service or PS-Poll period starts */
|
||||
set_sta_flag(sta, WLAN_STA_SP);
|
||||
|
||||
__skb_queue_head_init(&frames);
|
||||
|
||||
/* Get response frame(s) and more data bit for the last one. */
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
@@ -1352,26 +1398,13 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||
/* if we already have frames from software, then we can't also
|
||||
* release from hardware queues
|
||||
*/
|
||||
if (skb_queue_empty(&frames)) {
|
||||
driver_release_tids |= sta->driver_buffered_tids & tids;
|
||||
driver_release_tids |= sta->txq_buffered_tids & tids;
|
||||
if (skb_queue_empty(frames)) {
|
||||
*driver_release_tids |=
|
||||
sta->driver_buffered_tids & tids;
|
||||
*driver_release_tids |= sta->txq_buffered_tids & tids;
|
||||
}
|
||||
|
||||
if (driver_release_tids) {
|
||||
/* If the driver has data on more than one TID then
|
||||
* certainly there's more data if we release just a
|
||||
* single frame now (from a single TID). This will
|
||||
* only happen for PS-Poll.
|
||||
*/
|
||||
if (reason == IEEE80211_FRAME_RELEASE_PSPOLL &&
|
||||
hweight16(driver_release_tids) > 1) {
|
||||
more_data = true;
|
||||
driver_release_tids =
|
||||
BIT(find_highest_prio_tid(
|
||||
driver_release_tids));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!*driver_release_tids) {
|
||||
struct sk_buff *skb;
|
||||
|
||||
while (n_frames > 0) {
|
||||
@@ -1385,20 +1418,44 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||
if (!skb)
|
||||
break;
|
||||
n_frames--;
|
||||
__skb_queue_tail(&frames, skb);
|
||||
__skb_queue_tail(frames, skb);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have more frames buffered on this AC, then set the
|
||||
* more-data bit and abort the loop since we can't send more
|
||||
* data from other ACs before the buffered frames from this.
|
||||
/* If we have more frames buffered on this AC, then abort the
|
||||
* loop since we can't send more data from other ACs before
|
||||
* the buffered frames from this.
|
||||
*/
|
||||
if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
|
||||
!skb_queue_empty(&sta->ps_tx_buf[ac])) {
|
||||
more_data = true;
|
||||
!skb_queue_empty(&sta->ps_tx_buf[ac]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||
int n_frames, u8 ignored_acs,
|
||||
enum ieee80211_frame_release_type reason)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
unsigned long driver_release_tids = 0;
|
||||
struct sk_buff_head frames;
|
||||
bool more_data;
|
||||
|
||||
/* Service or PS-Poll period starts */
|
||||
set_sta_flag(sta, WLAN_STA_SP);
|
||||
|
||||
__skb_queue_head_init(&frames);
|
||||
|
||||
ieee80211_sta_ps_get_frames(sta, n_frames, ignored_acs, reason,
|
||||
&frames, &driver_release_tids);
|
||||
|
||||
more_data = ieee80211_sta_ps_more_data(sta, ignored_acs, reason, driver_release_tids);
|
||||
|
||||
if (reason == IEEE80211_FRAME_RELEASE_PSPOLL)
|
||||
driver_release_tids =
|
||||
BIT(find_highest_prio_tid(driver_release_tids));
|
||||
|
||||
if (skb_queue_empty(&frames) && !driver_release_tids) {
|
||||
int tid;
|
||||
@@ -1421,7 +1478,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||
/* This will evaluate to 1, 3, 5 or 7. */
|
||||
tid = 7 - ((ffs(~ignored_acs) - 1) << 1);
|
||||
|
||||
ieee80211_send_null_response(sdata, sta, tid, reason, true);
|
||||
ieee80211_send_null_response(sta, tid, reason, true, false);
|
||||
} else if (!driver_release_tids) {
|
||||
struct sk_buff_head pending;
|
||||
struct sk_buff *skb;
|
||||
@@ -1521,8 +1578,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||
|
||||
if (need_null)
|
||||
ieee80211_send_null_response(
|
||||
sdata, sta, find_highest_prio_tid(tids),
|
||||
reason, false);
|
||||
sta, find_highest_prio_tid(tids),
|
||||
reason, false, false);
|
||||
|
||||
sta_info_recalc_tim(sta);
|
||||
} else {
|
||||
@@ -1660,6 +1717,22 @@ void ieee80211_sta_eosp(struct ieee80211_sta *pubsta)
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sta_eosp);
|
||||
|
||||
void ieee80211_send_eosp_nullfunc(struct ieee80211_sta *pubsta, int tid)
|
||||
{
|
||||
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
enum ieee80211_frame_release_type reason;
|
||||
bool more_data;
|
||||
|
||||
trace_api_send_eosp_nullfunc(sta->local, pubsta, tid);
|
||||
|
||||
reason = IEEE80211_FRAME_RELEASE_UAPSD;
|
||||
more_data = ieee80211_sta_ps_more_data(sta, ~sta->sta.uapsd_queues,
|
||||
reason, 0);
|
||||
|
||||
ieee80211_send_null_response(sta, tid, reason, false, more_data);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_send_eosp_nullfunc);
|
||||
|
||||
void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
|
||||
u8 tid, bool buffered)
|
||||
{
|
||||
|
||||
@@ -367,6 +367,7 @@ DECLARE_EWMA(signal, 1024, 8)
|
||||
* @mesh: mesh STA information
|
||||
* @debugfs: debug filesystem info
|
||||
* @dead: set to true when sta is unlinked
|
||||
* @removed: set to true when sta is being removed from sta_list
|
||||
* @uploaded: set to true when sta is uploaded to the driver
|
||||
* @sta: station information we share with the driver
|
||||
* @sta_state: duplicates information about station state (for debug)
|
||||
@@ -412,6 +413,7 @@ struct sta_info {
|
||||
u16 listen_interval;
|
||||
|
||||
bool dead;
|
||||
bool removed;
|
||||
|
||||
bool uploaded;
|
||||
|
||||
|
||||
@@ -2027,6 +2027,31 @@ TRACE_EVENT(api_eosp,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(api_send_eosp_nullfunc,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sta *sta,
|
||||
u8 tid),
|
||||
|
||||
TP_ARGS(local, sta, tid),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
STA_ENTRY
|
||||
__field(u8, tid)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
STA_ASSIGN;
|
||||
__entry->tid = tid;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT STA_PR_FMT " tid:%d",
|
||||
LOCAL_PR_ARG, STA_PR_ARG, __entry->tid
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(api_sta_set_buffered,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sta *sta,
|
||||
|
||||
+1
-1
@@ -1431,7 +1431,7 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
|
||||
info->hw_queue =
|
||||
vif->hw_queue[skb_get_queue_mapping(skb)];
|
||||
} else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
|
||||
dev_kfree_skb(skb);
|
||||
ieee80211_purge_tx_queue(&local->hw, skbs);
|
||||
return true;
|
||||
} else
|
||||
vif = NULL;
|
||||
|
||||
+5
-2
@@ -288,10 +288,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
|
||||
if (!test_bit(reason, &local->queue_stop_reasons[queue]))
|
||||
return;
|
||||
|
||||
if (!refcounted)
|
||||
if (!refcounted) {
|
||||
local->q_stop_reasons[queue][reason] = 0;
|
||||
else
|
||||
} else {
|
||||
local->q_stop_reasons[queue][reason]--;
|
||||
if (WARN_ON(local->q_stop_reasons[queue][reason] < 0))
|
||||
local->q_stop_reasons[queue][reason] = 0;
|
||||
}
|
||||
|
||||
if (local->q_stop_reasons[queue][reason] == 0)
|
||||
__clear_bit(reason, &local->queue_stop_reasons[queue]);
|
||||
|
||||
@@ -416,13 +416,6 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
|
||||
void cfg80211_process_wdev_events(struct wireless_dev *wdev);
|
||||
|
||||
int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype,
|
||||
struct ieee80211_channel *chan,
|
||||
enum cfg80211_chan_mode chanmode,
|
||||
u8 radar_detect);
|
||||
|
||||
/**
|
||||
* cfg80211_chandef_dfs_usable - checks if chandef is DFS usable
|
||||
* @wiphy: the wiphy to validate against
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user