summaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/Kconfig1
-rw-r--r--net/mac80211/aes_ccm.c6
-rw-r--r--net/mac80211/cfg.c55
-rw-r--r--net/mac80211/debugfs.c89
-rw-r--r--net/mac80211/debugfs_sta.c26
-rw-r--r--net/mac80211/driver-ops.h31
-rw-r--r--net/mac80211/driver-trace.h47
-rw-r--r--net/mac80211/ibss.c10
-rw-r--r--net/mac80211/ieee80211_i.h12
-rw-r--r--net/mac80211/iface.c4
-rw-r--r--net/mac80211/key.c21
-rw-r--r--net/mac80211/main.c32
-rw-r--r--net/mac80211/mesh.c17
-rw-r--r--net/mac80211/mesh.h3
-rw-r--r--net/mac80211/mesh_hwmp.c4
-rw-r--r--net/mac80211/mesh_pathtbl.c49
-rw-r--r--net/mac80211/mesh_plink.c35
-rw-r--r--net/mac80211/mlme.c26
-rw-r--r--net/mac80211/pm.c16
-rw-r--r--net/mac80211/rx.c77
-rw-r--r--net/mac80211/sta_info.c33
-rw-r--r--net/mac80211/sta_info.h6
-rw-r--r--net/mac80211/status.c19
-rw-r--r--net/mac80211/tkip.c4
-rw-r--r--net/mac80211/tkip.h4
-rw-r--r--net/mac80211/tx.c17
-rw-r--r--net/mac80211/util.c2
-rw-r--r--net/mac80211/wep.c34
-rw-r--r--net/mac80211/wep.h4
-rw-r--r--net/mac80211/work.c6
-rw-r--r--net/mac80211/wpa.c62
31 files changed, 475 insertions, 277 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 513f85cc2ae1..f5fdfcbf552a 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -2,7 +2,6 @@ config MAC80211
tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
depends on CFG80211
select CRYPTO
- select CRYPTO_ECB
select CRYPTO_ARC4
select CRYPTO_AES
select CRC32
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
index 4bd6ef0be380..b9b595c08112 100644
--- a/net/mac80211/aes_ccm.c
+++ b/net/mac80211/aes_ccm.c
@@ -54,13 +54,12 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
u8 *cdata, u8 *mic)
{
int i, j, last_len, num_blocks;
- u8 *pos, *cpos, *b, *s_0, *e, *b_0, *aad;
+ u8 *pos, *cpos, *b, *s_0, *e, *b_0;
b = scratch;
s_0 = scratch + AES_BLOCK_LEN;
e = scratch + 2 * AES_BLOCK_LEN;
b_0 = scratch + 3 * AES_BLOCK_LEN;
- aad = scratch + 4 * AES_BLOCK_LEN;
num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
last_len = data_len % AES_BLOCK_LEN;
@@ -94,13 +93,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
u8 *cdata, size_t data_len, u8 *mic, u8 *data)
{
int i, j, last_len, num_blocks;
- u8 *pos, *cpos, *b, *s_0, *a, *b_0, *aad;
+ u8 *pos, *cpos, *b, *s_0, *a, *b_0;
b = scratch;
s_0 = scratch + AES_BLOCK_LEN;
a = scratch + 2 * AES_BLOCK_LEN;
b_0 = scratch + 3 * AES_BLOCK_LEN;
- aad = scratch + 4 * AES_BLOCK_LEN;
num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
last_len = data_len % AES_BLOCK_LEN;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 44049733c4ea..12d52cec9515 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -330,6 +330,7 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in
static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct timespec uptime;
sinfo->generation = sdata->local->sta_generation;
@@ -342,7 +343,12 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
STATION_INFO_TX_FAILED |
STATION_INFO_TX_BITRATE |
STATION_INFO_RX_BITRATE |
- STATION_INFO_RX_DROP_MISC;
+ STATION_INFO_RX_DROP_MISC |
+ STATION_INFO_BSS_PARAM |
+ STATION_INFO_CONNECTED_TIME;
+
+ do_posix_clock_monotonic_gettime(&uptime);
+ sinfo->connected_time = uptime.tv_sec - sta->last_connected;
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
sinfo->rx_bytes = sta->rx_bytes;
@@ -389,6 +395,16 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->plink_state = sta->plink_state;
#endif
}
+
+ sinfo->bss_param.flags = 0;
+ if (sdata->vif.bss_conf.use_cts_prot)
+ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
+ if (sdata->vif.bss_conf.use_short_preamble)
+ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
+ if (sdata->vif.bss_conf.use_short_slot)
+ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+ sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period;
+ sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int;
}
@@ -675,6 +691,12 @@ static void sta_apply_parameters(struct ieee80211_local *local,
if (set & BIT(NL80211_STA_FLAG_MFP))
sta->flags |= WLAN_STA_MFP;
}
+
+ if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
+ sta->flags &= ~WLAN_STA_AUTH;
+ if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
+ sta->flags |= WLAN_STA_AUTH;
+ }
spin_unlock_irqrestore(&sta->flaglock, flags);
/*
@@ -1023,26 +1045,26 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
u8 *new_ie;
const u8 *old_ie;
- /* first allocate the new vendor information element */
+ /* allocate information elements */
new_ie = NULL;
- old_ie = ifmsh->vendor_ie;
+ old_ie = ifmsh->ie;
- ifmsh->vendor_ie_len = setup->vendor_ie_len;
- if (setup->vendor_ie_len) {
- new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len,
+ if (setup->ie_len) {
+ new_ie = kmemdup(setup->ie, setup->ie_len,
GFP_KERNEL);
if (!new_ie)
return -ENOMEM;
}
+ ifmsh->ie_len = setup->ie_len;
+ ifmsh->ie = new_ie;
+ kfree(old_ie);
/* now copy the rest of the setup parameters */
ifmsh->mesh_id_len = setup->mesh_id_len;
memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
ifmsh->mesh_pp_id = setup->path_sel_proto;
ifmsh->mesh_pm_id = setup->path_metric;
- ifmsh->vendor_ie = new_ie;
-
- kfree(old_ie);
+ ifmsh->is_secure = setup->is_secure;
return 0;
}
@@ -1611,16 +1633,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- int i;
-
- /*
- * This _could_ be supported by providing a hook for
- * drivers for this function, but at this point it
- * doesn't seem worth bothering.
- */
- if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
- return -EOPNOTSUPP;
+ int i, ret;
+ if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {
+ ret = drv_set_bitrate_mask(local, sdata, mask);
+ if (ret)
+ return ret;
+ }
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 51f0d780dafa..0a602dbfdb2b 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -37,7 +37,7 @@ int mac80211_format_buffer(char __user *userbuf, size_t count,
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}
-#define DEBUGFS_READONLY_FILE(name, fmt, value...) \
+#define DEBUGFS_READONLY_FILE_FN(name, fmt, value...) \
static ssize_t name## _read(struct file *file, char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
@@ -45,14 +45,19 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \
\
return mac80211_format_buffer(userbuf, count, ppos, \
fmt "\n", ##value); \
-} \
- \
+}
+
+#define DEBUGFS_READONLY_FILE_OPS(name) \
static const struct file_operations name## _ops = { \
.read = name## _read, \
.open = mac80211_open_file_generic, \
.llseek = generic_file_llseek, \
};
+#define DEBUGFS_READONLY_FILE(name, fmt, value...) \
+ DEBUGFS_READONLY_FILE_FN(name, fmt, value) \
+ DEBUGFS_READONLY_FILE_OPS(name)
+
#define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0400, phyd, local, &name## _ops);
@@ -291,11 +296,70 @@ static ssize_t channel_type_read(struct file *file, char __user *user_buf,
return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
}
-static const struct file_operations channel_type_ops = {
- .read = channel_type_read,
- .open = mac80211_open_file_generic,
- .llseek = default_llseek,
-};
+static ssize_t hwflags_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_local *local = file->private_data;
+ int mxln = 500;
+ ssize_t rv;
+ char *buf = kzalloc(mxln, GFP_KERNEL);
+ int sf = 0; /* how many written so far */
+
+ sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags);
+ if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+ sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n");
+ if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+ sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n");
+ if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)
+ sf += snprintf(buf + sf, mxln - sf,
+ "HOST_BCAST_PS_BUFFERING\n");
+ if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)
+ sf += snprintf(buf + sf, mxln - sf,
+ "2GHZ_SHORT_SLOT_INCAPABLE\n");
+ if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)
+ sf += snprintf(buf + sf, mxln - sf,
+ "2GHZ_SHORT_PREAMBLE_INCAPABLE\n");
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
+ sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n");
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n");
+ if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
+ sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_PERIOD\n");
+ if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)
+ sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");
+ if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)
+ sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n");
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS)
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n");
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+ sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n");
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");
+ if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE)
+ sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");
+ if (local->hw.flags & IEEE80211_HW_BEACON_FILTER)
+ sf += snprintf(buf + sf, mxln - sf, "BEACON_FILTER\n");
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS)
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n");
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n");
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");
+ if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
+ sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n");
+ if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
+ sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n");
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_CQM_RSSI\n");
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n");
+ if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
+ sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");
+
+ rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+ kfree(buf);
+ return rv;
+}
static ssize_t queues_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@@ -315,11 +379,9 @@ static ssize_t queues_read(struct file *file, char __user *user_buf,
return simple_read_from_buffer(user_buf, count, ppos, buf, res);
}
-static const struct file_operations queues_ops = {
- .read = queues_read,
- .open = mac80211_open_file_generic,
- .llseek = default_llseek,
-};
+DEBUGFS_READONLY_FILE_OPS(hwflags);
+DEBUGFS_READONLY_FILE_OPS(channel_type);
+DEBUGFS_READONLY_FILE_OPS(queues);
/* statistics stuff */
@@ -395,6 +457,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(uapsd_queues);
DEBUGFS_ADD(uapsd_max_sp_len);
DEBUGFS_ADD(channel_type);
+ DEBUGFS_ADD(hwflags);
DEBUGFS_ADD(user_power);
DEBUGFS_ADD(power);
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index c04a1396cf8d..a01d2137fddc 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -92,6 +92,31 @@ static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf,
}
STA_OPS(inactive_ms);
+
+static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct sta_info *sta = file->private_data;
+ struct timespec uptime;
+ struct tm result;
+ long connected_time_secs;
+ char buf[100];
+ int res;
+ do_posix_clock_monotonic_gettime(&uptime);
+ connected_time_secs = uptime.tv_sec - sta->last_connected;
+ time_to_tm(connected_time_secs, 0, &result);
+ result.tm_year -= 70;
+ result.tm_mday -= 1;
+ res = scnprintf(buf, sizeof(buf),
+ "years - %ld\nmonths - %d\ndays - %d\nclock - %d:%d:%d\n\n",
+ result.tm_year, result.tm_mon, result.tm_mday,
+ result.tm_hour, result.tm_min, result.tm_sec);
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(connected_time);
+
+
+
static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
@@ -324,6 +349,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD(flags);
DEBUGFS_ADD(num_ps_buf_frames);
DEBUGFS_ADD(inactive_ms);
+ DEBUGFS_ADD(connected_time);
DEBUGFS_ADD(last_seq_ctrl);
DEBUGFS_ADD(agg_status);
DEBUGFS_ADD(dev);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 9c0d62bb0ea3..2ddb56e5b51f 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -552,4 +552,35 @@ static inline void drv_get_ringparam(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+static inline bool drv_tx_frames_pending(struct ieee80211_local *local)
+{
+ bool ret = false;
+
+ might_sleep();
+
+ trace_drv_tx_frames_pending(local);
+ if (local->ops->tx_frames_pending)
+ ret = local->ops->tx_frames_pending(&local->hw);
+ trace_drv_return_bool(local, ret);
+
+ return ret;
+}
+
+static inline int drv_set_bitrate_mask(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ int ret = -EOPNOTSUPP;
+
+ might_sleep();
+
+ trace_drv_set_bitrate_mask(local, sdata, mask);
+ if (local->ops->set_bitrate_mask)
+ ret = local->ops->set_bitrate_mask(&local->hw,
+ &sdata->vif, mask);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 45aab80738e2..191e834ec46b 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -74,6 +74,21 @@ TRACE_EVENT(drv_return_int,
TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret)
);
+TRACE_EVENT(drv_return_bool,
+ TP_PROTO(struct ieee80211_local *local, bool ret),
+ TP_ARGS(local, ret),
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(bool, ret)
+ ),
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+ TP_printk(LOCAL_PR_FMT " - %s", LOCAL_PR_ARG, (__entry->ret) ?
+ "true" : "false")
+);
+
TRACE_EVENT(drv_return_u64,
TP_PROTO(struct ieee80211_local *local, u64 ret),
TP_ARGS(local, ret),
@@ -964,11 +979,43 @@ TRACE_EVENT(drv_get_ringparam,
)
);
+DEFINE_EVENT(local_only_evt, drv_tx_frames_pending,
+ TP_PROTO(struct ieee80211_local *local),
+ TP_ARGS(local)
+);
+
DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
);
+TRACE_EVENT(drv_set_bitrate_mask,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_bitrate_mask *mask),
+
+ TP_ARGS(local, sdata, mask),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __field(u32, legacy_2g)
+ __field(u32, legacy_5g)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ __entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy;
+ __entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g
+ )
+);
+
/*
* Tracing for API calls that drivers call.
*/
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 3e81af1fce58..b81860c94698 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -40,7 +40,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len)
{
- u16 auth_alg, auth_transaction, status_code;
+ u16 auth_alg, auth_transaction;
lockdep_assert_held(&sdata->u.ibss.mtx);
@@ -49,7 +49,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
- status_code = le16_to_cpu(mgmt->u.auth.status_code);
/*
* IEEE 802.11 standard does not require authentication in IBSS
@@ -527,8 +526,6 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_supported_band *sband;
u8 bssid[ETH_ALEN];
u16 capability;
int i;
@@ -551,8 +548,6 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
sdata->name, bssid);
- sband = local->hw.wiphy->bands[ifibss->channel->band];
-
capability = WLAN_CAPABILITY_IBSS;
if (ifibss->privacy)
@@ -661,7 +656,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
struct sk_buff *req)
{
- struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(req);
struct ieee80211_mgmt *mgmt = (void *)req->data;
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
@@ -685,7 +679,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
mgmt->bssid, tx_last_beacon);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- if (!tx_last_beacon && !(rx_status->rx_flags & IEEE80211_RX_RA_MATCH))
+ if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da))
return;
if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 &&
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c18396c248d7..027c0467d7a3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -488,8 +488,9 @@ struct ieee80211_if_mesh {
struct mesh_config mshcfg;
u32 mesh_seqnum;
bool accepting_plinks;
- const u8 *vendor_ie;
- u8 vendor_ie_len;
+ const u8 *ie;
+ u8 ie_len;
+ bool is_secure;
};
#ifdef CONFIG_MAC80211_MESH
@@ -765,6 +766,9 @@ struct ieee80211_local {
int tx_headroom; /* required headroom for hardware/radiotap */
+ /* count for keys needing tailroom space allocation */
+ int crypto_tx_tailroom_needed_cnt;
+
/* Tasklet and skb queue to process calls from IRQ mode. All frames
* added to skb_queue will be processed, but frames in
* skb_queue_unreliable may be dropped if the total length of these
@@ -809,8 +813,8 @@ struct ieee80211_local {
struct rate_control_ref *rate_ctrl;
- struct crypto_blkcipher *wep_tx_tfm;
- struct crypto_blkcipher *wep_rx_tfm;
+ struct crypto_cipher *wep_tx_tfm;
+ struct crypto_cipher *wep_rx_tfm;
u32 wep_iv;
/* see iface.c */
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 4054399be907..80c29d626aa4 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1144,10 +1144,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
+ IEEE80211_ENCRYPT_HEADROOM;
ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
- ret = dev_alloc_name(ndev, ndev->name);
- if (ret < 0)
- goto fail;
-
ieee80211_assign_perm_addr(local, ndev, type);
memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index af3c56482c80..b510721e3b3d 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -101,6 +101,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
if (!ret) {
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+ if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+ (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+ key->local->crypto_tx_tailroom_needed_cnt--;
+
return 0;
}
@@ -156,6 +161,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+ if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+ (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+ key->local->crypto_tx_tailroom_needed_cnt++;
}
void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
@@ -388,8 +397,10 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
ieee80211_aes_key_free(key->u.ccmp.tfm);
if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
- if (key->local)
+ if (key->local) {
ieee80211_debugfs_key_remove(key);
+ key->local->crypto_tx_tailroom_needed_cnt--;
+ }
kfree(key);
}
@@ -451,6 +462,8 @@ int ieee80211_key_link(struct ieee80211_key *key,
ieee80211_debugfs_key_add(key);
+ key->local->crypto_tx_tailroom_needed_cnt++;
+
ret = ieee80211_key_enable_hw_accel(key);
mutex_unlock(&sdata->local->key_mtx);
@@ -492,8 +505,12 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
mutex_lock(&sdata->local->key_mtx);
- list_for_each_entry(key, &sdata->key_list, list)
+ sdata->local->crypto_tx_tailroom_needed_cnt = 0;
+
+ list_for_each_entry(key, &sdata->key_list, list) {
+ sdata->local->crypto_tx_tailroom_needed_cnt++;
ieee80211_key_enable_hw_accel(key);
+ }
mutex_unlock(&sdata->local->key_mtx);
}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 562d2984c482..61877662e8f8 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -33,12 +33,6 @@
#include "cfg.h"
#include "debugfs.h"
-
-static bool ieee80211_disable_40mhz_24ghz;
-module_param(ieee80211_disable_40mhz_24ghz, bool, 0644);
-MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz,
- "Disable 40MHz support in the 2.4GHz band");
-
static struct lock_class_key ieee80211_rx_skb_queue_class;
void ieee80211_configure_filter(struct ieee80211_local *local)
@@ -545,7 +539,9 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
},
[NL80211_IFTYPE_MESH_POINT] = {
.tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4),
},
};
@@ -726,18 +722,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
channels += sband->n_channels;
- /*
- * Since ieee80211_disable_40mhz_24ghz is global, we can
- * modify the sband's ht data even if the driver uses a
- * global structure for that.
- */
- if (ieee80211_disable_40mhz_24ghz &&
- band == IEEE80211_BAND_2GHZ &&
- sband->ht_cap.ht_supported) {
- sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
- }
-
if (max_bitrates < sband->n_bitrates)
max_bitrates = sband->n_bitrates;
supp_ht = supp_ht || sband->ht_cap.ht_supported;
@@ -760,6 +744,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
#endif
+ /* if the underlying driver supports mesh, mac80211 will (at least)
+ * provide routing of mesh authentication frames to userspace */
+ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT))
+ local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
+
/* mac80211 supports control port protocol changing */
local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
@@ -879,10 +868,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->dynamic_ps_forced_timeout = -1;
- result = sta_info_start(local);
- if (result < 0)
- goto fail_sta_info;
-
result = ieee80211_wep_init(local);
if (result < 0)
wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
@@ -945,7 +930,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
rtnl_unlock();
ieee80211_wep_free(local);
sta_info_stop(local);
- fail_sta_info:
destroy_workqueue(local->workqueue);
fail_workqueue:
wiphy_unregister(local->hw.wiphy);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 2a57cc02c618..c1299e249541 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -279,9 +279,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
*pos++ = 0x00;
- if (sdata->u.mesh.vendor_ie) {
- int len = sdata->u.mesh.vendor_ie_len;
- const u8 *data = sdata->u.mesh.vendor_ie;
+ if (sdata->u.mesh.ie) {
+ int len = sdata->u.mesh.ie_len;
+ const u8 *data = sdata->u.mesh.ie;
if (skb_tailroom(skb) > len)
memcpy(skb_put(skb, len), data, len);
}
@@ -573,6 +573,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
&elems);
+ /* ignore beacons from secure mesh peers if our security is off */
+ if (elems.rsn_len && !sdata->u.mesh.is_secure)
+ return;
+
if (elems.ds_params && elems.ds_params_len == 1)
freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
else
@@ -586,9 +590,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
if (elems.mesh_id && elems.mesh_config &&
mesh_matches_local(&elems, sdata)) {
supp_rates = ieee80211_sta_get_rates(local, &elems, band);
-
- mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
- mesh_peer_accepts_plinks(&elems));
+ mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems);
}
}
@@ -611,12 +613,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_rx_status *rx_status;
- struct ieee80211_if_mesh *ifmsh;
struct ieee80211_mgmt *mgmt;
u16 stype;
- ifmsh = &sdata->u.mesh;
-
rx_status = IEEE80211_SKB_RXCB(skb);
mgmt = (struct ieee80211_mgmt *) skb->data;
stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index b99e230fe31c..10acf1cc8082 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -226,7 +226,8 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata);
/* Mesh plinks */
void mesh_neighbour_update(u8 *hw_addr, u32 rates,
- struct ieee80211_sub_if_data *sdata, bool add);
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *ie);
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
void mesh_plink_broken(struct sta_info *sta);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 5bf64d7112b3..e57f2e728cfe 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -633,7 +633,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
struct mesh_path *mpath;
u8 ttl;
u8 *ta, *target_addr;
- u8 target_flags;
u32 target_sn;
u16 target_rcode;
@@ -644,7 +643,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
return;
}
ttl--;
- target_flags = PERR_IE_TARGET_FLAGS(perr_elem);
target_addr = PERR_IE_TARGET_ADDR(perr_elem);
target_sn = PERR_IE_TARGET_SN(perr_elem);
target_rcode = PERR_IE_TARGET_RCODE(perr_elem);
@@ -675,12 +673,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct mesh_path *mpath;
- u8 *ta;
u8 ttl, flags, hopcount;
u8 *orig_addr;
u32 orig_sn, metric;
- ta = mgmt->sa;
ttl = rann->rann_ttl;
if (ttl <= 1) {
ifmsh->mshstats.dropped_frames_ttl++;
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 336ca9d0c5c4..35c715adaae2 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -65,42 +65,37 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
__mesh_table_free(tbl);
}
-static struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
+static int mesh_table_grow(struct mesh_table *oldtbl,
+ struct mesh_table *newtbl)
{
- struct mesh_table *newtbl;
struct hlist_head *oldhash;
struct hlist_node *p, *q;
int i;
- if (atomic_read(&tbl->entries)
- < tbl->mean_chain_len * (tbl->hash_mask + 1))
- goto endgrow;
+ if (atomic_read(&oldtbl->entries)
+ < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1))
+ return -EAGAIN;
- newtbl = mesh_table_alloc(tbl->size_order + 1);
- if (!newtbl)
- goto endgrow;
- newtbl->free_node = tbl->free_node;
- newtbl->mean_chain_len = tbl->mean_chain_len;
- newtbl->copy_node = tbl->copy_node;
- atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
+ newtbl->free_node = oldtbl->free_node;
+ newtbl->mean_chain_len = oldtbl->mean_chain_len;
+ newtbl->copy_node = oldtbl->copy_node;
+ atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries));
- oldhash = tbl->hash_buckets;
- for (i = 0; i <= tbl->hash_mask; i++)
+ oldhash = oldtbl->hash_buckets;
+ for (i = 0; i <= oldtbl->hash_mask; i++)
hlist_for_each(p, &oldhash[i])
- if (tbl->copy_node(p, newtbl) < 0)
+ if (oldtbl->copy_node(p, newtbl) < 0)
goto errcopy;
- return newtbl;
+ return 0;
errcopy:
for (i = 0; i <= newtbl->hash_mask; i++) {
hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
- tbl->free_node(p, 0);
+ oldtbl->free_node(p, 0);
}
- __mesh_table_free(newtbl);
-endgrow:
- return NULL;
+ return -ENOMEM;
}
@@ -334,10 +329,13 @@ void mesh_mpath_table_grow(void)
{
struct mesh_table *oldtbl, *newtbl;
+ newtbl = mesh_table_alloc(mesh_paths->size_order + 1);
+ if (!newtbl)
+ return;
write_lock(&pathtbl_resize_lock);
oldtbl = mesh_paths;
- newtbl = mesh_table_grow(mesh_paths);
- if (!newtbl) {
+ if (mesh_table_grow(mesh_paths, newtbl) < 0) {
+ __mesh_table_free(newtbl);
write_unlock(&pathtbl_resize_lock);
return;
}
@@ -352,10 +350,13 @@ void mesh_mpp_table_grow(void)
{
struct mesh_table *oldtbl, *newtbl;
+ newtbl = mesh_table_alloc(mpp_paths->size_order + 1);
+ if (!newtbl)
+ return;
write_lock(&pathtbl_resize_lock);
oldtbl = mpp_paths;
- newtbl = mesh_table_grow(mpp_paths);
- if (!newtbl) {
+ if (mesh_table_grow(mpp_paths, newtbl) < 0) {
+ __mesh_table_free(newtbl);
write_unlock(&pathtbl_resize_lock);
return;
}
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 44b53931ba5e..84e5b056af02 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta)
return NULL;
- sta->flags = WLAN_STA_AUTHORIZED;
+ sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH;
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
rate_control_rate_init(sta);
@@ -161,7 +161,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
__le16 reason) {
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
- sdata->u.mesh.vendor_ie_len);
+ sdata->u.mesh.ie_len);
struct ieee80211_mgmt *mgmt;
bool include_plid = false;
static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
@@ -237,8 +237,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
return 0;
}
-void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data *sdata,
- bool peer_accepting_plinks)
+void mesh_neighbour_update(u8 *hw_addr, u32 rates,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *elems)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
@@ -248,8 +249,14 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data
sta = sta_info_get(sdata, hw_addr);
if (!sta) {
rcu_read_unlock();
-
- sta = mesh_plink_alloc(sdata, hw_addr, rates);
+ /* Userspace handles peer allocation when security is enabled
+ * */
+ if (sdata->u.mesh.is_secure)
+ cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
+ elems->ie_start, elems->total_len,
+ GFP_KERNEL);
+ else
+ sta = mesh_plink_alloc(sdata, hw_addr, rates);
if (!sta)
return;
if (sta_info_insert_rcu(sta)) {
@@ -260,7 +267,8 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data
sta->last_rx = jiffies;
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
- if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN &&
+ if (mesh_peer_accepts_plinks(elems) &&
+ sta->plink_state == PLINK_LISTEN &&
sdata->u.mesh.accepting_plinks &&
sdata->u.mesh.mshcfg.auto_open_plinks)
mesh_plink_open(sta);
@@ -372,6 +380,9 @@ int mesh_plink_open(struct sta_info *sta)
__le16 llid;
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ if (!test_sta_flags(sta, WLAN_STA_AUTH))
+ return -EPERM;
+
spin_lock_bh(&sta->lock);
get_random_bytes(&llid, 2);
sta->llid = llid;
@@ -449,6 +460,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
mpl_dbg("Mesh plink: missing necessary peer link ie\n");
return;
}
+ if (elems.rsn_len && !sdata->u.mesh.is_secure) {
+ mpl_dbg("Mesh plink: can't establish link with secure peer\n");
+ return;
+ }
ftype = mgmt->u.action.u.plink_action.action_code;
ie_len = elems.peer_link_len;
@@ -480,6 +495,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
return;
}
+ if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) {
+ mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
+ rcu_read_unlock();
+ return;
+ }
+
if (sta && sta->plink_state == PLINK_BLOCKED) {
rcu_read_unlock();
return;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 64d92d5a7f40..a41f234bd486 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -90,20 +90,11 @@ enum rx_mgmt_action {
/* no action required */
RX_MGMT_NONE,
- /* caller must call cfg80211_send_rx_auth() */
- RX_MGMT_CFG80211_AUTH,
-
- /* caller must call cfg80211_send_rx_assoc() */
- RX_MGMT_CFG80211_ASSOC,
-
/* caller must call cfg80211_send_deauth() */
RX_MGMT_CFG80211_DEAUTH,
/* caller must call cfg80211_send_disassoc() */
RX_MGMT_CFG80211_DISASSOC,
-
- /* caller must tell cfg80211 about internal error */
- RX_MGMT_CFG80211_ASSOC_ERROR,
};
/* utils */
@@ -770,15 +761,16 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
(!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) {
netif_tx_stop_all_queues(sdata->dev);
- /*
- * Flush all the frames queued in the driver before
- * going to power save
- */
- drv_flush(local, false);
- ieee80211_send_nullfunc(local, sdata, 1);
- /* Flush once again to get the tx status of nullfunc frame */
- drv_flush(local, false);
+ if (drv_tx_frames_pending(local))
+ mod_timer(&local->dynamic_ps_timer, jiffies +
+ msecs_to_jiffies(
+ local->hw.conf.dynamic_ps_timeout));
+ else {
+ ieee80211_send_nullfunc(local, sdata, 1);
+ /* Flush to get the tx status of nullfunc frame */
+ drv_flush(local, false);
+ }
}
if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index e37355193ed1..042461710880 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -14,12 +14,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
ieee80211_scan_cancel(local);
+ if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
+ mutex_lock(&local->sta_mtx);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+ ieee80211_sta_tear_down_BA_sessions(sta, true);
+ }
+ mutex_unlock(&local->sta_mtx);
+ }
+
ieee80211_stop_queues_by_reason(hw,
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
/* flush out all packets */
synchronize_net();
+ drv_flush(local, false);
+
local->quiescing = true;
/* make quiescing visible to timers everywhere */
mb();
@@ -43,11 +54,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
/* tear down aggregation sessions and remove STAs */
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
- if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
- set_sta_flags(sta, WLAN_STA_BLOCK_BA);
- ieee80211_sta_tear_down_BA_sessions(sta, true);
- }
-
if (sta->uploaded) {
sdata = sta->sdata;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index c5d4530d8284..13a6697651ad 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -143,7 +143,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
if (status->flag & RX_FLAG_HT) {
/*
* MCS information is a separate field in radiotap,
- * added below.
+ * added below. The byte here is needed as padding
+ * for the channel though, so initialise it to 0.
*/
*pos = 0;
} else {
@@ -502,7 +503,8 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
if (ieee80211_is_probe_req(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control) ||
- ieee80211_is_beacon(hdr->frame_control))
+ ieee80211_is_beacon(hdr->frame_control) ||
+ ieee80211_is_auth(hdr->frame_control))
return RX_CONTINUE;
return RX_DROP_MONITOR;
@@ -650,7 +652,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
set_release_timer:
mod_timer(&tid_agg_rx->reorder_timer,
- tid_agg_rx->reorder_time[j] +
+ tid_agg_rx->reorder_time[j] + 1 +
HT_RX_REORDER_BUF_TIMEOUT);
} else {
del_timer(&tid_agg_rx->reorder_timer);
@@ -707,6 +709,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
/*
* If the current MPDU is in the right order and nothing else
* is stored we can process it directly, no need to buffer it.
+ * If it is first but there's something stored, we may be able
+ * to release frames after this one.
*/
if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
tid_agg_rx->stored_mpdu_num == 0) {
@@ -1583,7 +1587,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
}
static int
-__ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
+__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
@@ -1591,6 +1595,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
struct ethhdr *ehdr;
int ret;
+ *port_control = false;
if (ieee80211_has_a4(hdr->frame_control) &&
sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
return -1;
@@ -1609,11 +1614,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
return -1;
ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
- if (ret < 0 || !check_port_control)
+ if (ret < 0)
return ret;
ehdr = (struct ethhdr *) rx->skb->data;
- if (ehdr->h_proto != rx->sdata->control_port_protocol)
+ if (ehdr->h_proto == rx->sdata->control_port_protocol)
+ *port_control = true;
+ else if (check_port_control)
return -1;
return 0;
@@ -1914,6 +1921,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
struct net_device *dev = sdata->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
__le16 fc = hdr->frame_control;
+ bool port_control;
int err;
if (unlikely(!ieee80211_is_data(hdr->frame_control)))
@@ -1930,13 +1938,21 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
sdata->vif.type == NL80211_IFTYPE_AP)
return RX_DROP_MONITOR;
- err = __ieee80211_data_to_8023(rx);
+ err = __ieee80211_data_to_8023(rx, &port_control);
if (unlikely(err))
return RX_DROP_UNUSABLE;
if (!ieee80211_frame_allowed(rx, fc))
return RX_DROP_MONITOR;
+ if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+ unlikely(port_control) && sdata->bss) {
+ sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
+ u.ap);
+ dev = sdata->dev;
+ rx->sdata = sdata;
+ }
+
rx->skb->dev = dev;
dev->stats.rx_packets++;
@@ -2352,47 +2368,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
return RX_QUEUED;
}
-static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
- struct ieee80211_rx_data *rx)
-{
- int keyidx;
- unsigned int hdrlen;
-
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
- if (rx->skb->len >= hdrlen + 4)
- keyidx = rx->skb->data[hdrlen + 3] >> 6;
- else
- keyidx = -1;
-
- if (!rx->sta) {
- /*
- * Some hardware seem to generate incorrect Michael MIC
- * reports; ignore them to avoid triggering countermeasures.
- */
- return;
- }
-
- if (!ieee80211_has_protected(hdr->frame_control))
- return;
-
- if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) {
- /*
- * APs with pairwise keys should never receive Michael MIC
- * errors for non-zero keyidx because these are reserved for
- * group keys and only the AP is sending real multicast
- * frames in the BSS.
- */
- return;
- }
-
- if (!ieee80211_is_data(hdr->frame_control) &&
- !ieee80211_is_auth(hdr->frame_control))
- return;
-
- mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL,
- GFP_ATOMIC);
-}
-
/* TODO: use IEEE80211_RX_FRAGMENTED */
static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
struct ieee80211_rate *rate)
@@ -2736,12 +2711,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
if (!prepares)
return false;
- if (status->flag & RX_FLAG_MMIC_ERROR) {
- if (status->rx_flags & IEEE80211_RX_RA_MATCH)
- ieee80211_rx_michael_mic_report(hdr, rx);
- return false;
- }
-
if (!consume) {
skb = skb_copy(skb, GFP_ATOMIC);
if (!skb) {
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 13e8c30adf01..d9e6e81ff6b2 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -228,6 +228,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
+ struct timespec uptime;
int i;
sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
@@ -245,6 +246,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->sdata = sdata;
sta->last_rx = jiffies;
+ do_posix_clock_monotonic_gettime(&uptime);
+ sta->last_connected = uptime.tv_sec;
ewma_init(&sta->avg_signal, 1024, 8);
if (sta_prepare_rate_control(local, sta, gfp)) {
@@ -584,7 +587,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
{
unsigned long flags;
struct sk_buff *skb;
- struct ieee80211_sub_if_data *sdata;
if (skb_queue_empty(&sta->ps_tx_buf))
return false;
@@ -601,7 +603,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
if (!skb)
break;
- sdata = sta->sdata;
local->total_ps_buffered--;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n",
@@ -609,7 +610,8 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
#endif
dev_kfree_skb(skb);
- if (skb_queue_empty(&sta->ps_tx_buf))
+ if (skb_queue_empty(&sta->ps_tx_buf) &&
+ !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
sta_info_clear_tim_bit(sta);
}
@@ -698,6 +700,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
cancel_work_sync(&sta->drv_unblock_wk);
+ cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL);
+
rate_control_remove_sta_debugfs(sta);
ieee80211_sta_debugfs_remove(sta);
@@ -766,9 +770,8 @@ static void sta_info_cleanup(unsigned long data)
if (!timer_needed)
return;
- local->sta_cleanup.expires =
- round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
- add_timer(&local->sta_cleanup);
+ mod_timer(&local->sta_cleanup,
+ round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL));
}
void sta_info_init(struct ieee80211_local *local)
@@ -781,14 +784,6 @@ void sta_info_init(struct ieee80211_local *local)
setup_timer(&local->sta_cleanup, sta_info_cleanup,
(unsigned long)local);
- local->sta_cleanup.expires =
- round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
-}
-
-int sta_info_start(struct ieee80211_local *local)
-{
- add_timer(&local->sta_cleanup);
- return 0;
}
void sta_info_stop(struct ieee80211_local *local)
@@ -900,6 +895,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
struct ieee80211_local *local = sdata->local;
int sent, buffered;
+ clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
@@ -992,3 +988,12 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
ieee80211_queue_work(hw, &sta->drv_unblock_wk);
}
EXPORT_SYMBOL(ieee80211_sta_block_awake);
+
+void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
+{
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+
+ set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
+ sta_info_set_tim_bit(sta);
+}
+EXPORT_SYMBOL(ieee80211_sta_set_tim);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index b2f95966c7f4..aa0adcbf3a93 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -43,6 +43,8 @@
* be in the queues
* @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
* station in power-save mode, reply when the driver unblocks.
+ * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
+ * buffers. Automatically cleared on station wake-up.
*/
enum ieee80211_sta_info_flags {
WLAN_STA_AUTH = 1<<0,
@@ -58,6 +60,7 @@ enum ieee80211_sta_info_flags {
WLAN_STA_BLOCK_BA = 1<<11,
WLAN_STA_PS_DRIVER = 1<<12,
WLAN_STA_PSPOLL = 1<<13,
+ WLAN_STA_PS_DRIVER_BUF = 1<<14,
};
#define STA_TID_NUM 16
@@ -226,6 +229,7 @@ enum plink_state {
* @rx_bytes: Number of bytes received from this STA
* @wep_weak_iv_count: number of weak WEP IVs received from this station
* @last_rx: time (in jiffies) when last frame was received from this STA
+ * @last_connected: time (in seconds) when a station got connected
* @num_duplicates: number of duplicate frames received from this STA
* @rx_fragments: number of received MPDUs
* @rx_dropped: number of dropped MPDUs from this STA
@@ -295,6 +299,7 @@ struct sta_info {
unsigned long rx_packets, rx_bytes;
unsigned long wep_weak_iv_count;
unsigned long last_rx;
+ long last_connected;
unsigned long num_duplicates;
unsigned long rx_fragments;
unsigned long rx_dropped;
@@ -497,7 +502,6 @@ void sta_info_set_tim_bit(struct sta_info *sta);
void sta_info_clear_tim_bit(struct sta_info *sta);
void sta_info_init(struct ieee80211_local *local);
-int sta_info_start(struct ieee80211_local *local);
void sta_info_stop(struct ieee80211_local *local);
int sta_info_flush(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index b936dd29e92b..1658efaa2e8e 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -189,16 +189,19 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
bool acked;
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
- /* the HW cannot have attempted that rate */
- if (i >= hw->max_report_rates) {
+ if (info->status.rates[i].idx < 0) {
+ break;
+ } else if (i >= hw->max_report_rates) {
+ /* the HW cannot have attempted that rate */
info->status.rates[i].idx = -1;
info->status.rates[i].count = 0;
- } else if (info->status.rates[i].idx >= 0) {
- rates_idx = i;
+ break;
}
retry_count += info->status.rates[i].count;
}
+ rates_idx = i - 1;
+
if (retry_count < 0)
retry_count = 0;
@@ -443,3 +446,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status);
+
+void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
+{
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+ cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
+ num_packets, GFP_ATOMIC);
+}
+EXPORT_SYMBOL(ieee80211_report_low_ack);
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index e840c9cd46db..757e4eb2baf7 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -202,7 +202,7 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key);
* @payload_len is the length of payload (_not_ including IV/ICV length).
* @ta is the transmitter addresses.
*/
-int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
struct ieee80211_key *key,
u8 *pos, size_t payload_len, u8 *ta)
{
@@ -223,7 +223,7 @@ int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
* beginning of the buffer containing IEEE 802.11 header payload, i.e.,
* including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the
* length of payload, including IV, Ext. IV, MIC, ICV. */
-int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
+int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
struct ieee80211_key *key,
u8 *payload, size_t payload_len, u8 *ta,
u8 *ra, int only_iv, int queue,
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
index 7e83dee976fa..1cab9c86978f 100644
--- a/net/mac80211/tkip.h
+++ b/net/mac80211/tkip.h
@@ -15,7 +15,7 @@
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16);
-int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
struct ieee80211_key *key,
u8 *pos, size_t payload_len, u8 *ta);
enum {
@@ -24,7 +24,7 @@ enum {
TKIP_DECRYPT_INVALID_KEYIDX = -2,
TKIP_DECRYPT_REPLAY = -3,
};
-int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
+int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
struct ieee80211_key *key,
u8 *payload, size_t payload_len, u8 *ta,
u8 *ra, int only_iv, int queue,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index ce4596ed1268..e3e3aa173af0 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1036,14 +1036,11 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
struct ieee80211_radiotap_iterator iterator;
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *) skb->data;
- struct ieee80211_supported_band *sband;
bool hw_frag;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
NULL);
- sband = tx->local->hw.wiphy->bands[tx->channel->band];
-
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
@@ -1442,11 +1439,8 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_data tx;
ieee80211_tx_result res_prepare;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- u16 queue;
bool result = true;
- queue = skb_get_queue_mapping(skb);
-
if (unlikely(skb->len < 10)) {
dev_kfree_skb(skb);
return true;
@@ -1482,12 +1476,7 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
{
int tail_need = 0;
- /*
- * This could be optimised, devices that do full hardware
- * crypto (including TKIP MMIC) need no tailroom... But we
- * have no drivers for such devices currently.
- */
- if (may_encrypt) {
+ if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) {
tail_need = IEEE80211_ENCRYPT_TAILROOM;
tail_need -= skb_tailroom(skb);
tail_need = max_t(int, tail_need, 0);
@@ -2262,7 +2251,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
/* headroom, head length, tail length and maximum TIM length */
skb = dev_alloc_skb(local->tx_headroom + 400 +
- sdata->u.mesh.vendor_ie_len);
+ sdata->u.mesh.ie_len);
if (!skb)
goto out;
@@ -2485,7 +2474,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
{
struct ieee80211_local *local = hw_to_local(hw);
struct sk_buff *skb = NULL;
- struct sta_info *sta;
struct ieee80211_tx_data tx;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_ap *bss = NULL;
@@ -2527,7 +2515,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
info = IEEE80211_SKB_CB(skb);
- sta = tx.sta;
tx.flags |= IEEE80211_TX_PS_BUFFERED;
tx.channel = local->hw.conf.channel;
info->band = tx.channel->band;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 556647a910ac..ef0560a2346a 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1290,7 +1290,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
}
- add_timer(&local->sta_cleanup);
+ mod_timer(&local->sta_cleanup, jiffies + 1);
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list)
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 2ff6d1e3ed21..a1c6bfd55f0f 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -30,17 +30,15 @@ int ieee80211_wep_init(struct ieee80211_local *local)
/* start WEP IV from a random value */
get_random_bytes(&local->wep_iv, WEP_IV_LEN);
- local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
- CRYPTO_ALG_ASYNC);
+ local->wep_tx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(local->wep_tx_tfm)) {
local->wep_rx_tfm = ERR_PTR(-EINVAL);
return PTR_ERR(local->wep_tx_tfm);
}
- local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
- CRYPTO_ALG_ASYNC);
+ local->wep_rx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(local->wep_rx_tfm)) {
- crypto_free_blkcipher(local->wep_tx_tfm);
+ crypto_free_cipher(local->wep_tx_tfm);
local->wep_tx_tfm = ERR_PTR(-EINVAL);
return PTR_ERR(local->wep_rx_tfm);
}
@@ -51,9 +49,9 @@ int ieee80211_wep_init(struct ieee80211_local *local)
void ieee80211_wep_free(struct ieee80211_local *local)
{
if (!IS_ERR(local->wep_tx_tfm))
- crypto_free_blkcipher(local->wep_tx_tfm);
+ crypto_free_cipher(local->wep_tx_tfm);
if (!IS_ERR(local->wep_rx_tfm))
- crypto_free_blkcipher(local->wep_rx_tfm);
+ crypto_free_cipher(local->wep_rx_tfm);
}
static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
@@ -127,12 +125,11 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local,
/* Perform WEP encryption using given key. data buffer must have tailroom
* for 4-byte ICV. data_len must not include this ICV. Note: this function
* does _not_ add IV. data = RC4(data | CRC32(data)) */
-int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
size_t klen, u8 *data, size_t data_len)
{
- struct blkcipher_desc desc = { .tfm = tfm };
- struct scatterlist sg;
__le32 icv;
+ int i;
if (IS_ERR(tfm))
return -1;
@@ -140,9 +137,9 @@ int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
icv = cpu_to_le32(~crc32_le(~0, data, data_len));
put_unaligned(icv, (__le32 *)(data + data_len));
- crypto_blkcipher_setkey(tfm, rc4key, klen);
- sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
- crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
+ crypto_cipher_setkey(tfm, rc4key, klen);
+ for (i = 0; i < data_len + WEP_ICV_LEN; i++)
+ crypto_cipher_encrypt_one(tfm, data + i, data + i);
return 0;
}
@@ -186,19 +183,18 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local,
/* Perform WEP decryption using given key. data buffer includes encrypted
* payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV.
* Return 0 on success and -1 on ICV mismatch. */
-int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
size_t klen, u8 *data, size_t data_len)
{
- struct blkcipher_desc desc = { .tfm = tfm };
- struct scatterlist sg;
__le32 crc;
+ int i;
if (IS_ERR(tfm))
return -1;
- crypto_blkcipher_setkey(tfm, rc4key, klen);
- sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
- crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
+ crypto_cipher_setkey(tfm, rc4key, klen);
+ for (i = 0; i < data_len + WEP_ICV_LEN; i++)
+ crypto_cipher_decrypt_one(tfm, data + i, data + i);
crc = cpu_to_le32(~crc32_le(~0, data, data_len));
if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0)
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index 58654ee33518..01e54840a628 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -18,12 +18,12 @@
int ieee80211_wep_init(struct ieee80211_local *local);
void ieee80211_wep_free(struct ieee80211_local *local);
-int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
size_t klen, u8 *data, size_t data_len);
int ieee80211_wep_encrypt(struct ieee80211_local *local,
struct sk_buff *skb,
const u8 *key, int keylen, int keyidx);
-int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
size_t klen, u8 *data, size_t data_len);
bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index e73c8cae036b..a94b312dbfac 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -198,9 +198,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, qos_info;
- const u8 *ies;
size_t offset = 0, noffset;
- int i, len, count, rates_len, supp_rates_len;
+ int i, count, rates_len, supp_rates_len;
u16 capab;
struct ieee80211_supported_band *sband;
u32 rates = 0;
@@ -285,7 +284,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
}
/* SSID */
- ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len);
+ pos = skb_put(skb, 2 + wk->assoc.ssid_len);
*pos++ = WLAN_EID_SSID;
*pos++ = wk->assoc.ssid_len;
memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len);
@@ -295,7 +294,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
if (supp_rates_len > 8)
supp_rates_len = 8;
- len = sband->n_bitrates;
pos = skb_put(skb, supp_rates_len + 2);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = supp_rates_len;
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index f1765de2f4bf..9dc3b5f26e80 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -87,42 +87,76 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- /* No way to verify the MIC if the hardware stripped it */
- if (status->flag & RX_FLAG_MMIC_STRIPPED)
+ /*
+ * it makes no sense to check for MIC errors on anything other
+ * than data frames.
+ */
+ if (!ieee80211_is_data_present(hdr->frame_control))
+ return RX_CONTINUE;
+
+ /*
+ * No way to verify the MIC if the hardware stripped it or
+ * the IV with the key index. In this case we have solely rely
+ * on the driver to set RX_FLAG_MMIC_ERROR in the event of a
+ * MIC failure report.
+ */
+ if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) {
+ if (status->flag & RX_FLAG_MMIC_ERROR)
+ goto mic_fail;
+
+ if (!(status->flag & RX_FLAG_IV_STRIPPED))
+ goto update_iv;
+
return RX_CONTINUE;
+ }
+ /*
+ * Some hardware seems to generate Michael MIC failure reports; even
+ * though, the frame was not encrypted with TKIP and therefore has no
+ * MIC. Ignore the flag them to avoid triggering countermeasures.
+ */
if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
- !ieee80211_has_protected(hdr->frame_control) ||
- !ieee80211_is_data_present(hdr->frame_control))
+ !(status->flag & RX_FLAG_DECRYPTED))
return RX_CONTINUE;
+ if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) {
+ /*
+ * APs with pairwise keys should never receive Michael MIC
+ * errors for non-zero keyidx because these are reserved for
+ * group keys and only the AP is sending real multicast
+ * frames in the BSS. (
+ */
+ return RX_DROP_UNUSABLE;
+ }
+
+ if (status->flag & RX_FLAG_MMIC_ERROR)
+ goto mic_fail;
+
hdrlen = ieee80211_hdrlen(hdr->frame_control);
if (skb->len < hdrlen + MICHAEL_MIC_LEN)
return RX_DROP_UNUSABLE;
data = skb->data + hdrlen;
data_len = skb->len - hdrlen - MICHAEL_MIC_LEN;
-
key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
michael_mic(key, hdr, data, data_len, mic);
- if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) {
- if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
- return RX_DROP_UNUSABLE;
-
- mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
- (void *) skb->data, NULL,
- GFP_ATOMIC);
- return RX_DROP_UNUSABLE;
- }
+ if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0)
+ goto mic_fail;
/* remove Michael MIC from payload */
skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
+update_iv:
/* update IV in key information to be able to detect replays */
rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
return RX_CONTINUE;
+
+mic_fail:
+ mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
+ (void *) skb->data, NULL, GFP_ATOMIC);
+ return RX_DROP_UNUSABLE;
}