aboutsummaryrefslogtreecommitdiff
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c10
-rw-r--r--net/wireless/core.h6
-rw-r--r--net/wireless/ibss.c60
-rw-r--r--net/wireless/nl80211.c128
-rw-r--r--net/wireless/util.c45
-rw-r--r--net/wireless/wext-compat.c286
-rw-r--r--net/wireless/wext.c20
7 files changed, 464 insertions, 91 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 2006a4ee60e..47c20eb0c04 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1,7 +1,7 @@
/*
* This is the linux wireless configuration interface.
*
- * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/if.h>
@@ -457,6 +457,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
"symlink to netdev!\n");
}
dev->ieee80211_ptr->netdev = dev;
+#ifdef CONFIG_WIRELESS_EXT
+ dev->ieee80211_ptr->wext.default_key = -1;
+ dev->ieee80211_ptr->wext.default_mgmt_key = -1;
+#endif
mutex_unlock(&rdev->devlist_mtx);
break;
case NETDEV_GOING_DOWN:
@@ -470,9 +474,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
#ifdef CONFIG_WIRELESS_EXT
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
break;
- if (!dev->ieee80211_ptr->wext.ssid_len)
+ if (!dev->ieee80211_ptr->wext.ibss.ssid_len)
break;
- cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext);
+ cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext.ibss);
break;
#endif
case NETDEV_UNREGISTER:
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 3e49d339931..f14b6c5f422 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -1,7 +1,7 @@
/*
* Wireless configuration interface internals.
*
- * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
*/
#ifndef __NET_WIRELESS_CORE_H
#define __NET_WIRELESS_CORE_H
@@ -151,4 +151,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool nowext);
+/* internal helpers */
+int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+ const u8 *mac_addr);
+
#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 3c38afaed28..a4a1c3498ff 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -63,7 +63,7 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
return -EALREADY;
#ifdef CONFIG_WIRELESS_EXT
- wdev->wext.channel = params->channel;
+ wdev->wext.ibss.channel = params->channel;
#endif
err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
@@ -90,7 +90,7 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
memset(wdev->bssid, 0, ETH_ALEN);
#ifdef CONFIG_WIRELESS_EXT
if (!nowext)
- wdev->wext.ssid_len = 0;
+ wdev->wext.ibss.ssid_len = 0;
#endif
}
@@ -116,11 +116,11 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
enum ieee80211_band band;
int i;
- if (!wdev->wext.beacon_interval)
- wdev->wext.beacon_interval = 100;
+ if (!wdev->wext.ibss.beacon_interval)
+ wdev->wext.ibss.beacon_interval = 100;
/* try to find an IBSS channel if none requested ... */
- if (!wdev->wext.channel) {
+ if (!wdev->wext.ibss.channel) {
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
@@ -135,27 +135,27 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
continue;
if (chan->flags & IEEE80211_CHAN_DISABLED)
continue;
- wdev->wext.channel = chan;
+ wdev->wext.ibss.channel = chan;
break;
}
- if (wdev->wext.channel)
+ if (wdev->wext.ibss.channel)
break;
}
- if (!wdev->wext.channel)
+ if (!wdev->wext.ibss.channel)
return -EINVAL;
}
/* don't join -- SSID is not there */
- if (!wdev->wext.ssid_len)
+ if (!wdev->wext.ibss.ssid_len)
return 0;
if (!netif_running(wdev->netdev))
return 0;
return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
- wdev->netdev, &wdev->wext);
+ wdev->netdev, &wdev->wext.ibss);
}
int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
@@ -182,7 +182,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
chan->flags & IEEE80211_CHAN_DISABLED))
return -EINVAL;
- if (wdev->wext.channel == chan)
+ if (wdev->wext.ibss.channel == chan)
return 0;
if (wdev->ssid_len) {
@@ -193,11 +193,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
}
if (chan) {
- wdev->wext.channel = chan;
- wdev->wext.channel_fixed = true;
+ wdev->wext.ibss.channel = chan;
+ wdev->wext.ibss.channel_fixed = true;
} else {
/* cfg80211_ibss_wext_join will pick one if needed */
- wdev->wext.channel_fixed = false;
+ wdev->wext.ibss.channel_fixed = false;
}
return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
@@ -218,8 +218,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
if (wdev->current_bss)
chan = wdev->current_bss->channel;
- else if (wdev->wext.channel)
- chan = wdev->wext.channel;
+ else if (wdev->wext.ibss.channel)
+ chan = wdev->wext.ibss.channel;
if (chan) {
freq->m = chan->center_freq;
@@ -259,9 +259,9 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
if (len > 0 && ssid[len - 1] == '\0')
len--;
- wdev->wext.ssid = wdev->ssid;
- memcpy(wdev->wext.ssid, ssid, len);
- wdev->wext.ssid_len = len;
+ wdev->wext.ibss.ssid = wdev->ssid;
+ memcpy(wdev->wext.ibss.ssid, ssid, len);
+ wdev->wext.ibss.ssid_len = len;
return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
}
@@ -284,10 +284,10 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
data->flags = 1;
data->length = wdev->ssid_len;
memcpy(ssid, wdev->ssid, data->length);
- } else if (wdev->wext.ssid && wdev->wext.ssid_len) {
+ } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) {
data->flags = 1;
- data->length = wdev->wext.ssid_len;
- memcpy(ssid, wdev->wext.ssid, data->length);
+ data->length = wdev->wext.ibss.ssid_len;
+ memcpy(ssid, wdev->wext.ibss.ssid, data->length);
}
return 0;
@@ -318,12 +318,12 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
bssid = NULL;
/* both automatic */
- if (!bssid && !wdev->wext.bssid)
+ if (!bssid && !wdev->wext.ibss.bssid)
return 0;
/* fixed already - and no change */
- if (wdev->wext.bssid && bssid &&
- compare_ether_addr(bssid, wdev->wext.bssid) == 0)
+ if (wdev->wext.ibss.bssid && bssid &&
+ compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0)
return 0;
if (wdev->ssid_len) {
@@ -334,10 +334,10 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
}
if (bssid) {
- memcpy(wdev->wext_bssid, bssid, ETH_ALEN);
- wdev->wext.bssid = wdev->wext_bssid;
+ memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
+ wdev->wext.ibss.bssid = wdev->wext.bssid;
} else
- wdev->wext.bssid = NULL;
+ wdev->wext.ibss.bssid = NULL;
return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
}
@@ -356,8 +356,8 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
ap_addr->sa_family = ARPHRD_ETHER;
- if (wdev->wext.bssid) {
- memcpy(ap_addr->sa_data, wdev->wext.bssid, ETH_ALEN);
+ if (wdev->wext.ibss.bssid) {
+ memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
return 0;
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3c53c5cbc3a..f0fec2f4982 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1,7 +1,7 @@
/*
* This is the new netlink-based wireless configuration interface.
*
- * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/if.h>
@@ -122,6 +122,11 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
[NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
[NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
+ [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 },
+ [NL80211_ATTR_STA_FLAGS2] = {
+ .len = sizeof(struct nl80211_sta_flag_update),
+ },
+ [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
};
/* IE validation */
@@ -1072,6 +1077,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
}
err = func(&drv->wiphy, dev, key_idx);
+#ifdef CONFIG_WIRELESS_EXT
+ if (!err) {
+ if (func == drv->ops->set_default_key)
+ dev->ieee80211_ptr->wext.default_key = key_idx;
+ else
+ dev->ieee80211_ptr->wext.default_mgmt_key = key_idx;
+ }
+#endif
out:
cfg80211_put_dev(drv);
@@ -1102,6 +1115,11 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
}
+ if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
+ params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
+ params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
+ }
+
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
@@ -1110,44 +1128,8 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- if (key_idx > 5)
- return -EINVAL;
-
- /*
- * Disallow pairwise keys with non-zero index unless it's WEP
- * (because current deployments use pairwise WEP keys with
- * non-zero indizes but 802.11i clearly specifies to use zero)
- */
- if (mac_addr && key_idx &&
- params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
- params.cipher != WLAN_CIPHER_SUITE_WEP104)
- return -EINVAL;
-
- /* TODO: add definitions for the lengths to linux/ieee80211.h */
- switch (params.cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- if (params.key_len != 5)
- return -EINVAL;
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- if (params.key_len != 32)
- return -EINVAL;
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- if (params.key_len != 16)
- return -EINVAL;
- break;
- case WLAN_CIPHER_SUITE_WEP104:
- if (params.key_len != 13)
- return -EINVAL;
- break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- if (params.key_len != 16)
- return -EINVAL;
- break;
- default:
+ if (cfg80211_validate_key_settings(&params, key_idx, mac_addr))
return -EINVAL;
- }
rtnl_lock();
@@ -1209,6 +1191,15 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
+#ifdef CONFIG_WIRELESS_EXT
+ if (!err) {
+ if (key_idx == dev->ieee80211_ptr->wext.default_key)
+ dev->ieee80211_ptr->wext.default_key = -1;
+ else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key)
+ dev->ieee80211_ptr->wext.default_mgmt_key = -1;
+ }
+#endif
+
out:
cfg80211_put_dev(drv);
dev_put(dev);
@@ -1349,15 +1340,36 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
[NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
+ [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
};
-static int parse_station_flags(struct nlattr *nla, u32 *staflags)
+static int parse_station_flags(struct genl_info *info,
+ struct station_parameters *params)
{
struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
+ struct nlattr *nla;
int flag;
- *staflags = 0;
+ /*
+ * Try parsing the new attribute first so userspace
+ * can specify both for older kernels.
+ */
+ nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
+ if (nla) {
+ struct nl80211_sta_flag_update *sta_flags;
+
+ sta_flags = nla_data(nla);
+ params->sta_flags_mask = sta_flags->mask;
+ params->sta_flags_set = sta_flags->set;
+ if ((params->sta_flags_mask |
+ params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
+ return -EINVAL;
+ return 0;
+ }
+
+ /* if present, parse the old attribute */
+ nla = info->attrs[NL80211_ATTR_STA_FLAGS];
if (!nla)
return 0;
@@ -1365,11 +1377,12 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags)
nla, sta_flags_policy))
return -EINVAL;
- *staflags = STATION_FLAG_CHANGED;
+ params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1;
+ params->sta_flags_mask &= ~1;
for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
if (flags[flag])
- *staflags |= (1<<flag);
+ params->sta_flags_set |= (1<<flag);
return 0;
}
@@ -1665,8 +1678,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
- if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
- &params.station_flags))
+ if (parse_station_flags(info, &params))
return -EINVAL;
if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
@@ -1735,8 +1747,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
- if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
- &params.station_flags))
+ if (parse_station_flags(info, &params))
return -EINVAL;
rtnl_lock();
@@ -1745,6 +1756,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
if (err)
goto out_rtnl;
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
+ err = -EINVAL;
+ goto out;
+ }
+
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
if (err)
goto out;
@@ -1788,6 +1805,12 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
if (err)
goto out_rtnl;
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
+ err = -EINVAL;
+ goto out;
+ }
+
if (!drv->ops->del_station) {
err = -EOPNOTSUPP;
goto out;
@@ -3012,6 +3035,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
+ if (info->attrs[NL80211_ATTR_USE_MFP]) {
+ enum nl80211_mfp use_mfp =
+ nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
+ if (use_mfp == NL80211_MFP_REQUIRED)
+ req.use_mfp = true;
+ else if (use_mfp != NL80211_MFP_NO) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
+
err = drv->ops->assoc(&drv->wiphy, dev, &req);
out:
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 5f7e997195c..beb226e78cd 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -138,3 +138,48 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
if (wiphy->bands[band])
set_mandatory_flags_band(wiphy->bands[band], band);
}
+
+int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+ const u8 *mac_addr)
+{
+ if (key_idx > 5)
+ return -EINVAL;
+
+ /*
+ * Disallow pairwise keys with non-zero index unless it's WEP
+ * (because current deployments use pairwise WEP keys with
+ * non-zero indizes but 802.11i clearly specifies to use zero)
+ */
+ if (mac_addr && key_idx &&
+ params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
+ params->cipher != WLAN_CIPHER_SUITE_WEP104)
+ return -EINVAL;
+
+ /* TODO: add definitions for the lengths to linux/ieee80211.h */
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ if (params->key_len != 5)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (params->key_len != 32)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (params->key_len != 16)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ if (params->key_len != 13)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ if (params->key_len != 16)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 5ef82f2ca88..f98090b90fb 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -5,12 +5,13 @@
* into cfg80211, when that happens all the exports here go away and
* we directly assign the wireless handlers of wireless interfaces.
*
- * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/wireless.h>
#include <linux/nl80211.h>
#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
#include <net/iw_handler.h>
#include <net/cfg80211.h>
#include "core.h"
@@ -296,22 +297,34 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);
struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
struct iw_freq *freq)
{
+ struct ieee80211_channel *chan;
+ int f;
+
+ /*
+ * Parse frequency - return NULL for auto and
+ * -EINVAL for impossible things.
+ */
if (freq->e == 0) {
if (freq->m < 0)
return NULL;
- else
- return ieee80211_get_channel(wiphy,
- ieee80211_channel_to_frequency(freq->m));
+ f = ieee80211_channel_to_frequency(freq->m);
} else {
int i, div = 1000000;
for (i = 0; i < freq->e; i++)
div /= 10;
- if (div > 0)
- return ieee80211_get_channel(wiphy, freq->m / div);
- else
+ if (div <= 0)
return ERR_PTR(-EINVAL);
+ f = freq->m / div;
}
+ /*
+ * Look up channel struct and return -EINVAL when
+ * it cannot be found.
+ */
+ chan = ieee80211_get_channel(wiphy, f);
+ if (!chan)
+ return ERR_PTR(-EINVAL);
+ return chan;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_freq);
@@ -465,3 +478,262 @@ int cfg80211_wext_giwretry(struct net_device *dev,
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
+
+static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *addr,
+ bool remove, bool tx_key, int idx,
+ struct key_params *params)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ if (!rdev->ops->set_default_mgmt_key)
+ return -EOPNOTSUPP;
+
+ if (idx < 4 || idx > 5)
+ return -EINVAL;
+ } else if (idx < 0 || idx > 3)
+ return -EINVAL;
+
+ if (remove) {
+ err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
+ if (!err) {
+ if (idx == wdev->wext.default_key)
+ wdev->wext.default_key = -1;
+ else if (idx == wdev->wext.default_mgmt_key)
+ wdev->wext.default_mgmt_key = -1;
+ }
+ return err;
+ } else {
+ if (addr)
+ tx_key = false;
+
+ if (cfg80211_validate_key_settings(params, idx, addr))
+ return -EINVAL;
+
+ err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
+ if (err)
+ return err;
+
+ if (tx_key || (!addr && wdev->wext.default_key == -1)) {
+ err = rdev->ops->set_default_key(&rdev->wiphy,
+ dev, idx);
+ if (!err)
+ wdev->wext.default_key = idx;
+ return err;
+ }
+
+ if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
+ (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+ err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
+ dev, idx);
+ if (!err)
+ wdev->wext.default_mgmt_key = idx;
+ return err;
+ }
+
+ return 0;
+ }
+}
+
+int cfg80211_wext_siwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ int idx, err;
+ bool remove = false;
+ struct key_params params;
+
+ /* no use -- only MFP (set_default_mgmt_key) is optional */
+ if (!rdev->ops->del_key ||
+ !rdev->ops->add_key ||
+ !rdev->ops->set_default_key)
+ return -EOPNOTSUPP;
+
+ idx = erq->flags & IW_ENCODE_INDEX;
+ if (idx == 0) {
+ idx = wdev->wext.default_key;
+ if (idx < 0)
+ idx = 0;
+ } else if (idx < 1 || idx > 4)
+ return -EINVAL;
+ else
+ idx--;
+
+ if (erq->flags & IW_ENCODE_DISABLED)
+ remove = true;
+ else if (erq->length == 0) {
+ /* No key data - just set the default TX key index */
+ err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx);
+ if (!err)
+ wdev->wext.default_key = idx;
+ return err;
+ }
+
+ memset(&params, 0, sizeof(params));
+ params.key = keybuf;
+ params.key_len = erq->length;
+ if (erq->length == 5)
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
+ else if (erq->length == 13)
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ else if (!remove)
+ return -EINVAL;
+
+ return cfg80211_set_encryption(rdev, dev, NULL, remove,
+ wdev->wext.default_key == -1,
+ idx, &params);
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode);
+
+int cfg80211_wext_siwencodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+ const u8 *addr;
+ int idx;
+ bool remove = false;
+ struct key_params params;
+ u32 cipher;
+
+ /* no use -- only MFP (set_default_mgmt_key) is optional */
+ if (!rdev->ops->del_key ||
+ !rdev->ops->add_key ||
+ !rdev->ops->set_default_key)
+ return -EOPNOTSUPP;
+
+ switch (ext->alg) {
+ case IW_ENCODE_ALG_NONE:
+ remove = true;
+ cipher = 0;
+ break;
+ case IW_ENCODE_ALG_WEP:
+ if (ext->key_len == 5)
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ else if (ext->key_len == 13)
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ else
+ return -EINVAL;
+ break;
+ case IW_ENCODE_ALG_TKIP:
+ cipher = WLAN_CIPHER_SUITE_TKIP;
+ break;
+ case IW_ENCODE_ALG_CCMP:
+ cipher = WLAN_CIPHER_SUITE_CCMP;
+ break;
+ case IW_ENCODE_ALG_AES_CMAC:
+ cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (erq->flags & IW_ENCODE_DISABLED)
+ remove = true;
+
+ idx = erq->flags & IW_ENCODE_INDEX;
+ if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ if (idx < 4 || idx > 5) {
+ idx = wdev->wext.default_mgmt_key;
+ if (idx < 0)
+ return -EINVAL;
+ } else
+ idx--;
+ } else {
+ if (idx < 1 || idx > 4) {
+ idx = wdev->wext.default_key;
+ if (idx < 0)
+ return -EINVAL;
+ } else
+ idx--;
+ }
+
+ addr = ext->addr.sa_data;
+ if (is_broadcast_ether_addr(addr))
+ addr = NULL;
+
+ memset(&params, 0, sizeof(params));
+ params.key = ext->key;
+ params.key_len = ext->key_len;
+ params.cipher = cipher;
+
+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ params.seq = ext->rx_seq;
+ params.seq_len = 6;
+ }
+
+ return cfg80211_set_encryption(
+ rdev, dev, addr, remove,
+ ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
+ idx, &params);
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
+
+struct giwencode_cookie {
+ size_t buflen;
+ char *keybuf;
+};
+
+static void giwencode_get_key_cb(void *cookie, struct key_params *params)
+{
+ struct giwencode_cookie *data = cookie;
+
+ if (!params->key) {
+ data->buflen = 0;
+ return;
+ }
+
+ data->buflen = min_t(size_t, data->buflen, params->key_len);
+ memcpy(data->keybuf, params->key, data->buflen);
+}
+
+int cfg80211_wext_giwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ int idx, err;
+ struct giwencode_cookie data = {
+ .keybuf = keybuf,
+ .buflen = erq->length,
+ };
+
+ if (!rdev->ops->get_key)
+ return -EOPNOTSUPP;
+
+ idx = erq->flags & IW_ENCODE_INDEX;
+ if (idx == 0) {
+ idx = wdev->wext.default_key;
+ if (idx < 0)
+ idx = 0;
+ } else if (idx < 1 || idx > 4)
+ return -EINVAL;
+ else
+ idx--;
+
+ erq->flags = idx + 1;
+
+ err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data,
+ giwencode_get_key_cb);
+ if (!err) {
+ erq->length = data.buflen;
+ erq->flags |= IW_ENCODE_ENABLED;
+ return 0;
+ }
+
+ if (err == -ENOENT) {
+ erq->flags |= IW_ENCODE_DISABLED;
+ erq->length = 0;
+ return 0;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index cb6a5bb85d8..d3bbef70cc7 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -649,14 +649,26 @@ static int wireless_seq_show(struct seq_file *seq, void *v)
return 0;
}
+static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ rtnl_lock();
+ return dev_seq_start(seq, pos);
+}
+
+static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ dev_seq_stop(seq, v);
+ rtnl_unlock();
+}
+
static const struct seq_operations wireless_seq_ops = {
- .start = dev_seq_start,
+ .start = wireless_dev_seq_start,
.next = dev_seq_next,
- .stop = dev_seq_stop,
+ .stop = wireless_dev_seq_stop,
.show = wireless_seq_show,
};
-static int wireless_seq_open(struct inode *inode, struct file *file)
+static int seq_open_wireless(struct inode *inode, struct file *file)
{
return seq_open_net(inode, file, &wireless_seq_ops,
sizeof(struct seq_net_private));
@@ -664,7 +676,7 @@ static int wireless_seq_open(struct inode *inode, struct file *file)
static const struct file_operations wireless_seq_fops = {
.owner = THIS_MODULE,
- .open = wireless_seq_open,
+ .open = seq_open_wireless,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_net,