Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

This commit is contained in:
John W. Linville 2012-11-16 13:59:51 -05:00
commit 0f62248501
41 changed files with 1325 additions and 482 deletions

View File

@ -511,8 +511,9 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah,
ath5k_vif_iter(&iter_data, vif->addr, vif);
/* Get list of all active MAC addresses */
ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter,
&iter_data);
ieee80211_iterate_active_interfaces_atomic(
ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath5k_vif_iter, &iter_data);
memcpy(ah->bssidmask, iter_data.mask, ETH_ALEN);
ah->opmode = iter_data.opmode;
@ -3045,8 +3046,9 @@ ath5k_any_vif_assoc(struct ath5k_hw *ah)
iter_data.need_set_hw_addr = false;
iter_data.found_active = true;
ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter,
&iter_data);
ieee80211_iterate_active_interfaces_atomic(
ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath5k_vif_iter, &iter_data);
return iter_data.any_assoc;
}

View File

@ -452,8 +452,9 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
iter_data.hw_macaddr = NULL;
iter_data.n_stas = 0;
iter_data.need_set_hw_addr = false;
ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter,
&iter_data);
ieee80211_iterate_active_interfaces_atomic(
ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath5k_vif_iter, &iter_data);
/* Set up RX Filter */
if (iter_data.n_stas > 1) {

View File

@ -1384,11 +1384,8 @@ static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
return 0;
}
/*
* The type nl80211_tx_power_setting replaces the following
* data type from 2.6.36 onwards
*/
static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
struct wireless_dev *wdev,
enum nl80211_tx_power_setting type,
int mbm)
{
@ -1423,7 +1420,9 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
return 0;
}
static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy,
struct wireless_dev *wdev,
int *dbm)
{
struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
struct ath6kl_vif *vif;

View File

@ -587,9 +587,9 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv,
(priv->num_sta_vif > 1) &&
(vif->type == NL80211_IFTYPE_STATION)) {
beacon_configured = false;
ieee80211_iterate_active_interfaces_atomic(priv->hw,
ath9k_htc_beacon_iter,
&beacon_configured);
ieee80211_iterate_active_interfaces_atomic(
priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_htc_beacon_iter, &beacon_configured);
if (beacon_configured) {
ath_dbg(common, CONFIG,

View File

@ -127,8 +127,9 @@ static void ath9k_htc_vif_reconfig(struct ath9k_htc_priv *priv)
priv->rearm_ani = false;
priv->reconfig_beacon = false;
ieee80211_iterate_active_interfaces_atomic(priv->hw,
ath9k_htc_vif_iter, priv);
ieee80211_iterate_active_interfaces_atomic(
priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_htc_vif_iter, priv);
if (priv->rearm_ani)
ath9k_htc_start_ani(priv);
@ -165,8 +166,9 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv,
ath9k_htc_bssid_iter(&iter_data, vif->addr, vif);
/* Get list of all active MAC addresses */
ieee80211_iterate_active_interfaces_atomic(priv->hw, ath9k_htc_bssid_iter,
&iter_data);
ieee80211_iterate_active_interfaces_atomic(
priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_htc_bssid_iter, &iter_data);
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
ath_hw_setbssidmask(common);
@ -1144,8 +1146,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
*/
if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) {
priv->rearm_ani = false;
ieee80211_iterate_active_interfaces_atomic(priv->hw,
ath9k_htc_vif_iter, priv);
ieee80211_iterate_active_interfaces_atomic(
priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_htc_vif_iter, priv);
if (!priv->rearm_ani)
ath9k_htc_stop_ani(priv);
}
@ -1466,8 +1469,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv)
{
if (priv->num_sta_assoc_vif == 1) {
ieee80211_iterate_active_interfaces_atomic(priv->hw,
ath9k_htc_bss_iter, priv);
ieee80211_iterate_active_interfaces_atomic(
priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_htc_bss_iter, priv);
ath9k_htc_set_bssid(priv);
}
}

View File

@ -924,8 +924,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
ath9k_vif_iter(iter_data, vif->addr, vif);
/* Get list of all active MAC addresses */
ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,
iter_data);
ieee80211_iterate_active_interfaces_atomic(
sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_vif_iter, iter_data);
}
/* Called with sc->mutex held. */
@ -975,8 +976,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
if (ah->opmode == NL80211_IFTYPE_STATION &&
old_opmode == NL80211_IFTYPE_AP &&
test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
ieee80211_iterate_active_interfaces_atomic(sc->hw,
ath9k_sta_vif_iter, sc);
ieee80211_iterate_active_interfaces_atomic(
sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_sta_vif_iter, sc);
}
}
@ -1505,8 +1507,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
clear_bit(SC_OP_BEACONS, &sc->sc_flags);
}
ieee80211_iterate_active_interfaces_atomic(sc->hw,
ath9k_bss_assoc_iter, sc);
ieee80211_iterate_active_interfaces_atomic(
sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_bss_assoc_iter, sc);
if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) &&
ah->opmode == NL80211_IFTYPE_STATION) {

View File

@ -1529,7 +1529,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
}
static s32
brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
enum nl80211_tx_power_setting type, s32 mbm)
{
@ -1578,7 +1578,9 @@ done:
return err;
}
static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
struct wireless_dev *wdev,
s32 *dbm)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));

View File

@ -44,9 +44,9 @@ static int radios = 2;
module_param(radios, int, 0444);
MODULE_PARM_DESC(radios, "Number of simulated radios");
static bool fake_hw_scan;
module_param(fake_hw_scan, bool, 0444);
MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler");
static int channels = 1;
module_param(channels, int, 0444);
MODULE_PARM_DESC(channels, "Number of concurrent channels");
/**
* enum hwsim_regtest - the type of regulatory tests we offer
@ -166,7 +166,9 @@ struct hwsim_vif_priv {
static inline void hwsim_check_magic(struct ieee80211_vif *vif)
{
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
WARN_ON(vp->magic != HWSIM_VIF_MAGIC);
WARN(vp->magic != HWSIM_VIF_MAGIC,
"Invalid VIF (%p) magic %#x, %pM, %d/%d\n",
vif, vp->magic, vif->addr, vif->type, vif->p2p);
}
static inline void hwsim_set_magic(struct ieee80211_vif *vif)
@ -185,7 +187,7 @@ struct hwsim_sta_priv {
u32 magic;
};
#define HWSIM_STA_MAGIC 0x6d537748
#define HWSIM_STA_MAGIC 0x6d537749
static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta)
{
@ -205,6 +207,30 @@ static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta)
sp->magic = 0;
}
struct hwsim_chanctx_priv {
u32 magic;
};
#define HWSIM_CHANCTX_MAGIC 0x6d53774a
static inline void hwsim_check_chanctx_magic(struct ieee80211_chanctx_conf *c)
{
struct hwsim_chanctx_priv *cp = (void *)c->drv_priv;
WARN_ON(cp->magic != HWSIM_CHANCTX_MAGIC);
}
static inline void hwsim_set_chanctx_magic(struct ieee80211_chanctx_conf *c)
{
struct hwsim_chanctx_priv *cp = (void *)c->drv_priv;
cp->magic = HWSIM_CHANCTX_MAGIC;
}
static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c)
{
struct hwsim_chanctx_priv *cp = (void *)c->drv_priv;
cp->magic = 0;
}
static struct class *hwsim_class;
static struct net_device *hwsim_mon; /* global monitor netdev */
@ -299,6 +325,13 @@ struct mac80211_hwsim_data {
struct mac_address addresses[2];
struct ieee80211_channel *tmp_chan;
struct delayed_work roc_done;
struct delayed_work hw_scan;
struct cfg80211_scan_request *hw_scan_request;
struct ieee80211_vif *hw_scan_vif;
int scan_chan_idx;
struct ieee80211_channel *channel;
unsigned long beacon_int; /* in jiffies unit */
unsigned int rx_filter;
@ -396,7 +429,8 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
}
static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
struct sk_buff *tx_skb)
struct sk_buff *tx_skb,
struct ieee80211_channel *chan)
{
struct mac80211_hwsim_data *data = hw->priv;
struct sk_buff *skb;
@ -423,7 +457,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
hdr->rt_tsft = __mac80211_hwsim_get_tsf(data);
hdr->rt_flags = 0;
hdr->rt_rate = txrate->bitrate / 5;
hdr->rt_channel = cpu_to_le16(data->channel->center_freq);
hdr->rt_channel = cpu_to_le16(chan->center_freq);
flags = IEEE80211_CHAN_2GHZ;
if (txrate->flags & IEEE80211_RATE_ERP_G)
flags |= IEEE80211_CHAN_OFDM;
@ -441,9 +475,9 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
}
static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr)
static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan,
const u8 *addr)
{
struct mac80211_hwsim_data *data = hw->priv;
struct sk_buff *skb;
struct hwsim_radiotap_hdr *hdr;
u16 flags;
@ -464,7 +498,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr)
(1 << IEEE80211_RADIOTAP_CHANNEL));
hdr->rt_flags = 0;
hdr->rt_rate = 0;
hdr->rt_channel = cpu_to_le16(data->channel->center_freq);
hdr->rt_channel = cpu_to_le16(chan->center_freq);
flags = IEEE80211_CHAN_2GHZ;
hdr->rt_chbitmask = cpu_to_le16(flags);
@ -537,6 +571,7 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
md.ret = false;
md.addr = addr;
ieee80211_iterate_active_interfaces_atomic(data->hw,
IEEE80211_IFACE_ITER_NORMAL,
mac80211_hwsim_addr_iter,
&md);
@ -556,12 +591,6 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
int i;
struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES];
if (data->idle) {
wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n");
dev_kfree_skb(my_skb);
return;
}
if (data->ps != PS_DISABLED)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
/* If the queue contains MAX_QUEUE skb's drop some */
@ -629,8 +658,38 @@ nla_put_failure:
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
}
static bool hwsim_chans_compat(struct ieee80211_channel *c1,
struct ieee80211_channel *c2)
{
if (!c1 || !c2)
return false;
return c1->center_freq == c2->center_freq;
}
struct tx_iter_data {
struct ieee80211_channel *channel;
bool receive;
};
static void mac80211_hwsim_tx_iter(void *_data, u8 *addr,
struct ieee80211_vif *vif)
{
struct tx_iter_data *data = _data;
if (!vif->chanctx_conf)
return;
if (!hwsim_chans_compat(data->channel,
rcu_dereference(vif->chanctx_conf)->channel))
return;
data->receive = true;
}
static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
struct sk_buff *skb)
struct sk_buff *skb,
struct ieee80211_channel *chan)
{
struct mac80211_hwsim_data *data = hw->priv, *data2;
bool ack = false;
@ -639,15 +698,10 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
struct ieee80211_rx_status rx_status;
struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
if (data->idle) {
wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n");
return false;
}
memset(&rx_status, 0, sizeof(rx_status));
rx_status.flag |= RX_FLAG_MACTIME_MPDU;
rx_status.freq = data->channel->center_freq;
rx_status.band = data->channel->band;
rx_status.freq = chan->center_freq;
rx_status.band = chan->band;
rx_status.rate_idx = info->control.rates[0].idx;
if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
rx_status.flag |= RX_FLAG_HT;
@ -673,16 +727,30 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
list_for_each_entry(data2, &hwsim_radios, list) {
struct sk_buff *nskb;
struct ieee80211_mgmt *mgmt;
struct tx_iter_data tx_iter_data = {
.receive = false,
.channel = chan,
};
if (data == data2)
continue;
if (data2->idle || !data2->started ||
!hwsim_ps_rx_ok(data2, skb) || !data2->channel ||
data->channel->center_freq != data2->channel->center_freq ||
!(data->group & data2->group))
if (!data2->started || (data2->idle && !data2->tmp_chan) ||
!hwsim_ps_rx_ok(data2, skb))
continue;
if (!(data->group & data2->group))
continue;
if (!hwsim_chans_compat(chan, data2->tmp_chan) &&
!hwsim_chans_compat(chan, data2->channel)) {
ieee80211_iterate_active_interfaces_atomic(
data2->hw, IEEE80211_IFACE_ITER_NORMAL,
mac80211_hwsim_tx_iter, &tx_iter_data);
if (!tx_iter_data.receive)
continue;
}
nskb = skb_copy(skb, GFP_ATOMIC);
if (nskb == NULL)
continue;
@ -713,18 +781,51 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control,
struct sk_buff *skb)
{
struct mac80211_hwsim_data *data = hw->priv;
struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *channel;
bool ack;
struct ieee80211_tx_info *txi;
u32 _portid;
mac80211_hwsim_monitor_rx(hw, skb);
if (skb->len < 10) {
if (WARN_ON(skb->len < 10)) {
/* Should not happen; just a sanity check for addr1 use */
dev_kfree_skb(skb);
return;
}
if (channels == 1) {
channel = data->channel;
} else if (txi->hw_queue == 4) {
channel = data->tmp_chan;
} else {
chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf);
if (chanctx_conf)
channel = chanctx_conf->channel;
else
channel = NULL;
}
if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) {
dev_kfree_skb(skb);
return;
}
if (data->idle && !data->tmp_chan) {
wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n");
dev_kfree_skb(skb);
return;
}
if (txi->control.vif)
hwsim_check_magic(txi->control.vif);
if (control->sta)
hwsim_check_sta_magic(control->sta);
txi->rate_driver_data[0] = channel;
mac80211_hwsim_monitor_rx(hw, skb, channel);
/* wmediumd mode check */
_portid = ACCESS_ONCE(wmediumd_portid);
@ -732,15 +833,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
/* NO wmediumd detected, perfect medium simulation */
ack = mac80211_hwsim_tx_frame_no_nl(hw, skb);
ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
if (ack && skb->len >= 16) {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
mac80211_hwsim_monitor_ack(hw, hdr->addr2);
mac80211_hwsim_monitor_ack(channel, hdr->addr2);
}
txi = IEEE80211_SKB_CB(skb);
ieee80211_tx_info_clear_status(txi);
/* frame was transmitted at most favorable rate at first attempt */
@ -778,6 +877,13 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
__func__, ieee80211_vif_type_p2p(vif),
vif->addr);
hwsim_set_magic(vif);
vif->cab_queue = 0;
vif->hw_queue[IEEE80211_AC_VO] = 0;
vif->hw_queue[IEEE80211_AC_VI] = 1;
vif->hw_queue[IEEE80211_AC_BE] = 2;
vif->hw_queue[IEEE80211_AC_BK] = 3;
return 0;
}
@ -807,14 +913,26 @@ static void mac80211_hwsim_remove_interface(
hwsim_clear_magic(vif);
}
static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_channel *chan)
{
u32 _pid = ACCESS_ONCE(wmediumd_portid);
mac80211_hwsim_monitor_rx(hw, skb, chan);
if (_pid)
return mac80211_hwsim_tx_frame_nl(hw, skb, _pid);
mac80211_hwsim_tx_frame_no_nl(hw, skb, chan);
dev_kfree_skb(skb);
}
static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
struct ieee80211_vif *vif)
{
struct ieee80211_hw *hw = arg;
struct sk_buff *skb;
struct ieee80211_tx_info *info;
u32 _portid;
hwsim_check_magic(vif);
@ -826,18 +944,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
skb = ieee80211_beacon_get(hw, vif);
if (skb == NULL)
return;
info = IEEE80211_SKB_CB(skb);
mac80211_hwsim_monitor_rx(hw, skb);
/* wmediumd mode check */
_portid = ACCESS_ONCE(wmediumd_portid);
if (_portid)
return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
mac80211_hwsim_tx_frame_no_nl(hw, skb);
dev_kfree_skb(skb);
mac80211_hwsim_tx_frame(hw, skb,
rcu_dereference(vif->chanctx_conf)->channel);
}
@ -850,7 +959,8 @@ static void mac80211_hwsim_beacon(unsigned long arg)
return;
ieee80211_iterate_active_interfaces_atomic(
hw, mac80211_hwsim_beacon_tx, hw);
hw, IEEE80211_IFACE_ITER_NORMAL,
mac80211_hwsim_beacon_tx, hw);
data->beacon_timer.expires = jiffies + data->beacon_int;
add_timer(&data->beacon_timer);
@ -877,7 +987,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
wiphy_debug(hw->wiphy,
"%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
__func__,
conf->channel->center_freq,
conf->channel ? conf->channel->center_freq : 0,
hwsim_chantypes[conf->channel_type],
!!(conf->flags & IEEE80211_CONF_IDLE),
!!(conf->flags & IEEE80211_CONF_PS),
@ -886,6 +996,9 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
data->channel = conf->channel;
WARN_ON(data->channel && channels > 1);
data->power_level = conf->power_level;
if (!data->started || !data->beacon_int)
del_timer(&data->beacon_timer);
@ -972,6 +1085,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
wiphy_debug(hw->wiphy, " BASIC_RATES: 0x%llx\n",
(unsigned long long) info->basic_rates);
}
if (changed & BSS_CHANGED_TXPOWER)
wiphy_debug(hw->wiphy, " TX Power: %d dBm\n", info->txpower);
}
static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw,
@ -1166,45 +1282,102 @@ static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
/* Not implemented, queues only on kernel side */
}
struct hw_scan_done {
struct delayed_work w;
struct ieee80211_hw *hw;
};
static void hw_scan_done(struct work_struct *work)
static void hw_scan_work(struct work_struct *work)
{
struct hw_scan_done *hsd =
container_of(work, struct hw_scan_done, w.work);
struct mac80211_hwsim_data *hwsim =
container_of(work, struct mac80211_hwsim_data, hw_scan.work);
struct cfg80211_scan_request *req = hwsim->hw_scan_request;
int dwell, i;
ieee80211_scan_completed(hsd->hw, false);
kfree(hsd);
mutex_lock(&hwsim->mutex);
if (hwsim->scan_chan_idx >= req->n_channels) {
wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n");
ieee80211_scan_completed(hwsim->hw, false);
hwsim->hw_scan_request = NULL;
hwsim->hw_scan_vif = NULL;
hwsim->tmp_chan = NULL;
mutex_unlock(&hwsim->mutex);
return;
}
wiphy_debug(hwsim->hw->wiphy, "hw scan %d MHz\n",
req->channels[hwsim->scan_chan_idx]->center_freq);
hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx];
if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
!req->n_ssids) {
dwell = 120;
} else {
dwell = 30;
/* send probes */
for (i = 0; i < req->n_ssids; i++) {
struct sk_buff *probe;
probe = ieee80211_probereq_get(hwsim->hw,
hwsim->hw_scan_vif,
req->ssids[i].ssid,
req->ssids[i].ssid_len,
req->ie, req->ie_len);
if (!probe)
continue;
local_bh_disable();
mac80211_hwsim_tx_frame(hwsim->hw, probe,
hwsim->tmp_chan);
local_bh_enable();
}
}
ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan,
msecs_to_jiffies(dwell));
hwsim->scan_chan_idx++;
mutex_unlock(&hwsim->mutex);
}
static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_scan_request *req)
{
struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL);
struct mac80211_hwsim_data *hwsim = hw->priv;
int i;
if (!hsd)
return -ENOMEM;
mutex_lock(&hwsim->mutex);
if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) {
mutex_unlock(&hwsim->mutex);
return -EBUSY;
}
hwsim->hw_scan_request = req;
hwsim->hw_scan_vif = vif;
hwsim->scan_chan_idx = 0;
mutex_unlock(&hwsim->mutex);
hsd->hw = hw;
INIT_DELAYED_WORK(&hsd->w, hw_scan_done);
printk(KERN_DEBUG "hwsim hw_scan request\n");
wiphy_debug(hw->wiphy, "hwsim hw_scan request\n");
for (i = 0; i < req->n_channels; i++)
printk(KERN_DEBUG "hwsim hw_scan freq %d\n",
req->channels[i]->center_freq);
print_hex_dump(KERN_DEBUG, "scan IEs: ", DUMP_PREFIX_OFFSET,
16, 1, req->ie, req->ie_len, 1);
ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ);
ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0);
return 0;
}
static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mac80211_hwsim_data *hwsim = hw->priv;
wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n");
cancel_delayed_work_sync(&hwsim->hw_scan);
mutex_lock(&hwsim->mutex);
ieee80211_scan_completed(hwsim->hw, true);
hwsim->tmp_chan = NULL;
hwsim->hw_scan_request = NULL;
hwsim->hw_scan_vif = NULL;
mutex_unlock(&hwsim->mutex);
}
static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw)
{
struct mac80211_hwsim_data *hwsim = hw->priv;
@ -1235,6 +1408,105 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw)
mutex_unlock(&hwsim->mutex);
}
static void hw_roc_done(struct work_struct *work)
{
struct mac80211_hwsim_data *hwsim =
container_of(work, struct mac80211_hwsim_data, roc_done.work);
mutex_lock(&hwsim->mutex);
ieee80211_remain_on_channel_expired(hwsim->hw);
hwsim->tmp_chan = NULL;
mutex_unlock(&hwsim->mutex);
wiphy_debug(hwsim->hw->wiphy, "hwsim ROC expired\n");
}
static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
int duration)
{
struct mac80211_hwsim_data *hwsim = hw->priv;
mutex_lock(&hwsim->mutex);
if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) {
mutex_unlock(&hwsim->mutex);
return -EBUSY;
}
hwsim->tmp_chan = chan;
mutex_unlock(&hwsim->mutex);
wiphy_debug(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n",
chan->center_freq, duration);
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_done);
mutex_lock(&hwsim->mutex);
hwsim->tmp_chan = NULL;
mutex_unlock(&hwsim->mutex);
wiphy_debug(hw->wiphy, "hwsim ROC canceled\n");
return 0;
}
static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
hwsim_set_chanctx_magic(ctx);
wiphy_debug(hw->wiphy, "add channel context %d MHz/%d\n",
ctx->channel->center_freq, ctx->channel_type);
return 0;
}
static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
wiphy_debug(hw->wiphy, "remove channel context %d MHz/%d\n",
ctx->channel->center_freq, ctx->channel_type);
hwsim_check_chanctx_magic(ctx);
hwsim_clear_chanctx_magic(ctx);
}
static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx,
u32 changed)
{
hwsim_check_chanctx_magic(ctx);
wiphy_debug(hw->wiphy, "change channel context %#x (%d MHz/%d)\n",
changed, ctx->channel->center_freq, ctx->channel_type);
}
static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_chanctx_conf *ctx)
{
hwsim_check_magic(vif);
hwsim_check_chanctx_magic(ctx);
return 0;
}
static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_chanctx_conf *ctx)
{
hwsim_check_magic(vif);
hwsim_check_chanctx_magic(ctx);
}
static struct ieee80211_ops mac80211_hwsim_ops =
{
.tx = mac80211_hwsim_tx,
@ -1315,7 +1587,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
struct sk_buff *skb;
struct ieee80211_pspoll *pspoll;
u32 _portid;
if (!vp->assoc)
return;
@ -1335,25 +1606,18 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
memcpy(pspoll->ta, mac, ETH_ALEN);
/* wmediumd mode check */
_portid = ACCESS_ONCE(wmediumd_portid);
if (_portid)
return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid);
if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb))
printk(KERN_DEBUG "%s: PS-poll frame not ack'ed\n", __func__);
dev_kfree_skb(skb);
rcu_read_lock();
mac80211_hwsim_tx_frame(data->hw, skb,
rcu_dereference(vif->chanctx_conf)->channel);
rcu_read_unlock();
}
static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
struct ieee80211_vif *vif, int ps)
{
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
u32 _portid;
if (!vp->assoc)
return;
@ -1374,15 +1638,10 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
memcpy(hdr->addr2, mac, ETH_ALEN);
memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
/* wmediumd mode check */
_portid = ACCESS_ONCE(wmediumd_portid);
if (_portid)
return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid);
if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb))
printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
dev_kfree_skb(skb);
rcu_read_lock();
mac80211_hwsim_tx_frame(data->hw, skb,
rcu_dereference(vif->chanctx_conf)->channel);
rcu_read_unlock();
}
@ -1423,14 +1682,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val)
if (val == PS_MANUAL_POLL) {
ieee80211_iterate_active_interfaces(data->hw,
IEEE80211_IFACE_ITER_NORMAL,
hwsim_send_ps_poll, data);
data->ps_poll_pending = true;
} else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
ieee80211_iterate_active_interfaces(data->hw,
IEEE80211_IFACE_ITER_NORMAL,
hwsim_send_nullfunc_ps,
data);
} else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
ieee80211_iterate_active_interfaces(data->hw,
IEEE80211_IFACE_ITER_NORMAL,
hwsim_send_nullfunc_no_ps,
data);
}
@ -1551,7 +1813,8 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
(hwsim_flags & HWSIM_TX_STAT_ACK)) {
if (skb->len >= 16) {
hdr = (struct ieee80211_hdr *) skb->data;
mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2);
mac80211_hwsim_monitor_ack(txi->rate_driver_data[0],
hdr->addr2);
}
txi->flags |= IEEE80211_TX_STAT_ACK;
}
@ -1566,7 +1829,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
struct genl_info *info)
{
struct mac80211_hwsim_data *data2;
struct mac80211_hwsim_data *data2;
struct ieee80211_rx_status rx_status;
struct mac_address *dst;
int frame_data_len;
@ -1574,9 +1837,9 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
struct sk_buff *skb = NULL;
if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
!info->attrs[HWSIM_ATTR_FRAME] ||
!info->attrs[HWSIM_ATTR_RX_RATE] ||
!info->attrs[HWSIM_ATTR_SIGNAL])
!info->attrs[HWSIM_ATTR_FRAME] ||
!info->attrs[HWSIM_ATTR_RX_RATE] ||
!info->attrs[HWSIM_ATTR_SIGNAL])
goto out;
dst = (struct mac_address *)nla_data(
@ -1604,7 +1867,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
/* check if radio is configured properly */
if (data2->idle || !data2->started || !data2->channel)
if (data2->idle || !data2->started)
goto out;
/*A frame is received from user space*/
@ -1688,6 +1951,11 @@ static struct notifier_block hwsim_netlink_notifier = {
static int hwsim_init_netlink(void)
{
int rc;
/* userspace test API hasn't been adjusted for multi-channel */
if (channels > 1)
return 0;
printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
rc = genl_register_family_with_ops(&hwsim_genl_family,
@ -1710,6 +1978,10 @@ static void hwsim_exit_netlink(void)
{
int ret;
/* userspace test API hasn't been adjusted for multi-channel */
if (channels > 1)
return;
printk(KERN_INFO "mac80211_hwsim: closing netlink\n");
/* unregister the notifier */
netlink_unregister_notifier(&hwsim_netlink_notifier);
@ -1732,7 +2004,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
};
static const struct ieee80211_iface_combination hwsim_if_comb = {
static struct ieee80211_iface_combination hwsim_if_comb = {
.limits = hwsim_if_limits,
.n_limits = ARRAY_SIZE(hwsim_if_limits),
.max_interfaces = 2048,
@ -1750,10 +2022,30 @@ static int __init init_mac80211_hwsim(void)
if (radios < 1 || radios > 100)
return -EINVAL;
if (fake_hw_scan) {
if (channels < 1)
return -EINVAL;
if (channels > 1) {
hwsim_if_comb.num_different_channels = channels;
mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan;
mac80211_hwsim_ops.cancel_hw_scan =
mac80211_hwsim_cancel_hw_scan;
mac80211_hwsim_ops.sw_scan_start = NULL;
mac80211_hwsim_ops.sw_scan_complete = NULL;
mac80211_hwsim_ops.remain_on_channel =
mac80211_hwsim_roc;
mac80211_hwsim_ops.cancel_remain_on_channel =
mac80211_hwsim_croc;
mac80211_hwsim_ops.add_chanctx =
mac80211_hwsim_add_chanctx;
mac80211_hwsim_ops.remove_chanctx =
mac80211_hwsim_remove_chanctx;
mac80211_hwsim_ops.change_chanctx =
mac80211_hwsim_change_chanctx;
mac80211_hwsim_ops.assign_vif_chanctx =
mac80211_hwsim_assign_vif_chanctx;
mac80211_hwsim_ops.unassign_vif_chanctx =
mac80211_hwsim_unassign_vif_chanctx;
}
spin_lock_init(&hwsim_radio_lock);
@ -1803,13 +2095,18 @@ static int __init init_mac80211_hwsim(void)
hw->wiphy->iface_combinations = &hwsim_if_comb;
hw->wiphy->n_iface_combinations = 1;
if (fake_hw_scan) {
if (channels > 1) {
hw->wiphy->max_scan_ssids = 255;
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
hw->wiphy->max_remain_on_channel_duration = 1000;
}
INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work);
hw->channel_change_time = 1;
hw->queues = 4;
hw->queues = 5;
hw->offchannel_tx_hw_queue = 4;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
@ -1824,7 +2121,8 @@ static int __init init_mac80211_hwsim(void)
IEEE80211_HW_SUPPORTS_STATIC_SMPS |
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_WANT_MONITOR_VIF;
IEEE80211_HW_WANT_MONITOR_VIF |
IEEE80211_HW_QUEUE_CONTROL;
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;

View File

@ -324,6 +324,7 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
*/
static int
mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
struct wireless_dev *wdev,
enum nl80211_tx_power_setting type,
int mbm)
{

View File

@ -490,9 +490,12 @@ static int rndis_scan(struct wiphy *wiphy,
static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
static int rndis_set_tx_power(struct wiphy *wiphy,
struct wireless_dev *wdev,
enum nl80211_tx_power_setting type,
int mbm);
static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);
static int rndis_get_tx_power(struct wiphy *wiphy,
struct wireless_dev *wdev,
int *dbm);
static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme);
@ -1903,6 +1906,7 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)
}
static int rndis_set_tx_power(struct wiphy *wiphy,
struct wireless_dev *wdev,
enum nl80211_tx_power_setting type,
int mbm)
{
@ -1930,7 +1934,9 @@ static int rndis_set_tx_power(struct wiphy *wiphy,
return -ENOTSUPP;
}
static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm)
static int rndis_get_tx_power(struct wiphy *wiphy,
struct wireless_dev *wdev,
int *dbm)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;

View File

@ -157,6 +157,7 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
* requested configurations.
*/
ieee80211_iterate_active_interfaces(rt2x00dev->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
rt2x00lib_intf_scheduled_iter,
rt2x00dev);
}
@ -225,9 +226,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
return;
/* send buffered bc/mc frames out for every bssid */
ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
rt2x00lib_bc_buffer_iter,
rt2x00dev);
ieee80211_iterate_active_interfaces_atomic(
rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
rt2x00lib_bc_buffer_iter, rt2x00dev);
/*
* Devices with pre tbtt interrupt don't need to update the beacon
* here as they will fetch the next beacon directly prior to
@ -237,9 +238,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
return;
/* fetch next beacon */
ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
rt2x00lib_beaconupdate_iter,
rt2x00dev);
ieee80211_iterate_active_interfaces_atomic(
rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
rt2x00lib_beaconupdate_iter, rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
@ -249,9 +250,9 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
return;
/* fetch next beacon */
ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
rt2x00lib_beaconupdate_iter,
rt2x00dev);
ieee80211_iterate_active_interfaces_atomic(
rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
rt2x00lib_beaconupdate_iter, rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);

View File

@ -424,9 +424,9 @@ int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return 0;
ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
rt2x00mac_set_tim_iter,
rt2x00dev);
ieee80211_iterate_active_interfaces_atomic(
rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
rt2x00mac_set_tim_iter, rt2x00dev);
/* queue work to upodate the beacon template */
ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);

View File

@ -677,7 +677,7 @@ static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
memset(data, 0, sizeof(*data));
data->cur_vif = cur_vif;
ieee80211_iterate_active_interfaces(hw,
ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL,
wl12xx_vif_count_iter, data);
}

View File

@ -905,6 +905,38 @@ struct ieee80211_tdls_data {
} u;
} __packed;
/*
* Peer-to-Peer IE attribute related definitions.
*/
/**
* enum ieee80211_p2p_attr_id - identifies type of peer-to-peer attribute.
*/
enum ieee80211_p2p_attr_id {
IEEE80211_P2P_ATTR_STATUS = 0,
IEEE80211_P2P_ATTR_MINOR_REASON,
IEEE80211_P2P_ATTR_CAPABILITY,
IEEE80211_P2P_ATTR_DEVICE_ID,
IEEE80211_P2P_ATTR_GO_INTENT,
IEEE80211_P2P_ATTR_GO_CONFIG_TIMEOUT,
IEEE80211_P2P_ATTR_LISTEN_CHANNEL,
IEEE80211_P2P_ATTR_GROUP_BSSID,
IEEE80211_P2P_ATTR_EXT_LISTEN_TIMING,
IEEE80211_P2P_ATTR_INTENDED_IFACE_ADDR,
IEEE80211_P2P_ATTR_MANAGABILITY,
IEEE80211_P2P_ATTR_CHANNEL_LIST,
IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
IEEE80211_P2P_ATTR_DEVICE_INFO,
IEEE80211_P2P_ATTR_GROUP_INFO,
IEEE80211_P2P_ATTR_GROUP_ID,
IEEE80211_P2P_ATTR_INTERFACE,
IEEE80211_P2P_ATTR_OPER_CHANNEL,
IEEE80211_P2P_ATTR_INVITE_FLAGS,
/* 19 - 220: Reserved */
IEEE80211_P2P_ATTR_VENDOR_SPECIFIC = 221,
IEEE80211_P2P_ATTR_MAX
};
/**
* struct ieee80211_bar - HT Block Ack Request
*

View File

@ -1545,13 +1545,19 @@ struct cfg80211_gtk_rekey_data {
* to a merge.
* @leave_ibss: Leave the IBSS.
*
* @set_mcast_rate: Set the specified multicast rate (only if vif is in ADHOC or
* MESH mode)
*
* @set_wiphy_params: Notify that wiphy parameters have changed;
* @changed bitfield (see &enum wiphy_params_flags) describes which values
* have changed. The actual parameter values are available in
* struct wiphy. If returning an error, no value should be changed.
*
* @set_tx_power: set the transmit power according to the parameters,
* the power passed is in mBm, to get dBm use MBM_TO_DBM().
* the power passed is in mBm, to get dBm use MBM_TO_DBM(). The
* wdev may be %NULL if power was set for the wiphy, and will
* always be %NULL unless the driver supports per-vif TX power
* (as advertised by the nl80211 feature flag.)
* @get_tx_power: store the current TX power into the dbm variable;
* return 0 if successful
*
@ -1746,11 +1752,15 @@ struct cfg80211_ops {
struct cfg80211_ibss_params *params);
int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev);
int (*set_mcast_rate)(struct wiphy *wiphy, struct net_device *dev,
int rate[IEEE80211_NUM_BANDS]);
int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);
int (*set_tx_power)(struct wiphy *wiphy,
int (*set_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
enum nl80211_tx_power_setting type, int mbm);
int (*get_tx_power)(struct wiphy *wiphy, int *dbm);
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
int *dbm);
int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
const u8 *addr);
@ -3550,7 +3560,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
* @len: length of the frame
* @freq: frequency the frame was received on
* @sig_dbm: signal strength in mBm, or 0 if unknown
* @gfp: allocation flags
*
* Use this function to report to userspace when a beacon was
* received. It is not useful to call this when there is no
@ -3558,7 +3567,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
*/
void cfg80211_report_obss_beacon(struct wiphy *wiphy,
const u8 *frame, size_t len,
int freq, int sig_dbm, gfp_t gfp);
int freq, int sig_dbm);
/**
* cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
@ -3608,6 +3617,25 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate);
*/
void cfg80211_unregister_wdev(struct wireless_dev *wdev);
/**
* cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer
* @ies: the input IE buffer
* @len: the input length
* @attr: the attribute ID to find
* @buf: output buffer, can be %NULL if the data isn't needed, e.g.
* if the function is only called to get the needed buffer size
* @bufsize: size of the output buffer
*
* The function finds a given P2P attribute in the (vendor) IEs and
* copies its contents to the given buffer.
*
* The return value is a negative error code (-%EILSEQ or -%ENOENT) if
* the data is malformed or the attribute can't be found (respectively),
* or the length of the found attribute (which can be zero).
*/
unsigned int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
u8 attr, u8 *buf, unsigned int bufsize);
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */

View File

@ -207,6 +207,9 @@ struct ieee80211_chanctx_conf {
* @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
* @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)
* @BSS_CHANGED_PS: PS changed for this BSS (STA mode)
* @BSS_CHANGED_TXPOWER: TX power setting changed for this interface
* @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS)
* changed (currently only in P2P client mode, GO mode will be later)
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@ -227,6 +230,8 @@ enum ieee80211_bss_change {
BSS_CHANGED_SSID = 1<<15,
BSS_CHANGED_AP_PROBE_RESP = 1<<16,
BSS_CHANGED_PS = 1<<17,
BSS_CHANGED_TXPOWER = 1<<18,
BSS_CHANGED_P2P_PS = 1<<19,
/* when adding here, make sure to change ieee80211_reconfig */
};
@ -309,6 +314,9 @@ enum ieee80211_rssi_event {
* @ssid: The SSID of the current vif. Only valid in AP-mode.
* @ssid_len: Length of SSID given in @ssid.
* @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode.
* @txpower: TX power in dBm
* @p2p_ctwindow: P2P CTWindow, only for P2P client interfaces
* @p2p_oppps: P2P opportunistic PS is enabled
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@ -341,6 +349,9 @@ struct ieee80211_bss_conf {
u8 ssid[IEEE80211_MAX_SSID_LEN];
size_t ssid_len;
bool hidden_ssid;
int txpower;
u8 p2p_ctwindow;
bool p2p_oppps;
};
/**
@ -884,7 +895,8 @@ enum ieee80211_smps_mode {
* powersave documentation below. This variable is valid only when
* the CONF_PS flag is set.
*
* @power_level: requested transmit power (in dBm)
* @power_level: requested transmit power (in dBm), backward compatibility
* value only that is set to the minimum of all interfaces
*
* @channel: the channel to tune to
* @channel_type: the channel (HT) type
@ -2381,6 +2393,17 @@ enum ieee80211_rate_control_changed {
* to vif. Possible use is for hw queue remapping.
* @unassign_vif_chanctx: Notifies device driver about channel context being
* unbound from vif.
* @start_ap: Start operation on the AP interface, this is called after all the
* information in bss_conf is set and beacon can be retrieved. A channel
* context is bound before this is called. Note that if the driver uses
* software scan or ROC, this (and @stop_ap) isn't called when the AP is
* just "paused" for scanning/ROC, which is indicated by the beacon being
* disabled/enabled via @bss_info_changed.
* @stop_ap: Stop operation on the AP interface.
*
* @restart_complete: Called after a call to ieee80211_restart_hw(), when the
* reconfiguration has completed. This can help the driver implement the
* reconfiguration step. This callback may sleep.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@ -2406,6 +2429,9 @@ struct ieee80211_ops {
struct ieee80211_bss_conf *info,
u32 changed);
int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
u64 (*prepare_multicast)(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list);
void (*configure_filter)(struct ieee80211_hw *hw,
@ -2539,6 +2565,8 @@ struct ieee80211_ops {
void (*unassign_vif_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_chanctx_conf *ctx);
void (*restart_complete)(struct ieee80211_hw *hw);
};
/**
@ -3384,6 +3412,21 @@ void ieee80211_sched_scan_results(struct ieee80211_hw *hw);
*/
void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);
/**
* enum ieee80211_interface_iteration_flags - interface iteration flags
* @IEEE80211_IFACE_ITER_NORMAL: Iterate over all interfaces that have
* been added to the driver; However, note that during hardware
* reconfiguration (after restart_hw) it will iterate over a new
* interface and over all the existing interfaces even if they
* haven't been re-added to the driver yet.
* @IEEE80211_IFACE_ITER_RESUME_ALL: During resume, iterate over all
* interfaces, even if they haven't been re-added to the driver yet.
*/
enum ieee80211_interface_iteration_flags {
IEEE80211_IFACE_ITER_NORMAL = 0,
IEEE80211_IFACE_ITER_RESUME_ALL = BIT(0),
};
/**
* ieee80211_iterate_active_interfaces - iterate active interfaces
*
@ -3392,13 +3435,15 @@ void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);
* This function allows the iterator function to sleep, when the iterator
* function is atomic @ieee80211_iterate_active_interfaces_atomic can
* be used.
* Does not iterate over a new interface during add_interface()
* Does not iterate over a new interface during add_interface().
*
* @hw: the hardware struct of which the interfaces should be iterated over
* @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
* @iterator: the iterator function to call
* @data: first argument of the iterator function
*/
void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
u32 iter_flags,
void (*iterator)(void *data, u8 *mac,
struct ieee80211_vif *vif),
void *data);
@ -3410,13 +3455,15 @@ void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
* hardware that are currently active and calls the callback for them.
* This function requires the iterator callback function to be atomic,
* if that is not desired, use @ieee80211_iterate_active_interfaces instead.
* Does not iterate over a new interface during add_interface()
* Does not iterate over a new interface during add_interface().
*
* @hw: the hardware struct of which the interfaces should be iterated over
* @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
* @iterator: the iterator function to call, cannot sleep
* @data: first argument of the iterator function
*/
void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
u32 iter_flags,
void (*iterator)(void *data,
u8 *mac,
struct ieee80211_vif *vif),

View File

@ -578,6 +578,9 @@
* station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON
* is used for this.
*
* @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames
* for IBSS or MESH vif.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@ -726,6 +729,8 @@ enum nl80211_commands {
NL80211_CMD_CONN_FAILED,
NL80211_CMD_SET_MCAST_RATE,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@ -3051,6 +3056,7 @@ enum nl80211_ap_sme_features {
* @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan
* @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported
* @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif
* @NL80211_FEATURE_VIF_TXPOWER: The driver supports per-vif TX power setting
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@ -3062,6 +3068,7 @@ enum nl80211_feature_flags {
NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6,
NL80211_FEATURE_SCAN_FLUSH = 1 << 7,
NL80211_FEATURE_AP_SCAN = 1 << 8,
NL80211_FEATURE_VIF_TXPOWER = 1 << 9,
};
/**

View File

@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/crypto.h>
#include <linux/export.h>
#include <linux/err.h>
#include <crypto/aes.h>

View File

@ -922,6 +922,15 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
return err;
changed |= err;
err = drv_start_ap(sdata->local, sdata);
if (err) {
old = rtnl_dereference(sdata->u.ap.beacon);
if (old)
kfree_rcu(old, rcu_head);
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
return err;
}
ieee80211_bss_info_change_notify(sdata, changed);
netif_carrier_on(dev);
@ -953,26 +962,38 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata, *vlan;
struct beacon_data *old;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_sub_if_data *vlan;
struct ieee80211_local *local = sdata->local;
struct beacon_data *old_beacon;
struct probe_resp *old_probe_resp;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
old = rtnl_dereference(sdata->u.ap.beacon);
if (!old)
old_beacon = rtnl_dereference(sdata->u.ap.beacon);
if (!old_beacon)
return -ENOENT;
old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);
/* turn off carrier for this interface and dependent VLANs */
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
netif_carrier_off(vlan->dev);
netif_carrier_off(dev);
/* remove beacon and probe response */
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
kfree_rcu(old_beacon, rcu_head);
if (old_probe_resp)
kfree_rcu(old_probe_resp, rcu_head);
kfree_rcu(old, rcu_head);
sta_info_flush(sdata->local, sdata);
sta_info_flush(local, sdata);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
drv_stop_ap(sdata->local, sdata);
/* free all potentially still buffered bcast frames */
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
skb_queue_purge(&sdata->u.ap.ps.bc_buf);
ieee80211_vif_release_channel(sdata);
return 0;
@ -1933,6 +1954,16 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));
}
static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
int rate[IEEE80211_NUM_BANDS])
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate));
return 0;
}
static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
@ -1971,45 +2002,65 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
}
static int ieee80211_set_tx_power(struct wiphy *wiphy,
struct wireless_dev *wdev,
enum nl80211_tx_power_setting type, int mbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_channel *chan = local->_oper_channel;
u32 changes = 0;
struct ieee80211_sub_if_data *sdata;
/* FIXME */
if (local->use_chanctx)
return -EOPNOTSUPP;
if (wdev) {
sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
switch (type) {
case NL80211_TX_POWER_AUTOMATIC:
sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
break;
case NL80211_TX_POWER_LIMITED:
case NL80211_TX_POWER_FIXED:
if (mbm < 0 || (mbm % 100))
return -EOPNOTSUPP;
sdata->user_power_level = MBM_TO_DBM(mbm);
break;
}
ieee80211_recalc_txpower(sdata);
return 0;
}
switch (type) {
case NL80211_TX_POWER_AUTOMATIC:
local->user_power_level = -1;
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
break;
case NL80211_TX_POWER_LIMITED:
if (mbm < 0 || (mbm % 100))
return -EOPNOTSUPP;
local->user_power_level = MBM_TO_DBM(mbm);
break;
case NL80211_TX_POWER_FIXED:
if (mbm < 0 || (mbm % 100))
return -EOPNOTSUPP;
/* TODO: move to cfg80211 when it knows the channel */
if (MBM_TO_DBM(mbm) > chan->max_power)
return -EINVAL;
local->user_power_level = MBM_TO_DBM(mbm);
break;
}
ieee80211_hw_config(local, changes);
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list)
sdata->user_power_level = local->user_power_level;
list_for_each_entry(sdata, &local->interfaces, list)
ieee80211_recalc_txpower(sdata);
mutex_unlock(&local->iflist_mtx);
return 0;
}
static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
static int ieee80211_get_tx_power(struct wiphy *wiphy,
struct wireless_dev *wdev,
int *dbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
*dbm = local->hw.conf.power_level;
if (!local->use_chanctx)
*dbm = local->hw.conf.power_level;
else
*dbm = sdata->vif.bss_conf.txpower;
return 0;
}
@ -2341,13 +2392,22 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
list_add_tail(&roc->list, &local->roc_list);
/*
* cookie is either the roc (for normal roc)
* cookie is either the roc cookie (for normal roc)
* or the SKB (for mgmt TX)
*/
if (txskb)
if (!txskb) {
/* local->mtx protects this */
local->roc_cookie_counter++;
roc->cookie = local->roc_cookie_counter;
/* wow, you wrapped 64 bits ... more likely a bug */
if (WARN_ON(roc->cookie == 0)) {
roc->cookie = 1;
local->roc_cookie_counter++;
}
*cookie = roc->cookie;
} else {
*cookie = (unsigned long)txskb;
else
*cookie = (unsigned long)roc;
}
return 0;
}
@ -2382,7 +2442,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
struct ieee80211_roc_work *dep, *tmp2;
list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) {
if (!mgmt_tx && (unsigned long)dep != cookie)
if (!mgmt_tx && dep->cookie != cookie)
continue;
else if (mgmt_tx && dep->mgmt_tx_cookie != cookie)
continue;
@ -2394,7 +2454,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
return 0;
}
if (!mgmt_tx && (unsigned long)roc != cookie)
if (!mgmt_tx && roc->cookie != cookie)
continue;
else if (mgmt_tx && roc->mgmt_tx_cookie != cookie)
continue;
@ -3130,6 +3190,7 @@ struct cfg80211_ops mac80211_config_ops = {
.disassoc = ieee80211_disassoc,
.join_ibss = ieee80211_join_ibss,
.leave_ibss = ieee80211_leave_ibss,
.set_mcast_rate = ieee80211_set_mcast_rate,
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,

View File

@ -173,6 +173,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
ctx->refcount++;
ieee80211_recalc_txpower(sdata);
return 0;
}

View File

@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
@ -168,6 +169,29 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
IEEE80211_IF_FILE(flags, flags, HEX);
IEEE80211_IF_FILE(state, state, LHEX);
IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC);
IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC);
IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC);
IEEE80211_IF_FILE(user_power_level, user_power_level, DEC);
static ssize_t
ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata,
char *buf, int buflen)
{
int len;
len = scnprintf(buf, buflen, "AC queues: VO:%d VI:%d BE:%d BK:%d\n",
sdata->vif.hw_queue[IEEE80211_AC_VO],
sdata->vif.hw_queue[IEEE80211_AC_VI],
sdata->vif.hw_queue[IEEE80211_AC_BE],
sdata->vif.hw_queue[IEEE80211_AC_BK]);
if (sdata->vif.type == NL80211_IFTYPE_AP)
len += scnprintf(buf + len, buflen - len, "cab queue: %d\n",
sdata->vif.cab_queue);
return len;
}
__IEEE80211_IF_FILE(hw_queues, NULL);
/* STA attributes */
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
@ -245,27 +269,6 @@ static ssize_t ieee80211_if_fmt_tkip_mic_test(
return -EOPNOTSUPP;
}
static int hwaddr_aton(const char *txt, u8 *addr)
{
int i;
for (i = 0; i < ETH_ALEN; i++) {
int a, b;
a = hex_to_bin(*txt++);
if (a < 0)
return -1;
b = hex_to_bin(*txt++);
if (b < 0)
return -1;
*addr++ = (a << 4) | b;
if (i < 5 && *txt++ != ':')
return -1;
}
return 0;
}
static ssize_t ieee80211_if_parse_tkip_mic_test(
struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
{
@ -275,13 +278,7 @@ static ssize_t ieee80211_if_parse_tkip_mic_test(
struct ieee80211_hdr *hdr;
__le16 fc;
/*
* Assume colon-delimited MAC address with possible white space
* following.
*/
if (buflen < 3 * ETH_ALEN - 1)
return -EINVAL;
if (hwaddr_aton(buf, addr) < 0)
if (!mac_pton(buf, addr))
return -EINVAL;
if (!ieee80211_sdata_running(sdata))
@ -307,13 +304,16 @@ static ssize_t ieee80211_if_parse_tkip_mic_test(
case NL80211_IFTYPE_STATION:
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
/* BSSID SA DA */
if (sdata->vif.bss_conf.bssid == NULL) {
mutex_lock(&sdata->u.mgd.mtx);
if (!sdata->u.mgd.associated) {
mutex_unlock(&sdata->u.mgd.mtx);
dev_kfree_skb(skb);
return -ENOTCONN;
}
memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN);
memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN);
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
memcpy(hdr->addr3, addr, ETH_ALEN);
mutex_unlock(&sdata->u.mgd.mtx);
break;
default:
dev_kfree_skb(skb);
@ -443,7 +443,7 @@ static ssize_t ieee80211_if_parse_tsf(
}
ret = kstrtoull(buf, 10, &tsf);
if (ret < 0)
return -EINVAL;
return ret;
if (tsf_is_delta)
tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf;
if (local->ops->set_tsf) {
@ -531,6 +531,7 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
DEBUGFS_ADD(hw_queues);
}
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
@ -632,6 +633,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(flags);
DEBUGFS_ADD(state);
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(txpower);
DEBUGFS_ADD(user_power_level);
DEBUGFS_ADD(ap_power_level);
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
add_common_files(sdata);

View File

@ -936,4 +936,39 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
trace_drv_return_void(local);
}
static inline int drv_start_ap(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
int ret = 0;
check_sdata_in_driver(sdata);
trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf);
if (local->ops->start_ap)
ret = local->ops->start_ap(&local->hw, &sdata->vif);
trace_drv_return_int(local, ret);
return ret;
}
static inline void drv_stop_ap(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
check_sdata_in_driver(sdata);
trace_drv_stop_ap(local, sdata);
if (local->ops->stop_ap)
local->ops->stop_ap(&local->hw, &sdata->vif);
trace_drv_return_void(local);
}
static inline void drv_restart_complete(struct ieee80211_local *local)
{
might_sleep();
trace_drv_restart_complete(local);
if (local->ops->restart_complete)
local->ops->restart_complete(&local->hw);
trace_drv_return_void(local);
}
#endif /* __MAC80211_DRIVER_OPS */

View File

@ -56,6 +56,9 @@ struct ieee80211_local;
#define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024))
#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x))
/* power level hasn't been configured (or set to automatic) */
#define IEEE80211_UNSET_POWER_LEVEL INT_MIN
/*
* Some APs experience problems when working with U-APSD. Decrease the
* probability of that happening by using legacy mode for all ACs but VO.
@ -353,7 +356,7 @@ struct ieee80211_roc_work {
u32 duration, req_duration;
struct sk_buff *frame;
u64 mgmt_tx_cookie;
u64 cookie, mgmt_tx_cookie;
};
/* flags used in struct ieee80211_if_managed.flags */
@ -470,6 +473,8 @@ struct ieee80211_if_managed {
u8 use_4addr;
u8 p2p_noa_index;
/* Signal strength from the last Beacon frame in the current BSS. */
int last_beacon_signal;
@ -743,6 +748,9 @@ struct ieee80211_sub_if_data {
u8 needed_rx_chains;
enum ieee80211_smps_mode smps_mode;
int user_power_level; /* in dBm */
int ap_power_level; /* in dBm */
/*
* AP this belongs to: self in AP mode and
* corresponding AP in VLAN mode, NULL for
@ -1117,8 +1125,7 @@ struct ieee80211_local {
int dynamic_ps_user_timeout;
bool disable_dynamic_ps;
int user_power_level; /* in dBm */
int ap_power_level; /* in dBm */
int user_power_level; /* in dBm, for all interfaces */
enum ieee80211_smps_mode smps_mode;
@ -1137,6 +1144,7 @@ struct ieee80211_local {
struct list_head roc_list;
struct work_struct hw_roc_start, hw_roc_done;
unsigned long hw_roc_start_time;
u64 roc_cookie_counter;
struct idr ack_status_frames;
spinlock_t ack_status_lock;
@ -1365,6 +1373,9 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up);
void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata);
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
{
return test_bit(SDATA_STATE_RUNNING, &sdata->state);

View File

@ -42,6 +42,41 @@
* by either the RTNL, the iflist_mtx or RCU.
*/
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_chanctx_conf *chanctx_conf;
int power;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
return false;
}
power = chanctx_conf->channel->max_power;
rcu_read_unlock();
if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
power = min(power, sdata->user_power_level);
if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL)
power = min(power, sdata->ap_power_level);
if (power != sdata->vif.bss_conf.txpower) {
sdata->vif.bss_conf.txpower = power;
ieee80211_hw_config(sdata->local, 0);
return true;
}
return false;
}
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
{
if (__ieee80211_recalc_txpower(sdata))
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
}
static u32 ieee80211_idle_off(struct ieee80211_local *local,
const char *reason)
@ -744,31 +779,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
/* APs need special treatment */
if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan, *tmpsdata;
struct beacon_data *old_beacon =
rtnl_dereference(sdata->u.ap.beacon);
struct probe_resp *old_probe_resp =
rtnl_dereference(sdata->u.ap.probe_resp);
/* sdata_running will return false, so this will disable */
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BEACON_ENABLED);
/* remove beacon and probe response */
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
synchronize_rcu();
kfree(old_beacon);
kfree(old_probe_resp);
/* down all dependent devices, that is VLANs */
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
u.vlan.list)
dev_close(vlan->dev);
WARN_ON(!list_empty(&sdata->u.ap.vlans));
/* free all potentially still buffered bcast frames */
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
skb_queue_purge(&sdata->u.ap.ps.bc_buf);
} else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
ieee80211_mgd_stop(sdata);
}
@ -1529,6 +1545,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
ieee80211_set_default_queues(sdata);
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
sdata->user_power_level = local->user_power_level;
/* setup type-dependent data */
ieee80211_setup_sdata(sdata, type);

View File

@ -95,11 +95,13 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_channel *chan;
u32 changed = 0;
int power;
enum nl80211_channel_type channel_type;
u32 offchannel_flag;
bool scanning = false;
offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
if (local->scan_channel) {
@ -146,16 +148,18 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
changed |= IEEE80211_CONF_CHANGE_SMPS;
}
if (test_bit(SCAN_SW_SCANNING, &local->scanning) ||
test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
test_bit(SCAN_HW_SCANNING, &local->scanning) ||
!local->ap_power_level)
power = chan->max_power;
else
power = min(chan->max_power, local->ap_power_level);
scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
test_bit(SCAN_HW_SCANNING, &local->scanning);
power = chan->max_power;
if (local->user_power_level >= 0)
power = min(power, local->user_power_level);
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (!rcu_access_pointer(sdata->vif.chanctx_conf))
continue;
power = min(power, sdata->vif.bss_conf.txpower);
}
rcu_read_unlock();
if (local->hw.conf.power_level != power) {
changed |= IEEE80211_CONF_CHANGE_POWER;
@ -600,7 +604,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
NL80211_FEATURE_SAE |
NL80211_FEATURE_HT_IBSS;
NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_VIF_TXPOWER;
if (!ops->hw_scan)
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
@ -633,7 +638,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
IEEE80211_RADIOTAP_MCS_HAVE_GI |
IEEE80211_RADIOTAP_MCS_HAVE_BW;
local->user_power_level = -1;
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
INIT_LIST_HEAD(&local->interfaces);

View File

@ -820,10 +820,10 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
cbss->beacon_interval));
}
static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel,
const u8 *country_ie, u8 country_ie_len,
const u8 *pwr_constr_elem)
static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel,
const u8 *country_ie, u8 country_ie_len,
const u8 *pwr_constr_elem)
{
struct ieee80211_country_ie_triplet *triplet;
int chan = ieee80211_frequency_to_channel(channel->center_freq);
@ -832,7 +832,7 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
/* Invalid IE */
if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
return;
return 0;
triplet = (void *)(country_ie + 3);
country_ie_len -= 3;
@ -873,19 +873,21 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
}
if (!have_chan_pwr)
return;
return 0;
new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
if (sdata->local->ap_power_level == new_ap_level)
return;
if (sdata->ap_power_level == new_ap_level)
return 0;
sdata_info(sdata,
"Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
new_ap_level, chan_pwr, *pwr_constr_elem,
sdata->u.mgd.bssid);
sdata->local->ap_power_level = new_ap_level;
ieee80211_hw_config(sdata->local, 0);
sdata->ap_power_level = new_ap_level;
if (__ieee80211_recalc_txpower(sdata))
return BSS_CHANGED_TXPOWER;
return 0;
}
void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
@ -1363,6 +1365,22 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
if (sdata->vif.p2p) {
u8 noa[2];
int ret;
ret = cfg80211_get_p2p_attr(cbss->information_elements,
cbss->len_information_elements,
IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
noa, sizeof(noa));
if (ret >= 2) {
bss_conf->p2p_oppps = noa[1] & 0x80;
bss_conf->p2p_ctwindow = noa[1] & 0x7f;
bss_info_changed |= BSS_CHANGED_P2P_PS;
sdata->u.mgd.p2p_noa_index = noa[0];
}
}
/* just to be sure */
ieee80211_stop_poll(sdata);
@ -1485,11 +1503,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_ASSOC;
sdata->vif.bss_conf.assoc = false;
sdata->vif.bss_conf.p2p_ctwindow = 0;
sdata->vif.bss_conf.p2p_oppps = false;
/* on the next assoc, re-program HT parameters */
memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
local->ap_power_level = 0;
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
@ -2592,6 +2613,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}
}
if (sdata->vif.p2p) {
u8 noa[2];
int ret;
ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable,
len - baselen,
IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
noa, sizeof(noa));
if (ret >= 2 && sdata->u.mgd.p2p_noa_index != noa[0]) {
bss_conf->p2p_oppps = noa[1] & 0x80;
bss_conf->p2p_ctwindow = noa[1] & 0x7f;
changed |= BSS_CHANGED_P2P_PS;
sdata->u.mgd.p2p_noa_index = noa[0];
/*
* make sure we update all information, the CRC
* mechanism doesn't look at P2P attributes.
*/
ifmgd->beacon_crc_valid = false;
}
}
if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
return;
ifmgd->beacon_crc = ncrc;
@ -2623,10 +2665,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (elems.country_elem && elems.pwr_constr_elem &&
mgmt->u.probe_resp.capab_info &
cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
ieee80211_handle_pwr_constr(sdata, chan,
elems.country_elem,
elems.country_elem_len,
elems.pwr_constr_elem);
changed |= ieee80211_handle_pwr_constr(sdata, chan,
elems.country_elem,
elems.country_elem_len,
elems.pwr_constr_elem);
ieee80211_bss_info_change_notify(sdata, changed);
}
@ -3660,40 +3702,44 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
bool tx = !req->local_state_change;
bool sent_frame = false;
mutex_lock(&ifmgd->mtx);
if (ifmgd->auth_data) {
ieee80211_destroy_auth_data(sdata, false);
mutex_unlock(&ifmgd->mtx);
return 0;
}
sdata_info(sdata,
"deauthenticating from %pM by local choice (reason=%d)\n",
req->bssid, req->reason_code);
if (ifmgd->associated &&
ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
req->reason_code, tx, frame_buf);
} else {
if (ifmgd->auth_data) {
drv_mgd_prepare_tx(sdata->local, sdata);
ieee80211_send_deauth_disassoc(sdata, req->bssid,
IEEE80211_STYPE_DEAUTH,
req->reason_code, tx,
frame_buf);
ieee80211_destroy_auth_data(sdata, false);
mutex_unlock(&ifmgd->mtx);
sent_frame = tx;
goto out;
}
if (ifmgd->associated &&
ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
req->reason_code, tx, frame_buf);
sent_frame = tx;
}
mutex_unlock(&ifmgd->mtx);
__cfg80211_send_deauth(sdata->dev, frame_buf,
IEEE80211_DEAUTH_FRAME_LEN);
out:
mutex_lock(&sdata->local->mtx);
ieee80211_recalc_idle(sdata->local);
mutex_unlock(&sdata->local->mtx);
if (sent_frame)
__cfg80211_send_deauth(sdata->dev, frame_buf,
IEEE80211_DEAUTH_FRAME_LEN);
return 0;
}

View File

@ -204,7 +204,7 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
roc->frame = NULL;
}
} else {
cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc,
cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie,
roc->chan, roc->chan_type,
roc->req_duration, GFP_KERNEL);
}
@ -320,9 +320,8 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
if (!roc->mgmt_tx_cookie)
cfg80211_remain_on_channel_expired(&roc->sdata->wdev,
(unsigned long)roc,
roc->chan, roc->chan_type,
GFP_KERNEL);
roc->cookie, roc->chan,
roc->chan_type, GFP_KERNEL);
list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
ieee80211_roc_notify_destroy(dep);

View File

@ -135,6 +135,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BEACON_ENABLED);
if (sdata->vif.type == NL80211_IFTYPE_AP &&
rcu_access_pointer(sdata->u.ap.beacon))
drv_stop_ap(local, sdata);
/* the interface is leaving the channel and is removed */
ieee80211_vif_release_channel(sdata);
drv_remove_interface(local, sdata);

View File

@ -54,8 +54,7 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
return skb;
}
static inline int should_drop_frame(struct sk_buff *skb,
int present_fcs_len)
static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@ -130,15 +129,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
(1 << IEEE80211_RADIOTAP_RX_FLAGS));
rthdr->it_len = cpu_to_le16(rtap_len);
pos = (unsigned char *)(rthdr+1);
pos = (unsigned char *)(rthdr + 1);
/* the order of the following fields is important */
/* IEEE80211_RADIOTAP_TSFT */
if (status->flag & RX_FLAG_MACTIME_MPDU) {
put_unaligned_le64(status->mactime, pos);
rthdr->it_present |=
cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
pos += 8;
}
@ -374,7 +372,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
return origskb;
}
static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
@ -481,8 +478,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data;
struct ieee80211_mmie *mmie;
if (skb->len < 24 + sizeof(*mmie) ||
!is_multicast_ether_addr(hdr->da))
if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
return -1;
if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr))
@ -497,9 +493,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
return le16_to_cpu(mmie->key_id);
}
static ieee80211_rx_result
ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
char *dev_addr = rx->sdata->vif.addr;
@ -507,7 +501,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
if (ieee80211_is_data(hdr->frame_control)) {
if (is_multicast_ether_addr(hdr->addr1)) {
if (ieee80211_has_tods(hdr->frame_control) ||
!ieee80211_has_fromds(hdr->frame_control))
!ieee80211_has_fromds(hdr->frame_control))
return RX_DROP_MONITOR;
if (ether_addr_equal(hdr->addr3, dev_addr))
return RX_DROP_MONITOR;
@ -539,7 +533,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
mgmt = (struct ieee80211_mgmt *)hdr;
category = mgmt->u.action.category;
if (category != WLAN_CATEGORY_MESH_ACTION &&
category != WLAN_CATEGORY_SELF_PROTECTED)
category != WLAN_CATEGORY_SELF_PROTECTED)
return RX_DROP_MONITOR;
return RX_CONTINUE;
}
@ -551,7 +545,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
return RX_DROP_MONITOR;
}
return RX_CONTINUE;
@ -575,7 +568,6 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
return (sq1 - sq2) & SEQ_MASK;
}
static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
struct tid_ampdu_rx *tid_agg_rx,
int index)
@ -1585,18 +1577,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
}
static int
ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
{
if (unlikely(!rx->sta ||
!test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
return -EACCES;
return 0;
}
static int
ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
{
struct sk_buff *skb = rx->skb;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
@ -1618,8 +1607,7 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
return 0;
}
static int
ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
@ -2003,7 +1991,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
} else {
/* unable to resolve next hop */
mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3,
0, reason, fwd_hdr->addr2, sdata);
0, reason, fwd_hdr->addr2, sdata);
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
kfree_skb(fwd_skb);
return RX_DROP_MONITOR;
@ -2212,7 +2200,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
cfg80211_report_obss_beacon(rx->local->hw.wiphy,
rx->skb->data, rx->skb->len,
status->freq, sig, GFP_ATOMIC);
status->freq, sig);
rx->flags |= IEEE80211_RX_BEACON_REPORTED;
}
@ -2412,7 +2400,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (!ieee80211_vif_is_mesh(&sdata->vif))
break;
if (mesh_action_is_path_sel(mgmt) &&
(!mesh_path_sel_is_hwmp(sdata)))
!mesh_path_sel_is_hwmp(sdata))
break;
goto queue;
}
@ -2468,7 +2456,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
return RX_QUEUED;
}
return RX_CONTINUE;
}

View File

@ -325,6 +325,75 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band
}
static void ieee80211_report_used_skb(struct ieee80211_local *local,
struct sk_buff *skb, bool dropped)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (void *)skb->data;
bool acked = info->flags & IEEE80211_TX_STAT_ACK;
if (dropped)
acked = false;
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_sub_if_data *iter_sdata;
u64 cookie = (unsigned long)skb;
rcu_read_lock();
if (skb->dev) {
list_for_each_entry_rcu(iter_sdata, &local->interfaces,
list) {
if (!iter_sdata->dev)
continue;
if (skb->dev == iter_sdata->dev) {
sdata = iter_sdata;
break;
}
}
} else {
sdata = rcu_dereference(local->p2p_sdata);
}
if (!sdata)
skb->dev = NULL;
else if (ieee80211_is_nullfunc(hdr->frame_control) ||
ieee80211_is_qos_nullfunc(hdr->frame_control)) {
cfg80211_probe_status(sdata->dev, hdr->addr1,
cookie, acked, GFP_ATOMIC);
} else {
cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
skb->len, acked, GFP_ATOMIC);
}
rcu_read_unlock();
}
if (unlikely(info->ack_frame_id)) {
struct sk_buff *ack_skb;
unsigned long flags;
spin_lock_irqsave(&local->ack_status_lock, flags);
ack_skb = idr_find(&local->ack_status_frames,
info->ack_frame_id);
if (ack_skb)
idr_remove(&local->ack_status_frames,
info->ack_frame_id);
spin_unlock_irqrestore(&local->ack_status_lock, flags);
if (ack_skb) {
if (!dropped) {
/* consumes ack_skb */
skb_complete_wifi_ack(ack_skb, acked);
} else {
dev_kfree_skb_any(ack_skb);
}
}
}
}
/*
* Use a static threshold for now, best value to be determined
* by testing ...
@ -516,62 +585,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
msecs_to_jiffies(10));
}
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
u64 cookie = (unsigned long)skb;
bool found = false;
acked = info->flags & IEEE80211_TX_STAT_ACK;
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (!sdata->dev)
continue;
if (skb->dev != sdata->dev)
continue;
found = true;
break;
}
if (!skb->dev) {
sdata = rcu_dereference(local->p2p_sdata);
if (sdata)
found = true;
}
if (!found)
skb->dev = NULL;
else if (ieee80211_is_nullfunc(hdr->frame_control) ||
ieee80211_is_qos_nullfunc(hdr->frame_control)) {
cfg80211_probe_status(sdata->dev, hdr->addr1,
cookie, acked, GFP_ATOMIC);
} else {
cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
skb->len, acked, GFP_ATOMIC);
}
rcu_read_unlock();
}
if (unlikely(info->ack_frame_id)) {
struct sk_buff *ack_skb;
unsigned long flags;
spin_lock_irqsave(&local->ack_status_lock, flags);
ack_skb = idr_find(&local->ack_status_frames,
info->ack_frame_id);
if (ack_skb)
idr_remove(&local->ack_status_frames,
info->ack_frame_id);
spin_unlock_irqrestore(&local->ack_status_lock, flags);
/* consumes ack_skb */
if (ack_skb)
skb_complete_wifi_ack(ack_skb,
info->flags & IEEE80211_TX_STAT_ACK);
}
ieee80211_report_used_skb(local, skb, false);
/* this was a transmitted frame, but now we want to reuse it */
skb_orphan(skb);
@ -647,25 +661,8 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);
void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (unlikely(info->ack_frame_id)) {
struct sk_buff *ack_skb;
unsigned long flags;
spin_lock_irqsave(&local->ack_status_lock, flags);
ack_skb = idr_find(&local->ack_status_frames,
info->ack_frame_id);
if (ack_skb)
idr_remove(&local->ack_status_frames,
info->ack_frame_id);
spin_unlock_irqrestore(&local->ack_status_lock, flags);
/* consumes ack_skb */
if (ack_skb)
dev_kfree_skb_any(ack_skb);
}
ieee80211_report_used_skb(local, skb, true);
dev_kfree_skb_any(skb);
}
EXPORT_SYMBOL(ieee80211_free_txskb);

View File

@ -342,6 +342,9 @@ TRACE_EVENT(drv_bss_info_changed,
__field(bool, ps);
__dynamic_array(u8, ssid, info->ssid_len);
__field(bool, hidden_ssid);
__field(int, txpower)
__field(u8, p2p_ctwindow)
__field(bool, p2p_oppps)
),
TP_fast_assign(
@ -376,6 +379,9 @@ TRACE_EVENT(drv_bss_info_changed,
__entry->ps = info->ps;
memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len);
__entry->hidden_ssid = info->hidden_ssid;
__entry->txpower = info->txpower;
__entry->p2p_ctwindow = info->p2p_ctwindow;
__entry->p2p_oppps = info->p2p_oppps;
),
TP_printk(
@ -1043,34 +1049,6 @@ DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel,
TP_ARGS(local)
);
TRACE_EVENT(drv_offchannel_tx,
TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int wait),
TP_ARGS(local, skb, chan, channel_type, wait),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(int, center_freq)
__field(int, channel_type)
__field(unsigned int, wait)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->center_freq = chan->center_freq;
__entry->channel_type = channel_type;
__entry->wait = wait;
),
TP_printk(
LOCAL_PR_FMT " freq:%dMHz, wait:%dms",
LOCAL_PR_ARG, __entry->center_freq, __entry->wait
)
);
TRACE_EVENT(drv_set_ringparam,
TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx),
@ -1396,6 +1374,48 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx,
TP_ARGS(local, sdata, ctx)
);
TRACE_EVENT(drv_start_ap,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *info),
TP_ARGS(local, sdata, info),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
__field(u8, dtimper)
__field(u16, bcnint)
__dynamic_array(u8, ssid, info->ssid_len);
__field(bool, hidden_ssid);
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
__entry->dtimper = info->dtim_period;
__entry->bcnint = info->beacon_int;
memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len);
__entry->hidden_ssid = info->hidden_ssid;
),
TP_printk(
LOCAL_PR_FMT VIF_PR_FMT,
LOCAL_PR_ARG, VIF_PR_ARG
)
);
DEFINE_EVENT(local_sdata_evt, drv_stop_ap,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata),
TP_ARGS(local, sdata)
);
DEFINE_EVENT(local_only_evt, drv_restart_complete,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
);
/*
* Tracing for API calls that drivers call.
*/

View File

@ -2089,6 +2089,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
head_need = max_t(int, 0, head_need);
if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
ieee80211_free_txskb(&local->hw, skb);
skb = NULL;
goto fail_rcu;
}
}

View File

@ -512,7 +512,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
EXPORT_SYMBOL(ieee80211_wake_queues);
void ieee80211_iterate_active_interfaces(
struct ieee80211_hw *hw,
struct ieee80211_hw *hw, u32 iter_flags,
void (*iterator)(void *data, u8 *mac,
struct ieee80211_vif *vif),
void *data)
@ -530,6 +530,9 @@ void ieee80211_iterate_active_interfaces(
default:
break;
}
if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
!(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
continue;
if (ieee80211_sdata_running(sdata))
iterator(data, sdata->vif.addr,
&sdata->vif);
@ -537,7 +540,9 @@ void ieee80211_iterate_active_interfaces(
sdata = rcu_dereference_protected(local->monitor_sdata,
lockdep_is_held(&local->iflist_mtx));
if (sdata)
if (sdata &&
(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
sdata->flags & IEEE80211_SDATA_IN_DRIVER))
iterator(data, sdata->vif.addr, &sdata->vif);
mutex_unlock(&local->iflist_mtx);
@ -545,7 +550,7 @@ void ieee80211_iterate_active_interfaces(
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
void ieee80211_iterate_active_interfaces_atomic(
struct ieee80211_hw *hw,
struct ieee80211_hw *hw, u32 iter_flags,
void (*iterator)(void *data, u8 *mac,
struct ieee80211_vif *vif),
void *data)
@ -563,13 +568,18 @@ void ieee80211_iterate_active_interfaces_atomic(
default:
break;
}
if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
!(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
continue;
if (ieee80211_sdata_running(sdata))
iterator(data, sdata->vif.addr,
&sdata->vif);
}
sdata = rcu_dereference(local->monitor_sdata);
if (sdata)
if (sdata &&
(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
sdata->flags & IEEE80211_SDATA_IN_DRIVER))
iterator(data, sdata->vif.addr, &sdata->vif);
rcu_read_unlock();
@ -1412,6 +1422,23 @@ int ieee80211_reconfig(struct ieee80211_local *local)
WARN_ON(drv_add_chanctx(local, ctx));
mutex_unlock(&local->chanctx_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
struct ieee80211_chanctx_conf *ctx_conf;
if (!ieee80211_sdata_running(sdata))
continue;
mutex_lock(&local->chanctx_mtx);
ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (ctx_conf) {
ctx = container_of(ctx_conf, struct ieee80211_chanctx,
conf);
drv_assign_vif_chanctx(local, sdata, ctx);
}
mutex_unlock(&local->chanctx_mtx);
}
/* add STAs back */
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
@ -1452,22 +1479,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* Finally also reconfigure all the BSS information */
list_for_each_entry(sdata, &local->interfaces, list) {
struct ieee80211_chanctx_conf *ctx_conf;
u32 changed;
if (!ieee80211_sdata_running(sdata))
continue;
mutex_lock(&local->chanctx_mtx);
ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (ctx_conf) {
ctx = container_of(ctx_conf, struct ieee80211_chanctx,
conf);
drv_assign_vif_chanctx(local, sdata, ctx);
}
mutex_unlock(&local->chanctx_mtx);
/* common change flags for all interface types */
changed = BSS_CHANGED_ERP_CTS_PROT |
BSS_CHANGED_ERP_PREAMBLE |
@ -1478,7 +1494,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
BSS_CHANGED_BSSID |
BSS_CHANGED_CQM |
BSS_CHANGED_QOS |
BSS_CHANGED_IDLE;
BSS_CHANGED_IDLE |
BSS_CHANGED_TXPOWER;
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
@ -1495,9 +1512,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
case NL80211_IFTYPE_AP:
changed |= BSS_CHANGED_SSID;
if (sdata->vif.type == NL80211_IFTYPE_AP)
if (sdata->vif.type == NL80211_IFTYPE_AP) {
changed |= BSS_CHANGED_AP_PROBE_RESP;
if (rcu_access_pointer(sdata->u.ap.beacon))
drv_start_ap(local, sdata);
}
/* fall through */
case NL80211_IFTYPE_MESH_POINT:
changed |= BSS_CHANGED_BEACON |
@ -1594,8 +1615,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
* If this is for hw restart things are still running.
* We may want to change that later, however.
*/
if (!local->suspended)
if (!local->suspended) {
drv_restart_complete(local);
return 0;
}
#ifdef CONFIG_PM
/* first set suspended false, then resuming */

View File

@ -28,6 +28,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
if (!err) {
wdev->beacon_interval = 0;
wdev->channel = NULL;
wdev->ssid_len = 0;
}
return err;

View File

@ -326,6 +326,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
mutex_init(&rdev->devlist_mtx);
mutex_init(&rdev->sched_scan_mtx);
INIT_LIST_HEAD(&rdev->wdev_list);
INIT_LIST_HEAD(&rdev->beacon_registrations);
spin_lock_init(&rdev->beacon_registrations_lock);
spin_lock_init(&rdev->bss_lock);
INIT_LIST_HEAD(&rdev->bss_list);
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
@ -698,10 +700,15 @@ EXPORT_SYMBOL(wiphy_unregister);
void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
{
struct cfg80211_internal_bss *scan, *tmp;
struct cfg80211_beacon_registration *reg, *treg;
rfkill_destroy(rdev->rfkill);
mutex_destroy(&rdev->mtx);
mutex_destroy(&rdev->devlist_mtx);
mutex_destroy(&rdev->sched_scan_mtx);
list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) {
list_del(&reg->list);
kfree(reg);
}
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
cfg80211_put_bss(&scan->pub);
kfree(rdev);

View File

@ -55,7 +55,8 @@ struct cfg80211_registered_device {
int opencount; /* also protected by devlist_mtx */
wait_queue_head_t dev_wait;
u32 ap_beacons_nlportid;
struct list_head beacon_registrations;
spinlock_t beacon_registrations_lock;
/* protected by RTNL only */
int num_running_ifaces;
@ -260,6 +261,10 @@ enum cfg80211_chan_mode {
CHAN_MODE_EXCLUSIVE,
};
struct cfg80211_beacon_registration {
struct list_head list;
u32 nlportid;
};
/* free object */
extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);

View File

@ -1110,6 +1110,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag
goto nla_put_failure;
}
CMD(start_p2p_device, START_P2P_DEVICE);
CMD(set_mcast_rate, SET_MCAST_RATE);
#ifdef CONFIG_NL80211_TESTMODE
CMD(testmode_cmd, TESTMODE);
@ -1516,10 +1517,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
result = 0;
mutex_lock(&rdev->mtx);
} else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
} else
wdev = netdev->ieee80211_ptr;
else
wdev = NULL;
/*
* end workaround code, by now the rdev is available
@ -1579,15 +1578,21 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
}
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
result = __nl80211_set_channel(rdev, wdev, info);
result = __nl80211_set_channel(rdev,
nl80211_can_set_dev_channel(wdev) ? wdev : NULL,
info);
if (result)
goto bad_res;
}
if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
struct wireless_dev *txp_wdev = wdev;
enum nl80211_tx_power_setting type;
int idx, mbm = 0;
if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
txp_wdev = NULL;
if (!rdev->ops->set_tx_power) {
result = -EOPNOTSUPP;
goto bad_res;
@ -1607,7 +1612,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
mbm = nla_get_u32(info->attrs[idx]);
}
result = rdev_set_tx_power(rdev, type, mbm);
result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
if (result)
goto bad_res;
}
@ -1782,6 +1787,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
goto nla_put_failure;
}
if (wdev->ssid_len) {
if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
goto nla_put_failure;
}
return genlmsg_end(msg, hdr);
nla_put_failure:
@ -2644,6 +2654,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
wdev->preset_chantype = params.channel_type;
wdev->beacon_interval = params.beacon_interval;
wdev->channel = params.channel;
wdev->ssid_len = params.ssid_len;
memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
}
return err;
}
@ -5444,6 +5456,36 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
return cfg80211_leave_ibss(rdev, dev, false);
}
static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
int mcast_rate[IEEE80211_NUM_BANDS];
u32 nla_rate;
int err;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
return -EOPNOTSUPP;
if (!rdev->ops->set_mcast_rate)
return -EOPNOTSUPP;
memset(mcast_rate, 0, sizeof(mcast_rate));
if (!info->attrs[NL80211_ATTR_MCAST_RATE])
return -EINVAL;
nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
return -EINVAL;
err = rdev->ops->set_mcast_rate(&rdev->wiphy, dev, mcast_rate);
return err;
}
#ifdef CONFIG_NL80211_TESTMODE
static struct genl_multicast_group nl80211_testmode_mcgrp = {
.name = "testmode",
@ -6899,16 +6941,35 @@ static int nl80211_probe_client(struct sk_buff *skb,
static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct cfg80211_beacon_registration *reg, *nreg;
int rv;
if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
return -EOPNOTSUPP;
if (rdev->ap_beacons_nlportid)
return -EBUSY;
nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
if (!nreg)
return -ENOMEM;
rdev->ap_beacons_nlportid = info->snd_portid;
/* First, check if already registered. */
spin_lock_bh(&rdev->beacon_registrations_lock);
list_for_each_entry(reg, &rdev->beacon_registrations, list) {
if (reg->nlportid == info->snd_portid) {
rv = -EALREADY;
goto out_err;
}
}
/* Add it to the list */
nreg->nlportid = info->snd_portid;
list_add(&nreg->list, &rdev->beacon_registrations);
spin_unlock_bh(&rdev->beacon_registrations_lock);
return 0;
out_err:
spin_unlock_bh(&rdev->beacon_registrations_lock);
kfree(nreg);
return rv;
}
static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
@ -7625,6 +7686,14 @@ static struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_MCAST_RATE,
.doit = nl80211_set_mcast_rate,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
@ -8914,43 +8983,46 @@ EXPORT_SYMBOL(cfg80211_probe_status);
void cfg80211_report_obss_beacon(struct wiphy *wiphy,
const u8 *frame, size_t len,
int freq, int sig_dbm, gfp_t gfp)
int freq, int sig_dbm)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct sk_buff *msg;
void *hdr;
u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid);
struct cfg80211_beacon_registration *reg;
trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
if (!nlportid)
return;
spin_lock_bh(&rdev->beacon_registrations_lock);
list_for_each_entry(reg, &rdev->beacon_registrations, list) {
msg = nlmsg_new(len + 100, GFP_ATOMIC);
if (!msg) {
spin_unlock_bh(&rdev->beacon_registrations_lock);
return;
}
msg = nlmsg_new(len + 100, gfp);
if (!msg)
return;
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
if (!hdr)
goto nla_put_failure;
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
if (!hdr) {
nlmsg_free(msg);
return;
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
(freq &&
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, frame))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
(freq &&
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, frame))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
spin_unlock_bh(&rdev->beacon_registrations_lock);
return;
nla_put_failure:
genlmsg_cancel(msg, hdr);
spin_unlock_bh(&rdev->beacon_registrations_lock);
if (hdr)
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
EXPORT_SYMBOL(cfg80211_report_obss_beacon);
@ -8962,6 +9034,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
struct netlink_notify *notify = _notify;
struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
struct cfg80211_beacon_registration *reg, *tmp;
if (state != NETLINK_URELEASE)
return NOTIFY_DONE;
@ -8971,8 +9044,17 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
cfg80211_mlme_unregister_socket(wdev, notify->portid);
if (rdev->ap_beacons_nlportid == notify->portid)
rdev->ap_beacons_nlportid = 0;
spin_lock_bh(&rdev->beacon_registrations_lock);
list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
list) {
if (reg->nlportid == notify->portid) {
list_del(&reg->list);
kfree(reg);
break;
}
}
spin_unlock_bh(&rdev->beacon_registrations_lock);
}
rcu_read_unlock();

View File

@ -476,21 +476,22 @@ rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed)
}
static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
enum nl80211_tx_power_setting type, int mbm)
{
int ret;
trace_rdev_set_tx_power(&rdev->wiphy, type, mbm);
ret = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm);
trace_rdev_set_tx_power(&rdev->wiphy, wdev, type, mbm);
ret = rdev->ops->set_tx_power(&rdev->wiphy, wdev, type, mbm);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev,
int *dbm)
struct wireless_dev *wdev, int *dbm)
{
int ret;
trace_rdev_get_tx_power(&rdev->wiphy);
ret = rdev->ops->get_tx_power(&rdev->wiphy, dbm);
trace_rdev_get_tx_power(&rdev->wiphy, wdev);
ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, dbm);
trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm);
return ret;
}

View File

@ -26,7 +26,7 @@
#define WIPHY_PR_ARG MAC_PR_ARG(wiphy_mac)
#define WDEV_ENTRY __field(u32, id)
#define WDEV_ASSIGN (__entry->id) = (wdev->identifier)
#define WDEV_ASSIGN (__entry->id) = (wdev ? wdev->identifier : 0)
#define WDEV_PR_FMT ", wdev id: %u"
#define WDEV_PR_ARG (__entry->id)
@ -260,11 +260,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna,
TP_ARGS(wiphy)
);
DEFINE_EVENT(wiphy_only_evt, rdev_get_tx_power,
TP_PROTO(struct wiphy *wiphy),
TP_ARGS(wiphy)
);
DEFINE_EVENT(wiphy_only_evt, rdev_rfkill_poll,
TP_PROTO(struct wiphy *wiphy),
TP_ARGS(wiphy)
@ -1230,22 +1225,29 @@ TRACE_EVENT(rdev_set_wiphy_params,
WIPHY_PR_ARG, __entry->changed)
);
DEFINE_EVENT(wiphy_wdev_evt, rdev_get_tx_power,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
TP_ARGS(wiphy, wdev)
);
TRACE_EVENT(rdev_set_tx_power,
TP_PROTO(struct wiphy *wiphy, enum nl80211_tx_power_setting type,
int mbm),
TP_ARGS(wiphy, type, mbm),
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
enum nl80211_tx_power_setting type, int mbm),
TP_ARGS(wiphy, wdev, type, mbm),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
__field(enum nl80211_tx_power_setting, type)
__field(int, mbm)
),
TP_fast_assign(
WIPHY_ASSIGN;
WDEV_ASSIGN;
__entry->type = type;
__entry->mbm = mbm;
),
TP_printk(WIPHY_PR_FMT ", type: %d, mbm: %d",
WIPHY_PR_ARG, __entry->type, __entry->mbm)
TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", type: %d, mbm: %d",
WIPHY_PR_ARG, WDEV_PR_ARG,__entry->type, __entry->mbm)
);
TRACE_EVENT(rdev_return_int_int,

View File

@ -980,6 +980,105 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
}
EXPORT_SYMBOL(cfg80211_calculate_bitrate);
unsigned int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
u8 attr, u8 *buf, unsigned int bufsize)
{
u8 *out = buf;
u16 attr_remaining = 0;
bool desired_attr = false;
u16 desired_len = 0;
while (len > 0) {
unsigned int iedatalen;
unsigned int copy;
const u8 *iedata;
if (len < 2)
return -EILSEQ;
iedatalen = ies[1];
if (iedatalen + 2 > len)
return -EILSEQ;
if (ies[0] != WLAN_EID_VENDOR_SPECIFIC)
goto cont;
if (iedatalen < 4)
goto cont;
iedata = ies + 2;
/* check WFA OUI, P2P subtype */
if (iedata[0] != 0x50 || iedata[1] != 0x6f ||
iedata[2] != 0x9a || iedata[3] != 0x09)
goto cont;
iedatalen -= 4;
iedata += 4;
/* check attribute continuation into this IE */
copy = min_t(unsigned int, attr_remaining, iedatalen);
if (copy && desired_attr) {
desired_len += copy;
if (out) {
memcpy(out, iedata, min(bufsize, copy));
out += min(bufsize, copy);
bufsize -= min(bufsize, copy);
}
if (copy == attr_remaining)
return desired_len;
}
attr_remaining -= copy;
if (attr_remaining)
goto cont;
iedatalen -= copy;
iedata += copy;
while (iedatalen > 0) {
u16 attr_len;
/* P2P attribute ID & size must fit */
if (iedatalen < 3)
return -EILSEQ;
desired_attr = iedata[0] == attr;
attr_len = get_unaligned_le16(iedata + 1);
iedatalen -= 3;
iedata += 3;
copy = min_t(unsigned int, attr_len, iedatalen);
if (desired_attr) {
desired_len += copy;
if (out) {
memcpy(out, iedata, min(bufsize, copy));
out += min(bufsize, copy);
bufsize -= min(bufsize, copy);
}
if (copy == attr_len)
return desired_len;
}
iedata += copy;
iedatalen -= copy;
attr_remaining = attr_len - copy;
}
cont:
len -= ies[1] + 2;
ies += ies[1] + 2;
}
if (attr_remaining && desired_attr)
return -EILSEQ;
return -ENOENT;
}
EXPORT_SYMBOL(cfg80211_get_p2p_attr);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
u32 beacon_int)
{

View File

@ -895,7 +895,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev,
return 0;
}
return rdev_set_tx_power(rdev, type, DBM_TO_MBM(dbm));
return rdev_set_tx_power(rdev, wdev, type, DBM_TO_MBM(dbm));
}
static int cfg80211_wext_giwtxpower(struct net_device *dev,
@ -914,7 +914,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev,
if (!rdev->ops->get_tx_power)
return -EOPNOTSUPP;
err = rdev_get_tx_power(rdev, &val);
err = rdev_get_tx_power(rdev, wdev, &val);
if (err)
return err;