Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
commit
f13352519e
|
@ -1865,7 +1865,6 @@ static int adm8211_probe(struct pci_dev *pdev,
|
||||||
dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
|
dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
|
||||||
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||||
|
|
||||||
dev->channel_change_time = 1000;
|
|
||||||
dev->max_signal = 100; /* FIXME: find better value */
|
dev->max_signal = 100; /* FIXME: find better value */
|
||||||
|
|
||||||
dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
|
dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
|
||||||
|
|
|
@ -2112,7 +2112,6 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
|
||||||
priv->pm_period = 0;
|
priv->pm_period = 0;
|
||||||
|
|
||||||
/* unit us */
|
/* unit us */
|
||||||
priv->hw->channel_change_time = 100000;
|
|
||||||
|
|
||||||
return priv;
|
return priv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4039,7 +4039,6 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||||
|
|
||||||
ar->hw->vif_data_size = sizeof(struct ath10k_vif);
|
ar->hw->vif_data_size = sizeof(struct ath10k_vif);
|
||||||
|
|
||||||
ar->hw->channel_change_time = 5000;
|
|
||||||
ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
|
ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
|
||||||
|
|
||||||
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||||
|
|
|
@ -2549,7 +2549,6 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
|
||||||
hw->wiphy->available_antennas_rx = 0x3;
|
hw->wiphy->available_antennas_rx = 0x3;
|
||||||
|
|
||||||
hw->extra_tx_headroom = 2;
|
hw->extra_tx_headroom = 2;
|
||||||
hw->channel_change_time = 5000;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark the device as detached to avoid processing
|
* Mark the device as detached to avoid processing
|
||||||
|
|
|
@ -748,7 +748,6 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
|
||||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||||
|
|
||||||
hw->queues = 4;
|
hw->queues = 4;
|
||||||
hw->channel_change_time = 5000;
|
|
||||||
hw->max_listen_interval = 1;
|
hw->max_listen_interval = 1;
|
||||||
|
|
||||||
hw->vif_data_size = sizeof(struct ath9k_htc_vif);
|
hw->vif_data_size = sizeof(struct ath9k_htc_vif);
|
||||||
|
|
|
@ -946,7 +946,6 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||||
|
|
||||||
hw->queues = 4;
|
hw->queues = 4;
|
||||||
hw->max_rates = 4;
|
hw->max_rates = 4;
|
||||||
hw->channel_change_time = 5000;
|
|
||||||
hw->max_listen_interval = 1;
|
hw->max_listen_interval = 1;
|
||||||
hw->max_rate_tries = 10;
|
hw->max_rate_tries = 10;
|
||||||
hw->sta_data_size = sizeof(struct ath_node);
|
hw->sta_data_size = sizeof(struct ath_node);
|
||||||
|
|
|
@ -1967,18 +1967,6 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
ar->num_channels = chans;
|
ar->num_channels = chans;
|
||||||
|
|
||||||
/*
|
|
||||||
* I measured this, a bandswitch takes roughly
|
|
||||||
* 135 ms and a frequency switch about 80.
|
|
||||||
*
|
|
||||||
* FIXME: measure these values again once EEPROM settings
|
|
||||||
* are used, that will influence them!
|
|
||||||
*/
|
|
||||||
if (bands == 2)
|
|
||||||
ar->hw->channel_change_time = 135 * 1000;
|
|
||||||
else
|
|
||||||
ar->hw->channel_change_time = 80 * 1000;
|
|
||||||
|
|
||||||
regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
|
regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
|
||||||
|
|
||||||
/* second part of wiphy init */
|
/* second part of wiphy init */
|
||||||
|
|
|
@ -1071,7 +1071,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
|
||||||
hw->max_rates = 2; /* Primary rate and 1 fallback rate */
|
hw->max_rates = 2; /* Primary rate and 1 fallback rate */
|
||||||
|
|
||||||
/* channel change time is dependent on chip and band */
|
/* channel change time is dependent on chip and band */
|
||||||
hw->channel_change_time = 7 * 1000;
|
|
||||||
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||||
BIT(NL80211_IFTYPE_AP) |
|
BIT(NL80211_IFTYPE_AP) |
|
||||||
BIT(NL80211_IFTYPE_ADHOC);
|
BIT(NL80211_IFTYPE_ADHOC);
|
||||||
|
|
|
@ -301,7 +301,6 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
|
||||||
|
|
||||||
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
||||||
|
|
||||||
hw->channel_change_time = 1000; /* TODO: find actual value */
|
|
||||||
hw->queues = 4;
|
hw->queues = 4;
|
||||||
|
|
||||||
priv->rts_threshold = -1;
|
priv->rts_threshold = -1;
|
||||||
|
|
|
@ -1268,14 +1268,9 @@ static struct cfg80211_scan_request *
|
||||||
_new_connect_scan_req(struct wiphy *wiphy, struct cfg80211_connect_params *sme)
|
_new_connect_scan_req(struct wiphy *wiphy, struct cfg80211_connect_params *sme)
|
||||||
{
|
{
|
||||||
struct cfg80211_scan_request *creq = NULL;
|
struct cfg80211_scan_request *creq = NULL;
|
||||||
int i, n_channels = 0;
|
int i, n_channels = ieee80211_get_num_supported_channels(wiphy);
|
||||||
enum ieee80211_band band;
|
enum ieee80211_band band;
|
||||||
|
|
||||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
|
||||||
if (wiphy->bands[band])
|
|
||||||
n_channels += wiphy->bands[band]->n_channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
|
creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
|
||||||
n_channels * sizeof(void *),
|
n_channels * sizeof(void *),
|
||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -65,6 +65,9 @@ enum hwsim_tx_control_flags {
|
||||||
* kernel, uses:
|
* kernel, uses:
|
||||||
* %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS,
|
* %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS,
|
||||||
* %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
|
* %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
|
||||||
|
* @HWSIM_CMD_CREATE_RADIO: create a new radio with the given parameters,
|
||||||
|
* returns the radio ID (>= 0) or negative on errors
|
||||||
|
* @HWSIM_CMD_DESTROY_RADIO: destroy a radio
|
||||||
* @__HWSIM_CMD_MAX: enum limit
|
* @__HWSIM_CMD_MAX: enum limit
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
|
@ -72,6 +75,8 @@ enum {
|
||||||
HWSIM_CMD_REGISTER,
|
HWSIM_CMD_REGISTER,
|
||||||
HWSIM_CMD_FRAME,
|
HWSIM_CMD_FRAME,
|
||||||
HWSIM_CMD_TX_INFO_FRAME,
|
HWSIM_CMD_TX_INFO_FRAME,
|
||||||
|
HWSIM_CMD_CREATE_RADIO,
|
||||||
|
HWSIM_CMD_DESTROY_RADIO,
|
||||||
__HWSIM_CMD_MAX,
|
__HWSIM_CMD_MAX,
|
||||||
};
|
};
|
||||||
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
|
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
|
||||||
|
@ -94,6 +99,14 @@ enum {
|
||||||
space
|
space
|
||||||
* @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array
|
* @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array
|
||||||
* @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame
|
* @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame
|
||||||
|
* @HWSIM_ATTR_CHANNELS: u32 attribute used with the %HWSIM_CMD_CREATE_RADIO
|
||||||
|
* command giving the number of channels supported by the new radio
|
||||||
|
* @HWSIM_ATTR_RADIO_ID: u32 attribute used with %HWSIM_CMD_DESTROY_RADIO
|
||||||
|
* only to destroy a radio
|
||||||
|
* @HWSIM_ATTR_REG_HINT_ALPHA2: alpha2 for regulatoro driver hint
|
||||||
|
* (nla string, length 2)
|
||||||
|
* @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute)
|
||||||
|
* @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute)
|
||||||
* @__HWSIM_ATTR_MAX: enum limit
|
* @__HWSIM_ATTR_MAX: enum limit
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -108,6 +121,11 @@ enum {
|
||||||
HWSIM_ATTR_SIGNAL,
|
HWSIM_ATTR_SIGNAL,
|
||||||
HWSIM_ATTR_TX_INFO,
|
HWSIM_ATTR_TX_INFO,
|
||||||
HWSIM_ATTR_COOKIE,
|
HWSIM_ATTR_COOKIE,
|
||||||
|
HWSIM_ATTR_CHANNELS,
|
||||||
|
HWSIM_ATTR_RADIO_ID,
|
||||||
|
HWSIM_ATTR_REG_HINT_ALPHA2,
|
||||||
|
HWSIM_ATTR_REG_CUSTOM_REG,
|
||||||
|
HWSIM_ATTR_REG_STRICT_REG,
|
||||||
__HWSIM_ATTR_MAX,
|
__HWSIM_ATTR_MAX,
|
||||||
};
|
};
|
||||||
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
|
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
|
||||||
|
|
|
@ -5892,8 +5892,6 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
|
||||||
|
|
||||||
hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0;
|
hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0;
|
||||||
|
|
||||||
hw->channel_change_time = 10;
|
|
||||||
|
|
||||||
hw->queues = MWL8K_TX_WMM_QUEUES;
|
hw->queues = MWL8K_TX_WMM_QUEUES;
|
||||||
|
|
||||||
/* Set rssi values to dBm */
|
/* Set rssi values to dBm */
|
||||||
|
|
|
@ -756,7 +756,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
|
||||||
BIT(NL80211_IFTYPE_AP) |
|
BIT(NL80211_IFTYPE_AP) |
|
||||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||||
|
|
||||||
dev->channel_change_time = 1000; /* TODO: find actual value */
|
|
||||||
priv->beacon_req_id = cpu_to_le32(0);
|
priv->beacon_req_id = cpu_to_le32(0);
|
||||||
priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
|
priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
|
||||||
priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
|
priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
|
||||||
|
|
|
@ -353,7 +353,6 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
|
||||||
|
|
||||||
/* TODO: Correct this value for our hw */
|
/* TODO: Correct this value for our hw */
|
||||||
/* TODO: define these hard code value */
|
/* TODO: define these hard code value */
|
||||||
hw->channel_change_time = 100;
|
|
||||||
hw->max_listen_interval = 10;
|
hw->max_listen_interval = 10;
|
||||||
hw->max_rate_tries = 4;
|
hw->max_rate_tries = 4;
|
||||||
/* hw->max_rates = 1; */
|
/* hw->max_rates = 1; */
|
||||||
|
|
|
@ -1468,7 +1468,6 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
|
||||||
|
|
||||||
/* unit us */
|
/* unit us */
|
||||||
/* FIXME: find a proper value */
|
/* FIXME: find a proper value */
|
||||||
wl->hw->channel_change_time = 10000;
|
|
||||||
|
|
||||||
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||||
IEEE80211_HW_SUPPORTS_PS |
|
IEEE80211_HW_SUPPORTS_PS |
|
||||||
|
|
|
@ -5710,7 +5710,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||||
|
|
||||||
/* unit us */
|
/* unit us */
|
||||||
/* FIXME: find a proper value */
|
/* FIXME: find a proper value */
|
||||||
wl->hw->channel_change_time = 10000;
|
|
||||||
wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
|
wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
|
||||||
|
|
||||||
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||||
|
|
|
@ -788,7 +788,6 @@ static int wb35_probe(struct usb_interface *intf,
|
||||||
dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
|
dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
|
||||||
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||||
|
|
||||||
dev->channel_change_time = 1000;
|
|
||||||
dev->max_signal = 100;
|
dev->max_signal = 100;
|
||||||
dev->queues = 1;
|
dev->queues = 1;
|
||||||
|
|
||||||
|
|
|
@ -1857,6 +1857,7 @@ enum ieee80211_key_len {
|
||||||
WLAN_KEY_LEN_CCMP = 16,
|
WLAN_KEY_LEN_CCMP = 16,
|
||||||
WLAN_KEY_LEN_TKIP = 32,
|
WLAN_KEY_LEN_TKIP = 32,
|
||||||
WLAN_KEY_LEN_AES_CMAC = 16,
|
WLAN_KEY_LEN_AES_CMAC = 16,
|
||||||
|
WLAN_KEY_LEN_SMS4 = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IEEE80211_WEP_IV_LEN 4
|
#define IEEE80211_WEP_IV_LEN 4
|
||||||
|
@ -1902,6 +1903,7 @@ enum ieee80211_tdls_actioncode {
|
||||||
#define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6)
|
#define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6)
|
||||||
|
|
||||||
#define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6)
|
#define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6)
|
||||||
|
#define WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED BIT(7)
|
||||||
|
|
||||||
/* TDLS specific payload type in the LLC/SNAP header */
|
/* TDLS specific payload type in the LLC/SNAP header */
|
||||||
#define WLAN_TDLS_SNAP_RFTYPE 0x2
|
#define WLAN_TDLS_SNAP_RFTYPE 0x2
|
||||||
|
|
|
@ -4640,6 +4640,14 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
|
||||||
*/
|
*/
|
||||||
void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp);
|
void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_get_num_supported_channels - get number of channels device has
|
||||||
|
* @wiphy: the wiphy
|
||||||
|
*
|
||||||
|
* Return: the number of channels supported by the device.
|
||||||
|
*/
|
||||||
|
unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
|
||||||
|
|
||||||
/* Logging, debugging and troubleshooting/diagnostic helpers. */
|
/* Logging, debugging and troubleshooting/diagnostic helpers. */
|
||||||
|
|
||||||
/* wiphy_printk helpers, similar to dev_printk */
|
/* wiphy_printk helpers, similar to dev_printk */
|
||||||
|
|
|
@ -1616,8 +1616,6 @@ enum ieee80211_hw_flags {
|
||||||
* @extra_beacon_tailroom: tailroom to reserve in each beacon tx skb.
|
* @extra_beacon_tailroom: tailroom to reserve in each beacon tx skb.
|
||||||
* Can be used by drivers to add extra IEs.
|
* Can be used by drivers to add extra IEs.
|
||||||
*
|
*
|
||||||
* @channel_change_time: time (in microseconds) it takes to change channels.
|
|
||||||
*
|
|
||||||
* @max_signal: Maximum value for signal (rssi) in RX information, used
|
* @max_signal: Maximum value for signal (rssi) in RX information, used
|
||||||
* only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB
|
* only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB
|
||||||
*
|
*
|
||||||
|
@ -1699,7 +1697,6 @@ struct ieee80211_hw {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
unsigned int extra_tx_headroom;
|
unsigned int extra_tx_headroom;
|
||||||
unsigned int extra_beacon_tailroom;
|
unsigned int extra_beacon_tailroom;
|
||||||
int channel_change_time;
|
|
||||||
int vif_data_size;
|
int vif_data_size;
|
||||||
int sta_data_size;
|
int sta_data_size;
|
||||||
int chanctx_data_size;
|
int chanctx_data_size;
|
||||||
|
@ -2122,6 +2119,11 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||||
* appropriately (only the last frame may have %IEEE80211_TX_STATUS_EOSP)
|
* appropriately (only the last frame may have %IEEE80211_TX_STATUS_EOSP)
|
||||||
* and also take care of the EOSP and MORE_DATA bits in the frame.
|
* and also take care of the EOSP and MORE_DATA bits in the frame.
|
||||||
* The driver may also use ieee80211_sta_eosp() in this case.
|
* The driver may also use ieee80211_sta_eosp() in this case.
|
||||||
|
*
|
||||||
|
* Note that if the driver ever buffers frames other than QoS-data
|
||||||
|
* frames, it must take care to never send a non-QoS-data frame as
|
||||||
|
* the last frame in a service period, adding a QoS-nulldata frame
|
||||||
|
* after a non-QoS-data frame if needed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1035,6 +1035,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ieee80211_recalc_dtim(local, sdata);
|
||||||
ieee80211_bss_info_change_notify(sdata, changed);
|
ieee80211_bss_info_change_notify(sdata, changed);
|
||||||
|
|
||||||
netif_carrier_on(dev);
|
netif_carrier_on(dev);
|
||||||
|
@ -3854,7 +3855,7 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy,
|
||||||
new_qos_map = NULL;
|
new_qos_map = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_qos_map = rtnl_dereference(sdata->qos_map);
|
old_qos_map = sdata_dereference(sdata->qos_map, sdata);
|
||||||
rcu_assign_pointer(sdata->qos_map, new_qos_map);
|
rcu_assign_pointer(sdata->qos_map, new_qos_map);
|
||||||
if (old_qos_map)
|
if (old_qos_map)
|
||||||
kfree_rcu(old_qos_map, rcu_head);
|
kfree_rcu(old_qos_map, rcu_head);
|
||||||
|
|
|
@ -133,7 +133,15 @@ static ssize_t ieee80211_if_fmt_##name( \
|
||||||
jiffies_to_msecs(sdata->field)); \
|
jiffies_to_msecs(sdata->field)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __IEEE80211_IF_FILE(name, _write) \
|
#define _IEEE80211_IF_FILE_OPS(name, _read, _write) \
|
||||||
|
static const struct file_operations name##_ops = { \
|
||||||
|
.read = (_read), \
|
||||||
|
.write = (_write), \
|
||||||
|
.open = simple_open, \
|
||||||
|
.llseek = generic_file_llseek, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _IEEE80211_IF_FILE_R_FN(name) \
|
||||||
static ssize_t ieee80211_if_read_##name(struct file *file, \
|
static ssize_t ieee80211_if_read_##name(struct file *file, \
|
||||||
char __user *userbuf, \
|
char __user *userbuf, \
|
||||||
size_t count, loff_t *ppos) \
|
size_t count, loff_t *ppos) \
|
||||||
|
@ -141,28 +149,34 @@ static ssize_t ieee80211_if_read_##name(struct file *file, \
|
||||||
return ieee80211_if_read(file->private_data, \
|
return ieee80211_if_read(file->private_data, \
|
||||||
userbuf, count, ppos, \
|
userbuf, count, ppos, \
|
||||||
ieee80211_if_fmt_##name); \
|
ieee80211_if_fmt_##name); \
|
||||||
} \
|
|
||||||
static const struct file_operations name##_ops = { \
|
|
||||||
.read = ieee80211_if_read_##name, \
|
|
||||||
.write = (_write), \
|
|
||||||
.open = simple_open, \
|
|
||||||
.llseek = generic_file_llseek, \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __IEEE80211_IF_FILE_W(name) \
|
#define _IEEE80211_IF_FILE_W_FN(name) \
|
||||||
static ssize_t ieee80211_if_write_##name(struct file *file, \
|
static ssize_t ieee80211_if_write_##name(struct file *file, \
|
||||||
const char __user *userbuf, \
|
const char __user *userbuf, \
|
||||||
size_t count, loff_t *ppos) \
|
size_t count, loff_t *ppos) \
|
||||||
{ \
|
{ \
|
||||||
return ieee80211_if_write(file->private_data, userbuf, count, \
|
return ieee80211_if_write(file->private_data, userbuf, count, \
|
||||||
ppos, ieee80211_if_parse_##name); \
|
ppos, ieee80211_if_parse_##name); \
|
||||||
} \
|
}
|
||||||
__IEEE80211_IF_FILE(name, ieee80211_if_write_##name)
|
|
||||||
|
|
||||||
|
#define IEEE80211_IF_FILE_R(name) \
|
||||||
|
_IEEE80211_IF_FILE_R_FN(name) \
|
||||||
|
_IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, NULL)
|
||||||
|
|
||||||
|
#define IEEE80211_IF_FILE_W(name) \
|
||||||
|
_IEEE80211_IF_FILE_W_FN(name) \
|
||||||
|
_IEEE80211_IF_FILE_OPS(name, NULL, ieee80211_if_write_##name)
|
||||||
|
|
||||||
|
#define IEEE80211_IF_FILE_RW(name) \
|
||||||
|
_IEEE80211_IF_FILE_R_FN(name) \
|
||||||
|
_IEEE80211_IF_FILE_W_FN(name) \
|
||||||
|
_IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, \
|
||||||
|
ieee80211_if_write_##name)
|
||||||
|
|
||||||
#define IEEE80211_IF_FILE(name, field, format) \
|
#define IEEE80211_IF_FILE(name, field, format) \
|
||||||
IEEE80211_IF_FMT_##format(name, field) \
|
IEEE80211_IF_FMT_##format(name, field) \
|
||||||
__IEEE80211_IF_FILE(name, NULL)
|
IEEE80211_IF_FILE_R(name)
|
||||||
|
|
||||||
/* common attributes */
|
/* common attributes */
|
||||||
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
|
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
|
||||||
|
@ -199,7 +213,7 @@ ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
__IEEE80211_IF_FILE(hw_queues, NULL);
|
IEEE80211_IF_FILE_R(hw_queues);
|
||||||
|
|
||||||
/* STA attributes */
|
/* STA attributes */
|
||||||
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
|
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
|
||||||
|
@ -275,14 +289,7 @@ static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
IEEE80211_IF_FILE_RW(smps);
|
||||||
__IEEE80211_IF_FILE_W(smps);
|
|
||||||
|
|
||||||
static ssize_t ieee80211_if_fmt_tkip_mic_test(
|
|
||||||
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
|
|
||||||
{
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ieee80211_if_parse_tkip_mic_test(
|
static ssize_t ieee80211_if_parse_tkip_mic_test(
|
||||||
struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
|
struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
|
||||||
|
@ -349,8 +356,7 @@ static ssize_t ieee80211_if_parse_tkip_mic_test(
|
||||||
|
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
|
IEEE80211_IF_FILE_W(tkip_mic_test);
|
||||||
__IEEE80211_IF_FILE_W(tkip_mic_test);
|
|
||||||
|
|
||||||
static ssize_t ieee80211_if_fmt_uapsd_queues(
|
static ssize_t ieee80211_if_fmt_uapsd_queues(
|
||||||
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
|
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
|
||||||
|
@ -378,7 +384,7 @@ static ssize_t ieee80211_if_parse_uapsd_queues(
|
||||||
|
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
__IEEE80211_IF_FILE_W(uapsd_queues);
|
IEEE80211_IF_FILE_RW(uapsd_queues);
|
||||||
|
|
||||||
static ssize_t ieee80211_if_fmt_uapsd_max_sp_len(
|
static ssize_t ieee80211_if_fmt_uapsd_max_sp_len(
|
||||||
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
|
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
|
||||||
|
@ -406,7 +412,7 @@ static ssize_t ieee80211_if_parse_uapsd_max_sp_len(
|
||||||
|
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
__IEEE80211_IF_FILE_W(uapsd_max_sp_len);
|
IEEE80211_IF_FILE_RW(uapsd_max_sp_len);
|
||||||
|
|
||||||
/* AP attributes */
|
/* AP attributes */
|
||||||
IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
|
IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
|
||||||
|
@ -419,7 +425,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
|
||||||
return scnprintf(buf, buflen, "%u\n",
|
return scnprintf(buf, buflen, "%u\n",
|
||||||
skb_queue_len(&sdata->u.ap.ps.bc_buf));
|
skb_queue_len(&sdata->u.ap.ps.bc_buf));
|
||||||
}
|
}
|
||||||
__IEEE80211_IF_FILE(num_buffered_multicast, NULL);
|
IEEE80211_IF_FILE_R(num_buffered_multicast);
|
||||||
|
|
||||||
/* IBSS attributes */
|
/* IBSS attributes */
|
||||||
static ssize_t ieee80211_if_fmt_tsf(
|
static ssize_t ieee80211_if_fmt_tsf(
|
||||||
|
@ -468,9 +474,10 @@ static ssize_t ieee80211_if_parse_tsf(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ieee80211_recalc_dtim(local, sdata);
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
__IEEE80211_IF_FILE_W(tsf);
|
IEEE80211_IF_FILE_RW(tsf);
|
||||||
|
|
||||||
|
|
||||||
/* WDS attributes */
|
/* WDS attributes */
|
||||||
|
|
|
@ -479,10 +479,9 @@ void ieee80211_request_smps(struct ieee80211_vif *vif,
|
||||||
vif->type != NL80211_IFTYPE_AP))
|
vif->type != NL80211_IFTYPE_AP))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
|
|
||||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
|
||||||
|
|
||||||
if (vif->type == NL80211_IFTYPE_STATION) {
|
if (vif->type == NL80211_IFTYPE_STATION) {
|
||||||
|
if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
|
||||||
|
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||||
if (sdata->u.mgd.driver_smps_mode == smps_mode)
|
if (sdata->u.mgd.driver_smps_mode == smps_mode)
|
||||||
return;
|
return;
|
||||||
sdata->u.mgd.driver_smps_mode = smps_mode;
|
sdata->u.mgd.driver_smps_mode = smps_mode;
|
||||||
|
|
|
@ -1800,6 +1800,8 @@ ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
|
||||||
int ieee80211_cs_headroom(struct ieee80211_local *local,
|
int ieee80211_cs_headroom(struct ieee80211_local *local,
|
||||||
struct cfg80211_crypto_settings *crypto,
|
struct cfg80211_crypto_settings *crypto,
|
||||||
enum nl80211_iftype iftype);
|
enum nl80211_iftype iftype);
|
||||||
|
void ieee80211_recalc_dtim(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sub_if_data *sdata);
|
||||||
|
|
||||||
#ifdef CONFIG_MAC80211_NOINLINE
|
#ifdef CONFIG_MAC80211_NOINLINE
|
||||||
#define debug_noinline noinline
|
#define debug_noinline noinline
|
||||||
|
|
|
@ -846,17 +846,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||||
/* TODO: consider VHT for RX chains, hopefully it's the same */
|
/* TODO: consider VHT for RX chains, hopefully it's the same */
|
||||||
}
|
}
|
||||||
|
|
||||||
local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
|
|
||||||
sizeof(void *) * channels, GFP_KERNEL);
|
|
||||||
if (!local->int_scan_req)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
|
||||||
if (!local->hw.wiphy->bands[band])
|
|
||||||
continue;
|
|
||||||
local->int_scan_req->rates[band] = (u32) -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if low-level driver supports AP, we also support VLAN */
|
/* if low-level driver supports AP, we also support VLAN */
|
||||||
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
|
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
|
||||||
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
|
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
|
||||||
|
@ -880,6 +869,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
|
||||||
|
sizeof(void *) * channels, GFP_KERNEL);
|
||||||
|
if (!local->int_scan_req)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||||
|
if (!local->hw.wiphy->bands[band])
|
||||||
|
continue;
|
||||||
|
local->int_scan_req->rates[band] = (u32) -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_MAC80211_MESH
|
#ifndef CONFIG_MAC80211_MESH
|
||||||
/* mesh depends on Kconfig, but drivers should set it if they want */
|
/* mesh depends on Kconfig, but drivers should set it if they want */
|
||||||
local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
|
local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
|
||||||
|
|
|
@ -807,6 +807,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ieee80211_recalc_dtim(local, sdata);
|
||||||
ieee80211_bss_info_change_notify(sdata, changed);
|
ieee80211_bss_info_change_notify(sdata, changed);
|
||||||
|
|
||||||
netif_carrier_on(sdata->dev);
|
netif_carrier_on(sdata->dev);
|
||||||
|
|
|
@ -437,6 +437,7 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
|
||||||
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
||||||
|
|
||||||
set_sta_flag(sta, WLAN_STA_WME);
|
set_sta_flag(sta, WLAN_STA_WME);
|
||||||
|
sta->sta.wme = true;
|
||||||
|
|
||||||
return sta;
|
return sta;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3076,8 +3076,8 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
||||||
|
|
||||||
/* main receive path */
|
/* main receive path */
|
||||||
|
|
||||||
static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||||
struct ieee80211_hdr *hdr)
|
struct ieee80211_hdr *hdr)
|
||||||
{
|
{
|
||||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||||
struct sk_buff *skb = rx->skb;
|
struct sk_buff *skb = rx->skb;
|
||||||
|
@ -3088,29 +3088,29 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||||
switch (sdata->vif.type) {
|
switch (sdata->vif.type) {
|
||||||
case NL80211_IFTYPE_STATION:
|
case NL80211_IFTYPE_STATION:
|
||||||
if (!bssid && !sdata->u.mgd.use_4addr)
|
if (!bssid && !sdata->u.mgd.use_4addr)
|
||||||
return 0;
|
return false;
|
||||||
if (!multicast &&
|
if (!multicast &&
|
||||||
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
|
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
|
||||||
if (!(sdata->dev->flags & IFF_PROMISC) ||
|
if (!(sdata->dev->flags & IFF_PROMISC) ||
|
||||||
sdata->u.mgd.use_4addr)
|
sdata->u.mgd.use_4addr)
|
||||||
return 0;
|
return false;
|
||||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
if (!bssid)
|
if (!bssid)
|
||||||
return 0;
|
return false;
|
||||||
if (ether_addr_equal(sdata->vif.addr, hdr->addr2) ||
|
if (ether_addr_equal(sdata->vif.addr, hdr->addr2) ||
|
||||||
ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2))
|
ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2))
|
||||||
return 0;
|
return false;
|
||||||
if (ieee80211_is_beacon(hdr->frame_control)) {
|
if (ieee80211_is_beacon(hdr->frame_control)) {
|
||||||
return 1;
|
return true;
|
||||||
} else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
|
} else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
|
||||||
return 0;
|
return false;
|
||||||
} else if (!multicast &&
|
} else if (!multicast &&
|
||||||
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
|
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
|
||||||
if (!(sdata->dev->flags & IFF_PROMISC))
|
if (!(sdata->dev->flags & IFF_PROMISC))
|
||||||
return 0;
|
return false;
|
||||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||||
} else if (!rx->sta) {
|
} else if (!rx->sta) {
|
||||||
int rate_idx;
|
int rate_idx;
|
||||||
|
@ -3126,7 +3126,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||||
if (!multicast &&
|
if (!multicast &&
|
||||||
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
|
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
|
||||||
if (!(sdata->dev->flags & IFF_PROMISC))
|
if (!(sdata->dev->flags & IFF_PROMISC))
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||||
}
|
}
|
||||||
|
@ -3135,7 +3135,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||||
case NL80211_IFTYPE_AP:
|
case NL80211_IFTYPE_AP:
|
||||||
if (!bssid) {
|
if (!bssid) {
|
||||||
if (!ether_addr_equal(sdata->vif.addr, hdr->addr1))
|
if (!ether_addr_equal(sdata->vif.addr, hdr->addr1))
|
||||||
return 0;
|
return false;
|
||||||
} else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) {
|
} else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) {
|
||||||
/*
|
/*
|
||||||
* Accept public action frames even when the
|
* Accept public action frames even when the
|
||||||
|
@ -3145,26 +3145,26 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||||
*/
|
*/
|
||||||
if (!multicast &&
|
if (!multicast &&
|
||||||
!ether_addr_equal(sdata->vif.addr, hdr->addr1))
|
!ether_addr_equal(sdata->vif.addr, hdr->addr1))
|
||||||
return 0;
|
return false;
|
||||||
if (ieee80211_is_public_action(hdr, skb->len))
|
if (ieee80211_is_public_action(hdr, skb->len))
|
||||||
return 1;
|
return true;
|
||||||
if (!ieee80211_is_beacon(hdr->frame_control))
|
if (!ieee80211_is_beacon(hdr->frame_control))
|
||||||
return 0;
|
return false;
|
||||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_WDS:
|
case NL80211_IFTYPE_WDS:
|
||||||
if (bssid || !ieee80211_is_data(hdr->frame_control))
|
if (bssid || !ieee80211_is_data(hdr->frame_control))
|
||||||
return 0;
|
return false;
|
||||||
if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2))
|
if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2))
|
||||||
return 0;
|
return false;
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_P2P_DEVICE:
|
case NL80211_IFTYPE_P2P_DEVICE:
|
||||||
if (!ieee80211_is_public_action(hdr, skb->len) &&
|
if (!ieee80211_is_public_action(hdr, skb->len) &&
|
||||||
!ieee80211_is_probe_req(hdr->frame_control) &&
|
!ieee80211_is_probe_req(hdr->frame_control) &&
|
||||||
!ieee80211_is_probe_resp(hdr->frame_control) &&
|
!ieee80211_is_probe_resp(hdr->frame_control) &&
|
||||||
!ieee80211_is_beacon(hdr->frame_control))
|
!ieee80211_is_beacon(hdr->frame_control))
|
||||||
return 0;
|
return false;
|
||||||
if (!ether_addr_equal(sdata->vif.addr, hdr->addr1) &&
|
if (!ether_addr_equal(sdata->vif.addr, hdr->addr1) &&
|
||||||
!multicast)
|
!multicast)
|
||||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||||
|
@ -3175,7 +3175,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3191,13 +3191,11 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
|
||||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||||
int prepares;
|
|
||||||
|
|
||||||
rx->skb = skb;
|
rx->skb = skb;
|
||||||
status->rx_flags |= IEEE80211_RX_RA_MATCH;
|
status->rx_flags |= IEEE80211_RX_RA_MATCH;
|
||||||
prepares = prepare_for_handlers(rx, hdr);
|
|
||||||
|
|
||||||
if (!prepares)
|
if (!prepare_for_handlers(rx, hdr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!consume) {
|
if (!consume) {
|
||||||
|
|
|
@ -300,6 +300,35 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||||
if (!sta)
|
if (!sta)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
tx_latency = rcu_dereference(local->tx_latency);
|
||||||
|
/* init stations Tx latency statistics && TID bins */
|
||||||
|
if (tx_latency) {
|
||||||
|
sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS *
|
||||||
|
sizeof(struct ieee80211_tx_latency_stat),
|
||||||
|
GFP_ATOMIC);
|
||||||
|
if (!sta->tx_lat) {
|
||||||
|
rcu_read_unlock();
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx_latency->n_ranges) {
|
||||||
|
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||||
|
/* size of bins is size of the ranges +1 */
|
||||||
|
sta->tx_lat[i].bin_count =
|
||||||
|
tx_latency->n_ranges + 1;
|
||||||
|
sta->tx_lat[i].bins =
|
||||||
|
kcalloc(sta->tx_lat[i].bin_count,
|
||||||
|
sizeof(u32), GFP_ATOMIC);
|
||||||
|
if (!sta->tx_lat[i].bins) {
|
||||||
|
rcu_read_unlock();
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
spin_lock_init(&sta->lock);
|
spin_lock_init(&sta->lock);
|
||||||
INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
|
INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
|
||||||
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
|
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
|
||||||
|
@ -324,10 +353,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||||
for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
|
for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
|
||||||
ewma_init(&sta->chain_signal_avg[i], 1024, 8);
|
ewma_init(&sta->chain_signal_avg[i], 1024, 8);
|
||||||
|
|
||||||
if (sta_prepare_rate_control(local, sta, gfp)) {
|
if (sta_prepare_rate_control(local, sta, gfp))
|
||||||
kfree(sta);
|
goto free;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||||
/*
|
/*
|
||||||
|
@ -371,34 +398,17 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
tx_latency = rcu_dereference(local->tx_latency);
|
|
||||||
/* init stations Tx latency statistics && TID bins */
|
|
||||||
if (tx_latency)
|
|
||||||
sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS *
|
|
||||||
sizeof(struct ieee80211_tx_latency_stat),
|
|
||||||
GFP_ATOMIC);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if Tx latency and bins are enabled and the previous allocation
|
|
||||||
* succeeded
|
|
||||||
*/
|
|
||||||
if (tx_latency && tx_latency->n_ranges && sta->tx_lat)
|
|
||||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
|
||||||
/* size of bins is size of the ranges +1 */
|
|
||||||
sta->tx_lat[i].bin_count =
|
|
||||||
tx_latency->n_ranges + 1;
|
|
||||||
sta->tx_lat[i].bins = kcalloc(sta->tx_lat[i].bin_count,
|
|
||||||
sizeof(u32),
|
|
||||||
GFP_ATOMIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
|
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
|
||||||
|
|
||||||
return sta;
|
return sta;
|
||||||
|
|
||||||
|
free:
|
||||||
|
if (sta->tx_lat) {
|
||||||
|
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
|
||||||
|
kfree(sta->tx_lat[i].bins);
|
||||||
|
kfree(sta->tx_lat);
|
||||||
|
}
|
||||||
|
kfree(sta);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sta_info_insert_check(struct sta_info *sta)
|
static int sta_info_insert_check(struct sta_info *sta)
|
||||||
|
@ -1143,7 +1153,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||||||
|
|
||||||
static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
|
static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
|
||||||
struct sta_info *sta, int tid,
|
struct sta_info *sta, int tid,
|
||||||
enum ieee80211_frame_release_type reason)
|
enum ieee80211_frame_release_type reason,
|
||||||
|
bool call_driver)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
struct ieee80211_qos_hdr *nullfunc;
|
struct ieee80211_qos_hdr *nullfunc;
|
||||||
|
@ -1201,7 +1212,9 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
|
||||||
IEEE80211_TX_STATUS_EOSP |
|
IEEE80211_TX_STATUS_EOSP |
|
||||||
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||||
|
|
||||||
drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false);
|
if (call_driver)
|
||||||
|
drv_allow_buffered_frames(local, sta, BIT(tid), 1,
|
||||||
|
reason, false);
|
||||||
|
|
||||||
skb->dev = sdata->dev;
|
skb->dev = sdata->dev;
|
||||||
|
|
||||||
|
@ -1217,6 +1230,17 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int find_highest_prio_tid(unsigned long tids)
|
||||||
|
{
|
||||||
|
/* lower 3 TIDs aren't ordered perfectly */
|
||||||
|
if (tids & 0xF8)
|
||||||
|
return fls(tids) - 1;
|
||||||
|
/* TID 0 is BE just like TID 3 */
|
||||||
|
if (tids & BIT(0))
|
||||||
|
return 0;
|
||||||
|
return fls(tids) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||||
int n_frames, u8 ignored_acs,
|
int n_frames, u8 ignored_acs,
|
||||||
|
@ -1224,7 +1248,6 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||||
{
|
{
|
||||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
bool found = false;
|
|
||||||
bool more_data = false;
|
bool more_data = false;
|
||||||
int ac;
|
int ac;
|
||||||
unsigned long driver_release_tids = 0;
|
unsigned long driver_release_tids = 0;
|
||||||
|
@ -1235,9 +1258,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||||
|
|
||||||
__skb_queue_head_init(&frames);
|
__skb_queue_head_init(&frames);
|
||||||
|
|
||||||
/*
|
/* Get response frame(s) and more data bit for the last one. */
|
||||||
* Get response frame(s) and more data bit for it.
|
|
||||||
*/
|
|
||||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||||
unsigned long tids;
|
unsigned long tids;
|
||||||
|
|
||||||
|
@ -1246,43 +1267,48 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||||
|
|
||||||
tids = ieee80211_tids_for_ac(ac);
|
tids = ieee80211_tids_for_ac(ac);
|
||||||
|
|
||||||
if (!found) {
|
/* if we already have frames from software, then we can't also
|
||||||
driver_release_tids = sta->driver_buffered_tids & tids;
|
* release from hardware queues
|
||||||
if (driver_release_tids) {
|
*/
|
||||||
found = true;
|
if (skb_queue_empty(&frames))
|
||||||
} else {
|
driver_release_tids |= sta->driver_buffered_tids & tids;
|
||||||
struct sk_buff *skb;
|
|
||||||
|
|
||||||
while (n_frames > 0) {
|
if (driver_release_tids) {
|
||||||
skb = skb_dequeue(&sta->tx_filtered[ac]);
|
/* If the driver has data on more than one TID then
|
||||||
if (!skb) {
|
|
||||||
skb = skb_dequeue(
|
|
||||||
&sta->ps_tx_buf[ac]);
|
|
||||||
if (skb)
|
|
||||||
local->total_ps_buffered--;
|
|
||||||
}
|
|
||||||
if (!skb)
|
|
||||||
break;
|
|
||||||
n_frames--;
|
|
||||||
found = true;
|
|
||||||
__skb_queue_tail(&frames, skb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the driver has data on more than one TID then
|
|
||||||
* certainly there's more data if we release just a
|
* certainly there's more data if we release just a
|
||||||
* single frame now (from a single TID).
|
* single frame now (from a single TID). This will
|
||||||
|
* only happen for PS-Poll.
|
||||||
*/
|
*/
|
||||||
if (reason == IEEE80211_FRAME_RELEASE_PSPOLL &&
|
if (reason == IEEE80211_FRAME_RELEASE_PSPOLL &&
|
||||||
hweight16(driver_release_tids) > 1) {
|
hweight16(driver_release_tids) > 1) {
|
||||||
more_data = true;
|
more_data = true;
|
||||||
driver_release_tids =
|
driver_release_tids =
|
||||||
BIT(ffs(driver_release_tids) - 1);
|
BIT(find_highest_prio_tid(
|
||||||
|
driver_release_tids));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
while (n_frames > 0) {
|
||||||
|
skb = skb_dequeue(&sta->tx_filtered[ac]);
|
||||||
|
if (!skb) {
|
||||||
|
skb = skb_dequeue(
|
||||||
|
&sta->ps_tx_buf[ac]);
|
||||||
|
if (skb)
|
||||||
|
local->total_ps_buffered--;
|
||||||
|
}
|
||||||
|
if (!skb)
|
||||||
|
break;
|
||||||
|
n_frames--;
|
||||||
|
__skb_queue_tail(&frames, skb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we have more frames buffered on this AC, then set the
|
||||||
|
* more-data bit and abort the loop since we can't send more
|
||||||
|
* data from other ACs before the buffered frames from this.
|
||||||
|
*/
|
||||||
if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
|
if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
|
||||||
!skb_queue_empty(&sta->ps_tx_buf[ac])) {
|
!skb_queue_empty(&sta->ps_tx_buf[ac])) {
|
||||||
more_data = true;
|
more_data = true;
|
||||||
|
@ -1290,7 +1316,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (skb_queue_empty(&frames) && !driver_release_tids) {
|
||||||
int tid;
|
int tid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1311,15 +1337,13 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||||
/* This will evaluate to 1, 3, 5 or 7. */
|
/* This will evaluate to 1, 3, 5 or 7. */
|
||||||
tid = 7 - ((ffs(~ignored_acs) - 1) << 1);
|
tid = 7 - ((ffs(~ignored_acs) - 1) << 1);
|
||||||
|
|
||||||
ieee80211_send_null_response(sdata, sta, tid, reason);
|
ieee80211_send_null_response(sdata, sta, tid, reason, true);
|
||||||
return;
|
} else if (!driver_release_tids) {
|
||||||
}
|
|
||||||
|
|
||||||
if (!driver_release_tids) {
|
|
||||||
struct sk_buff_head pending;
|
struct sk_buff_head pending;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
u16 tids = 0;
|
u16 tids = 0;
|
||||||
|
bool need_null = false;
|
||||||
|
|
||||||
skb_queue_head_init(&pending);
|
skb_queue_head_init(&pending);
|
||||||
|
|
||||||
|
@ -1353,22 +1377,57 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||||
ieee80211_is_qos_nullfunc(hdr->frame_control))
|
ieee80211_is_qos_nullfunc(hdr->frame_control))
|
||||||
qoshdr = ieee80211_get_qos_ctl(hdr);
|
qoshdr = ieee80211_get_qos_ctl(hdr);
|
||||||
|
|
||||||
/* end service period after last frame */
|
tids |= BIT(skb->priority);
|
||||||
if (skb_queue_empty(&frames)) {
|
|
||||||
if (reason == IEEE80211_FRAME_RELEASE_UAPSD &&
|
__skb_queue_tail(&pending, skb);
|
||||||
qoshdr)
|
|
||||||
*qoshdr |= IEEE80211_QOS_CTL_EOSP;
|
/* end service period after last frame or add one */
|
||||||
|
if (!skb_queue_empty(&frames))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (reason != IEEE80211_FRAME_RELEASE_UAPSD) {
|
||||||
|
/* for PS-Poll, there's only one frame */
|
||||||
|
info->flags |= IEEE80211_TX_STATUS_EOSP |
|
||||||
|
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For uAPSD, things are a bit more complicated. If the
|
||||||
|
* last frame has a QoS header (i.e. is a QoS-data or
|
||||||
|
* QoS-nulldata frame) then just set the EOSP bit there
|
||||||
|
* and be done.
|
||||||
|
* If the frame doesn't have a QoS header (which means
|
||||||
|
* it should be a bufferable MMPDU) then we can't set
|
||||||
|
* the EOSP bit in the QoS header; add a QoS-nulldata
|
||||||
|
* frame to the list to send it after the MMPDU.
|
||||||
|
*
|
||||||
|
* Note that this code is only in the mac80211-release
|
||||||
|
* code path, we assume that the driver will not buffer
|
||||||
|
* anything but QoS-data frames, or if it does, will
|
||||||
|
* create the QoS-nulldata frame by itself if needed.
|
||||||
|
*
|
||||||
|
* Cf. 802.11-2012 10.2.1.10 (c).
|
||||||
|
*/
|
||||||
|
if (qoshdr) {
|
||||||
|
*qoshdr |= IEEE80211_QOS_CTL_EOSP;
|
||||||
|
|
||||||
info->flags |= IEEE80211_TX_STATUS_EOSP |
|
info->flags |= IEEE80211_TX_STATUS_EOSP |
|
||||||
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||||
|
} else {
|
||||||
|
/* The standard isn't completely clear on this
|
||||||
|
* as it says the more-data bit should be set
|
||||||
|
* if there are more BUs. The QoS-Null frame
|
||||||
|
* we're about to send isn't buffered yet, we
|
||||||
|
* only create it below, but let's pretend it
|
||||||
|
* was buffered just in case some clients only
|
||||||
|
* expect more-data=0 when eosp=1.
|
||||||
|
*/
|
||||||
|
hdr->frame_control |=
|
||||||
|
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||||
|
need_null = true;
|
||||||
|
num++;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
if (qoshdr)
|
|
||||||
tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK);
|
|
||||||
else
|
|
||||||
tids |= BIT(0);
|
|
||||||
|
|
||||||
__skb_queue_tail(&pending, skb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drv_allow_buffered_frames(local, sta, tids, num,
|
drv_allow_buffered_frames(local, sta, tids, num,
|
||||||
|
@ -1376,17 +1435,22 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||||
|
|
||||||
ieee80211_add_pending_skbs(local, &pending);
|
ieee80211_add_pending_skbs(local, &pending);
|
||||||
|
|
||||||
|
if (need_null)
|
||||||
|
ieee80211_send_null_response(
|
||||||
|
sdata, sta, find_highest_prio_tid(tids),
|
||||||
|
reason, false);
|
||||||
|
|
||||||
sta_info_recalc_tim(sta);
|
sta_info_recalc_tim(sta);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* We need to release a frame that is buffered somewhere in the
|
* We need to release a frame that is buffered somewhere in the
|
||||||
* driver ... it'll have to handle that.
|
* driver ... it'll have to handle that.
|
||||||
* Note that, as per the comment above, it'll also have to see
|
* Note that the driver also has to check the number of frames
|
||||||
* if there is more than just one frame on the specific TID that
|
* on the TIDs we're releasing from - if there are more than
|
||||||
* we're releasing from, and it needs to set the more-data bit
|
* n_frames it has to set the more-data bit (if we didn't ask
|
||||||
* accordingly if we tell it that there's no more data. If we do
|
* it to set it anyway due to other buffered frames); if there
|
||||||
* tell it there's more data, then of course the more-data bit
|
* are fewer than n_frames it has to make sure to adjust that
|
||||||
* needs to be set anyway.
|
* to allow the service period to end properly.
|
||||||
*/
|
*/
|
||||||
drv_release_buffered_frames(local, sta, driver_release_tids,
|
drv_release_buffered_frames(local, sta, driver_release_tids,
|
||||||
n_frames, reason, more_data);
|
n_frames, reason, more_data);
|
||||||
|
@ -1394,9 +1458,9 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||||
/*
|
/*
|
||||||
* Note that we don't recalculate the TIM bit here as it would
|
* Note that we don't recalculate the TIM bit here as it would
|
||||||
* most likely have no effect at all unless the driver told us
|
* most likely have no effect at all unless the driver told us
|
||||||
* that the TID became empty before returning here from the
|
* that the TID(s) became empty before returning here from the
|
||||||
* release function.
|
* release function.
|
||||||
* Either way, however, when the driver tells us that the TID
|
* Either way, however, when the driver tells us that the TID(s)
|
||||||
* became empty we'll do the TIM recalculation.
|
* became empty we'll do the TIM recalculation.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
@ -1485,6 +1549,8 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
|
||||||
if (WARN_ON(tid >= IEEE80211_NUM_TIDS))
|
if (WARN_ON(tid >= IEEE80211_NUM_TIDS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
trace_api_sta_set_buffered(sta->local, pubsta, tid, buffered);
|
||||||
|
|
||||||
if (buffered)
|
if (buffered)
|
||||||
set_bit(tid, &sta->driver_buffered_tids);
|
set_bit(tid, &sta->driver_buffered_tids);
|
||||||
else
|
else
|
||||||
|
|
|
@ -1835,6 +1835,33 @@ TRACE_EVENT(api_eosp,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(api_sta_set_buffered,
|
||||||
|
TP_PROTO(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
|
u8 tid, bool buffered),
|
||||||
|
|
||||||
|
TP_ARGS(local, sta, tid, buffered),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
LOCAL_ENTRY
|
||||||
|
STA_ENTRY
|
||||||
|
__field(u8, tid)
|
||||||
|
__field(bool, buffered)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
LOCAL_ASSIGN;
|
||||||
|
STA_ASSIGN;
|
||||||
|
__entry->tid = tid;
|
||||||
|
__entry->buffered = buffered;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk(
|
||||||
|
LOCAL_PR_FMT STA_PR_FMT " tid:%d buffered:%d",
|
||||||
|
LOCAL_PR_ARG, STA_PR_ARG, __entry->tid, __entry->buffered
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tracing for internal functions
|
* Tracing for internal functions
|
||||||
* (which may also be called in response to driver calls)
|
* (which may also be called in response to driver calls)
|
||||||
|
|
|
@ -500,6 +500,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
||||||
info->control.jiffies = jiffies;
|
info->control.jiffies = jiffies;
|
||||||
info->control.vif = &tx->sdata->vif;
|
info->control.vif = &tx->sdata->vif;
|
||||||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||||
|
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
|
||||||
skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
|
skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
|
||||||
|
|
||||||
if (!timer_pending(&local->sta_cleanup))
|
if (!timer_pending(&local->sta_cleanup))
|
||||||
|
@ -1073,6 +1074,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
|
||||||
queued = true;
|
queued = true;
|
||||||
info->control.vif = &tx->sdata->vif;
|
info->control.vif = &tx->sdata->vif;
|
||||||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||||
|
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
|
||||||
__skb_queue_tail(&tid_tx->pending, skb);
|
__skb_queue_tail(&tid_tx->pending, skb);
|
||||||
if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
|
if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
|
||||||
purge_skb = __skb_dequeue(&tid_tx->pending);
|
purge_skb = __skb_dequeue(&tid_tx->pending);
|
||||||
|
|
|
@ -2734,3 +2734,44 @@ int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_parse_p2p_noa);
|
EXPORT_SYMBOL(ieee80211_parse_p2p_noa);
|
||||||
|
|
||||||
|
void ieee80211_recalc_dtim(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sub_if_data *sdata)
|
||||||
|
{
|
||||||
|
u64 tsf = drv_get_tsf(local, sdata);
|
||||||
|
u64 dtim_count = 0;
|
||||||
|
u16 beacon_int = sdata->vif.bss_conf.beacon_int * 1024;
|
||||||
|
u8 dtim_period = sdata->vif.bss_conf.dtim_period;
|
||||||
|
struct ps_data *ps;
|
||||||
|
u8 bcns_from_dtim;
|
||||||
|
|
||||||
|
if (tsf == -1ULL || !beacon_int || !dtim_period)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||||
|
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
||||||
|
if (!sdata->bss)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ps = &sdata->bss->ps;
|
||||||
|
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||||
|
ps = &sdata->u.mesh.ps;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* actually finds last dtim_count, mac80211 will update in
|
||||||
|
* __beacon_add_tim().
|
||||||
|
* dtim_count = dtim_period - (tsf / bcn_int) % dtim_period
|
||||||
|
*/
|
||||||
|
do_div(tsf, beacon_int);
|
||||||
|
bcns_from_dtim = do_div(tsf, dtim_period);
|
||||||
|
/* just had a DTIM */
|
||||||
|
if (!bcns_from_dtim)
|
||||||
|
dtim_count = 0;
|
||||||
|
else
|
||||||
|
dtim_count = dtim_period - bcns_from_dtim;
|
||||||
|
|
||||||
|
ps->dtim_count = dtim_count;
|
||||||
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
||||||
* APs with pairwise keys should never receive Michael MIC
|
* APs with pairwise keys should never receive Michael MIC
|
||||||
* errors for non-zero keyidx because these are reserved for
|
* errors for non-zero keyidx because these are reserved for
|
||||||
* group keys and only the AP is sending real multicast
|
* group keys and only the AP is sending real multicast
|
||||||
* frames in the BSS. (
|
* frames in the BSS.
|
||||||
*/
|
*/
|
||||||
return RX_DROP_UNUSABLE;
|
return RX_DROP_UNUSABLE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5285,12 +5285,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
enum ieee80211_band band;
|
n_channels = ieee80211_get_num_supported_channels(wiphy);
|
||||||
n_channels = 0;
|
|
||||||
|
|
||||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++)
|
|
||||||
if (wiphy->bands[band])
|
|
||||||
n_channels += wiphy->bands[band]->n_channels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
|
if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
|
||||||
|
@ -5498,11 +5493,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
||||||
if (!n_channels)
|
if (!n_channels)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
} else {
|
} else {
|
||||||
n_channels = 0;
|
n_channels = ieee80211_get_num_supported_channels(wiphy);
|
||||||
|
|
||||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++)
|
|
||||||
if (wiphy->bands[band])
|
|
||||||
n_channels += wiphy->bands[band]->n_channels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
|
if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
|
||||||
|
@ -6795,6 +6786,55 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
||||||
|
enum nl80211_commands cmd,
|
||||||
|
enum nl80211_attrs attr,
|
||||||
|
int vendor_event_idx,
|
||||||
|
int approxlen, gfp_t gfp)
|
||||||
|
{
|
||||||
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||||
|
const struct nl80211_vendor_cmd_info *info;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case NL80211_CMD_TESTMODE:
|
||||||
|
if (WARN_ON(vendor_event_idx != -1))
|
||||||
|
return NULL;
|
||||||
|
info = NULL;
|
||||||
|
break;
|
||||||
|
case NL80211_CMD_VENDOR:
|
||||||
|
if (WARN_ON(vendor_event_idx < 0 ||
|
||||||
|
vendor_event_idx >= wiphy->n_vendor_events))
|
||||||
|
return NULL;
|
||||||
|
info = &wiphy->vendor_events[vendor_event_idx];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN_ON(1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
|
||||||
|
cmd, attr, info, gfp);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
|
||||||
|
|
||||||
|
void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
|
||||||
|
{
|
||||||
|
struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
|
||||||
|
void *hdr = ((void **)skb->cb)[1];
|
||||||
|
struct nlattr *data = ((void **)skb->cb)[2];
|
||||||
|
enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
|
||||||
|
|
||||||
|
nla_nest_end(skb, data);
|
||||||
|
genlmsg_end(skb, hdr);
|
||||||
|
|
||||||
|
if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
|
||||||
|
mcgrp = NL80211_MCGRP_VENDOR;
|
||||||
|
|
||||||
|
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
|
||||||
|
mcgrp, gfp);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__cfg80211_send_event_skb);
|
||||||
|
|
||||||
#ifdef CONFIG_NL80211_TESTMODE
|
#ifdef CONFIG_NL80211_TESTMODE
|
||||||
static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
|
static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
|
||||||
{
|
{
|
||||||
|
@ -6921,55 +6961,6 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
|
||||||
enum nl80211_commands cmd,
|
|
||||||
enum nl80211_attrs attr,
|
|
||||||
int vendor_event_idx,
|
|
||||||
int approxlen, gfp_t gfp)
|
|
||||||
{
|
|
||||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
||||||
const struct nl80211_vendor_cmd_info *info;
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case NL80211_CMD_TESTMODE:
|
|
||||||
if (WARN_ON(vendor_event_idx != -1))
|
|
||||||
return NULL;
|
|
||||||
info = NULL;
|
|
||||||
break;
|
|
||||||
case NL80211_CMD_VENDOR:
|
|
||||||
if (WARN_ON(vendor_event_idx < 0 ||
|
|
||||||
vendor_event_idx >= wiphy->n_vendor_events))
|
|
||||||
return NULL;
|
|
||||||
info = &wiphy->vendor_events[vendor_event_idx];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
WARN_ON(1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
|
|
||||||
cmd, attr, info, gfp);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
|
|
||||||
|
|
||||||
void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
|
|
||||||
{
|
|
||||||
struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
|
|
||||||
void *hdr = ((void **)skb->cb)[1];
|
|
||||||
struct nlattr *data = ((void **)skb->cb)[2];
|
|
||||||
enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
|
|
||||||
|
|
||||||
nla_nest_end(skb, data);
|
|
||||||
genlmsg_end(skb, hdr);
|
|
||||||
|
|
||||||
if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
|
|
||||||
mcgrp = NL80211_MCGRP_VENDOR;
|
|
||||||
|
|
||||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
|
|
||||||
mcgrp, gfp);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(__cfg80211_send_event_skb);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
|
|
@ -1089,11 +1089,8 @@ int cfg80211_wext_siwscan(struct net_device *dev,
|
||||||
/* Determine number of channels, needed to allocate creq */
|
/* Determine number of channels, needed to allocate creq */
|
||||||
if (wreq && wreq->num_channels)
|
if (wreq && wreq->num_channels)
|
||||||
n_channels = wreq->num_channels;
|
n_channels = wreq->num_channels;
|
||||||
else {
|
else
|
||||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++)
|
n_channels = ieee80211_get_num_supported_channels(wiphy);
|
||||||
if (wiphy->bands[band])
|
|
||||||
n_channels += wiphy->bands[band]->n_channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
|
creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
|
||||||
n_channels * sizeof(void *),
|
n_channels * sizeof(void *),
|
||||||
|
|
|
@ -70,18 +70,11 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
|
||||||
if (rdev->scan_req)
|
if (rdev->scan_req)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
if (wdev->conn->params.channel) {
|
if (wdev->conn->params.channel)
|
||||||
n_channels = 1;
|
n_channels = 1;
|
||||||
} else {
|
else
|
||||||
enum ieee80211_band band;
|
n_channels = ieee80211_get_num_supported_channels(wdev->wiphy);
|
||||||
n_channels = 0;
|
|
||||||
|
|
||||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
|
||||||
if (!wdev->wiphy->bands[band])
|
|
||||||
continue;
|
|
||||||
n_channels += wdev->wiphy->bands[band]->n_channels;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
|
request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
|
||||||
sizeof(request->channels[0]) * n_channels,
|
sizeof(request->channels[0]) * n_channels,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
|
|
@ -879,7 +879,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||||
|
|
||||||
dev->ieee80211_ptr->use_4addr = false;
|
dev->ieee80211_ptr->use_4addr = false;
|
||||||
dev->ieee80211_ptr->mesh_id_up_len = 0;
|
dev->ieee80211_ptr->mesh_id_up_len = 0;
|
||||||
|
wdev_lock(dev->ieee80211_ptr);
|
||||||
rdev_set_qos_map(rdev, dev, NULL);
|
rdev_set_qos_map(rdev, dev, NULL);
|
||||||
|
wdev_unlock(dev->ieee80211_ptr);
|
||||||
|
|
||||||
switch (otype) {
|
switch (otype) {
|
||||||
case NL80211_IFTYPE_AP:
|
case NL80211_IFTYPE_AP:
|
||||||
|
@ -1479,6 +1481,19 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy)
|
||||||
|
{
|
||||||
|
enum ieee80211_band band;
|
||||||
|
unsigned int n_channels = 0;
|
||||||
|
|
||||||
|
for (band = 0; band < IEEE80211_NUM_BANDS; band++)
|
||||||
|
if (wiphy->bands[band])
|
||||||
|
n_channels += wiphy->bands[band]->n_channels;
|
||||||
|
|
||||||
|
return n_channels;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_get_num_supported_channels);
|
||||||
|
|
||||||
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
|
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
|
||||||
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
|
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
|
||||||
const unsigned char rfc1042_header[] __aligned(2) =
|
const unsigned char rfc1042_header[] __aligned(2) =
|
||||||
|
|
|
@ -370,7 +370,7 @@ static int cfg80211_wext_siwretry(struct net_device *dev,
|
||||||
u8 oshort = wdev->wiphy->retry_short;
|
u8 oshort = wdev->wiphy->retry_short;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (retry->disabled ||
|
if (retry->disabled || retry->value < 1 || retry->value > 255 ||
|
||||||
(retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
|
(retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -412,9 +412,9 @@ int cfg80211_wext_giwretry(struct net_device *dev,
|
||||||
* First return short value, iwconfig will ask long value
|
* First return short value, iwconfig will ask long value
|
||||||
* later if needed
|
* later if needed
|
||||||
*/
|
*/
|
||||||
retry->flags |= IW_RETRY_LIMIT;
|
retry->flags |= IW_RETRY_LIMIT | IW_RETRY_SHORT;
|
||||||
retry->value = wdev->wiphy->retry_short;
|
retry->value = wdev->wiphy->retry_short;
|
||||||
if (wdev->wiphy->retry_long != wdev->wiphy->retry_short)
|
if (wdev->wiphy->retry_long == wdev->wiphy->retry_short)
|
||||||
retry->flags |= IW_RETRY_LONG;
|
retry->flags |= IW_RETRY_LONG;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue