Skip to content

Commit

Permalink
Merge tag 'mac80211-next-for-davem-2015-12-07' of git://git.kernel.or…
Browse files Browse the repository at this point in the history
…g/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>
  • Loading branch information
David S. Miller committed Dec 7, 2015
2 parents 4c9668d + 1b89452 commit ad9360b
Show file tree
Hide file tree
Showing 28 changed files with 1,328 additions and 957 deletions.
95 changes: 81 additions & 14 deletions drivers/net/wireless/mac80211_hwsim.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -2014,23 +2060,22 @@ 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;
}

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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -2728,15 +2775,20 @@ 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)
goto out;

/* 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;
Expand Down Expand Up @@ -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]);
Expand Down
10 changes: 8 additions & 2 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
56 changes: 56 additions & 0 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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),
};

/**
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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().
Expand Down
11 changes: 9 additions & 2 deletions include/uapi/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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.
Expand Down
Loading

0 comments on commit ad9360b

Please sign in to comment.