nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
/*
|
|
|
|
* cfg80211 MLME SAP interface
|
|
|
|
*
|
|
|
|
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/nl80211.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 15:04:11 +07:00
|
|
|
#include <linux/slab.h>
|
2009-07-27 17:01:53 +07:00
|
|
|
#include <linux/wireless.h>
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
#include <net/cfg80211.h>
|
2009-07-27 17:01:53 +07:00
|
|
|
#include <net/iw_handler.h>
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
#include "core.h"
|
|
|
|
#include "nl80211.h"
|
|
|
|
|
2009-07-07 08:56:07 +07:00
|
|
|
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
{
|
2009-07-02 22:20:43 +07:00
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
2009-07-02 22:20:43 +07:00
|
|
|
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;
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
wdev_lock(wdev);
|
2009-07-07 08:56:07 +07:00
|
|
|
|
2009-07-02 22:20:43 +07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-12 19:46:43 +07:00
|
|
|
if (done) {
|
|
|
|
nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
|
|
|
|
cfg80211_sme_rx_auth(dev, buf, len);
|
|
|
|
}
|
2009-07-07 08:56:11 +07:00
|
|
|
|
|
|
|
wdev_unlock(wdev);
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_send_rx_auth);
|
|
|
|
|
2009-07-07 08:56:07 +07:00
|
|
|
void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
{
|
2009-07-02 14:13:27 +07:00
|
|
|
u16 status_code;
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
2009-07-02 14:13:27 +07:00
|
|
|
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
|
|
|
|
u8 *ie = mgmt->u.assoc_resp.variable;
|
2009-07-02 22:20:43 +07:00
|
|
|
int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
|
2009-07-29 16:23:49 +07:00
|
|
|
struct cfg80211_internal_bss *bss = NULL;
|
2009-07-02 14:13:27 +07:00
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
wdev_lock(wdev);
|
2009-07-07 08:56:07 +07:00
|
|
|
|
2009-07-02 14:13:27 +07:00
|
|
|
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
|
|
|
|
2009-08-07 19:51:05 +07:00
|
|
|
/*
|
|
|
|
* This is a bit of a hack, we don't notify userspace of
|
|
|
|
* a (re-)association reply if we tried to send a reassoc
|
|
|
|
* and got a reject -- we only try again with an assoc
|
|
|
|
* frame instead of reassoc.
|
|
|
|
*/
|
|
|
|
if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
|
|
|
|
cfg80211_sme_failed_reassoc(wdev))
|
|
|
|
goto out;
|
|
|
|
|
2009-07-07 08:56:07 +07:00
|
|
|
nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
|
2009-07-02 14:13:27 +07:00
|
|
|
|
2009-07-02 22:20:43 +07:00
|
|
|
if (status_code == WLAN_STATUS_SUCCESS) {
|
2009-07-29 16:23:49 +07:00
|
|
|
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];
|
2009-07-02 22:20:43 +07:00
|
|
|
wdev->auth_bsses[i] = NULL;
|
2009-07-29 16:23:49 +07:00
|
|
|
/* additional reference to drop hold */
|
|
|
|
cfg80211_ref_bss(bss);
|
2009-07-02 22:20:43 +07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
cfg80211: fix race between deauth and assoc response
Joseph Nahmias reported, in http://bugs.debian.org/562016,
that he was getting the following warning (with some log
around the issue):
ath0: direct probe to AP 00:11:95:77:e0:b0 (try 1)
ath0: direct probe responded
ath0: authenticate with AP 00:11:95:77:e0:b0 (try 1)
ath0: authenticated
ath0: associate with AP 00:11:95:77:e0:b0 (try 1)
ath0: deauthenticating from 00:11:95:77:e0:b0 by local choice (reason=3)
ath0: direct probe to AP 00:11:95:77:e0:b0 (try 1)
ath0: RX AssocResp from 00:11:95:77:e0:b0 (capab=0x421 status=0 aid=2)
ath0: associated
------------[ cut here ]------------
WARNING: at net/wireless/mlme.c:97 cfg80211_send_rx_assoc+0x14d/0x152 [cfg80211]()
Hardware name: 7658CTO
...
Pid: 761, comm: phy0 Not tainted 2.6.32-trunk-686 #1
Call Trace:
[<c1030a5d>] ? warn_slowpath_common+0x5e/0x8a
[<c1030a93>] ? warn_slowpath_null+0xa/0xc
[<f86cafc7>] ? cfg80211_send_rx_assoc+0x14d/0x152
...
ath0: link becomes ready
ath0: deauthenticating from 00:11:95:77:e0:b0 by local choice (reason=3)
ath0: no IPv6 routers present
ath0: link is not ready
ath0: direct probe to AP 00:11:95:77:e0:b0 (try 1)
ath0: direct probe responded
ath0: authenticate with AP 00:11:95:77:e0:b0 (try 1)
ath0: authenticated
ath0: associate with AP 00:11:95:77:e0:b0 (try 1)
ath0: RX ReassocResp from 00:11:95:77:e0:b0 (capab=0x421 status=0 aid=2)
ath0: associated
It is not clear to me how the first "direct probe" here
happens, but this seems to be a race condition, if the
user requests to deauth after requesting assoc, but before
the assoc response is received. In that case, it may
happen that mac80211 tries to report the assoc success to
cfg80211, but gets blocked on the wdev lock that is held
because the user is requesting the deauth.
The result is that we run into a warning. This is mostly
harmless, but maybe cause an unexpected event to be sent
to userspace; we'd send an assoc success event although
userspace was no longer expecting that.
To fix this, remove the warning and check whether the
race happened and in that case abort processing.
Reported-by: Joseph Nahmias <joe@nahmias.net>
Cc: stable@kernel.org
Cc: 562016-quiet@bugs.debian.org
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-12-23 19:12:05 +07:00
|
|
|
/*
|
|
|
|
* 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;
|
2009-10-20 13:08:53 +07:00
|
|
|
} else if (wdev->conn) {
|
|
|
|
cfg80211_sme_failed_assoc(wdev);
|
|
|
|
/*
|
|
|
|
* do not call connect_result() now because the
|
|
|
|
* sme will schedule work that does it later.
|
|
|
|
*/
|
|
|
|
goto out;
|
2009-07-29 16:23:49 +07:00
|
|
|
}
|
|
|
|
|
2009-08-17 17:22:14 +07:00
|
|
|
if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
|
|
|
|
/*
|
|
|
|
* This is for the userspace SME, the CONNECTING
|
|
|
|
* state will be changed to CONNECTED by
|
|
|
|
* __cfg80211_connect_result() below.
|
|
|
|
*/
|
|
|
|
wdev->sme_state = CFG80211_SME_CONNECTING;
|
|
|
|
}
|
|
|
|
|
2009-07-29 16:23:49 +07:00
|
|
|
/* this consumes one bss reference (unless bss is NULL) */
|
|
|
|
__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);
|
2009-07-02 22:20:43 +07:00
|
|
|
}
|
2009-07-07 08:56:11 +07:00
|
|
|
|
2009-08-07 19:51:05 +07:00
|
|
|
out:
|
2009-07-07 08:56:11 +07:00
|
|
|
wdev_unlock(wdev);
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_send_rx_assoc);
|
|
|
|
|
2009-10-13 18:28:13 +07:00
|
|
|
void __cfg80211_send_deauth(struct net_device *dev,
|
2009-07-07 08:56:11 +07:00
|
|
|
const u8 *buf, size_t len)
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
{
|
2009-07-02 14:13:27 +07:00
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
2009-07-02 14:13:27 +07:00
|
|
|
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
|
2009-07-02 22:20:43 +07:00
|
|
|
const u8 *bssid = mgmt->bssid;
|
|
|
|
int i;
|
2010-08-05 15:20:27 +07:00
|
|
|
bool found = false, was_current = false;
|
2009-07-02 14:13:27 +07:00
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
ASSERT_WDEV_LOCK(wdev);
|
2009-07-07 08:56:07 +07:00
|
|
|
|
2009-07-02 22:20:43 +07:00
|
|
|
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;
|
2009-12-02 18:43:42 +07:00
|
|
|
found = true;
|
2010-08-05 15:20:27 +07:00
|
|
|
was_current = true;
|
2009-07-02 22:20:43 +07:00
|
|
|
} 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;
|
2009-12-02 18:43:42 +07:00
|
|
|
found = true;
|
2009-07-02 22:20:43 +07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (wdev->authtry_bsses[i] &&
|
2011-06-08 19:52:52 +07:00
|
|
|
memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
|
|
|
|
ETH_ALEN) == 0 &&
|
|
|
|
memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) == 0) {
|
2009-07-02 22:20:43 +07:00
|
|
|
cfg80211_unhold_bss(wdev->authtry_bsses[i]);
|
|
|
|
cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
|
|
|
|
wdev->authtry_bsses[i] = NULL;
|
2009-12-02 18:43:42 +07:00
|
|
|
found = true;
|
2009-07-02 22:20:43 +07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-02 18:43:42 +07:00
|
|
|
if (!found)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
|
|
|
|
|
2010-08-05 15:20:27 +07:00
|
|
|
if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) {
|
2009-07-02 14:13:27 +07:00
|
|
|
u16 reason_code;
|
|
|
|
bool from_ap;
|
|
|
|
|
|
|
|
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
|
|
|
|
|
2009-08-07 01:41:33 +07:00
|
|
|
from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
|
2009-07-07 08:56:11 +07:00
|
|
|
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
|
2009-07-02 14:13:27 +07:00
|
|
|
} else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
|
2009-07-07 08:56:11 +07:00
|
|
|
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
|
|
|
|
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
2009-07-29 16:23:49 +07:00
|
|
|
false, NULL);
|
2009-07-07 08:56:11 +07:00
|
|
|
}
|
|
|
|
}
|
2009-10-13 18:28:13 +07:00
|
|
|
EXPORT_SYMBOL(__cfg80211_send_deauth);
|
2009-07-07 08:56:11 +07:00
|
|
|
|
2009-10-13 18:28:13 +07:00
|
|
|
void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
|
2009-07-07 08:56:11 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
|
2009-10-13 18:28:13 +07:00
|
|
|
wdev_lock(wdev);
|
|
|
|
__cfg80211_send_deauth(dev, buf, len);
|
|
|
|
wdev_unlock(wdev);
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
}
|
2009-03-28 01:53:56 +07:00
|
|
|
EXPORT_SYMBOL(cfg80211_send_deauth);
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
|
2009-10-13 18:28:13 +07:00
|
|
|
void __cfg80211_send_disassoc(struct net_device *dev,
|
2009-07-07 08:56:11 +07:00
|
|
|
const u8 *buf, size_t len)
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
{
|
2009-07-02 14:13:27 +07:00
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
nl80211: Event notifications for MLME events
Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.
This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-03-19 18:39:21 +07:00
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
2009-07-02 14:13:27 +07:00
|
|
|
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
|
2009-07-02 22:20:43 +07:00
|
|
|
const u8 *bssid = mgmt->bssid;
|
|
|
|
int i;
|
|
|
|
u16 reason_code;
|
|
|
|
bool from_ap;
|
|
|
|
bool done = false;
|
2009-07-02 14:13:27 +07:00
|
|
|
|
2009-07-11 05:17:32 +07:00
|
|
|
ASSERT_WDEV_LOCK(wdev);
|
2009-07-07 08:56:07 +07:00
|
|
|
|
|
|
|
nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
|
2009-03-28 02:59:49 +07:00
|
|
|
|
2009-07-11 05:17:32 +07:00
|
|
|
if (wdev->sme_state != CFG80211_SME_CONNECTED)
|
|
|
|
return;
|
2009-07-02 14:13:27 +07:00
|
|
|
|
2009-07-02 22:20:43 +07:00
|
|
|
if (wdev->current_bss &&
|
2009-08-06 15:52:42 +07:00
|
|
|
memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
|
2009-07-02 22:20:43 +07:00
|
|
|
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);
|
|
|
|
} else
|
|
|
|
WARN_ON(1);
|
2009-07-02 14:13:27 +07:00
|
|
|
|
|
|
|
|
2009-07-02 22:20:43 +07:00
|
|
|
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
|
|
|
|
|
2009-08-07 01:41:33 +07:00
|
|
|
from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
|
2009-07-07 08:56:11 +07:00
|
|
|
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
|
|
|
|
}
|
2009-10-13 18:28:13 +07:00
|
|
|
EXPORT_SYMBOL(__cfg80211_send_disassoc);
|
2009-07-07 08:56:11 +07:00
|
|
|
|
2009-10-13 18:28:13 +07:00
|
|
|
void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
|
2009-07-07 08:56:11 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
|
2009-10-13 18:28:13 +07:00
|
|
|
wdev_lock(wdev);
|
|
|
|
__cfg80211_send_disassoc(dev, buf, len);
|
|
|
|
wdev_unlock(wdev);
|
2009-04-23 01:38:25 +07:00
|
|
|
}
|
2009-07-02 14:13:27 +07:00
|
|
|
EXPORT_SYMBOL(cfg80211_send_disassoc);
|
2009-04-23 01:38:25 +07:00
|
|
|
|
2010-12-16 05:52:40 +07:00
|
|
|
void cfg80211_send_unprot_deauth(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);
|
|
|
|
|
|
|
|
nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
|
|
|
|
|
|
|
|
void cfg80211_send_unprot_disassoc(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);
|
|
|
|
|
|
|
|
nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
|
|
|
|
|
2009-11-19 18:45:42 +07:00
|
|
|
static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
|
2009-04-23 01:38:25 +07:00
|
|
|
{
|
2009-07-02 22:20:43 +07:00
|
|
|
int i;
|
|
|
|
bool done = false;
|
|
|
|
|
2009-11-19 18:45:42 +07:00
|
|
|
ASSERT_WDEV_LOCK(wdev);
|
2009-07-02 22:20:43 +07:00
|
|
|
|
|
|
|
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);
|
2009-11-19 18:45:42 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
|
|
|
|
|
wdev_lock(wdev);
|
|
|
|
|
|
|
|
nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
|
|
|
|
if (wdev->sme_state == CFG80211_SME_CONNECTING)
|
|
|
|
__cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
|
|
|
|
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
|
|
|
false, NULL);
|
|
|
|
|
|
|
|
__cfg80211_auth_remove(wdev, addr);
|
2009-07-07 08:56:11 +07:00
|
|
|
|
|
|
|
wdev_unlock(wdev);
|
2009-04-23 01:38:25 +07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_send_auth_timeout);
|
|
|
|
|
2009-07-07 08:56:07 +07:00
|
|
|
void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
|
2009-04-23 01:38:25 +07:00
|
|
|
{
|
2009-07-02 14:13:27 +07:00
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
2009-04-23 01:38:25 +07:00
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
2009-07-02 22:20:43 +07:00
|
|
|
int i;
|
|
|
|
bool done = false;
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
wdev_lock(wdev);
|
2009-07-07 08:56:07 +07:00
|
|
|
|
|
|
|
nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
|
2009-07-02 14:13:27 +07:00
|
|
|
if (wdev->sme_state == CFG80211_SME_CONNECTING)
|
2009-07-07 08:56:11 +07:00
|
|
|
__cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
|
|
|
|
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
2009-07-29 16:23:49 +07:00
|
|
|
false, NULL);
|
2009-07-02 22:20:43 +07:00
|
|
|
|
|
|
|
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);
|
2009-07-07 08:56:11 +07:00
|
|
|
|
|
|
|
wdev_unlock(wdev);
|
2009-04-23 01:38:25 +07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
|
|
|
|
|
2009-03-28 02:59:49 +07:00
|
|
|
void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
|
|
|
|
enum nl80211_key_type key_type, int key_id,
|
2009-07-02 02:26:47 +07:00
|
|
|
const u8 *tsc, gfp_t gfp)
|
2009-03-28 02:59:49 +07:00
|
|
|
{
|
|
|
|
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
2009-09-30 04:27:28 +07:00
|
|
|
#ifdef CONFIG_CFG80211_WEXT
|
2009-06-19 07:45:21 +07:00
|
|
|
union iwreq_data wrqu;
|
2009-07-02 02:26:47 +07:00
|
|
|
char *buf = kmalloc(128, gfp);
|
2009-06-19 07:45:21 +07:00
|
|
|
|
|
|
|
if (buf) {
|
|
|
|
sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
|
|
|
|
"keyid=%d %scast addr=%pM)", key_id,
|
|
|
|
key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
|
|
|
|
addr);
|
|
|
|
memset(&wrqu, 0, sizeof(wrqu));
|
|
|
|
wrqu.data.length = strlen(buf);
|
|
|
|
wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
|
|
|
|
kfree(buf);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-07-02 02:26:47 +07:00
|
|
|
nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
|
2009-03-28 02:59:49 +07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_michael_mic_failure);
|
2009-07-02 22:20:43 +07:00
|
|
|
|
|
|
|
/* some MLME handling for userspace SME */
|
2009-07-07 08:56:11 +07:00
|
|
|
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,
|
cfg80211: rework key operation
This reworks the key operation in cfg80211, and now only
allows, from userspace, configuring keys (via nl80211)
after the connection has been established (in managed
mode), the IBSS been joined (in IBSS mode), at any time
(in AP[_VLAN] modes) or never for all the other modes.
In order to do shared key authentication correctly, it
is now possible to give a WEP key to the AUTH command.
To configure static WEP keys, these are given to the
CONNECT or IBSS_JOIN command directly, for a userspace
SME it is assumed it will configure it properly after
the connection has been established.
Since mac80211 used to check the default key in IBSS
mode to see whether or not the network is protected,
it needs an update in that area, as well as an update
to make use of the WEP key passed to auth() for shared
key authentication.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-07-08 19:22:54 +07:00
|
|
|
const u8 *ie, int ie_len,
|
2010-04-04 13:37:19 +07:00
|
|
|
const u8 *key, int key_len, int key_idx,
|
|
|
|
bool local_state_change)
|
2009-07-02 22:20:43 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct cfg80211_auth_request req;
|
|
|
|
struct cfg80211_internal_bss *bss;
|
|
|
|
int i, err, slot = -1, nfree = 0;
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
ASSERT_WDEV_LOCK(wdev);
|
|
|
|
|
cfg80211: rework key operation
This reworks the key operation in cfg80211, and now only
allows, from userspace, configuring keys (via nl80211)
after the connection has been established (in managed
mode), the IBSS been joined (in IBSS mode), at any time
(in AP[_VLAN] modes) or never for all the other modes.
In order to do shared key authentication correctly, it
is now possible to give a WEP key to the AUTH command.
To configure static WEP keys, these are given to the
CONNECT or IBSS_JOIN command directly, for a userspace
SME it is assumed it will configure it properly after
the connection has been established.
Since mac80211 used to check the default key in IBSS
mode to see whether or not the network is protected,
it needs an update in that area, as well as an update
to make use of the WEP key passed to auth() for shared
key authentication.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-07-08 19:22:54 +07:00
|
|
|
if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
|
|
|
|
if (!key || !key_len || key_idx < 0 || key_idx > 4)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2009-07-02 23:26:18 +07:00
|
|
|
if (wdev->current_bss &&
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-07-02 22:20:43 +07:00
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
|
2010-04-04 13:37:19 +07:00
|
|
|
req.local_state_change = local_state_change;
|
2009-07-02 22:20:43 +07:00
|
|
|
req.ie = ie;
|
|
|
|
req.ie_len = ie_len;
|
|
|
|
req.auth_type = auth_type;
|
|
|
|
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
|
|
|
|
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
cfg80211: rework key operation
This reworks the key operation in cfg80211, and now only
allows, from userspace, configuring keys (via nl80211)
after the connection has been established (in managed
mode), the IBSS been joined (in IBSS mode), at any time
(in AP[_VLAN] modes) or never for all the other modes.
In order to do shared key authentication correctly, it
is now possible to give a WEP key to the AUTH command.
To configure static WEP keys, these are given to the
CONNECT or IBSS_JOIN command directly, for a userspace
SME it is assumed it will configure it properly after
the connection has been established.
Since mac80211 used to check the default key in IBSS
mode to see whether or not the network is protected,
it needs an update in that area, as well as an update
to make use of the WEP key passed to auth() for shared
key authentication.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-07-08 19:22:54 +07:00
|
|
|
req.key = key;
|
|
|
|
req.key_len = key_len;
|
|
|
|
req.key_idx = key_idx;
|
2009-07-02 22:20:43 +07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-04-04 13:37:19 +07:00
|
|
|
if (local_state_change)
|
|
|
|
wdev->auth_bsses[slot] = bss;
|
|
|
|
else
|
|
|
|
wdev->authtry_bsses[slot] = bss;
|
2009-07-02 22:20:43 +07:00
|
|
|
cfg80211_hold_bss(bss);
|
|
|
|
|
|
|
|
err = rdev->ops->auth(&rdev->wiphy, dev, &req);
|
|
|
|
if (err) {
|
2010-04-04 13:37:19 +07:00
|
|
|
if (local_state_change)
|
|
|
|
wdev->auth_bsses[slot] = NULL;
|
|
|
|
else
|
|
|
|
wdev->authtry_bsses[slot] = NULL;
|
2009-07-02 22:20:43 +07:00
|
|
|
cfg80211_unhold_bss(bss);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (err)
|
|
|
|
cfg80211_put_bss(req.bss);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
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,
|
cfg80211: rework key operation
This reworks the key operation in cfg80211, and now only
allows, from userspace, configuring keys (via nl80211)
after the connection has been established (in managed
mode), the IBSS been joined (in IBSS mode), at any time
(in AP[_VLAN] modes) or never for all the other modes.
In order to do shared key authentication correctly, it
is now possible to give a WEP key to the AUTH command.
To configure static WEP keys, these are given to the
CONNECT or IBSS_JOIN command directly, for a userspace
SME it is assumed it will configure it properly after
the connection has been established.
Since mac80211 used to check the default key in IBSS
mode to see whether or not the network is protected,
it needs an update in that area, as well as an update
to make use of the WEP key passed to auth() for shared
key authentication.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-07-08 19:22:54 +07:00
|
|
|
const u8 *ie, int ie_len,
|
2010-04-04 13:37:19 +07:00
|
|
|
const u8 *key, int key_len, int key_idx,
|
|
|
|
bool local_state_change)
|
2009-07-07 08:56:11 +07:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
wdev_lock(dev->ieee80211_ptr);
|
|
|
|
err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
|
cfg80211: rework key operation
This reworks the key operation in cfg80211, and now only
allows, from userspace, configuring keys (via nl80211)
after the connection has been established (in managed
mode), the IBSS been joined (in IBSS mode), at any time
(in AP[_VLAN] modes) or never for all the other modes.
In order to do shared key authentication correctly, it
is now possible to give a WEP key to the AUTH command.
To configure static WEP keys, these are given to the
CONNECT or IBSS_JOIN command directly, for a userspace
SME it is assumed it will configure it properly after
the connection has been established.
Since mac80211 used to check the default key in IBSS
mode to see whether or not the network is protected,
it needs an update in that area, as well as an update
to make use of the WEP key passed to auth() for shared
key authentication.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-07-08 19:22:54 +07:00
|
|
|
ssid, ssid_len, ie, ie_len,
|
2010-04-04 13:37:19 +07:00
|
|
|
key, key_len, key_idx, local_state_change);
|
2009-07-07 08:56:11 +07:00
|
|
|
wdev_unlock(dev->ieee80211_ptr);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
|
|
|
struct net_device *dev,
|
|
|
|
struct ieee80211_channel *chan,
|
|
|
|
const u8 *bssid, const u8 *prev_bssid,
|
|
|
|
const u8 *ssid, int ssid_len,
|
|
|
|
const u8 *ie, int ie_len, bool use_mfp,
|
|
|
|
struct cfg80211_crypto_settings *crypt)
|
2009-07-02 22:20:43 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct cfg80211_assoc_request req;
|
|
|
|
struct cfg80211_internal_bss *bss;
|
|
|
|
int i, err, slot = -1;
|
2009-11-18 02:35:38 +07:00
|
|
|
bool was_connected = false;
|
2009-07-02 22:20:43 +07:00
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
ASSERT_WDEV_LOCK(wdev);
|
|
|
|
|
2009-07-02 22:20:43 +07:00
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
|
2009-11-18 02:35:38 +07:00
|
|
|
if (wdev->current_bss && prev_bssid &&
|
|
|
|
memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) {
|
|
|
|
/*
|
|
|
|
* Trying to reassociate: Allow this to proceed and let the old
|
|
|
|
* association to be dropped when the new one is completed.
|
|
|
|
*/
|
|
|
|
if (wdev->sme_state == CFG80211_SME_CONNECTED) {
|
|
|
|
was_connected = true;
|
|
|
|
wdev->sme_state = CFG80211_SME_CONNECTING;
|
|
|
|
}
|
|
|
|
} else if (wdev->current_bss)
|
2009-07-02 22:20:43 +07:00
|
|
|
return -EALREADY;
|
|
|
|
|
|
|
|
req.ie = ie;
|
|
|
|
req.ie_len = ie_len;
|
|
|
|
memcpy(&req.crypto, crypt, sizeof(req.crypto));
|
|
|
|
req.use_mfp = use_mfp;
|
2009-07-07 19:37:26 +07:00
|
|
|
req.prev_bssid = prev_bssid;
|
2009-07-02 22:20:43 +07:00
|
|
|
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
|
|
|
|
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
2009-11-18 02:35:38 +07:00
|
|
|
if (!req.bss) {
|
|
|
|
if (was_connected)
|
|
|
|
wdev->sme_state = CFG80211_SME_CONNECTED;
|
2009-07-02 22:20:43 +07:00
|
|
|
return -ENOENT;
|
2009-11-18 02:35:38 +07:00
|
|
|
}
|
2009-07-02 22:20:43 +07:00
|
|
|
|
|
|
|
bss = bss_from_pub(req.bss);
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_AUTH_BSSES; i++) {
|
|
|
|
if (bss == wdev->auth_bsses[i]) {
|
|
|
|
slot = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slot < 0) {
|
|
|
|
err = -ENOTCONN;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
|
|
|
|
out:
|
2009-11-18 02:35:38 +07:00
|
|
|
if (err && was_connected)
|
|
|
|
wdev->sme_state = CFG80211_SME_CONNECTED;
|
2009-07-02 22:20:43 +07:00
|
|
|
/* still a reference in wdev->auth_bsses[slot] */
|
|
|
|
cfg80211_put_bss(req.bss);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
|
|
|
struct net_device *dev,
|
|
|
|
struct ieee80211_channel *chan,
|
|
|
|
const u8 *bssid, const u8 *prev_bssid,
|
|
|
|
const u8 *ssid, int ssid_len,
|
|
|
|
const u8 *ie, int ie_len, bool use_mfp,
|
|
|
|
struct cfg80211_crypto_settings *crypt)
|
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
wdev_lock(wdev);
|
|
|
|
err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
|
|
|
|
ssid, ssid_len, ie, ie_len, use_mfp, crypt);
|
|
|
|
wdev_unlock(wdev);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
|
|
|
|
struct net_device *dev, const u8 *bssid,
|
2010-04-04 13:37:19 +07:00
|
|
|
const u8 *ie, int ie_len, u16 reason,
|
|
|
|
bool local_state_change)
|
2009-07-02 22:20:43 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct cfg80211_deauth_request req;
|
|
|
|
int i;
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
ASSERT_WDEV_LOCK(wdev);
|
|
|
|
|
2009-07-02 22:20:43 +07:00
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
req.reason_code = reason;
|
2010-04-04 13:37:19 +07:00
|
|
|
req.local_state_change = local_state_change;
|
2009-07-02 22:20:43 +07:00
|
|
|
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 (!req.bss)
|
|
|
|
return -ENOTCONN;
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
|
2009-07-02 22:20:43 +07:00
|
|
|
}
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
|
|
|
|
struct net_device *dev, const u8 *bssid,
|
2010-04-04 13:37:19 +07:00
|
|
|
const u8 *ie, int ie_len, u16 reason,
|
|
|
|
bool local_state_change)
|
2009-07-07 08:56:11 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
wdev_lock(wdev);
|
2010-04-04 13:37:19 +07:00
|
|
|
err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason,
|
|
|
|
local_state_change);
|
2009-07-07 08:56:11 +07:00
|
|
|
wdev_unlock(wdev);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
|
|
|
|
struct net_device *dev, const u8 *bssid,
|
2010-04-04 13:37:19 +07:00
|
|
|
const u8 *ie, int ie_len, u16 reason,
|
|
|
|
bool local_state_change)
|
2009-07-02 22:20:43 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct cfg80211_disassoc_request req;
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
ASSERT_WDEV_LOCK(wdev);
|
|
|
|
|
2009-07-27 15:22:28 +07:00
|
|
|
if (wdev->sme_state != CFG80211_SME_CONNECTED)
|
|
|
|
return -ENOTCONN;
|
|
|
|
|
|
|
|
if (WARN_ON(!wdev->current_bss))
|
|
|
|
return -ENOTCONN;
|
|
|
|
|
2009-07-02 22:20:43 +07:00
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
req.reason_code = reason;
|
2010-04-04 13:37:19 +07:00
|
|
|
req.local_state_change = local_state_change;
|
2009-07-02 22:20:43 +07:00
|
|
|
req.ie = ie;
|
|
|
|
req.ie_len = ie_len;
|
|
|
|
if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
|
|
|
|
req.bss = &wdev->current_bss->pub;
|
|
|
|
else
|
|
|
|
return -ENOTCONN;
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
|
|
|
|
struct net_device *dev, const u8 *bssid,
|
2010-04-04 13:37:19 +07:00
|
|
|
const u8 *ie, int ie_len, u16 reason,
|
|
|
|
bool local_state_change)
|
2009-07-07 08:56:11 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
wdev_lock(wdev);
|
2010-04-04 13:37:19 +07:00
|
|
|
err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason,
|
|
|
|
local_state_change);
|
2009-07-07 08:56:11 +07:00
|
|
|
wdev_unlock(wdev);
|
|
|
|
|
|
|
|
return err;
|
2009-07-02 22:20:43 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
|
|
|
|
struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct cfg80211_deauth_request req;
|
|
|
|
int i;
|
|
|
|
|
2009-07-07 08:56:11 +07:00
|
|
|
ASSERT_WDEV_LOCK(wdev);
|
|
|
|
|
2009-07-02 22:20:43 +07:00
|
|
|
if (!rdev->ops->deauth)
|
|
|
|
return;
|
|
|
|
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
|
|
|
|
req.ie = NULL;
|
|
|
|
req.ie_len = 0;
|
|
|
|
|
|
|
|
if (wdev->current_bss) {
|
|
|
|
req.bss = &wdev->current_bss->pub;
|
2009-07-07 08:56:11 +07:00
|
|
|
rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
|
2009-07-02 22:20:43 +07:00
|
|
|
if (wdev->current_bss) {
|
|
|
|
cfg80211_unhold_bss(wdev->current_bss);
|
|
|
|
cfg80211_put_bss(&wdev->current_bss->pub);
|
|
|
|
wdev->current_bss = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_AUTH_BSSES; i++) {
|
|
|
|
if (wdev->auth_bsses[i]) {
|
|
|
|
req.bss = &wdev->auth_bsses[i]->pub;
|
2009-07-07 08:56:11 +07:00
|
|
|
rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
|
2009-07-02 22:20:43 +07:00
|
|
|
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;
|
2009-07-07 08:56:11 +07:00
|
|
|
rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
|
2009-07-02 22:20:43 +07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-12-23 19:15:41 +07:00
|
|
|
|
|
|
|
void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
|
|
|
|
struct ieee80211_channel *chan,
|
|
|
|
enum nl80211_channel_type channel_type,
|
|
|
|
unsigned int duration, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
|
|
|
|
|
nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
|
|
|
|
duration, gfp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_ready_on_channel);
|
|
|
|
|
|
|
|
void cfg80211_remain_on_channel_expired(struct net_device *dev,
|
|
|
|
u64 cookie,
|
|
|
|
struct ieee80211_channel *chan,
|
|
|
|
enum nl80211_channel_type channel_type,
|
|
|
|
gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
|
|
|
|
|
nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan,
|
|
|
|
channel_type, gfp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
|
2009-12-23 19:15:44 +07:00
|
|
|
|
|
|
|
void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
|
|
|
|
struct station_info *sinfo, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
|
|
|
|
|
nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_new_sta);
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2011-03-23 20:29:52 +07:00
|
|
|
void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
|
|
|
|
|
nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_del_sta);
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
struct cfg80211_mgmt_registration {
|
2010-02-15 17:53:10 +07:00
|
|
|
struct list_head list;
|
|
|
|
|
|
|
|
u32 nlpid;
|
|
|
|
|
|
|
|
int match_len;
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
__le16 frame_type;
|
|
|
|
|
2010-02-15 17:53:10 +07:00
|
|
|
u8 match[];
|
|
|
|
};
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
|
|
|
|
u16 frame_type, const u8 *match_data,
|
|
|
|
int match_len)
|
2010-02-15 17:53:10 +07:00
|
|
|
{
|
2010-10-13 17:06:23 +07:00
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
2010-08-12 20:38:38 +07:00
|
|
|
struct cfg80211_mgmt_registration *reg, *nreg;
|
2010-02-15 17:53:10 +07:00
|
|
|
int err = 0;
|
2010-08-12 20:38:38 +07:00
|
|
|
u16 mgmt_type;
|
|
|
|
|
|
|
|
if (!wdev->wiphy->mgmt_stypes)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
|
|
|
|
if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type)))
|
|
|
|
return -EINVAL;
|
2010-02-15 17:53:10 +07:00
|
|
|
|
|
|
|
nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
|
|
|
|
if (!nreg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
spin_lock_bh(&wdev->mgmt_registrations_lock);
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
|
2010-02-15 17:53:10 +07:00
|
|
|
int mlen = min(match_len, reg->match_len);
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
if (frame_type != le16_to_cpu(reg->frame_type))
|
|
|
|
continue;
|
|
|
|
|
2010-02-15 17:53:10 +07:00
|
|
|
if (memcmp(reg->match, match_data, mlen) == 0) {
|
|
|
|
err = -EALREADY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
kfree(nreg);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(nreg->match, match_data, match_len);
|
|
|
|
nreg->match_len = match_len;
|
|
|
|
nreg->nlpid = snd_pid;
|
2010-08-12 20:38:38 +07:00
|
|
|
nreg->frame_type = cpu_to_le16(frame_type);
|
|
|
|
list_add(&nreg->list, &wdev->mgmt_registrations);
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-10-13 17:06:23 +07:00
|
|
|
if (rdev->ops->mgmt_frame_register)
|
|
|
|
rdev->ops->mgmt_frame_register(wiphy, wdev->netdev,
|
|
|
|
frame_type, true);
|
|
|
|
|
2010-02-15 17:53:10 +07:00
|
|
|
out:
|
2010-08-12 20:38:38 +07:00
|
|
|
spin_unlock_bh(&wdev->mgmt_registrations_lock);
|
2010-10-13 17:06:23 +07:00
|
|
|
|
2010-02-15 17:53:10 +07:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid)
|
2010-02-15 17:53:10 +07:00
|
|
|
{
|
2010-10-13 17:06:23 +07:00
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
2010-08-12 20:38:38 +07:00
|
|
|
struct cfg80211_mgmt_registration *reg, *tmp;
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
spin_lock_bh(&wdev->mgmt_registrations_lock);
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
|
2010-10-13 17:06:23 +07:00
|
|
|
if (reg->nlpid != nlpid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (rdev->ops->mgmt_frame_register) {
|
|
|
|
u16 frame_type = le16_to_cpu(reg->frame_type);
|
|
|
|
|
|
|
|
rdev->ops->mgmt_frame_register(wiphy, wdev->netdev,
|
|
|
|
frame_type, false);
|
2010-02-15 17:53:10 +07:00
|
|
|
}
|
2010-10-13 17:06:23 +07:00
|
|
|
|
|
|
|
list_del(®->list);
|
|
|
|
kfree(reg);
|
2010-02-15 17:53:10 +07:00
|
|
|
}
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
spin_unlock_bh(&wdev->mgmt_registrations_lock);
|
2011-11-04 17:18:12 +07:00
|
|
|
|
|
|
|
if (nlpid == wdev->ap_unexpected_nlpid)
|
|
|
|
wdev->ap_unexpected_nlpid = 0;
|
2010-02-15 17:53:10 +07:00
|
|
|
}
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
|
2010-02-15 17:53:10 +07:00
|
|
|
{
|
2010-08-12 20:38:38 +07:00
|
|
|
struct cfg80211_mgmt_registration *reg, *tmp;
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
spin_lock_bh(&wdev->mgmt_registrations_lock);
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
|
2010-02-15 17:53:10 +07:00
|
|
|
list_del(®->list);
|
|
|
|
kfree(reg);
|
|
|
|
}
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
spin_unlock_bh(&wdev->mgmt_registrations_lock);
|
2010-02-15 17:53:10 +07:00
|
|
|
}
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
|
|
|
|
struct net_device *dev,
|
2010-11-25 16:02:29 +07:00
|
|
|
struct ieee80211_channel *chan, bool offchan,
|
2010-08-12 20:38:38 +07:00
|
|
|
enum nl80211_channel_type channel_type,
|
2010-11-25 16:02:29 +07:00
|
|
|
bool channel_type_valid, unsigned int wait,
|
2011-09-25 16:23:30 +07:00
|
|
|
const u8 *buf, size_t len, bool no_cck,
|
|
|
|
u64 *cookie)
|
2010-02-15 17:53:10 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
const struct ieee80211_mgmt *mgmt;
|
2010-08-12 20:38:38 +07:00
|
|
|
u16 stype;
|
|
|
|
|
|
|
|
if (!wdev->wiphy->mgmt_stypes)
|
|
|
|
return -EOPNOTSUPP;
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
if (!rdev->ops->mgmt_tx)
|
2010-02-15 17:53:10 +07:00
|
|
|
return -EOPNOTSUPP;
|
2010-08-12 20:38:38 +07:00
|
|
|
|
2010-02-15 17:53:10 +07:00
|
|
|
if (len < 24 + 1)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
mgmt = (const struct ieee80211_mgmt *) buf;
|
2010-08-12 20:38:38 +07:00
|
|
|
|
|
|
|
if (!ieee80211_is_mgmt(mgmt->frame_control))
|
2010-02-15 17:53:10 +07:00
|
|
|
return -EINVAL;
|
2010-08-12 20:38:38 +07:00
|
|
|
|
|
|
|
stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
|
|
|
|
if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4)))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (ieee80211_is_action(mgmt->frame_control) &&
|
|
|
|
mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
|
2010-10-01 02:06:09 +07:00
|
|
|
int err = 0;
|
|
|
|
|
2010-08-09 20:52:03 +07:00
|
|
|
wdev_lock(wdev);
|
|
|
|
|
2010-10-01 02:06:09 +07:00
|
|
|
switch (wdev->iftype) {
|
|
|
|
case NL80211_IFTYPE_ADHOC:
|
|
|
|
case NL80211_IFTYPE_STATION:
|
|
|
|
case NL80211_IFTYPE_P2P_CLIENT:
|
|
|
|
if (!wdev->current_bss) {
|
|
|
|
err = -ENOTCONN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(wdev->current_bss->pub.bssid,
|
|
|
|
mgmt->bssid, ETH_ALEN)) {
|
|
|
|
err = -ENOTCONN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check for IBSS DA must be done by driver as
|
|
|
|
* cfg80211 doesn't track the stations
|
|
|
|
*/
|
|
|
|
if (wdev->iftype == NL80211_IFTYPE_ADHOC)
|
|
|
|
break;
|
2010-08-09 20:52:03 +07:00
|
|
|
|
2010-10-01 02:06:09 +07:00
|
|
|
/* for station, check that DA is the AP */
|
|
|
|
if (memcmp(wdev->current_bss->pub.bssid,
|
|
|
|
mgmt->da, ETH_ALEN)) {
|
|
|
|
err = -ENOTCONN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NL80211_IFTYPE_AP:
|
|
|
|
case NL80211_IFTYPE_P2P_GO:
|
|
|
|
case NL80211_IFTYPE_AP_VLAN:
|
|
|
|
if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN))
|
|
|
|
err = -EINVAL;
|
|
|
|
break;
|
2011-05-04 06:57:08 +07:00
|
|
|
case NL80211_IFTYPE_MESH_POINT:
|
|
|
|
if (memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* check for mesh DA must be done by driver as
|
|
|
|
* cfg80211 doesn't track the stations
|
|
|
|
*/
|
|
|
|
break;
|
2010-10-01 02:06:09 +07:00
|
|
|
default:
|
|
|
|
err = -EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
2010-08-09 20:52:03 +07:00
|
|
|
wdev_unlock(wdev);
|
2010-10-01 02:06:09 +07:00
|
|
|
|
|
|
|
if (err)
|
|
|
|
return err;
|
2010-02-15 17:53:10 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* Transmit the Action frame as requested by user space */
|
2010-11-25 16:02:29 +07:00
|
|
|
return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
|
|
|
|
channel_type, channel_type_valid,
|
2011-09-25 16:23:30 +07:00
|
|
|
wait, buf, len, no_cck, cookie);
|
2010-02-15 17:53:10 +07:00
|
|
|
}
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
|
|
|
|
size_t len, gfp_t gfp)
|
2010-02-15 17:53:10 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
2010-08-12 20:38:38 +07:00
|
|
|
struct cfg80211_mgmt_registration *reg;
|
|
|
|
const struct ieee80211_txrx_stypes *stypes =
|
|
|
|
&wiphy->mgmt_stypes[wdev->iftype];
|
|
|
|
struct ieee80211_mgmt *mgmt = (void *)buf;
|
|
|
|
const u8 *data;
|
|
|
|
int data_len;
|
2010-02-15 17:53:10 +07:00
|
|
|
bool result = false;
|
2010-08-12 20:38:38 +07:00
|
|
|
__le16 ftype = mgmt->frame_control &
|
|
|
|
cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);
|
|
|
|
u16 stype;
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4;
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
if (!(stypes->rx & BIT(stype)))
|
|
|
|
return false;
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
data = buf + ieee80211_hdrlen(mgmt->frame_control);
|
|
|
|
data_len = len - ieee80211_hdrlen(mgmt->frame_control);
|
|
|
|
|
|
|
|
spin_lock_bh(&wdev->mgmt_registrations_lock);
|
|
|
|
|
|
|
|
list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
|
|
|
|
if (reg->frame_type != ftype)
|
|
|
|
continue;
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
if (reg->match_len > data_len)
|
2010-02-15 17:53:10 +07:00
|
|
|
continue;
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
if (memcmp(reg->match, data, reg->match_len))
|
2010-02-15 17:53:10 +07:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* found match! */
|
|
|
|
|
|
|
|
/* Indicate the received Action frame to user space */
|
2010-08-12 20:38:38 +07:00
|
|
|
if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq,
|
|
|
|
buf, len, gfp))
|
2010-02-15 17:53:10 +07:00
|
|
|
continue;
|
|
|
|
|
|
|
|
result = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
spin_unlock_bh(&wdev->mgmt_registrations_lock);
|
2010-02-15 17:53:10 +07:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2010-08-12 20:38:38 +07:00
|
|
|
EXPORT_SYMBOL(cfg80211_rx_mgmt);
|
2010-02-15 17:53:10 +07:00
|
|
|
|
2010-08-12 20:38:38 +07:00
|
|
|
void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie,
|
|
|
|
const u8 *buf, size_t len, bool ack, gfp_t gfp)
|
2010-02-15 17:53:10 +07:00
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
|
|
|
|
|
/* Indicate TX status of the Action frame to user space */
|
2010-08-12 20:38:38 +07:00
|
|
|
nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
|
2010-02-15 17:53:10 +07:00
|
|
|
}
|
2010-08-12 20:38:38 +07:00
|
|
|
EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
|
2010-03-23 14:02:33 +07:00
|
|
|
|
|
|
|
void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
|
|
|
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
|
|
|
gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
|
|
|
|
|
/* Indicate roaming trigger event to user space */
|
|
|
|
nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
|
2010-11-24 14:10:05 +07:00
|
|
|
|
|
|
|
void cfg80211_cqm_pktloss_notify(struct net_device *dev,
|
|
|
|
const u8 *peer, u32 num_packets, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
|
|
|
|
|
/* Indicate roaming trigger event to user space */
|
|
|
|
nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
|
2011-07-05 21:35:40 +07:00
|
|
|
|
|
|
|
void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
|
|
|
|
const u8 *replay_ctr, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
|
|
|
|
|
nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
|
2011-09-16 22:56:23 +07:00
|
|
|
|
|
|
|
void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
|
|
|
|
const u8 *bssid, bool preauth, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
struct wiphy *wiphy = wdev->wiphy;
|
|
|
|
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
|
|
|
|
|
nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
|
2011-11-04 17:18:12 +07:00
|
|
|
|
|
|
|
bool cfg80211_rx_spurious_frame(struct net_device *dev,
|
|
|
|
const u8 *addr, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
|
|
|
|
|
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
|
|
|
|
wdev->iftype != NL80211_IFTYPE_P2P_GO))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return nl80211_unexpected_frame(dev, addr, gfp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
|