summaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-20 21:04:47 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-20 21:04:47 -0700
commit3b59bf081622b6446db77ad06c93fe23677bc533 (patch)
tree3f4bb5a27c90cc86994a1f6d3c53fbf9208003cb /net/wireless
parente45836fafe157df137a837093037f741ad8f4c90 (diff)
parentbbdb32cb5b73597386913d052165423b9d736145 (diff)
downloadop-kernel-dev-3b59bf081622b6446db77ad06c93fe23677bc533.zip
op-kernel-dev-3b59bf081622b6446db77ad06c93fe23677bc533.tar.gz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking merge from David Miller: "1) Move ixgbe driver over to purely page based buffering on receive. From Alexander Duyck. 2) Add receive packet steering support to e1000e, from Bruce Allan. 3) Convert TCP MD5 support over to RCU, from Eric Dumazet. 4) Reduce cpu usage in handling out-of-order TCP packets on modern systems, also from Eric Dumazet. 5) Support the IP{,V6}_UNICAST_IF socket options, making the wine folks happy, from Erich Hoover. 6) Support VLAN trunking from guests in hyperv driver, from Haiyang Zhang. 7) Support byte-queue-limtis in r8169, from Igor Maravic. 8) Outline code intended for IP_RECVTOS in IP_PKTOPTIONS existed but was never properly implemented, Jiri Benc fixed that. 9) 64-bit statistics support in r8169 and 8139too, from Junchang Wang. 10) Support kernel side dump filtering by ctmark in netfilter ctnetlink, from Pablo Neira Ayuso. 11) Support byte-queue-limits in gianfar driver, from Paul Gortmaker. 12) Add new peek socket options to assist with socket migration, from Pavel Emelyanov. 13) Add sch_plug packet scheduler whose queue is controlled by userland daemons using explicit freeze and release commands. From Shriram Rajagopalan. 14) Fix FCOE checksum offload handling on transmit, from Yi Zou." * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1846 commits) Fix pppol2tp getsockname() Remove printk from rds_sendmsg ipv6: fix incorrent ipv6 ipsec packet fragment cpsw: Hook up default ndo_change_mtu. net: qmi_wwan: fix build error due to cdc-wdm dependecy netdev: driver: ethernet: Add TI CPSW driver netdev: driver: ethernet: add cpsw address lookup engine support phy: add am79c874 PHY support mlx4_core: fix race on comm channel bonding: send igmp report for its master fs_enet: Add MPC5125 FEC support and PHY interface selection net: bpf_jit: fix BPF_S_LDX_B_MSH compilation net: update the usage of CHECKSUM_UNNECESSARY fcoe: use CHECKSUM_UNNECESSARY instead of CHECKSUM_PARTIAL on tx net: do not do gso for CHECKSUM_UNNECESSARY in netif_needs_gso ixgbe: Fix issues with SR-IOV loopback when flow control is disabled net/hyperv: Fix the code handling tx busy ixgbe: fix namespace issues when FCoE/DCB is not enabled rtlwifi: Remove unused ETH_ADDR_LEN defines igbvf: Use ETH_ALEN ... Fix up fairly trivial conflicts in drivers/isdn/gigaset/interface.c and drivers/net/usb/{Kconfig,qmi_wwan.c} as per David.
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.h14
-rw-r--r--net/wireless/mesh.c4
-rw-r--r--net/wireless/mlme.c333
-rw-r--r--net/wireless/nl80211.c397
-rw-r--r--net/wireless/nl80211.h3
-rw-r--r--net/wireless/reg.c19
-rw-r--r--net/wireless/scan.c19
-rw-r--r--net/wireless/sme.c41
-rw-r--r--net/wireless/util.c1
-rw-r--r--net/wireless/wext-sme.c3
10 files changed, 355 insertions, 479 deletions
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 43ad9c8..3ac2dd0 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -144,11 +144,6 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu
return container_of(pub, struct cfg80211_internal_bss, pub);
}
-static inline void cfg80211_ref_bss(struct cfg80211_internal_bss *bss)
-{
- kref_get(&bss->ref);
-}
-
static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss)
{
atomic_inc(&bss->hold);
@@ -325,15 +320,13 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
- const u8 *key, int key_len, int key_idx,
- bool local_state_change);
+ const u8 *key, int key_len, int key_idx);
int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct ieee80211_channel *chan,
enum nl80211_auth_type auth_type, const u8 *bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
- const u8 *key, int key_len, int key_idx,
- bool local_state_change);
+ const u8 *key, int key_len, int key_idx);
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
@@ -421,7 +414,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
size_t ie_len, u16 reason, bool from_ap);
void cfg80211_sme_scan_done(struct net_device *dev);
void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
-void cfg80211_sme_disassoc(struct net_device *dev, int idx);
+void cfg80211_sme_disassoc(struct net_device *dev,
+ struct cfg80211_internal_bss *bss);
void __cfg80211_scan_done(struct work_struct *wk);
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
void __cfg80211_sched_scan_results(struct work_struct *wk);
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 8c550df..ba21ab2 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -23,6 +23,8 @@
#define MESH_PERR_MIN_INT 100
#define MESH_DIAM_TRAVERSAL_TIME 50
+#define MESH_RSSI_THRESHOLD 0
+
/*
* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds
* before timing out. This way it will remain ACTIVE and no data frames
@@ -55,6 +57,8 @@ const struct mesh_config default_mesh_config = {
.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
.dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
.dot11MeshGateAnnouncementProtocol = false,
+ .dot11MeshForwarding = true,
+ .rssi_threshold = MESH_RSSI_THRESHOLD,
};
const struct mesh_setup default_mesh_setup = {
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 438dfc1..f5a7ac3 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -20,40 +20,18 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
- u8 *bssid = mgmt->bssid;
- int i;
- u16 status = le16_to_cpu(mgmt->u.auth.status_code);
- bool done = false;
wdev_lock(wdev);
- for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (wdev->authtry_bsses[i] &&
- memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
- ETH_ALEN) == 0) {
- if (status == WLAN_STATUS_SUCCESS) {
- wdev->auth_bsses[i] = wdev->authtry_bsses[i];
- } else {
- cfg80211_unhold_bss(wdev->authtry_bsses[i]);
- cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
- }
- wdev->authtry_bsses[i] = NULL;
- done = true;
- break;
- }
- }
-
- if (done) {
- nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
- cfg80211_sme_rx_auth(dev, buf, len);
- }
+ nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
+ cfg80211_sme_rx_auth(dev, buf, len);
wdev_unlock(wdev);
}
EXPORT_SYMBOL(cfg80211_send_rx_auth);
-void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
+void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
+ const u8 *buf, size_t len)
{
u16 status_code;
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -61,8 +39,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
u8 *ie = mgmt->u.assoc_resp.variable;
- int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
- struct cfg80211_internal_bss *bss = NULL;
+ int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
wdev_lock(wdev);
@@ -75,43 +52,20 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
* frame instead of reassoc.
*/
if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
- cfg80211_sme_failed_reassoc(wdev))
+ cfg80211_sme_failed_reassoc(wdev)) {
+ cfg80211_put_bss(bss);
goto out;
+ }
nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
- if (status_code == WLAN_STATUS_SUCCESS) {
- for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (!wdev->auth_bsses[i])
- continue;
- if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid,
- ETH_ALEN) == 0) {
- bss = wdev->auth_bsses[i];
- wdev->auth_bsses[i] = NULL;
- /* additional reference to drop hold */
- cfg80211_ref_bss(bss);
- break;
- }
- }
-
- /*
- * We might be coming here because the driver reported
- * a successful association at the same time as the
- * user requested a deauth. In that case, we will have
- * removed the BSS from the auth_bsses list due to the
- * deauth request when the assoc response makes it. If
- * the two code paths acquire the lock the other way
- * around, that's just the standard situation of a
- * deauth being requested while connected.
- */
- if (!bss)
- goto out;
- } else if (wdev->conn) {
+ if (status_code != WLAN_STATUS_SUCCESS && wdev->conn) {
cfg80211_sme_failed_assoc(wdev);
/*
* do not call connect_result() now because the
* sme will schedule work that does it later.
*/
+ cfg80211_put_bss(bss);
goto out;
}
@@ -124,17 +78,10 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
wdev->sme_state = CFG80211_SME_CONNECTING;
}
- /* this consumes one bss reference (unless bss is NULL) */
+ /* this consumes the bss reference */
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
status_code,
- status_code == WLAN_STATUS_SUCCESS,
- bss ? &bss->pub : NULL);
- /* drop hold now, and also reference acquired above */
- if (bss) {
- cfg80211_unhold_bss(bss);
- cfg80211_put_bss(&bss->pub);
- }
-
+ status_code == WLAN_STATUS_SUCCESS, bss);
out:
wdev_unlock(wdev);
}
@@ -148,8 +95,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
const u8 *bssid = mgmt->bssid;
- int i;
- bool found = false, was_current = false;
+ bool was_current = false;
ASSERT_WDEV_LOCK(wdev);
@@ -158,32 +104,9 @@ void __cfg80211_send_deauth(struct net_device *dev,
cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(&wdev->current_bss->pub);
wdev->current_bss = NULL;
- found = true;
was_current = true;
- } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (wdev->auth_bsses[i] &&
- memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
- cfg80211_unhold_bss(wdev->auth_bsses[i]);
- cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
- wdev->auth_bsses[i] = NULL;
- found = true;
- break;
- }
- if (wdev->authtry_bsses[i] &&
- memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
- ETH_ALEN) == 0 &&
- memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) == 0) {
- cfg80211_unhold_bss(wdev->authtry_bsses[i]);
- cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
- wdev->authtry_bsses[i] = NULL;
- found = true;
- break;
- }
}
- if (!found)
- return;
-
nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) {
@@ -220,10 +143,8 @@ void __cfg80211_send_disassoc(struct net_device *dev,
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
const u8 *bssid = mgmt->bssid;
- int i;
u16 reason_code;
bool from_ap;
- bool done = false;
ASSERT_WDEV_LOCK(wdev);
@@ -234,16 +155,10 @@ void __cfg80211_send_disassoc(struct net_device *dev,
if (wdev->current_bss &&
memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
- for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
- continue;
- wdev->auth_bsses[i] = wdev->current_bss;
- wdev->current_bss = NULL;
- done = true;
- cfg80211_sme_disassoc(dev, i);
- break;
- }
- WARN_ON(!done);
+ cfg80211_sme_disassoc(dev, wdev->current_bss);
+ cfg80211_unhold_bss(wdev->current_bss);
+ cfg80211_put_bss(&wdev->current_bss->pub);
+ wdev->current_bss = NULL;
} else
WARN_ON(1);
@@ -287,34 +202,6 @@ void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
}
EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
-static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
-{
- int i;
- bool done = false;
-
- ASSERT_WDEV_LOCK(wdev);
-
- for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
- if (wdev->authtry_bsses[i] &&
- memcmp(wdev->authtry_bsses[i]->pub.bssid,
- addr, ETH_ALEN) == 0) {
- cfg80211_unhold_bss(wdev->authtry_bsses[i]);
- cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
- wdev->authtry_bsses[i] = NULL;
- done = true;
- break;
- }
- }
-
- WARN_ON(!done);
-}
-
-void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr)
-{
- __cfg80211_auth_remove(dev->ieee80211_ptr, addr);
-}
-EXPORT_SYMBOL(__cfg80211_auth_canceled);
-
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -329,8 +216,6 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
WLAN_STATUS_UNSPECIFIED_FAILURE,
false, NULL);
- __cfg80211_auth_remove(wdev, addr);
-
wdev_unlock(wdev);
}
EXPORT_SYMBOL(cfg80211_send_auth_timeout);
@@ -340,8 +225,6 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- int i;
- bool done = false;
wdev_lock(wdev);
@@ -351,20 +234,6 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
WLAN_STATUS_UNSPECIFIED_FAILURE,
false, NULL);
- for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
- if (wdev->auth_bsses[i] &&
- memcmp(wdev->auth_bsses[i]->pub.bssid,
- addr, ETH_ALEN) == 0) {
- cfg80211_unhold_bss(wdev->auth_bsses[i]);
- cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
- wdev->auth_bsses[i] = NULL;
- done = true;
- break;
- }
- }
-
- WARN_ON(!done);
-
wdev_unlock(wdev);
}
EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
@@ -403,13 +272,11 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
- const u8 *key, int key_len, int key_idx,
- bool local_state_change)
+ const u8 *key, int key_len, int key_idx)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_auth_request req;
- struct cfg80211_internal_bss *bss;
- int i, err, slot = -1, nfree = 0;
+ int err;
ASSERT_WDEV_LOCK(wdev);
@@ -421,20 +288,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
return -EALREADY;
- for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (wdev->authtry_bsses[i] &&
- memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
- ETH_ALEN) == 0)
- return -EALREADY;
- if (wdev->auth_bsses[i] &&
- memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
- ETH_ALEN) == 0)
- return -EALREADY;
- }
-
memset(&req, 0, sizeof(req));
- req.local_state_change = local_state_change;
req.ie = ie;
req.ie_len = ie_len;
req.auth_type = auth_type;
@@ -446,39 +301,9 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
if (!req.bss)
return -ENOENT;
- bss = bss_from_pub(req.bss);
-
- for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
- slot = i;
- nfree++;
- }
- }
-
- /* we need one free slot for disassoc and one for this auth */
- if (nfree < 2) {
- err = -ENOSPC;
- goto out;
- }
-
- if (local_state_change)
- wdev->auth_bsses[slot] = bss;
- else
- wdev->authtry_bsses[slot] = bss;
- cfg80211_hold_bss(bss);
-
err = rdev->ops->auth(&rdev->wiphy, dev, &req);
- if (err) {
- if (local_state_change)
- wdev->auth_bsses[slot] = NULL;
- else
- wdev->authtry_bsses[slot] = NULL;
- cfg80211_unhold_bss(bss);
- }
- out:
- if (err)
- cfg80211_put_bss(req.bss);
+ cfg80211_put_bss(req.bss);
return err;
}
@@ -487,15 +312,14 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
enum nl80211_auth_type auth_type, const u8 *bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
- const u8 *key, int key_len, int key_idx,
- bool local_state_change)
+ const u8 *key, int key_len, int key_idx)
{
int err;
wdev_lock(dev->ieee80211_ptr);
err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
ssid, ssid_len, ie, ie_len,
- key, key_len, key_idx, local_state_change);
+ key, key_len, key_idx);
wdev_unlock(dev->ieee80211_ptr);
return err;
@@ -530,8 +354,7 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_assoc_request req;
- struct cfg80211_internal_bss *bss;
- int i, err, slot = -1;
+ int err;
bool was_connected = false;
ASSERT_WDEV_LOCK(wdev);
@@ -573,26 +396,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
return -ENOENT;
}
- bss = bss_from_pub(req.bss);
-
- for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (bss == wdev->auth_bsses[i]) {
- slot = i;
- break;
- }
- }
+ err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
- if (slot < 0) {
- err = -ENOTCONN;
- goto out;
+ if (err) {
+ if (was_connected)
+ wdev->sme_state = CFG80211_SME_CONNECTED;
+ cfg80211_put_bss(req.bss);
}
- err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
- out:
- if (err && was_connected)
- wdev->sme_state = CFG80211_SME_CONNECTED;
- /* still a reference in wdev->auth_bsses[slot] */
- cfg80211_put_bss(req.bss);
return err;
}
@@ -624,36 +435,27 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
bool local_state_change)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct cfg80211_deauth_request req;
- int i;
+ struct cfg80211_deauth_request req = {
+ .bssid = bssid,
+ .reason_code = reason,
+ .ie = ie,
+ .ie_len = ie_len,
+ };
ASSERT_WDEV_LOCK(wdev);
- memset(&req, 0, sizeof(req));
- req.reason_code = reason;
- req.local_state_change = local_state_change;
- req.ie = ie;
- req.ie_len = ie_len;
- if (wdev->current_bss &&
- memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
- req.bss = &wdev->current_bss->pub;
- } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (wdev->auth_bsses[i] &&
- memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
- req.bss = &wdev->auth_bsses[i]->pub;
- break;
- }
- if (wdev->authtry_bsses[i] &&
- memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
- req.bss = &wdev->authtry_bsses[i]->pub;
- break;
+ if (local_state_change) {
+ if (wdev->current_bss &&
+ memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
+ cfg80211_unhold_bss(wdev->current_bss);
+ cfg80211_put_bss(&wdev->current_bss->pub);
+ wdev->current_bss = NULL;
}
- }
- if (!req.bss)
- return -ENOTCONN;
+ return 0;
+ }
- return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+ return rdev->ops->deauth(&rdev->wiphy, dev, &req);
}
int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
@@ -698,7 +500,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
else
return -ENOTCONN;
- return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
+ return rdev->ops->disassoc(&rdev->wiphy, dev, &req);
}
int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
@@ -722,7 +524,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_deauth_request req;
- int i;
+ u8 bssid[ETH_ALEN];
ASSERT_WDEV_LOCK(wdev);
@@ -734,35 +536,17 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
req.ie = NULL;
req.ie_len = 0;
- if (wdev->current_bss) {
- req.bss = &wdev->current_bss->pub;
- rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
- if (wdev->current_bss) {
- cfg80211_unhold_bss(wdev->current_bss);
- cfg80211_put_bss(&wdev->current_bss->pub);
- wdev->current_bss = NULL;
- }
- }
+ if (!wdev->current_bss)
+ return;
- for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (wdev->auth_bsses[i]) {
- req.bss = &wdev->auth_bsses[i]->pub;
- rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
- if (wdev->auth_bsses[i]) {
- cfg80211_unhold_bss(wdev->auth_bsses[i]);
- cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
- wdev->auth_bsses[i] = NULL;
- }
- }
- if (wdev->authtry_bsses[i]) {
- req.bss = &wdev->authtry_bsses[i]->pub;
- rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
- if (wdev->authtry_bsses[i]) {
- cfg80211_unhold_bss(wdev->authtry_bsses[i]);
- cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
- wdev->authtry_bsses[i] = NULL;
- }
- }
+ memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
+ req.bssid = bssid;
+ rdev->ops->deauth(&rdev->wiphy, dev, &req);
+
+ if (wdev->current_bss) {
+ cfg80211_unhold_bss(wdev->current_bss);
+ cfg80211_put_bss(&wdev->current_bss->pub);
+ wdev->current_bss = NULL;
}
}
@@ -1030,8 +814,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
cookie);
}
-bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
- size_t len, gfp_t gfp)
+bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm,
+ const u8 *buf, size_t len, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
@@ -1070,7 +854,8 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
/* found match! */
/* Indicate the received Action frame to user space */
- if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq,
+ if (nl80211_send_mgmt(rdev, dev, reg->nlpid,
+ freq, sig_mbm,
buf, len, gfp))
continue;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index afeea32..4c1eb94 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -204,6 +204,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
.len = NL80211_HT_CAPABILITY_LEN
},
[NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
+ [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
+ [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
};
/* policy for the key attributes */
@@ -427,10 +429,9 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
if (tb[NL80211_KEY_DEFAULT_TYPES]) {
struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
- int err = nla_parse_nested(kdt,
- NUM_NL80211_KEY_DEFAULT_TYPES - 1,
- tb[NL80211_KEY_DEFAULT_TYPES],
- nl80211_key_default_policy);
+ err = nla_parse_nested(kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
+ tb[NL80211_KEY_DEFAULT_TYPES],
+ nl80211_key_default_policy);
if (err)
return err;
@@ -872,7 +873,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
CMD(add_virtual_intf, NEW_INTERFACE);
CMD(change_virtual_intf, SET_INTERFACE);
CMD(add_key, NEW_KEY);
- CMD(add_beacon, NEW_BEACON);
+ CMD(start_ap, START_AP);
CMD(add_station, NEW_STATION);
CMD(add_mpath, NEW_MPATH);
CMD(update_mesh_config, SET_MESH_CONFIG);
@@ -2076,15 +2077,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
return err;
}
-static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_parse_beacon(struct genl_info *info,
+ struct cfg80211_beacon_data *bcn)
{
- int (*call)(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *info);
- struct cfg80211_registered_device *rdev = info->user_ptr[0];
- struct net_device *dev = info->user_ptr[1];
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct beacon_parameters params;
- int haveinfo = 0, err;
+ bool haveinfo = false;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
@@ -2092,149 +2088,190 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
return -EINVAL;
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
- dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
- return -EOPNOTSUPP;
-
- memset(&params, 0, sizeof(params));
-
- switch (info->genlhdr->cmd) {
- case NL80211_CMD_NEW_BEACON:
- /* these are required for NEW_BEACON */
- if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
- !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
- !info->attrs[NL80211_ATTR_BEACON_HEAD])
- return -EINVAL;
-
- params.interval =
- nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- params.dtim_period =
- nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
-
- err = cfg80211_validate_beacon_int(rdev, params.interval);
- if (err)
- return err;
-
- /*
- * In theory, some of these attributes could be required for
- * NEW_BEACON, but since they were not used when the command was
- * originally added, keep them optional for old user space
- * programs to work with drivers that do not need the additional
- * information.
- */
- if (info->attrs[NL80211_ATTR_SSID]) {
- params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
- params.ssid_len =
- nla_len(info->attrs[NL80211_ATTR_SSID]);
- if (params.ssid_len == 0 ||
- params.ssid_len > IEEE80211_MAX_SSID_LEN)
- return -EINVAL;
- }
-
- if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
- params.hidden_ssid = nla_get_u32(
- info->attrs[NL80211_ATTR_HIDDEN_SSID]);
- if (params.hidden_ssid !=
- NL80211_HIDDEN_SSID_NOT_IN_USE &&
- params.hidden_ssid !=
- NL80211_HIDDEN_SSID_ZERO_LEN &&
- params.hidden_ssid !=
- NL80211_HIDDEN_SSID_ZERO_CONTENTS)
- return -EINVAL;
- }
-
- params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
-
- if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
- params.auth_type = nla_get_u32(
- info->attrs[NL80211_ATTR_AUTH_TYPE]);
- if (!nl80211_valid_auth_type(params.auth_type))
- return -EINVAL;
- } else
- params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
-
- err = nl80211_crypto_settings(rdev, info, &params.crypto,
- NL80211_MAX_NR_CIPHER_SUITES);
- if (err)
- return err;
-
- call = rdev->ops->add_beacon;
- break;
- case NL80211_CMD_SET_BEACON:
- call = rdev->ops->set_beacon;
- break;
- default:
- WARN_ON(1);
- return -EOPNOTSUPP;
- }
-
- if (!call)
- return -EOPNOTSUPP;
+ memset(bcn, 0, sizeof(*bcn));
if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
- params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
- params.head_len =
- nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
- haveinfo = 1;
+ bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+ bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+ if (!bcn->head_len)
+ return -EINVAL;
+ haveinfo = true;
}
if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
- params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
- params.tail_len =
+ bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+ bcn->tail_len =
nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
- haveinfo = 1;
+ haveinfo = true;
}
if (!haveinfo)
return -EINVAL;
if (info->attrs[NL80211_ATTR_IE]) {
- params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
- params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
+ bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
- params.proberesp_ies =
+ bcn->proberesp_ies =
nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
- params.proberesp_ies_len =
+ bcn->proberesp_ies_len =
nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
}
if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
- params.assocresp_ies =
+ bcn->assocresp_ies =
nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
- params.assocresp_ies_len =
+ bcn->assocresp_ies_len =
nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
}
if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
- params.probe_resp =
+ bcn->probe_resp =
nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
- params.probe_resp_len =
+ bcn->probe_resp_len =
nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
}
- err = call(&rdev->wiphy, dev, &params);
- if (!err && params.interval)
- wdev->beacon_interval = params.interval;
+ return 0;
+}
+
+static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_ap_settings params;
+ int err;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->start_ap)
+ return -EOPNOTSUPP;
+
+ if (wdev->beacon_interval)
+ return -EALREADY;
+
+ memset(&params, 0, sizeof(params));
+
+ /* these are required for START_AP */
+ if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+ !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+ !info->attrs[NL80211_ATTR_BEACON_HEAD])
+ return -EINVAL;
+
+ err = nl80211_parse_beacon(info, &params.beacon);
+ if (err)
+ return err;
+
+ params.beacon_interval =
+ nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+ params.dtim_period =
+ nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+
+ err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
+ if (err)
+ return err;
+
+ /*
+ * In theory, some of these attributes should be required here
+ * but since they were not used when the command was originally
+ * added, keep them optional for old user space programs to let
+ * them continue to work with drivers that do not need the
+ * additional information -- drivers must check!
+ */
+ if (info->attrs[NL80211_ATTR_SSID]) {
+ params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ params.ssid_len =
+ nla_len(info->attrs[NL80211_ATTR_SSID]);
+ if (params.ssid_len == 0 ||
+ params.ssid_len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
+ }
+
+ if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
+ params.hidden_ssid = nla_get_u32(
+ info->attrs[NL80211_ATTR_HIDDEN_SSID]);
+ if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
+ params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
+ params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
+ return -EINVAL;
+ }
+
+ params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+ if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+ params.auth_type = nla_get_u32(
+ info->attrs[NL80211_ATTR_AUTH_TYPE]);
+ if (!nl80211_valid_auth_type(params.auth_type))
+ return -EINVAL;
+ } else
+ params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+ err = nl80211_crypto_settings(rdev, info, &params.crypto,
+ NL80211_MAX_NR_CIPHER_SUITES);
+ if (err)
+ return err;
+
+ if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
+ if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
+ return -EOPNOTSUPP;
+ params.inactivity_timeout = nla_get_u16(
+ info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
+ }
+
+ err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
+ if (!err)
+ wdev->beacon_interval = params.beacon_interval;
return err;
}
-static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_beacon_data params;
int err;
- if (!rdev->ops->del_beacon)
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->change_beacon)
+ return -EOPNOTSUPP;
+
+ if (!wdev->beacon_interval)
+ return -EINVAL;
+
+ err = nl80211_parse_beacon(info, &params);
+ if (err)
+ return err;
+
+ return rdev->ops->change_beacon(&rdev->wiphy, dev, &params);
+}
+
+static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ if (!rdev->ops->stop_ap)
return -EOPNOTSUPP;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP;
- err = rdev->ops->del_beacon(&rdev->wiphy, dev);
+ if (!wdev->beacon_interval)
+ return -ENOENT;
+
+ err = rdev->ops->stop_ap(&rdev->wiphy, dev);
if (!err)
wdev->beacon_interval = 0;
return err;
@@ -2655,13 +2692,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
- /* disallow things sta doesn't support */
- if (params.plink_action)
- return -EINVAL;
- if (params.ht_capa)
- return -EINVAL;
- if (params.listen_interval >= 0)
- return -EINVAL;
/*
* Don't allow userspace to change the TDLS_PEER flag,
* but silently ignore attempts to change it since we
@@ -2669,7 +2699,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
* to change the flag.
*/
params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
-
+ /* fall through */
+ case NL80211_IFTYPE_ADHOC:
+ /* disallow things sta doesn't support */
+ if (params.plink_action)
+ return -EINVAL;
+ if (params.ht_capa)
+ return -EINVAL;
+ if (params.listen_interval >= 0)
+ return -EINVAL;
/* reject any changes other than AUTHORIZED */
if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
return -EINVAL;
@@ -3259,6 +3297,10 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
cur_params.dot11MeshHWMPRannInterval);
NLA_PUT_U8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
cur_params.dot11MeshGateAnnouncementProtocol);
+ NLA_PUT_U8(msg, NL80211_MESHCONF_FORWARDING,
+ cur_params.dot11MeshForwarding);
+ NLA_PUT_U32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
+ cur_params.rssi_threshold);
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -3290,6 +3332,8 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
[NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
[NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32},
};
static const struct nla_policy
@@ -3379,6 +3423,10 @@ do {\
dot11MeshGateAnnouncementProtocol, mask,
NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
nla_get_u8);
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding,
+ mask, NL80211_MESHCONF_FORWARDING, nla_get_u8);
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold,
+ mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32);
if (mask_out)
*mask_out = mask;
@@ -4079,7 +4127,6 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
struct cfg80211_bss *res = &intbss->pub;
void *hdr;
struct nlattr *bss;
- int i;
ASSERT_WDEV_LOCK(wdev);
@@ -4132,13 +4179,6 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
if (intbss == wdev->current_bss)
NLA_PUT_U32(msg, NL80211_BSS_STATUS,
NL80211_BSS_STATUS_ASSOCIATED);
- else for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (intbss != wdev->auth_bsses[i])
- continue;
- NLA_PUT_U32(msg, NL80211_BSS_STATUS,
- NL80211_BSS_STATUS_AUTHENTICATED);
- break;
- }
break;
case NL80211_IFTYPE_ADHOC:
if (intbss == wdev->current_bss)
@@ -4406,10 +4446,16 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
+ /*
+ * Since we no longer track auth state, ignore
+ * requests to only change local state.
+ */
+ if (local_state_change)
+ return 0;
+
return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
ssid, ssid_len, ie, ie_len,
- key.p.key, key.p.key_len, key.idx,
- local_state_change);
+ key.p.key, key.p.key_len, key.idx);
}
static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
@@ -4781,7 +4827,6 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
struct ieee80211_supported_band *sband =
wiphy->bands[ibss.channel->band];
- int err;
err = ieee80211_get_ratemask(sband, rates, n_rates,
&ibss.basic_rates);
@@ -4801,6 +4846,9 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
return PTR_ERR(connkeys);
}
+ ibss.control_port =
+ nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
+
err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
if (err)
kfree(connkeys);
@@ -5069,6 +5117,13 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
wiphy = &rdev->wiphy;
+ connect.bg_scan_period = -1;
+ if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
+ (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
+ connect.bg_scan_period =
+ nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
+ }
+
if (info->attrs[NL80211_ATTR_MAC])
connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
@@ -5390,9 +5445,39 @@ static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
return mask;
}
+static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
+ u8 *rates, u8 rates_len,
+ u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
+{
+ u8 i;
+
+ memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
+
+ for (i = 0; i < rates_len; i++) {
+ int ridx, rbit;
+
+ ridx = rates[i] / 8;
+ rbit = BIT(rates[i] % 8);
+
+ /* check validity */
+ if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
+ return false;
+
+ /* check availability */
+ if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
+ mcs[ridx] |= rbit;
+ else
+ return false;
+ }
+
+ return true;
+}
+
static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
[NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
.len = NL80211_MAX_SUPP_RATES },
+ [NL80211_TXRATE_MCS] = { .type = NLA_BINARY,
+ .len = NL80211_MAX_SUPP_HT_RATES },
};
static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
@@ -5418,12 +5503,20 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
sband = rdev->wiphy.bands[i];
mask.control[i].legacy =
sband ? (1 << sband->n_bitrates) - 1 : 0;
+ if (sband)
+ memcpy(mask.control[i].mcs,
+ sband->ht_cap.mcs.rx_mask,
+ sizeof(mask.control[i].mcs));
+ else
+ memset(mask.control[i].mcs, 0,
+ sizeof(mask.control[i].mcs));
}
/*
* The nested attribute uses enum nl80211_band as the index. This maps
* directly to the enum ieee80211_band values used in cfg80211.
*/
+ BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
{
enum ieee80211_band band = nla_type(tx_rates);
@@ -5439,7 +5532,28 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
sband,
nla_data(tb[NL80211_TXRATE_LEGACY]),
nla_len(tb[NL80211_TXRATE_LEGACY]));
- if (mask.control[band].legacy == 0)
+ }
+ if (tb[NL80211_TXRATE_MCS]) {
+ if (!ht_rateset_to_mask(
+ sband,
+ nla_data(tb[NL80211_TXRATE_MCS]),
+ nla_len(tb[NL80211_TXRATE_MCS]),
+ mask.control[band].mcs))
+ return -EINVAL;
+ }
+
+ if (mask.control[band].legacy == 0) {
+ /* don't allow empty legacy rates if HT
+ * is not even supported. */
+ if (!rdev->wiphy.bands[band]->ht_cap.ht_supported)
+ return -EINVAL;
+
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
+ if (mask.control[band].mcs[i])
+ break;
+
+ /* legacy and mcs rates may not be both empty */
+ if (i == IEEE80211_HT_MCS_MASK_LEN)
return -EINVAL;
}
}
@@ -6293,23 +6407,23 @@ static struct genl_ops nl80211_ops[] = {
.cmd = NL80211_CMD_SET_BEACON,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
- .doit = nl80211_addset_beacon,
+ .doit = nl80211_set_beacon,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
{
- .cmd = NL80211_CMD_NEW_BEACON,
+ .cmd = NL80211_CMD_START_AP,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
- .doit = nl80211_addset_beacon,
+ .doit = nl80211_start_ap,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
{
- .cmd = NL80211_CMD_DEL_BEACON,
+ .cmd = NL80211_CMD_STOP_AP,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
- .doit = nl80211_del_beacon,
+ .doit = nl80211_stop_ap,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
@@ -7580,7 +7694,8 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev,
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 nlpid,
- int freq, const u8 *buf, size_t len, gfp_t gfp)
+ int freq, int sig_dbm,
+ const u8 *buf, size_t len, gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
@@ -7598,6 +7713,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+ if (sig_dbm)
+ NLA_PUT_U32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm);
NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
genlmsg_end(msg, hdr);
@@ -7859,7 +7976,7 @@ EXPORT_SYMBOL(cfg80211_probe_status);
void cfg80211_report_obss_beacon(struct wiphy *wiphy,
const u8 *frame, size_t len,
- int freq, gfp_t gfp)
+ int freq, int sig_dbm, gfp_t gfp)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct sk_buff *msg;
@@ -7882,6 +7999,8 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
if (freq)
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+ if (sig_dbm)
+ NLA_PUT_U32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm);
NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame);
genlmsg_end(msg, hdr);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 12bf4d1..4ffe50d 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -92,7 +92,8 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
gfp_t gfp);
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, u32 nlpid, int freq,
+ struct net_device *netdev, u32 nlpid,
+ int freq, int sig_dbm,
const u8 *buf, size_t len, gfp_t gfp);
void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index f65feaa..e9a0ac8 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -882,23 +882,8 @@ static void handle_channel(struct wiphy *wiphy,
chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);
chan->max_antenna_gain = min(chan->orig_mag,
(int) MBI_TO_DBI(power_rule->max_antenna_gain));
- if (chan->orig_mpwr) {
- /*
- * Devices that have their own custom regulatory domain
- * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the
- * passed country IE power settings.
- */
- if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
- wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&
- wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
- chan->max_power =
- MBM_TO_DBM(power_rule->max_eirp);
- } else {
- chan->max_power = min(chan->orig_mpwr,
- (int) MBM_TO_DBM(power_rule->max_eirp));
- }
- } else
- chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
+ chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
+ chan->max_power = min(chan->max_power, chan->max_reg_power);
}
static void handle_band(struct wiphy *wiphy,
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 31119e3..70faadf 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -734,9 +734,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
struct cfg80211_bss*
cfg80211_inform_bss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
- const u8 *bssid,
- u64 timestamp, u16 capability, u16 beacon_interval,
- const u8 *ie, size_t ielen,
+ const u8 *bssid, u64 tsf, u16 capability,
+ u16 beacon_interval, const u8 *ie, size_t ielen,
s32 signal, gfp_t gfp)
{
struct cfg80211_internal_bss *res;
@@ -758,7 +757,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
memcpy(res->pub.bssid, bssid, ETH_ALEN);
res->pub.channel = channel;
res->pub.signal = signal;
- res->pub.tsf = timestamp;
+ res->pub.tsf = tsf;
res->pub.beacon_interval = beacon_interval;
res->pub.capability = capability;
/*
@@ -861,6 +860,18 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
}
EXPORT_SYMBOL(cfg80211_inform_bss_frame);
+void cfg80211_ref_bss(struct cfg80211_bss *pub)
+{
+ struct cfg80211_internal_bss *bss;
+
+ if (!pub)
+ return;
+
+ bss = container_of(pub, struct cfg80211_internal_bss, pub);
+ kref_get(&bss->ref);
+}
+EXPORT_SYMBOL(cfg80211_ref_bss);
+
void cfg80211_put_bss(struct cfg80211_bss *pub)
{
struct cfg80211_internal_bss *bss;
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 7b9ecae..f7e937f 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -179,7 +179,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
params->ssid, params->ssid_len,
NULL, 0,
params->key, params->key_len,
- params->key_idx, false);
+ params->key_idx);
case CFG80211_CONN_ASSOCIATE_NEXT:
BUG_ON(!rdev->ops->assoc);
wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -477,6 +477,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
kfree(wdev->connect_keys);
wdev->connect_keys = NULL;
wdev->ssid_len = 0;
+ cfg80211_put_bss(bss);
return;
}
@@ -701,31 +702,10 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
wdev->ssid_len = 0;
if (wdev->conn) {
- const u8 *bssid;
- int ret;
-
kfree(wdev->conn->ie);
wdev->conn->ie = NULL;
kfree(wdev->conn);
wdev->conn = NULL;
-
- /*
- * If this disconnect was due to a disassoc, we
- * we might still have an auth BSS around. For
- * the userspace SME that's currently expected,
- * but for the kernel SME (nl80211 CONNECT or
- * wireless extensions) we want to clear up all
- * state.
- */
- for (i = 0; i < MAX_AUTH_BSSES; i++) {
- if (!wdev->auth_bsses[i])
- continue;
- bssid = wdev->auth_bsses[i]->pub.bssid;
- ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
- WLAN_REASON_DEAUTH_LEAVING,
- false);
- WARN(ret, "deauth failed: %d\n", ret);
- }
}
nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
@@ -1012,7 +992,8 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
return err;
}
-void cfg80211_sme_disassoc(struct net_device *dev, int idx)
+void cfg80211_sme_disassoc(struct net_device *dev,
+ struct cfg80211_internal_bss *bss)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -1031,16 +1012,8 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx)
* want it any more so deauthenticate too.
*/
- if (!wdev->auth_bsses[idx])
- return;
+ memcpy(bssid, bss->pub.bssid, ETH_ALEN);
- memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
- if (__cfg80211_mlme_deauth(rdev, dev, bssid,
- NULL, 0, WLAN_REASON_DEAUTH_LEAVING,
- false)) {
- /* whatever -- assume gone anyway */
- cfg80211_unhold_bss(wdev->auth_bsses[idx]);
- cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
- wdev->auth_bsses[idx] = NULL;
- }
+ __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
+ WLAN_REASON_DEAUTH_LEAVING, false);
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 9aa9db6..1b7a08df 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -904,6 +904,7 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate)
/* do NOT round down here */
return (bitrate + 50000) / 100000;
}
+EXPORT_SYMBOL(cfg80211_calculate_bitrate);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
u32 beacon_int)
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 326750b..7c01c2f 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -30,6 +30,9 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
wdev->wext.connect.ie = wdev->wext.ie;
wdev->wext.connect.ie_len = wdev->wext.ie_len;
+ /* Use default background scan period */
+ wdev->wext.connect.bg_scan_period = -1;
+
if (wdev->wext.keys) {
wdev->wext.keys->def = wdev->wext.default_key;
wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
OpenPOWER on IntegriCloud