the scheduled ieee80211 softmac removal

Signed-off-by: Adrian Bunk <bunk@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Adrian Bunk
2008-03-04 15:26:14 -08:00
committed by John W. Linville
parent 2079fcdc06
commit 7524d7d6de
16 changed files with 0 additions and 3662 deletions
-1
View File
@@ -71,4 +71,3 @@ config IEEE80211_CRYPT_TKIP
This can be compiled as a module and it will be called
"ieee80211_crypt_tkip".
source "net/ieee80211/softmac/Kconfig"
-1
View File
@@ -10,4 +10,3 @@ ieee80211-objs := \
ieee80211_wx.o \
ieee80211_geo.o
obj-$(CONFIG_IEEE80211_SOFTMAC) += softmac/
-12
View File
@@ -1,12 +0,0 @@
config IEEE80211_SOFTMAC
tristate "Software MAC add-on to the IEEE 802.11 networking stack"
depends on IEEE80211 && EXPERIMENTAL
select WIRELESS_EXT
select IEEE80211_CRYPT_WEP
---help---
This option enables the hardware independent software MAC addon
for the IEEE 802.11 networking stack.
config IEEE80211_SOFTMAC_DEBUG
bool "Enable full debugging output"
depends on IEEE80211_SOFTMAC
-9
View File
@@ -1,9 +0,0 @@
obj-$(CONFIG_IEEE80211_SOFTMAC) += ieee80211softmac.o
ieee80211softmac-objs := \
ieee80211softmac_io.o \
ieee80211softmac_auth.o \
ieee80211softmac_module.o \
ieee80211softmac_scan.o \
ieee80211softmac_wx.o \
ieee80211softmac_assoc.o \
ieee80211softmac_event.o
@@ -1,489 +0,0 @@
/*
* This file contains the softmac's association logic.
*
* Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
* Joseph Jezak <josejx@gentoo.org>
* Larry Finger <Larry.Finger@lwfinger.net>
* Danny van Dyk <kugelfang@gentoo.org>
* Michael Buesch <mbuesch@freenet.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* The full GNU General Public License is included in this distribution in the
* file called COPYING.
*/
#include "ieee80211softmac_priv.h"
/*
* Overview
*
* Before you can associate, you have to authenticate.
*
*/
/* Sends out an association request to the desired AP */
static void
ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
{
unsigned long flags;
/* Switch to correct channel for this network */
mac->set_channel(mac->dev, net->channel);
/* Send association request */
ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_ASSOC_REQ, 0);
dprintk(KERN_INFO PFX "sent association request!\n");
spin_lock_irqsave(&mac->lock, flags);
mac->associnfo.associated = 0; /* just to make sure */
/* Set a timer for timeout */
/* FIXME: make timeout configurable */
if (likely(mac->running))
queue_delayed_work(mac->wq, &mac->associnfo.timeout, 5 * HZ);
spin_unlock_irqrestore(&mac->lock, flags);
}
void
ieee80211softmac_assoc_timeout(struct work_struct *work)
{
struct ieee80211softmac_device *mac =
container_of(work, struct ieee80211softmac_device,
associnfo.timeout.work);
struct ieee80211softmac_network *n;
mutex_lock(&mac->associnfo.mutex);
/* we might race against ieee80211softmac_handle_assoc_response,
* so make sure only one of us does something */
if (!mac->associnfo.associating)
goto out;
mac->associnfo.associating = 0;
mac->associnfo.bssvalid = 0;
mac->associnfo.associated = 0;
n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
dprintk(KERN_INFO PFX "assoc request timed out!\n");
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
out:
mutex_unlock(&mac->associnfo.mutex);
}
void
ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
{
unsigned long flags;
spin_lock_irqsave(&mac->lock, flags);
if (mac->associnfo.associating)
cancel_delayed_work(&mac->associnfo.timeout);
netif_carrier_off(mac->dev);
mac->associnfo.associated = 0;
mac->associnfo.bssvalid = 0;
mac->associnfo.associating = 0;
ieee80211softmac_init_bss(mac);
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
spin_unlock_irqrestore(&mac->lock, flags);
}
/* Sends out a disassociation request to the desired AP */
void
ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason)
{
struct ieee80211softmac_network *found;
if (mac->associnfo.bssvalid && mac->associnfo.associated) {
found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
if (found)
ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
}
ieee80211softmac_disassoc(mac);
}
static inline int
we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
{
int idx;
u8 rate;
for (idx = 0; idx < (from_len); idx++) {
rate = (from)[idx];
if (!(rate & IEEE80211_BASIC_RATE_MASK))
continue;
rate &= ~IEEE80211_BASIC_RATE_MASK;
if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
return 0;
}
return 1;
}
static int
network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net)
{
/* we cannot associate to networks whose name we don't know */
if (ieee80211_is_empty_essid(net->ssid, net->ssid_len))
return 0;
/* do not associate to a network whose BSSBasicRateSet we cannot support */
if (!we_support_all_basic_rates(mac, net->rates, net->rates_len))
return 0;
/* do we really need to check the ex rates? */
if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len))
return 0;
/* assume that users know what they're doing ...
* (note we don't let them select a net we're incompatible with) */
if (mac->associnfo.bssfixed) {
return !memcmp(mac->associnfo.bssid, net->bssid, ETH_ALEN);
}
/* if 'ANY' network requested, take any that doesn't have privacy enabled */
if (mac->associnfo.req_essid.len == 0
&& !(net->capability & WLAN_CAPABILITY_PRIVACY))
return 1;
if (net->ssid_len != mac->associnfo.req_essid.len)
return 0;
if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len))
return 1;
return 0;
}
static void
ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context)
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
ieee80211softmac_assoc_work(&mac->associnfo.work.work);
}
static void
ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void *context)
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
switch (event_type) {
case IEEE80211SOFTMAC_EVENT_AUTHENTICATED:
ieee80211softmac_assoc_work(&mac->associnfo.work.work);
break;
case IEEE80211SOFTMAC_EVENT_AUTH_FAILED:
case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT:
ieee80211softmac_disassoc(mac);
break;
}
}
/* This function is called to handle userspace requests (asynchronously) */
void
ieee80211softmac_assoc_work(struct work_struct *work)
{
struct ieee80211softmac_device *mac =
container_of(work, struct ieee80211softmac_device,
associnfo.work.work);
struct ieee80211softmac_network *found = NULL;
struct ieee80211_network *net = NULL, *best = NULL;
int bssvalid;
unsigned long flags;
mutex_lock(&mac->associnfo.mutex);
if (!mac->associnfo.associating)
goto out;
/* ieee80211_disassoc might clear this */
bssvalid = mac->associnfo.bssvalid;
/* meh */
if (mac->associnfo.associated)
ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
/* try to find the requested network in our list, if we found one already */
if (bssvalid || mac->associnfo.bssfixed)
found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
/* Search the ieee80211 networks for this network if we didn't find it by bssid,
* but only if we've scanned at least once (to get a better list of networks to
* select from). If we have not scanned before, the !found logic below will be
* invoked and will scan. */
if (!found && (mac->associnfo.scan_retry < IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT))
{
s8 rssi = -128; /* if I don't initialise, gcc emits an invalid warning
because it cannot follow the best pointer logic. */
spin_lock_irqsave(&mac->ieee->lock, flags);
list_for_each_entry(net, &mac->ieee->network_list, list) {
/* we're supposed to find the network with
* the best signal here, as we're asked to join
* any network with a specific ESSID, and many
* different ones could have that.
*
* I'll for now just go with the reported rssi.
*
* We also should take into account the rateset
* here to find the best BSSID to try.
*/
if (network_matches_request(mac, net)) {
if (!best) {
best = net;
rssi = best->stats.rssi;
continue;
}
/* we already had a matching network, so
* compare their properties to get the
* better of the two ... (see above)
*/
if (rssi < net->stats.rssi) {
best = net;
rssi = best->stats.rssi;
}
}
}
/* if we unlock here, we might get interrupted and the `best'
* pointer could go stale */
if (best) {
found = ieee80211softmac_create_network(mac, best);
/* if found is still NULL, then we got -ENOMEM somewhere */
if (found)
ieee80211softmac_add_network(mac, found);
}
spin_unlock_irqrestore(&mac->ieee->lock, flags);
}
if (!found) {
if (mac->associnfo.scan_retry > 0) {
mac->associnfo.scan_retry--;
/* We know of no such network. Let's scan.
* NB: this also happens if we had no memory to copy the network info...
* Maybe we can hope to have more memory after scanning finishes ;)
*/
dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n");
ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL);
if (ieee80211softmac_start_scan(mac)) {
dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
}
goto out;
} else {
mac->associnfo.associating = 0;
mac->associnfo.associated = 0;
dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
/* reset the retry counter for the next user request since we
* break out and don't reschedule ourselves after this point. */
mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
goto out;
}
}
/* reset the retry counter for the next user request since we
* now found a net and will try to associate to it, but not
* schedule this function again. */
mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
mac->associnfo.bssvalid = 1;
memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN);
/* copy the ESSID for displaying it */
mac->associnfo.associate_essid.len = found->essid.len;
memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
/* we found a network! authenticate (if necessary) and associate to it. */
if (found->authenticating) {
dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
if(!mac->associnfo.assoc_wait) {
mac->associnfo.assoc_wait = 1;
ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
}
goto out;
}
if (!found->authenticated && !found->authenticating) {
/* This relies on the fact that _auth_req only queues the work,
* otherwise adding the notification would be racy. */
if (!ieee80211softmac_auth_req(mac, found)) {
if(!mac->associnfo.assoc_wait) {
dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
mac->associnfo.assoc_wait = 1;
ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
}
} else {
printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
mac->associnfo.assoc_wait = 0;
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
}
goto out;
}
/* finally! now we can start associating */
mac->associnfo.assoc_wait = 0;
ieee80211softmac_assoc(mac, found);
out:
mutex_unlock(&mac->associnfo.mutex);
}
/* call this to do whatever is necessary when we're associated */
static void
ieee80211softmac_associated(struct ieee80211softmac_device *mac,
struct ieee80211_assoc_response * resp,
struct ieee80211softmac_network *net)
{
u16 cap = le16_to_cpu(resp->capability);
u8 erp_value = net->erp_value;
mac->associnfo.associating = 0;
mac->bssinfo.supported_rates = net->supported_rates;
ieee80211softmac_recalc_txrates(mac);
mac->associnfo.associated = 1;
mac->associnfo.short_preamble_available =
(cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
ieee80211softmac_process_erp(mac, erp_value);
if (mac->set_bssid_filter)
mac->set_bssid_filter(mac->dev, net->bssid);
memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
netif_carrier_on(mac->dev);
mac->association_id = le16_to_cpup(&resp->aid);
}
/* received frame handling functions */
int
ieee80211softmac_handle_assoc_response(struct net_device * dev,
struct ieee80211_assoc_response * resp,
struct ieee80211_network * _ieee80211_network)
{
/* NOTE: the network parameter has to be mostly ignored by
* this code because it is the ieee80211's pointer
* to the struct, not ours (we made a copy)
*/
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
u16 status = le16_to_cpup(&resp->status);
struct ieee80211softmac_network *network = NULL;
unsigned long flags;
DECLARE_MAC_BUF(mac2);
if (unlikely(!mac->running))
return -ENODEV;
spin_lock_irqsave(&mac->lock, flags);
if (!mac->associnfo.associating) {
/* we race against the timeout function, so make sure
* only one of us can do work */
spin_unlock_irqrestore(&mac->lock, flags);
return 0;
}
network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3);
/* someone sending us things without us knowing him? Ignore. */
if (!network) {
dprintk(KERN_INFO PFX "Received unrequested assocation response from %s\n",
print_mac(mac2, resp->header.addr3));
spin_unlock_irqrestore(&mac->lock, flags);
return 0;
}
/* now that we know it was for us, we can cancel the timeout */
cancel_delayed_work(&mac->associnfo.timeout);
/* if the association response included an ERP IE, update our saved
* copy */
if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
network->erp_value = _ieee80211_network->erp_value;
switch (status) {
case 0:
dprintk(KERN_INFO PFX "associated!\n");
ieee80211softmac_associated(mac, resp, network);
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network);
break;
case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
if (!network->auth_desynced_once) {
/* there seem to be a few rare cases where our view of
* the world is obscured, or buggy APs that don't DEAUTH
* us properly. So we handle that, but allow it only once.
*/
printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n");
network->authenticated = 0;
/* we don't want to do this more than once ... */
network->auth_desynced_once = 1;
queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
break;
}
default:
dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
mac->associnfo.associating = 0;
mac->associnfo.bssvalid = 0;
mac->associnfo.associated = 0;
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
}
spin_unlock_irqrestore(&mac->lock, flags);
return 0;
}
void
ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac)
{
unsigned long flags;
spin_lock_irqsave(&mac->lock, flags);
mac->associnfo.associating = 1;
queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
spin_unlock_irqrestore(&mac->lock, flags);
}
int
ieee80211softmac_handle_disassoc(struct net_device * dev,
struct ieee80211_disassoc *disassoc)
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
if (unlikely(!mac->running))
return -ENODEV;
if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN))
return 0;
if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN))
return 0;
dprintk(KERN_INFO PFX "got disassoc frame\n");
ieee80211softmac_disassoc(mac);
ieee80211softmac_try_reassoc(mac);
return 0;
}
int
ieee80211softmac_handle_reassoc_req(struct net_device * dev,
struct ieee80211_reassoc_request * resp)
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
struct ieee80211softmac_network *network;
if (unlikely(!mac->running))
return -ENODEV;
network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3);
if (!network) {
dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
return 0;
}
queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
return 0;
}
@@ -1,413 +0,0 @@
/*
* This file contains the softmac's authentication logic.
*
* Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
* Joseph Jezak <josejx@gentoo.org>
* Larry Finger <Larry.Finger@lwfinger.net>
* Danny van Dyk <kugelfang@gentoo.org>
* Michael Buesch <mbuesch@freenet.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* The full GNU General Public License is included in this distribution in the
* file called COPYING.
*/
#include "ieee80211softmac_priv.h"
static void ieee80211softmac_auth_queue(struct work_struct *work);
/* Queues an auth request to the desired AP */
int
ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
struct ieee80211softmac_network *net)
{
struct ieee80211softmac_auth_queue_item *auth;
unsigned long flags;
DECLARE_MAC_BUF(mac2);
if (net->authenticating || net->authenticated)
return 0;
net->authenticating = 1;
/* Add the network if it's not already added */
ieee80211softmac_add_network(mac, net);
dprintk(KERN_NOTICE PFX "Queueing Authentication Request to %s\n", print_mac(mac2, net->bssid));
/* Queue the auth request */
auth = (struct ieee80211softmac_auth_queue_item *)
kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL);
if(auth == NULL)
return -ENOMEM;
auth->net = net;
auth->mac = mac;
auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
INIT_DELAYED_WORK(&auth->work, ieee80211softmac_auth_queue);
/* Lock (for list) */
spin_lock_irqsave(&mac->lock, flags);
/* add to list */
list_add_tail(&auth->list, &mac->auth_queue);
queue_delayed_work(mac->wq, &auth->work, 0);
spin_unlock_irqrestore(&mac->lock, flags);
return 0;
}
/* Sends an auth request to the desired AP and handles timeouts */
static void
ieee80211softmac_auth_queue(struct work_struct *work)
{
struct ieee80211softmac_device *mac;
struct ieee80211softmac_auth_queue_item *auth;
struct ieee80211softmac_network *net;
unsigned long flags;
DECLARE_MAC_BUF(mac2);
auth = container_of(work, struct ieee80211softmac_auth_queue_item,
work.work);
net = auth->net;
mac = auth->mac;
if(auth->retry > 0) {
/* Switch to correct channel for this network */
mac->set_channel(mac->dev, net->channel);
/* Lock and set flags */
spin_lock_irqsave(&mac->lock, flags);
if (unlikely(!mac->running)) {
/* Prevent reschedule on workqueue flush */
spin_unlock_irqrestore(&mac->lock, flags);
return;
}
net->authenticated = 0;
/* add a timeout call so we eventually give up waiting for an auth reply */
queue_delayed_work(mac->wq, &auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
auth->retry--;
spin_unlock_irqrestore(&mac->lock, flags);
if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state))
dprintk(KERN_NOTICE PFX "Sending Authentication Request to %s failed (this shouldn't happen, wait for the timeout).\n",
print_mac(mac2, net->bssid));
else
dprintk(KERN_NOTICE PFX "Sent Authentication Request to %s.\n", print_mac(mac2, net->bssid));
return;
}
printkl(KERN_WARNING PFX "Authentication timed out with %s\n", print_mac(mac2, net->bssid));
/* Remove this item from the queue */
spin_lock_irqsave(&mac->lock, flags);
net->authenticating = 0;
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
cancel_delayed_work(&auth->work); /* just to make sure... */
list_del(&auth->list);
spin_unlock_irqrestore(&mac->lock, flags);
/* Free it */
kfree(auth);
}
/* Sends a response to an auth challenge (for shared key auth). */
static void
ieee80211softmac_auth_challenge_response(struct work_struct *work)
{
struct ieee80211softmac_auth_queue_item *aq =
container_of(work, struct ieee80211softmac_auth_queue_item,
work.work);
/* Send our response */
ieee80211softmac_send_mgt_frame(aq->mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
}
/* Handle the auth response from the AP
* This should be registered with ieee80211 as handle_auth
*/
int
ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
{
struct list_head *list_ptr;
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
struct ieee80211softmac_auth_queue_item *aq = NULL;
struct ieee80211softmac_network *net = NULL;
unsigned long flags;
u8 * data;
DECLARE_MAC_BUF(mac2);
if (unlikely(!mac->running))
return -ENODEV;
/* Find correct auth queue item */
spin_lock_irqsave(&mac->lock, flags);
list_for_each(list_ptr, &mac->auth_queue) {
aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
net = aq->net;
if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN))
break;
else
aq = NULL;
}
spin_unlock_irqrestore(&mac->lock, flags);
/* Make sure that we've got an auth queue item for this request */
if(aq == NULL)
{
dprintkl(KERN_DEBUG PFX "Authentication response received from %s but no queue item exists.\n", print_mac(mac2, auth->header.addr2));
/* Error #? */
return -1;
}
/* Check for out of order authentication */
if(!net->authenticating)
{
dprintkl(KERN_DEBUG PFX "Authentication response received from %s but did not request authentication.\n",print_mac(mac2, auth->header.addr2));
return -1;
}
/* Parse the auth packet */
switch(le16_to_cpu(auth->algorithm)) {
case WLAN_AUTH_OPEN:
/* Check the status code of the response */
switch(le16_to_cpu(auth->status)) {
case WLAN_STATUS_SUCCESS:
/* Update the status to Authenticated */
spin_lock_irqsave(&mac->lock, flags);
net->authenticating = 0;
net->authenticated = 1;
spin_unlock_irqrestore(&mac->lock, flags);
/* Send event */
printkl(KERN_NOTICE PFX "Open Authentication completed with %s\n", print_mac(mac2, net->bssid));
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
break;
default:
/* Lock and reset flags */
spin_lock_irqsave(&mac->lock, flags);
net->authenticated = 0;
net->authenticating = 0;
spin_unlock_irqrestore(&mac->lock, flags);
printkl(KERN_NOTICE PFX "Open Authentication with %s failed, error code: %i\n",
print_mac(mac2, net->bssid), le16_to_cpup(&auth->status));
/* Count the error? */
break;
}
goto free_aq;
break;
case WLAN_AUTH_SHARED_KEY:
/* Figure out where we are in the process */
switch(le16_to_cpu(auth->transaction)) {
case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
/* Check to make sure we have a challenge IE */
data = (u8 *)auth->info_element;
if (*data++ != MFIE_TYPE_CHALLENGE) {
printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
break;
}
/* Save the challenge */
spin_lock_irqsave(&mac->lock, flags);
net->challenge_len = *data++;
if (net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
kfree(net->challenge);
net->challenge = kmemdup(data, net->challenge_len,
GFP_ATOMIC);
if (net->challenge == NULL) {
printkl(KERN_NOTICE PFX "Shared Key "
"Authentication failed due to "
"memory shortage.\n");
spin_unlock_irqrestore(&mac->lock, flags);
break;
}
aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
/* We reuse the work struct from the auth request here.
* It is safe to do so as each one is per-request, and
* at this point (dealing with authentication response)
* we have obviously already sent the initial auth
* request. */
cancel_delayed_work(&aq->work);
INIT_DELAYED_WORK(&aq->work, &ieee80211softmac_auth_challenge_response);
queue_delayed_work(mac->wq, &aq->work, 0);
spin_unlock_irqrestore(&mac->lock, flags);
return 0;
case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
kfree(net->challenge);
net->challenge = NULL;
net->challenge_len = 0;
/* Check the status code of the response */
switch(auth->status) {
case WLAN_STATUS_SUCCESS:
/* Update the status to Authenticated */
spin_lock_irqsave(&mac->lock, flags);
net->authenticating = 0;
net->authenticated = 1;
spin_unlock_irqrestore(&mac->lock, flags);
printkl(KERN_NOTICE PFX "Shared Key Authentication completed with %s\n",
print_mac(mac2, net->bssid));
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
break;
default:
printkl(KERN_NOTICE PFX "Shared Key Authentication with %s failed, error code: %i\n",
print_mac(mac2, net->bssid), le16_to_cpup(&auth->status));
/* Lock and reset flags */
spin_lock_irqsave(&mac->lock, flags);
net->authenticating = 0;
net->authenticated = 0;
spin_unlock_irqrestore(&mac->lock, flags);
/* Count the error? */
break;
}
goto free_aq;
break;
default:
printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction);
break;
}
goto free_aq;
break;
default:
/* ERROR */
goto free_aq;
break;
}
return 0;
free_aq:
/* Cancel the timeout */
spin_lock_irqsave(&mac->lock, flags);
cancel_delayed_work(&aq->work);
/* Remove this item from the queue */
list_del(&aq->list);
spin_unlock_irqrestore(&mac->lock, flags);
/* Free it */
kfree(aq);
return 0;
}
/*
* Handle deauthorization
*/
static void
ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
struct ieee80211softmac_network *net)
{
struct ieee80211softmac_auth_queue_item *aq = NULL;
struct list_head *list_ptr;
unsigned long flags;
/* deauthentication implies disassociation */
ieee80211softmac_disassoc(mac);
/* Lock and reset status flags */
spin_lock_irqsave(&mac->lock, flags);
net->authenticating = 0;
net->authenticated = 0;
/* Find correct auth queue item, if it exists */
list_for_each(list_ptr, &mac->auth_queue) {
aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN))
break;
else
aq = NULL;
}
/* Cancel pending work */
if(aq != NULL)
/* Not entirely safe? What about running work? */
cancel_delayed_work(&aq->work);
/* Free our network ref */
ieee80211softmac_del_network_locked(mac, net);
if(net->challenge != NULL)
kfree(net->challenge);
kfree(net);
/* can't transmit data right now... */
netif_carrier_off(mac->dev);
spin_unlock_irqrestore(&mac->lock, flags);
ieee80211softmac_try_reassoc(mac);
}
/*
* Sends a deauth request to the desired AP
*/
int
ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac,
struct ieee80211softmac_network *net, int reason)
{
int ret;
/* Make sure the network is authenticated */
if (!net->authenticated)
{
dprintkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
/* Error okay? */
return -EPERM;
}
/* Send the de-auth packet */
if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason)))
return ret;
ieee80211softmac_deauth_from_net(mac, net);
return 0;
}
/*
* This should be registered with ieee80211 as handle_deauth
*/
int
ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth)
{
struct ieee80211softmac_network *net = NULL;
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
DECLARE_MAC_BUF(mac2);
if (unlikely(!mac->running))
return -ENODEV;
if (!deauth) {
dprintk("deauth without deauth packet. eek!\n");
return 0;
}
net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2);
if (net == NULL) {
dprintkl(KERN_DEBUG PFX "Received deauthentication packet from %s, but that network is unknown.\n",
print_mac(mac2, deauth->header.addr2));
return 0;
}
/* Make sure the network is authenticated */
if(!net->authenticated)
{
dprintkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
/* Error okay? */
return -EPERM;
}
ieee80211softmac_deauth_from_net(mac, net);
/* let's try to re-associate */
queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
return 0;
}
@@ -1,189 +0,0 @@
/*
* Event system
* Also see comments in public header file and longer explanation below.
*
* Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
* Joseph Jezak <josejx@gentoo.org>
* Larry Finger <Larry.Finger@lwfinger.net>
* Danny van Dyk <kugelfang@gentoo.org>
* Michael Buesch <mbuesch@freenet.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* The full GNU General Public License is included in this distribution in the
* file called COPYING.
*/
#include "ieee80211softmac_priv.h"
/*
* Each event has associated to it
* - an event type (see constants in public header)
* - an event context (see below)
* - the function to be called
* - a context (extra parameter to call the function with)
* - and the softmac struct
*
* The event context is private and can only be used from
* within this module. Its meaning varies with the event
* type:
* SCAN_FINISHED,
* DISASSOCIATED: NULL
* ASSOCIATED,
* ASSOCIATE_FAILED,
* ASSOCIATE_TIMEOUT,
* AUTHENTICATED,
* AUTH_FAILED,
* AUTH_TIMEOUT: a pointer to the network struct
* ...
* Code within this module can use the event context to be only
* called when the event is true for that specific context
* as per above table.
* If the event context is NULL, then the notification is always called,
* regardless of the event context. The event context is not passed to
* the callback, it is assumed that the context suffices.
*
* You can also use the event context only by setting the event type
* to -1 (private use only), in which case you'll be notified
* whenever the event context matches.
*/
static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
NULL, /* scan finished */
NULL, /* associated */
"associating failed",
"associating timed out",
"authenticated",
"authenticating failed",
"authenticating timed out",
"associating failed because no suitable network was found",
NULL, /* disassociated */
};
static void
ieee80211softmac_notify_callback(struct work_struct *work)
{
struct ieee80211softmac_event *pevent =
container_of(work, struct ieee80211softmac_event, work.work);
struct ieee80211softmac_event event = *pevent;
kfree(pevent);
event.fun(event.mac->dev, event.event_type, event.context);
}
int
ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask)
{
struct ieee80211softmac_event *eventptr;
unsigned long flags;
if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST)
return -ENOSYS;
if (!fun)
return -EINVAL;
eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask);
if (!eventptr)
return -ENOMEM;
eventptr->event_type = event;
INIT_DELAYED_WORK(&eventptr->work, ieee80211softmac_notify_callback);
eventptr->fun = fun;
eventptr->context = context;
eventptr->mac = mac;
eventptr->event_context = event_context;
spin_lock_irqsave(&mac->lock, flags);
list_add(&eventptr->list, &mac->events);
spin_unlock_irqrestore(&mac->lock, flags);
return 0;
}
int
ieee80211softmac_notify_gfp(struct net_device *dev,
int event, notify_function_ptr fun, void *context, gfp_t gfp_mask)
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST)
return -ENOSYS;
return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask);
}
EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp);
/* private -- calling all callbacks that were specified */
void
ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
{
struct ieee80211softmac_event *eventptr, *tmp;
struct ieee80211softmac_network *network;
if (event >= 0) {
union iwreq_data wrqu;
int we_event;
char *msg = NULL;
memset(&wrqu, '\0', sizeof (union iwreq_data));
switch(event) {
case IEEE80211SOFTMAC_EVENT_ASSOCIATED:
network = (struct ieee80211softmac_network *)event_ctx;
memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN);
/* fall through */
case IEEE80211SOFTMAC_EVENT_DISASSOCIATED:
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
we_event = SIOCGIWAP;
break;
case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED:
we_event = SIOCGIWSCAN;
break;
default:
msg = event_descriptions[event];
if (!msg)
msg = "SOFTMAC EVENT BUG";
wrqu.data.length = strlen(msg);
we_event = IWEVCUSTOM;
break;
}
wireless_send_event(mac->dev, we_event, &wrqu, msg);
}
if (!list_empty(&mac->events))
list_for_each_entry_safe(eventptr, tmp, &mac->events, list) {
if ((eventptr->event_type == event || eventptr->event_type == -1)
&& (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
list_del(&eventptr->list);
/* User may have subscribed to ANY event, so
* we tell them which event triggered it. */
eventptr->event_type = event;
queue_delayed_work(mac->wq, &eventptr->work, 0);
}
}
}
void
ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx)
{
unsigned long flags;
spin_lock_irqsave(&mac->lock, flags);
ieee80211softmac_call_events_locked(mac, event, event_ctx);
spin_unlock_irqrestore(&mac->lock, flags);
}
-488
View File
@@ -1,488 +0,0 @@
/*
* Some parts based on code from net80211
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ieee80211softmac_priv.h"
/* Helper functions for inserting data into the frames */
/*
* Adds an ESSID element to the frame
*
*/
static u8 *
ieee80211softmac_add_essid(u8 *dst, struct ieee80211softmac_essid *essid)
{
if (essid) {
*dst++ = MFIE_TYPE_SSID;
*dst++ = essid->len;
memcpy(dst, essid->data, essid->len);
return dst+essid->len;
} else {
*dst++ = MFIE_TYPE_SSID;
*dst++ = 0;
return dst;
}
}
/* Adds Supported Rates and if required Extended Rates Information Element
* to the frame, ASSUMES WE HAVE A SORTED LIST OF RATES */
static u8 *
ieee80211softmac_frame_add_rates(u8 *dst, const struct ieee80211softmac_ratesinfo *r)
{
int cck_len, ofdm_len;
*dst++ = MFIE_TYPE_RATES;
for(cck_len=0; ieee80211_is_cck_rate(r->rates[cck_len]) && (cck_len < r->count);cck_len++);
if(cck_len > IEEE80211SOFTMAC_MAX_RATES_LEN)
cck_len = IEEE80211SOFTMAC_MAX_RATES_LEN;
*dst++ = cck_len;
memcpy(dst, r->rates, cck_len);
dst += cck_len;
if(cck_len < r->count){
for (ofdm_len=0; ieee80211_is_ofdm_rate(r->rates[ofdm_len + cck_len]) && (ofdm_len + cck_len < r->count); ofdm_len++);
if (ofdm_len > 0) {
if (ofdm_len > IEEE80211SOFTMAC_MAX_EX_RATES_LEN)
ofdm_len = IEEE80211SOFTMAC_MAX_EX_RATES_LEN;
*dst++ = MFIE_TYPE_RATES_EX;
*dst++ = ofdm_len;
memcpy(dst, r->rates + cck_len, ofdm_len);
dst += ofdm_len;
}
}
return dst;
}
/* Allocate a management frame */
static u8 *
ieee80211softmac_alloc_mgt(u32 size)
{
u8 * data;
/* Add the header and FCS to the size */
size = size + IEEE80211_3ADDR_LEN;
if(size > IEEE80211_DATA_LEN)
return NULL;
/* Allocate the frame */
data = kzalloc(size, GFP_ATOMIC);
return data;
}
/*
* Add a 2 Address Header
*/
static void
ieee80211softmac_hdr_2addr(struct ieee80211softmac_device *mac,
struct ieee80211_hdr_2addr *header, u32 type, u8 *dest)
{
/* Fill in the frame control flags */
header->frame_ctl = cpu_to_le16(type);
/* Control packets always have WEP turned off */
if(type > IEEE80211_STYPE_CFENDACK && type < IEEE80211_STYPE_PSPOLL)
header->frame_ctl |= mac->ieee->sec.level ? cpu_to_le16(IEEE80211_FCTL_PROTECTED) : 0;
/* Fill in the duration */
header->duration_id = 0;
/* FIXME: How do I find this?
* calculate. But most drivers just fill in 0 (except if it's a station id of course) */
/* Fill in the Destination Address */
if(dest == NULL)
memset(header->addr1, 0xFF, ETH_ALEN);
else
memcpy(header->addr1, dest, ETH_ALEN);
/* Fill in the Source Address */
memcpy(header->addr2, mac->ieee->dev->dev_addr, ETH_ALEN);
}
/* Add a 3 Address Header */
static void
ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac,
struct ieee80211_hdr_3addr *header, u32 type, u8 *dest, u8 *bssid)
{
/* This is common with 2addr, so use that instead */
ieee80211softmac_hdr_2addr(mac, (struct ieee80211_hdr_2addr *)header, type, dest);
/* Fill in the BSS ID */
if(bssid == NULL)
memset(header->addr3, 0xFF, ETH_ALEN);
else
memcpy(header->addr3, bssid, ETH_ALEN);
/* Fill in the sequence # */
/* FIXME: I need to add this to the softmac struct
* shouldn't the sequence number be in ieee80211? */
}
static __le16
ieee80211softmac_capabilities(struct ieee80211softmac_device *mac,
struct ieee80211softmac_network *net)
{
__le16 capability = 0;
/* ESS and IBSS bits are set according to the current mode */
switch (mac->ieee->iw_mode) {
case IW_MODE_INFRA:
capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
break;
case IW_MODE_ADHOC:
capability = cpu_to_le16(WLAN_CAPABILITY_IBSS);
break;
case IW_MODE_AUTO:
capability = cpu_to_le16(net->capabilities &
(WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS));
break;
default:
/* bleh. we don't ever go to these modes */
printk(KERN_ERR PFX "invalid iw_mode!\n");
break;
}
/* CF Pollable / CF Poll Request */
/* Needs to be implemented, for now, the 0's == not supported */
/* Privacy Bit */
capability |= mac->ieee->sec.level ?
cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
/* Short Preamble */
/* Always supported: we probably won't ever be powering devices which
* dont support this... */
capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
/* PBCC */
/* Not widely used */
/* Channel Agility */
/* Not widely used */
/* Short Slot */
/* Will be implemented later */
/* DSSS-OFDM */
/* Not widely used */
return capability;
}
/*****************************************************************************
* Create Management packets
*****************************************************************************/
/* Creates an association request packet */
static u32
ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
{
u8 *data;
(*pkt) = (struct ieee80211_assoc_request *)ieee80211softmac_alloc_mgt(
2 + /* Capability Info */
2 + /* Listen Interval */
/* SSID IE */
1 + 1 + IW_ESSID_MAX_SIZE +
/* Rates IE */
1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
/* Extended Rates IE */
1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN +
/* WPA IE if present */
mac->wpa.IElen
/* Other IE's? Optional?
* Yeah, probably need an extra IE parameter -- lots of vendors like to
* fill in their own IEs */
);
if (unlikely((*pkt) == NULL))
return 0;
ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
/* Fill in the capabilities */
(*pkt)->capability = ieee80211softmac_capabilities(mac, net);
/* Fill in Listen Interval (?) */
(*pkt)->listen_interval = cpu_to_le16(10);
data = (u8 *)(*pkt)->info_element;
/* Add SSID */
data = ieee80211softmac_add_essid(data, &net->essid);
/* Add Rates */
data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
/* Add WPA IE */
if (mac->wpa.IElen && mac->wpa.IE) {
memcpy(data, mac->wpa.IE, mac->wpa.IElen);
data += mac->wpa.IElen;
}
/* Return the number of used bytes */
return (data - (u8*)(*pkt));
}
/* Create a reassociation request packet */
static u32
ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt,
struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
{
u8 *data;
(*pkt) = (struct ieee80211_reassoc_request *)ieee80211softmac_alloc_mgt(
2 + /* Capability Info */
2 + /* Listen Interval */
ETH_ALEN + /* AP MAC */
/* SSID IE */
1 + 1 + IW_ESSID_MAX_SIZE +
/* Rates IE */
1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
/* Extended Rates IE */
1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
/* Other IE's? */
);
if (unlikely((*pkt) == NULL))
return 0;
ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid);
/* Fill in the capabilities */
(*pkt)->capability = ieee80211softmac_capabilities(mac, net);
/* Fill in Listen Interval (?) */
(*pkt)->listen_interval = cpu_to_le16(10);
/* Fill in the current AP MAC */
memcpy((*pkt)->current_ap, mac->ieee->bssid, ETH_ALEN);
data = (u8 *)(*pkt)->info_element;
/* Add SSID */
data = ieee80211softmac_add_essid(data, &net->essid);
/* Add Rates */
data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
/* Return packet size */
return (data - (u8 *)(*pkt));
}
/* Create an authentication packet */
static u32
ieee80211softmac_auth(struct ieee80211_auth **pkt,
struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
u16 transaction, u16 status, int *encrypt_mpdu)
{
u8 *data;
int auth_mode = mac->ieee->sec.auth_mode;
int is_shared_response = (auth_mode == WLAN_AUTH_SHARED_KEY
&& transaction == IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE);
/* Allocate Packet */
(*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt(
2 + /* Auth Algorithm */
2 + /* Auth Transaction Seq */
2 + /* Status Code */
/* Challenge Text IE */
(is_shared_response ? 1 + 1 + net->challenge_len : 0)
);
if (unlikely((*pkt) == NULL))
return 0;
ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid);
/* Algorithm */
(*pkt)->algorithm = cpu_to_le16(auth_mode);
/* Transaction */
(*pkt)->transaction = cpu_to_le16(transaction);
/* Status */
(*pkt)->status = cpu_to_le16(status);
data = (u8 *)(*pkt)->info_element;
/* Challenge Text */
if (is_shared_response) {
*data = MFIE_TYPE_CHALLENGE;
data++;
/* Copy the challenge in */
*data = net->challenge_len;
data++;
memcpy(data, net->challenge, net->challenge_len);
data += net->challenge_len;
/* Make sure this frame gets encrypted with the shared key */
*encrypt_mpdu = 1;
} else
*encrypt_mpdu = 0;
/* Return the packet size */
return (data - (u8 *)(*pkt));
}
/* Create a disassocation or deauthentication packet */
static u32
ieee80211softmac_disassoc_deauth(struct ieee80211_disassoc **pkt,
struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
u16 type, u16 reason)
{
/* Allocate Packet */
(*pkt) = (struct ieee80211_disassoc *)ieee80211softmac_alloc_mgt(2);
if (unlikely((*pkt) == NULL))
return 0;
ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), type, net->bssid, net->bssid);
/* Reason */
(*pkt)->reason = cpu_to_le16(reason);
/* Return the packet size */
return (2 + IEEE80211_3ADDR_LEN);
}
/* Create a probe request packet */
static u32
ieee80211softmac_probe_req(struct ieee80211_probe_request **pkt,
struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid)
{
u8 *data;
/* Allocate Packet */
(*pkt) = (struct ieee80211_probe_request *)ieee80211softmac_alloc_mgt(
/* SSID of requested network */
1 + 1 + IW_ESSID_MAX_SIZE +
/* Rates IE */
1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
/* Extended Rates IE */
1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
);
if (unlikely((*pkt) == NULL))
return 0;
ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_REQ, NULL, NULL);
data = (u8 *)(*pkt)->info_element;
/* Add ESSID (can be NULL) */
data = ieee80211softmac_add_essid(data, essid);
/* Add Rates */
data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
/* Return packet size */
return (data - (u8 *)(*pkt));
}
/* Create a probe response packet */
/* FIXME: Not complete */
static u32
ieee80211softmac_probe_resp(struct ieee80211_probe_response **pkt,
struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
{
u8 *data;
/* Allocate Packet */
(*pkt) = (struct ieee80211_probe_response *)ieee80211softmac_alloc_mgt(
8 + /* Timestamp */
2 + /* Beacon Interval */
2 + /* Capability Info */
/* SSID IE */
1 + 1 + IW_ESSID_MAX_SIZE +
7 + /* FH Parameter Set */
2 + /* DS Parameter Set */
8 + /* CF Parameter Set */
4 /* IBSS Parameter Set */
);
if (unlikely((*pkt) == NULL))
return 0;
ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_RESP, net->bssid, net->bssid);
data = (u8 *)(*pkt)->info_element;
/* Return the packet size */
return (data - (u8 *)(*pkt));
}
/* Sends a manangement packet
* FIXME: document the use of the arg parameter
* for _AUTH: (transaction #) | (status << 16)
*/
int
ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
void *ptrarg, u32 type, u32 arg)
{
void *pkt = NULL;
u32 pkt_size = 0;
int encrypt_mpdu = 0;
switch(type) {
case IEEE80211_STYPE_ASSOC_REQ:
pkt_size = ieee80211softmac_assoc_req((struct ieee80211_assoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
break;
case IEEE80211_STYPE_REASSOC_REQ:
pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
break;
case IEEE80211_STYPE_AUTH:
pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16), &encrypt_mpdu);
break;
case IEEE80211_STYPE_DISASSOC:
case IEEE80211_STYPE_DEAUTH:
pkt_size = ieee80211softmac_disassoc_deauth((struct ieee80211_disassoc **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, type, (u16)(arg & 0xFFFF));
break;
case IEEE80211_STYPE_PROBE_REQ:
pkt_size = ieee80211softmac_probe_req((struct ieee80211_probe_request **)(&pkt), mac, (struct ieee80211softmac_essid *)ptrarg);
break;
case IEEE80211_STYPE_PROBE_RESP:
pkt_size = ieee80211softmac_probe_resp((struct ieee80211_probe_response **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
break;
default:
printkl(KERN_DEBUG PFX "Unsupported Management Frame type: %i\n", type);
return -EINVAL;
};
if(pkt_size == 0 || pkt == NULL) {
printkl(KERN_DEBUG PFX "Error, packet is nonexistant or 0 length\n");
return -ENOMEM;
}
/* Send the packet to the ieee80211 layer for tx */
/* we defined softmac->mgmt_xmit for this. Should we keep it
* as it is (that means we'd need to wrap this into a txb),
* modify the prototype (so it matches this function),
* or get rid of it alltogether?
* Does this work for you now?
*/
ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt,
IEEE80211_3ADDR_LEN, pkt_size, encrypt_mpdu);
kfree(pkt);
return 0;
}
/* Beacon handling */
int ieee80211softmac_handle_beacon(struct net_device *dev,
struct ieee80211_beacon *beacon,
struct ieee80211_network *network)
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
/* This might race, but we don't really care and it's not worth
* adding heavyweight locking in this fastpath.
*/
if (mac->associnfo.associated) {
if (memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
ieee80211softmac_process_erp(mac, network->erp_value);
}
return 0;
}
File diff suppressed because it is too large Load Diff
@@ -1,244 +0,0 @@
/*
* Internal softmac API definitions.
*
* Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
* Joseph Jezak <josejx@gentoo.org>
* Larry Finger <Larry.Finger@lwfinger.net>
* Danny van Dyk <kugelfang@gentoo.org>
* Michael Buesch <mbuesch@freenet.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* The full GNU General Public License is included in this distribution in the
* file called COPYING.
*/
#ifndef IEEE80211SOFTMAC_PRIV_H_
#define IEEE80211SOFTMAC_PRIV_H_
#include <net/ieee80211softmac.h>
#include <net/ieee80211softmac_wx.h>
#include <linux/kernel.h>
#include <linux/stringify.h>
#define PFX "SoftMAC: "
#ifdef assert
# undef assert
#endif
#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
#define assert(expr) \
do { \
if (unlikely(!(expr))) { \
printkl(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", #expr, \
__FILE__, __LINE__, __func__); \
} \
} while (0)
#else
#define assert(expr) do {} while (0)
#endif
/* rate limited printk(). */
#ifdef printkl
# undef printkl
#endif
#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0)
/* rate limited printk() for debugging */
#ifdef dprintkl
# undef dprintkl
#endif
#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
# define dprintkl printkl
#else
# define dprintkl(f, x...) do { /* nothing */ } while (0)
#endif
/* debugging printk() */
#ifdef dprintk
# undef dprintk
#endif
#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
# define dprintk(f, x...) do { printk(f ,##x); } while (0)
#else
# define dprintk(f, x...) do { /* nothing */ } while (0)
#endif
/* private definitions and prototypes */
/*** prototypes from _scan.c */
void ieee80211softmac_scan(struct work_struct *work);
/* for internal use if scanning is needed */
int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac);
void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac);
void ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *mac);
/* for use by _module.c to assign to the callbacks */
int ieee80211softmac_start_scan_implementation(struct net_device *dev);
void ieee80211softmac_stop_scan_implementation(struct net_device *dev);
void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev);
/*** Network prototypes from _module.c */
struct ieee80211softmac_network * ieee80211softmac_create_network(
struct ieee80211softmac_device *mac, struct ieee80211_network *net);
void ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
struct ieee80211softmac_network *net);
void ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
struct ieee80211softmac_network *net);
void ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
struct ieee80211softmac_network *net);
void ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
struct ieee80211softmac_network *net);
struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid_locked(
struct ieee80211softmac_device *mac, u8 *ea);
struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid(
struct ieee80211softmac_device *mac, u8 *ea);
struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid_locked(
struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid(
struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
struct ieee80211softmac_network *
ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
struct ieee80211softmac_essid *essid);
struct ieee80211softmac_network *
ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
struct ieee80211softmac_essid *essid);
/* Rates related */
void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
u8 erp_value);
int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac);
void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
return ieee80211softmac_lower_rate_delta(mac, rate, 1);
}
static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
{
return ieee80211softmac_lower_rate_delta(mac, rate, 2);
}
/*** prototypes from _io.c */
int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
void* ptrarg, u32 type, u32 arg);
int ieee80211softmac_handle_beacon(struct net_device *dev,
struct ieee80211_beacon *beacon,
struct ieee80211_network *network);
/*** prototypes from _auth.c */
/* do these have to go into the public header? */
int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net);
int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason);
/* for use by _module.c to assign to the callbacks */
int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth);
int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth);
/*** prototypes from _assoc.c */
void ieee80211softmac_assoc_work(struct work_struct *work);
int ieee80211softmac_handle_assoc_response(struct net_device * dev,
struct ieee80211_assoc_response * resp,
struct ieee80211_network * network);
int ieee80211softmac_handle_disassoc(struct net_device * dev,
struct ieee80211_disassoc * disassoc);
int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
struct ieee80211_reassoc_request * reassoc);
void ieee80211softmac_assoc_timeout(struct work_struct *work);
void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason);
void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac);
/* some helper functions */
static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
{
return (sm->start_scan == ieee80211softmac_start_scan_implementation) &&
(sm->stop_scan == ieee80211softmac_stop_scan_implementation) &&
(sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation);
}
static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm)
{
return ((sm->start_scan != ieee80211softmac_start_scan_implementation) &&
(sm->stop_scan != ieee80211softmac_stop_scan_implementation) &&
(sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation)
) || ieee80211softmac_scan_handlers_check_self(sm);
}
#define IEEE80211SOFTMAC_PROBE_DELAY HZ/50
#define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ)
struct ieee80211softmac_network {
struct list_head list; /* List */
/* Network information copied from ieee80211_network */
u8 bssid[ETH_ALEN];
u8 channel;
struct ieee80211softmac_essid essid;
struct ieee80211softmac_ratesinfo supported_rates;
/* SoftMAC specific */
u16 authenticating:1, /* Status Flags */
authenticated:1,
auth_desynced_once:1;
u8 erp_value; /* Saved ERP value */
u16 capabilities; /* Capabilities bitfield */
u8 challenge_len; /* Auth Challenge length */
char *challenge; /* Challenge Text */
};
/* structure used to keep track of networks we're auth'ing to */
struct ieee80211softmac_auth_queue_item {
struct list_head list; /* List head */
struct ieee80211softmac_network *net; /* Network to auth */
struct ieee80211softmac_device *mac; /* SoftMAC device */
u8 retry; /* Retry limit */
u8 state; /* Auth State */
struct delayed_work work; /* Work queue */
};
/* scanning information */
struct ieee80211softmac_scaninfo {
u8 current_channel_idx,
number_channels;
struct ieee80211_channel *channels;
u8 started:1,
stop:1;
u8 skip_flags;
struct completion finished;
struct delayed_work softmac_scan;
struct ieee80211softmac_device *mac;
};
/* private event struct */
struct ieee80211softmac_event {
struct list_head list;
int event_type;
void *event_context;
struct delayed_work work;
notify_function_ptr fun;
void *context;
struct ieee80211softmac_device *mac;
};
void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context);
void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context);
int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
void ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac);
#endif /* IEEE80211SOFTMAC_PRIV_H_ */
@@ -1,254 +0,0 @@
/*
* Scanning routines.
*
* These are not exported because they're assigned to the function pointers.
*
* Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
* Joseph Jezak <josejx@gentoo.org>
* Larry Finger <Larry.Finger@lwfinger.net>
* Danny van Dyk <kugelfang@gentoo.org>
* Michael Buesch <mbuesch@freenet.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* The full GNU General Public License is included in this distribution in the
* file called COPYING.
*/
#include <linux/completion.h>
#include "ieee80211softmac_priv.h"
/* internal, use to trigger scanning if needed.
* Returns -EBUSY if already scanning,
* result of start_scan otherwise */
int
ieee80211softmac_start_scan(struct ieee80211softmac_device *sm)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&sm->lock, flags);
if (sm->scanning)
{
spin_unlock_irqrestore(&sm->lock, flags);
return -EINPROGRESS;
}
sm->scanning = 1;
spin_unlock_irqrestore(&sm->lock, flags);
ret = sm->start_scan(sm->dev);
if (ret) {
spin_lock_irqsave(&sm->lock, flags);
sm->scanning = 0;
spin_unlock_irqrestore(&sm->lock, flags);
}
return ret;
}
void
ieee80211softmac_stop_scan(struct ieee80211softmac_device *sm)
{
unsigned long flags;
spin_lock_irqsave(&sm->lock, flags);
if (!sm->scanning) {
spin_unlock_irqrestore(&sm->lock, flags);
return;
}
spin_unlock_irqrestore(&sm->lock, flags);
sm->stop_scan(sm->dev);
}
void
ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm)
{
unsigned long flags;
spin_lock_irqsave(&sm->lock, flags);
if (!sm->scanning) {
spin_unlock_irqrestore(&sm->lock, flags);
return;
}
spin_unlock_irqrestore(&sm->lock, flags);
sm->wait_for_scan(sm->dev);
}
/* internal scanning implementation follows */
void ieee80211softmac_scan(struct work_struct *work)
{
int invalid_channel;
u8 current_channel_idx;
struct ieee80211softmac_scaninfo *si =
container_of(work, struct ieee80211softmac_scaninfo,
softmac_scan.work);
struct ieee80211softmac_device *sm = si->mac;
unsigned long flags;
while (!(si->stop) && (si->current_channel_idx < si->number_channels)) {
current_channel_idx = si->current_channel_idx;
si->current_channel_idx++; /* go to the next channel */
invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags);
if (!invalid_channel) {
sm->set_channel(sm->dev, si->channels[current_channel_idx].channel);
// FIXME make this user configurable (active/passive)
if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0))
printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n");
/* also send directed management frame for the network we're looking for */
// TODO: is this if correct, or should we do this only if scanning from assoc request?
if (sm->associnfo.req_essid.len)
ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0);
spin_lock_irqsave(&sm->lock, flags);
if (unlikely(!sm->running)) {
/* Prevent reschedule on workqueue flush */
spin_unlock_irqrestore(&sm->lock, flags);
break;
}
queue_delayed_work(sm->wq, &si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
spin_unlock_irqrestore(&sm->lock, flags);
return;
} else {
dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel);
}
}
spin_lock_irqsave(&sm->lock, flags);
cancel_delayed_work(&si->softmac_scan);
si->started = 0;
spin_unlock_irqrestore(&sm->lock, flags);
dprintk(PFX "Scanning finished: scanned %d channels starting with channel %d\n",
sm->scaninfo->number_channels, sm->scaninfo->channels[0].channel);
ieee80211softmac_scan_finished(sm);
complete_all(&sm->scaninfo->finished);
}
static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac)
{
/* ugh. can we call this without having the spinlock held? */
struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC);
if (unlikely(!info))
return NULL;
INIT_DELAYED_WORK(&info->softmac_scan, ieee80211softmac_scan);
info->mac = mac;
init_completion(&info->finished);
return info;
}
int ieee80211softmac_start_scan_implementation(struct net_device *dev)
{
struct ieee80211softmac_device *sm = ieee80211_priv(dev);
unsigned long flags;
if (!(dev->flags & IFF_UP))
return -ENODEV;
assert(ieee80211softmac_scan_handlers_check_self(sm));
if (!ieee80211softmac_scan_handlers_check_self(sm))
return -EINVAL;
spin_lock_irqsave(&sm->lock, flags);
/* it looks like we need to hold the lock here
* to make sure we don't allocate two of these... */
if (unlikely(!sm->scaninfo))
sm->scaninfo = allocate_scaninfo(sm);
if (unlikely(!sm->scaninfo)) {
spin_unlock_irqrestore(&sm->lock, flags);
return -ENOMEM;
}
sm->scaninfo->skip_flags = IEEE80211_CH_INVALID;
if (0 /* not scanning in IEEE802.11b */)//TODO
sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY;
if (0 /* IEEE802.11a */) {//TODO
sm->scaninfo->channels = sm->ieee->geo.a;
sm->scaninfo->number_channels = sm->ieee->geo.a_channels;
} else {
sm->scaninfo->channels = sm->ieee->geo.bg;
sm->scaninfo->number_channels = sm->ieee->geo.bg_channels;
}
sm->scaninfo->current_channel_idx = 0;
sm->scaninfo->started = 1;
sm->scaninfo->stop = 0;
INIT_COMPLETION(sm->scaninfo->finished);
queue_delayed_work(sm->wq, &sm->scaninfo->softmac_scan, 0);
spin_unlock_irqrestore(&sm->lock, flags);
return 0;
}
void ieee80211softmac_stop_scan_implementation(struct net_device *dev)
{
struct ieee80211softmac_device *sm = ieee80211_priv(dev);
unsigned long flags;
assert(ieee80211softmac_scan_handlers_check_self(sm));
if (!ieee80211softmac_scan_handlers_check_self(sm))
return;
spin_lock_irqsave(&sm->lock, flags);
assert(sm->scaninfo != NULL);
if (sm->scaninfo) {
if (sm->scaninfo->started)
sm->scaninfo->stop = 1;
else
complete_all(&sm->scaninfo->finished);
}
spin_unlock_irqrestore(&sm->lock, flags);
}
void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev)
{
struct ieee80211softmac_device *sm = ieee80211_priv(dev);
unsigned long flags;
assert(ieee80211softmac_scan_handlers_check_self(sm));
if (!ieee80211softmac_scan_handlers_check_self(sm))
return;
spin_lock_irqsave(&sm->lock, flags);
if (!sm->scaninfo->started) {
spin_unlock_irqrestore(&sm->lock, flags);
return;
}
spin_unlock_irqrestore(&sm->lock, flags);
wait_for_completion(&sm->scaninfo->finished);
}
/* this is what drivers (that do scanning) call when they're done */
void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
{
unsigned long flags;
spin_lock_irqsave(&sm->lock, flags);
sm->scanning = 0;
spin_unlock_irqrestore(&sm->lock, flags);
if (sm->associnfo.bssvalid) {
struct ieee80211softmac_network *net;
net = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
if (net)
sm->set_channel(sm->dev, net->channel);
}
ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
}
EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);
File diff suppressed because it is too large Load Diff