Commit ac075bdd authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-net-2021-04-08.2' of...

Merge tag 'mac80211-for-net-2021-04-08.2' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211

Johannes berg says:

====================
Various small fixes:
 * S1G beacon validation
 * potential leak in nl80211
 * fast-RX confusion with 4-addr mode
 * erroneous WARN_ON that userspace can trigger
 * wrong time units in virt_wifi
 * rfkill userspace API breakage
 * TXQ AC confusing that led to traffic stopped forever
 * connection monitoring time after/before confusion
 * netlink beacon head validation buffer overrun
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3583a4e8 9a6847ba
......@@ -12,6 +12,7 @@
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
#include <linux/etherdevice.h>
#include <linux/math64.h>
#include <linux/module.h>
static struct wiphy *common_wiphy;
......@@ -168,11 +169,11 @@ static void virt_wifi_scan_result(struct work_struct *work)
scan_result.work);
struct wiphy *wiphy = priv_to_wiphy(priv);
struct cfg80211_scan_info scan_info = { .aborted = false };
u64 tsf = div_u64(ktime_get_boottime_ns(), 1000);
informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz,
CFG80211_BSS_FTYPE_PRESP,
fake_router_bssid,
ktime_get_boottime_ns(),
fake_router_bssid, tsf,
WLAN_CAPABILITY_ESS, 0,
(void *)&ssid, sizeof(ssid),
DBM_TO_MBM(-50), GFP_KERNEL);
......
......@@ -86,34 +86,90 @@ enum rfkill_hard_block_reasons {
* @op: operation code
* @hard: hard state (0/1)
* @soft: soft state (0/1)
*
* Structure used for userspace communication on /dev/rfkill,
* used for events from the kernel and control to the kernel.
*/
struct rfkill_event {
__u32 idx;
__u8 type;
__u8 op;
__u8 soft;
__u8 hard;
} __attribute__((packed));
/**
* struct rfkill_event_ext - events for userspace on /dev/rfkill
* @idx: index of dev rfkill
* @type: type of the rfkill struct
* @op: operation code
* @hard: hard state (0/1)
* @soft: soft state (0/1)
* @hard_block_reasons: valid if hard is set. One or several reasons from
* &enum rfkill_hard_block_reasons.
*
* Structure used for userspace communication on /dev/rfkill,
* used for events from the kernel and control to the kernel.
*
* See the extensibility docs below.
*/
struct rfkill_event {
struct rfkill_event_ext {
__u32 idx;
__u8 type;
__u8 op;
__u8 soft;
__u8 hard;
/*
* older kernels will accept/send only up to this point,
* and if extended further up to any chunk marked below
*/
__u8 hard_block_reasons;
} __attribute__((packed));
/*
* We are planning to be backward and forward compatible with changes
* to the event struct, by adding new, optional, members at the end.
* When reading an event (whether the kernel from userspace or vice
* versa) we need to accept anything that's at least as large as the
* version 1 event size, but might be able to accept other sizes in
* the future.
/**
* DOC: Extensibility
*
* Originally, we had planned to allow backward and forward compatible
* changes by just adding fields at the end of the structure that are
* then not reported on older kernels on read(), and not written to by
* older kernels on write(), with the kernel reporting the size it did
* accept as the result.
*
* This would have allowed userspace to detect on read() and write()
* which kernel structure version it was dealing with, and if was just
* recompiled it would have gotten the new fields, but obviously not
* accessed them, but things should've continued to work.
*
* Unfortunately, while actually exercising this mechanism to add the
* hard block reasons field, we found that userspace (notably systemd)
* did all kinds of fun things not in line with this scheme:
*
* 1. treat the (expected) short writes as an error;
* 2. ask to read sizeof(struct rfkill_event) but then compare the
* actual return value to RFKILL_EVENT_SIZE_V1 and treat any
* mismatch as an error.
*
* As a consequence, just recompiling with a new struct version caused
* things to no longer work correctly on old and new kernels.
*
* Hence, we've rolled back &struct rfkill_event to the original version
* and added &struct rfkill_event_ext. This effectively reverts to the
* old behaviour for all userspace, unless it explicitly opts in to the
* rules outlined here by using the new &struct rfkill_event_ext.
*
* Userspace using &struct rfkill_event_ext must adhere to the following
* rules
*
* One exception is the kernel -- we already have two event sizes in
* that we've made the 'hard' member optional since our only option
* is to ignore it anyway.
* 1. accept short writes, optionally using them to detect that it's
* running on an older kernel;
* 2. accept short reads, knowing that this means it's running on an
* older kernel;
* 3. treat reads that are as long as requested as acceptable, not
* checking against RFKILL_EVENT_SIZE_V1 or such.
*/
#define RFKILL_EVENT_SIZE_V1 8
#define RFKILL_EVENT_SIZE_V1 sizeof(struct rfkill_event)
/* ioctl for turning off rfkill-input (if present) */
#define RFKILL_IOC_MAGIC 'R'
......
......@@ -1788,8 +1788,10 @@ static int ieee80211_change_station(struct wiphy *wiphy,
}
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
sta->sdata->u.vlan.sta)
sta->sdata->u.vlan.sta) {
ieee80211_clear_fast_rx(sta);
RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
}
if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
ieee80211_vif_dec_num_mcast(sta->sdata);
......
......@@ -4707,7 +4707,10 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
timeout = sta->rx_stats.last_rx;
timeout += IEEE80211_CONNECTION_IDLE_TIME;
if (time_is_before_jiffies(timeout)) {
/* If timeout is after now, then update timer to fire at
* the later date, but do not actually probe at this time.
*/
if (time_is_after_jiffies(timeout)) {
mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout));
return;
}
......
......@@ -3573,7 +3573,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags))
goto out;
if (vif->txqs_stopped[ieee80211_ac_from_tid(txq->tid)]) {
if (vif->txqs_stopped[txq->ac]) {
set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags);
goto out;
}
......
......@@ -69,7 +69,7 @@ struct rfkill {
struct rfkill_int_event {
struct list_head list;
struct rfkill_event ev;
struct rfkill_event_ext ev;
};
struct rfkill_data {
......@@ -253,7 +253,8 @@ static void rfkill_global_led_trigger_unregister(void)
}
#endif /* CONFIG_RFKILL_LEDS */
static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill,
static void rfkill_fill_event(struct rfkill_event_ext *ev,
struct rfkill *rfkill,
enum rfkill_operation op)
{
unsigned long flags;
......@@ -1237,7 +1238,7 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
struct rfkill *rfkill;
struct rfkill_event ev;
struct rfkill_event_ext ev;
int ret;
/* we don't need the 'hard' variable but accept it */
......
......@@ -5,7 +5,7 @@
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2020 Intel Corporation
* Copyright (C) 2018-2021 Intel Corporation
*/
#include <linux/if.h>
......@@ -229,9 +229,13 @@ static int validate_beacon_head(const struct nlattr *attr,
unsigned int len = nla_len(attr);
const struct element *elem;
const struct ieee80211_mgmt *mgmt = (void *)data;
bool s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
unsigned int fixedlen, hdrlen;
bool s1g_bcn;
if (len < offsetofend(typeof(*mgmt), frame_control))
goto err;
s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
if (s1g_bcn) {
fixedlen = offsetof(struct ieee80211_ext,
u.s1g_beacon.variable);
......@@ -5485,7 +5489,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP],
&params);
if (err)
return err;
goto out;
}
nl80211_calculate_ap_params(&params);
......
......@@ -2352,14 +2352,16 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
return NULL;
if (ext) {
struct ieee80211_s1g_bcn_compat_ie *compat;
u8 *ie;
const struct ieee80211_s1g_bcn_compat_ie *compat;
const struct element *elem;
ie = (void *)cfg80211_find_ie(WLAN_EID_S1G_BCN_COMPAT,
variable, ielen);
if (!ie)
elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT,
variable, ielen);
if (!elem)
return NULL;
if (elem->datalen < sizeof(*compat))
return NULL;
compat = (void *)(ie + 2);
compat = (void *)elem->data;
bssid = ext->u.s1g_beacon.sa;
capability = le16_to_cpu(compat->compat_info);
beacon_int = le16_to_cpu(compat->beacon_int);
......
......@@ -529,7 +529,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
cfg80211_sme_free(wdev);
}
if (WARN_ON(wdev->conn))
if (wdev->conn)
return -EINPROGRESS;
wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment