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 2014-01-13 14:40:59 -05:00
commit f13352519e
39 changed files with 1058 additions and 877 deletions

View File

@ -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 */

View File

@ -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;
} }

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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;

View File

@ -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; */

View File

@ -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 |

View File

@ -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 |

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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.
*/ */
/** /**

View File

@ -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);

View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;
} }

View File

@ -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) {

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
} }

View File

@ -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)

View File

@ -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 *),

View File

@ -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);

View File

@ -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) =

View File

@ -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;