Commit 370121e5190a86a2d8a717ecd6f33028c7dc6fd4

Authored by Johannes Berg
Committed by John W. Linville
1 parent 1c2e02750b

[PATCH] wireless: Add softmac layer to the kernel

Signed-off-by: John W. Linville <linville@tuxdriver.com>

Showing 13 changed files with 2920 additions and 0 deletions Side-by-side Diff

include/net/ieee80211softmac.h
  1 +#ifndef IEEE80211SOFTMAC_H_
  2 +#define IEEE80211SOFTMAC_H_
  3 +
  4 +#include <linux/kernel.h>
  5 +#include <linux/spinlock.h>
  6 +#include <linux/workqueue.h>
  7 +#include <linux/list.h>
  8 +#include <net/ieee80211.h>
  9 +
  10 +/* Once the API is considered more or less stable,
  11 + * this should be incremented on API incompatible changes.
  12 + */
  13 +#define IEEE80211SOFTMAC_API 0
  14 +
  15 +#define IEEE80211SOFTMAC_MAX_RATES_LEN 8
  16 +#define IEEE80211SOFTMAC_MAX_EX_RATES_LEN 255
  17 +
  18 +struct ieee80211softmac_ratesinfo {
  19 + u8 count;
  20 + u8 rates[IEEE80211SOFTMAC_MAX_RATES_LEN + IEEE80211SOFTMAC_MAX_EX_RATES_LEN];
  21 +};
  22 +
  23 +/* internal structures */
  24 +struct ieee80211softmac_network;
  25 +struct ieee80211softmac_scaninfo;
  26 +
  27 +struct ieee80211softmac_essid {
  28 + u8 len;
  29 + char data[IW_ESSID_MAX_SIZE+1];
  30 +};
  31 +
  32 +struct ieee80211softmac_wpa {
  33 + char *IE;
  34 + int IElen;
  35 + int IEbuflen;
  36 +};
  37 +
  38 +/*
  39 + * Information about association
  40 + *
  41 + * Do we need a lock for this?
  42 + * We only ever use this structure inlined
  43 + * into our global struct. I've used its lock,
  44 + * but maybe we need a local one here?
  45 + */
  46 +struct ieee80211softmac_assoc_info {
  47 + /*
  48 + * This is the requested ESSID. It is written
  49 + * only by the WX handlers.
  50 + *
  51 + */
  52 + struct ieee80211softmac_essid req_essid;
  53 + /*
  54 + * the ESSID of the network we're currently
  55 + * associated (or trying) to. This is
  56 + * updated to the network's actual ESSID
  57 + * even if the requested ESSID was 'ANY'
  58 + */
  59 + struct ieee80211softmac_essid associate_essid;
  60 +
  61 + /* BSSID we're trying to associate to */
  62 + char bssid[ETH_ALEN];
  63 +
  64 + /* some flags.
  65 + * static_essid is valid if the essid is constant,
  66 + * this is for use by the wx handlers only.
  67 + *
  68 + * associating is true, if the network has been
  69 + * auth'ed on and we are in the process of associating.
  70 + *
  71 + * bssvalid is true if we found a matching network
  72 + * and saved it's BSSID into the bssid above.
  73 + */
  74 + u8 static_essid:1,
  75 + associating:1,
  76 + bssvalid:1;
  77 +
  78 + /* Scan retries remaining */
  79 + int scan_retry;
  80 +
  81 + struct work_struct work;
  82 + struct work_struct timeout;
  83 +};
  84 +
  85 +enum {
  86 + IEEE80211SOFTMAC_AUTH_OPEN_REQUEST = 1,
  87 + IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE = 2,
  88 +};
  89 +
  90 +enum {
  91 + IEEE80211SOFTMAC_AUTH_SHARED_REQUEST = 1,
  92 + IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE = 2,
  93 + IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE = 3,
  94 + IEEE80211SOFTMAC_AUTH_SHARED_PASS = 4,
  95 +};
  96 +
  97 +/* We should make these tunable
  98 + * AUTH_TIMEOUT seems really long, but that's what it is in BSD */
  99 +#define IEEE80211SOFTMAC_AUTH_TIMEOUT (12 * HZ)
  100 +#define IEEE80211SOFTMAC_AUTH_RETRY_LIMIT 5
  101 +#define IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT 3
  102 +
  103 +struct ieee80211softmac_txrates {
  104 + /* The Bit-Rate to be used for multicast frames. */
  105 + u8 mcast_rate;
  106 + /* The Bit-Rate to be used for multicast fallback
  107 + * (If the device supports fallback and hardware-retry)
  108 + */
  109 + u8 mcast_fallback;
  110 + /* The Bit-Rate to be used for any other (normal) data packet. */
  111 + u8 default_rate;
  112 + /* The Bit-Rate to be used for default fallback
  113 + * (If the device supports fallback and hardware-retry)
  114 + */
  115 + u8 default_fallback;
  116 +};
  117 +
  118 +/* Bits for txrates_change callback. */
  119 +#define IEEE80211SOFTMAC_TXRATECHG_DEFAULT (1 << 0) /* default_rate */
  120 +#define IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK (1 << 1) /* default_fallback */
  121 +#define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */
  122 +#define IEEE80211SOFTMAC_TXRATECHG_MCAST_FBACK (1 << 3) /* mcast_fallback */
  123 +
  124 +struct ieee80211softmac_device {
  125 + /* 802.11 structure for data stuff */
  126 + struct ieee80211_device *ieee;
  127 + struct net_device *dev;
  128 +
  129 + /* only valid if associated, then holds the Association ID */
  130 + u16 association_id;
  131 +
  132 + /* the following methods are callbacks that the driver
  133 + * using this framework has to assign
  134 + */
  135 +
  136 + /* always assign these */
  137 + void (*set_bssid_filter)(struct net_device *dev, const u8 *bssid);
  138 + void (*set_channel)(struct net_device *dev, u8 channel);
  139 +
  140 + /* assign if you need it, informational only */
  141 + void (*link_change)(struct net_device *dev);
  142 +
  143 + /* If the hardware can do scanning, assign _all_ three of these callbacks.
  144 + * When the scan finishes, call ieee80211softmac_scan_finished().
  145 + */
  146 +
  147 + /* when called, start_scan is guaranteed to not be called again
  148 + * until you call ieee80211softmac_scan_finished.
  149 + * Return 0 if scanning could start, error otherwise.
  150 + * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_start_scan */
  151 + int (*start_scan)(struct net_device *dev);
  152 + /* this should block until after ieee80211softmac_scan_finished was called
  153 + * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_wait_for_scan */
  154 + void (*wait_for_scan)(struct net_device *dev);
  155 + /* stop_scan aborts a scan, but is asynchronous.
  156 + * if you want to wait for it too, use wait_for_scan
  157 + * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_stop_scan */
  158 + void (*stop_scan)(struct net_device *dev);
  159 +
  160 + /* we'll need something about beacons here too, for AP or ad-hoc modes */
  161 +
  162 + /* Transmission rates to be used by the driver.
  163 + * The SoftMAC figures out the best possible rates.
  164 + * The driver just needs to read them.
  165 + */
  166 + struct ieee80211softmac_txrates txrates;
  167 + /* If the driver needs to do stuff on TX rate changes, assign this callback. */
  168 + void (*txrates_change)(struct net_device *dev,
  169 + u32 changes, /* see IEEE80211SOFTMAC_TXRATECHG flags */
  170 + const struct ieee80211softmac_txrates *rates_before_change);
  171 +
  172 + /* private stuff follows */
  173 + /* this lock protects this structure */
  174 + spinlock_t lock;
  175 +
  176 + /* couple of flags */
  177 + u8 scanning:1, /* protects scanning from being done multiple times at once */
  178 + associated:1;
  179 +
  180 + /* workquere for scannning, ... */
  181 + struct workqueue_struct *workqueue;
  182 +
  183 + struct ieee80211softmac_scaninfo *scaninfo;
  184 + struct ieee80211softmac_assoc_info associnfo;
  185 +
  186 + struct list_head auth_queue;
  187 + struct list_head events;
  188 +
  189 + struct ieee80211softmac_ratesinfo ratesinfo;
  190 + int txrate_badness;
  191 +
  192 + /* WPA stuff */
  193 + struct ieee80211softmac_wpa wpa;
  194 +
  195 + /* we need to keep a list of network structs we copied */
  196 + struct list_head network_list;
  197 +
  198 + /* This must be the last item so that it points to the data
  199 + * allocated beyond this structure by alloc_ieee80211 */
  200 + u8 priv[0];
  201 +};
  202 +
  203 +extern void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm);
  204 +
  205 +static inline void * ieee80211softmac_priv(struct net_device *dev)
  206 +{
  207 + return ((struct ieee80211softmac_device *)ieee80211_priv(dev))->priv;
  208 +}
  209 +
  210 +extern struct net_device * alloc_ieee80211softmac(int sizeof_priv);
  211 +extern void free_ieee80211softmac(struct net_device *dev);
  212 +
  213 +/* Call this function if you detect a lost TX fragment.
  214 + * (If the device indicates failure of ACK RX, for example.)
  215 + * It is wise to call this function if you are able to detect lost packets,
  216 + * because it contributes to the TX Rates auto adjustment.
  217 + */
  218 +extern void ieee80211softmac_fragment_lost(struct net_device *dev,
  219 + u16 wireless_sequence_number);
  220 +/* Call this function before _start to tell the softmac what rates
  221 + * the hw supports. The rates parameter is copied, so you can
  222 + * free it right after calling this function.
  223 + * Note that the rates need to be sorted. */
  224 +extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates);
  225 +
  226 +/* Start the SoftMAC. Call this after you initialized the device
  227 + * and it is ready to run.
  228 + */
  229 +extern void ieee80211softmac_start(struct net_device *dev);
  230 +/* Stop the SoftMAC. Call this before you shutdown the device. */
  231 +extern void ieee80211softmac_stop(struct net_device *dev);
  232 +
  233 +/*
  234 + * Event system
  235 + */
  236 +
  237 +/* valid event types */
  238 +#define IEEE80211SOFTMAC_EVENT_ANY -1 /*private use only*/
  239 +#define IEEE80211SOFTMAC_EVENT_SCAN_FINISHED 0
  240 +#define IEEE80211SOFTMAC_EVENT_ASSOCIATED 1
  241 +#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED 2
  242 +#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT 3
  243 +#define IEEE80211SOFTMAC_EVENT_AUTHENTICATED 4
  244 +#define IEEE80211SOFTMAC_EVENT_AUTH_FAILED 5
  245 +#define IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT 6
  246 +#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND 7
  247 +/* keep this updated! */
  248 +#define IEEE80211SOFTMAC_EVENT_LAST 7
  249 +/*
  250 + * If you want to be notified of certain events, you can call
  251 + * ieee80211softmac_notify[_atomic] with
  252 + * - event set to one of the constants below
  253 + * - fun set to a function pointer of the appropriate type
  254 + * - context set to the context data you want passed
  255 + * The return value is 0, or an error.
  256 + */
  257 +typedef void (*notify_function_ptr)(struct net_device *dev, void *context);
  258 +
  259 +#define ieee80211softmac_notify(dev, event, fun, context) ieee80211softmac_notify_gfp(dev, event, fun, context, GFP_KERNEL);
  260 +#define ieee80211softmac_notify_atomic(dev, event, fun, context) ieee80211softmac_notify_gfp(dev, event, fun, context, GFP_ATOMIC);
  261 +
  262 +extern int ieee80211softmac_notify_gfp(struct net_device *dev,
  263 + int event, notify_function_ptr fun, void *context, gfp_t gfp_mask);
  264 +
  265 +/* To clear pending work (for ifconfig down, etc.) */
  266 +extern void
  267 +ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm);
  268 +
  269 +#endif /* IEEE80211SOFTMAC_H_ */
include/net/ieee80211softmac_wx.h
  1 +#ifndef _IEEE80211SOFTMAC_WX_H
  2 +#define _IEEE80211SOFTMAC_WX_H
  3 +
  4 +#include <net/ieee80211softmac.h>
  5 +#include <net/iw_handler.h>
  6 +
  7 +extern int
  8 +ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
  9 + struct iw_request_info *info,
  10 + union iwreq_data *data,
  11 + char *extra);
  12 +
  13 +extern int
  14 +ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
  15 + struct iw_request_info *info,
  16 + union iwreq_data *data,
  17 + char *extra);
  18 +
  19 +extern int
  20 +ieee80211softmac_wx_set_essid(struct net_device *net_dev,
  21 + struct iw_request_info *info,
  22 + union iwreq_data *data,
  23 + char *extra);
  24 +
  25 +extern int
  26 +ieee80211softmac_wx_get_essid(struct net_device *net_dev,
  27 + struct iw_request_info *info,
  28 + union iwreq_data *data,
  29 + char *extra);
  30 +
  31 +extern int
  32 +ieee80211softmac_wx_set_rate(struct net_device *net_dev,
  33 + struct iw_request_info *info,
  34 + union iwreq_data *data,
  35 + char *extra);
  36 +
  37 +extern int
  38 +ieee80211softmac_wx_get_rate(struct net_device *net_dev,
  39 + struct iw_request_info *info,
  40 + union iwreq_data *data,
  41 + char *extra);
  42 +
  43 +extern int
  44 +ieee80211softmac_wx_get_wap(struct net_device *net_dev,
  45 + struct iw_request_info *info,
  46 + union iwreq_data *data,
  47 + char *extra);
  48 +
  49 +extern int
  50 +ieee80211softmac_wx_set_wap(struct net_device *net_dev,
  51 + struct iw_request_info *info,
  52 + union iwreq_data *data,
  53 + char *extra);
  54 +
  55 +extern int
  56 +ieee80211softmac_wx_set_genie(struct net_device *dev,
  57 + struct iw_request_info *info,
  58 + union iwreq_data *wrqu,
  59 + char *extra);
  60 +
  61 +extern int
  62 +ieee80211softmac_wx_get_genie(struct net_device *dev,
  63 + struct iw_request_info *info,
  64 + union iwreq_data *wrqu,
  65 + char *extra);
  66 +#endif /* _IEEE80211SOFTMAC_WX */
net/ieee80211/Kconfig
... ... @@ -65,4 +65,6 @@
65 65  
66 66 This can be compiled as a modules and it will be called
67 67 "ieee80211_crypt_tkip".
  68 +
  69 +source "net/ieee80211/softmac/Kconfig"
net/ieee80211/softmac/Kconfig
  1 +config IEEE80211_SOFTMAC
  2 + tristate "Software MAC add-on to the IEEE 802.11 networking stack"
  3 + ---help---
  4 + This option enables the hardware independent software MAC addon
  5 + for the IEEE 802.11 networking stack.
  6 +
  7 +config IEEE80211_SOFTMAC_DEBUG
  8 + bool "Enable full debugging output"
  9 + depends on IEEE80211_SOFTMAC
net/ieee80211/softmac/Makefile
  1 +obj-$(CONFIG_IEEE80211_SOFTMAC) := ieee80211softmac.o
  2 +ieee80211softmac-objs := \
  3 + ieee80211softmac_io.o \
  4 + ieee80211softmac_auth.o \
  5 + ieee80211softmac_module.o \
  6 + ieee80211softmac_scan.o \
  7 + ieee80211softmac_wx.o \
  8 + ieee80211softmac_assoc.o \
  9 + ieee80211softmac_event.o
net/ieee80211/softmac/ieee80211softmac_assoc.c
  1 +#include "ieee80211softmac_priv.h"
  2 +
  3 +/*
  4 + * Overview
  5 + *
  6 + * Before you can associate, you have to authenticate.
  7 + *
  8 + */
  9 +
  10 +/* Sends out an association request to the desired AP */
  11 +static void
  12 +ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
  13 +{
  14 + unsigned long flags;
  15 + function_enter();
  16 + /* Switch to correct channel for this network */
  17 + mac->set_channel(mac->dev, net->channel);
  18 +
  19 + /* Send association request */
  20 + ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_ASSOC_REQ, 0);
  21 +
  22 + dprintk(KERN_INFO PFX "sent association request!\n");
  23 +
  24 + /* Change the state to associating */
  25 + spin_lock_irqsave(&mac->lock, flags);
  26 + mac->associnfo.associating = 1;
  27 + mac->associated = 0; /* just to make sure */
  28 + spin_unlock_irqrestore(&mac->lock, flags);
  29 +
  30 + /* Set a timer for timeout */
  31 + /* FIXME: make timeout configurable */
  32 + queue_delayed_work(mac->workqueue, &mac->associnfo.timeout, 5 * HZ);
  33 +}
  34 +
  35 +void
  36 +ieee80211softmac_assoc_timeout(void *d)
  37 +{
  38 + struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
  39 + unsigned long flags;
  40 +
  41 + function_enter();
  42 +
  43 + spin_lock_irqsave(&mac->lock, flags);
  44 + /* we might race against ieee80211softmac_handle_assoc_response,
  45 + * so make sure only one of us does something */
  46 + if (!mac->associnfo.associating) {
  47 + spin_unlock_irqrestore(&mac->lock, flags);
  48 + return;
  49 + }
  50 + mac->associnfo.associating = 0;
  51 + mac->associnfo.bssvalid = 0;
  52 + mac->associated = 0;
  53 + spin_unlock_irqrestore(&mac->lock, flags);
  54 +
  55 + dprintk(KERN_INFO PFX "assoc request timed out!\n");
  56 + /* FIXME: we need to know the network here. that requires a bit of restructuring */
  57 + ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
  58 +}
  59 +
  60 +static void
  61 +ieee80211softmac_reassoc(struct ieee80211softmac_device *mac)
  62 +{
  63 + function_enter();
  64 +}
  65 +
  66 +
  67 +/* Sends out a disassociation request to the desired AP */
  68 +static void
  69 +ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason)
  70 +{
  71 + unsigned long flags;
  72 + struct ieee80211softmac_network *found;
  73 + function_enter();
  74 +
  75 + if (mac->associnfo.bssvalid && mac->associated) {
  76 + found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
  77 + if (found)
  78 + ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
  79 + } else if (mac->associnfo.associating) {
  80 + cancel_delayed_work(&mac->associnfo.timeout);
  81 + }
  82 +
  83 + /* Change our state */
  84 + spin_lock_irqsave(&mac->lock, flags);
  85 + /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */
  86 + mac->associated = 0;
  87 + mac->associnfo.associating = 0;
  88 + spin_unlock_irqrestore(&mac->lock, flags);
  89 +}
  90 +
  91 +static inline int
  92 +we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
  93 +{
  94 + int idx, search, found;
  95 + u8 rate, search_rate;
  96 +
  97 + for (idx = 0; idx < (from_len); idx++) {
  98 + rate = (from)[idx];
  99 + if (!(rate & IEEE80211_BASIC_RATE_MASK))
  100 + continue;
  101 + found = 0;
  102 + rate &= ~IEEE80211_BASIC_RATE_MASK;
  103 + for (search = 0; search < mac->ratesinfo.count; search++) {
  104 + search_rate = mac->ratesinfo.rates[search];
  105 + search_rate &= ~IEEE80211_BASIC_RATE_MASK;
  106 + if (rate == search_rate) {
  107 + found = 1;
  108 + break;
  109 + }
  110 + }
  111 + if (!found)
  112 + return 0;
  113 + }
  114 + return 1;
  115 +}
  116 +
  117 +static int
  118 +network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net)
  119 +{
  120 + /* we cannot associate to networks whose name we don't know */
  121 + if (ieee80211_is_empty_essid(net->ssid, net->ssid_len))
  122 + return 0;
  123 + /* do not associate to a network whose BSSBasicRateSet we cannot support */
  124 + if (!we_support_all_basic_rates(mac, net->rates, net->rates_len))
  125 + return 0;
  126 + /* do we really need to check the ex rates? */
  127 + if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len))
  128 + return 0;
  129 +
  130 + /* if 'ANY' network requested, take any that doesn't have privacy enabled */
  131 + if (mac->associnfo.req_essid.len == 0
  132 + && !(net->capability & WLAN_CAPABILITY_PRIVACY))
  133 + return 1;
  134 + if (net->ssid_len != mac->associnfo.req_essid.len)
  135 + return 0;
  136 + if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len))
  137 + return 1;
  138 + return 0;
  139 +}
  140 +
  141 +static void
  142 +ieee80211softmac_assoc_notify(struct net_device *dev, void *context)
  143 +{
  144 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  145 + ieee80211softmac_assoc_work((void*)mac);
  146 +}
  147 +
  148 +/* This function is called to handle userspace requests (asynchronously) */
  149 +void
  150 +ieee80211softmac_assoc_work(void *d)
  151 +{
  152 + struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
  153 + struct ieee80211softmac_network *found = NULL;
  154 + struct ieee80211_network *net = NULL, *best = NULL;
  155 + unsigned long flags;
  156 +
  157 + function_enter();
  158 +
  159 + /* meh */
  160 + if (mac->associated)
  161 + ieee80211softmac_disassoc(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
  162 +
  163 + /* try to find the requested network in our list, if we found one already */
  164 + if (mac->associnfo.bssvalid)
  165 + found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
  166 +
  167 + /* Search the ieee80211 networks for this network if we didn't find it */
  168 + if (!found)
  169 + {
  170 + spin_lock_irqsave(&mac->ieee->lock, flags);
  171 + list_for_each_entry(net, &mac->ieee->network_list, list) {
  172 + /* we're supposed to find the network with
  173 + * the best signal here, as we're asked to join
  174 + * any network with a specific ESSID, and many
  175 + * different ones could have that.
  176 + *
  177 + * I'll for now implement just finding one at all
  178 + *
  179 + * We also should take into account the rateset
  180 + * here to find the best BSSID to try.
  181 + */
  182 + if (network_matches_request(mac, net)) {
  183 + if (!best) {
  184 + best = net;
  185 + continue;
  186 + }
  187 + /* we already had a matching network, so
  188 + * compare their properties to get the
  189 + * better of the two ... (see above)
  190 + */
  191 + /* TODO */
  192 + /* for now, just */
  193 + break;
  194 + }
  195 + }
  196 + /* if we unlock here, we might get interrupted and the `best'
  197 + * pointer could go stale */
  198 + if (best) {
  199 + found = ieee80211softmac_create_network(mac, best);
  200 + /* if found is still NULL, then we got -ENOMEM somewhere */
  201 + if (found)
  202 + ieee80211softmac_add_network(mac, found);
  203 + }
  204 + spin_unlock_irqrestore(&mac->ieee->lock, flags);
  205 + }
  206 +
  207 + if (!found) {
  208 + if (mac->associnfo.scan_retry > 0) {
  209 + spin_lock_irqsave(&mac->lock, flags);
  210 + mac->associnfo.scan_retry--;
  211 + spin_unlock_irqrestore(&mac->lock, flags);
  212 +
  213 + /* We know of no such network. Let's scan.
  214 + * NB: this also happens if we had no memory to copy the network info...
  215 + * Maybe we can hope to have more memory after scanning finishes ;)
  216 + */
  217 + dprintk(KERN_INFO PFX "Associate: Network not known, trying to initiate scan: ");
  218 + ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify, NULL);
  219 + if (ieee80211softmac_start_scan(mac))
  220 + dprintk("failed.\n");
  221 + else
  222 + dprintk("ok.\n");
  223 + return;
  224 + }
  225 + else {
  226 + spin_lock_irqsave(&mac->lock, flags);
  227 + mac->associnfo.associating = 0;
  228 + mac->associated = 0;
  229 + spin_unlock_irqrestore(&mac->lock, flags);
  230 +
  231 + dprintk(KERN_INFO PFX "Unable to find network after scan!\n");
  232 + ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
  233 + return;
  234 + }
  235 + }
  236 +
  237 + mac->associnfo.bssvalid = 1;
  238 + memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN);
  239 + /* copy the ESSID for displaying it */
  240 + mac->associnfo.associate_essid.len = found->essid.len;
  241 + memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
  242 +
  243 + /* we found a network! authenticate (if necessary) and associate to it. */
  244 + if (!found->authenticated) {
  245 + /* This relies on the fact that _auth_req only queues the work,
  246 + * otherwise adding the notification would be racy. */
  247 + if (!ieee80211softmac_auth_req(mac, found)) {
  248 + dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
  249 + ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify, NULL, GFP_KERNEL);
  250 + } else {
  251 + printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
  252 + ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
  253 + }
  254 + return;
  255 + }
  256 + /* finally! now we can start associating */
  257 + ieee80211softmac_assoc(mac, found);
  258 +}
  259 +
  260 +/* call this to do whatever is necessary when we're associated */
  261 +static void
  262 +ieee80211softmac_associated(struct ieee80211softmac_device *mac,
  263 + struct ieee80211_assoc_response * resp,
  264 + struct ieee80211softmac_network *net)
  265 +{
  266 + mac->associnfo.associating = 0;
  267 + mac->associated = 1;
  268 + if (mac->set_bssid_filter)
  269 + mac->set_bssid_filter(mac->dev, net->bssid);
  270 + memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
  271 + mac->dev->flags |= IFF_RUNNING;
  272 +
  273 + mac->association_id = le16_to_cpup(&resp->aid);
  274 +}
  275 +
  276 +/* received frame handling functions */
  277 +int
  278 +ieee80211softmac_handle_assoc_response(struct net_device * dev,
  279 + struct ieee80211_assoc_response * resp,
  280 + struct ieee80211_network * _ieee80211_network_do_not_use)
  281 +{
  282 + /* NOTE: the network parameter has to be ignored by
  283 + * this code because it is the ieee80211's pointer
  284 + * to the struct, not ours (we made a copy)
  285 + */
  286 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  287 + u16 status = le16_to_cpup(&resp->status);
  288 + struct ieee80211softmac_network *network = NULL;
  289 + unsigned long flags;
  290 +
  291 + spin_lock_irqsave(&mac->lock, flags);
  292 +
  293 + if (!mac->associnfo.associating) {
  294 + /* we race against the timeout function, so make sure
  295 + * only one of us can do work */
  296 + spin_unlock_irqrestore(&mac->lock, flags);
  297 + return 0;
  298 + }
  299 + network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3);
  300 +
  301 + /* someone sending us things without us knowing him? Ignore. */
  302 + if (!network) {
  303 + dprintk(KERN_INFO PFX "Received unrequested assocation response from " MAC_FMT "\n", MAC_ARG(resp->header.addr3));
  304 + spin_unlock_irqrestore(&mac->lock, flags);
  305 + return 0;
  306 + }
  307 +
  308 + /* now that we know it was for us, we can cancel the timeout */
  309 + cancel_delayed_work(&mac->associnfo.timeout);
  310 +
  311 + switch (status) {
  312 + case 0:
  313 + dprintk(KERN_INFO PFX "associated!\n");
  314 + ieee80211softmac_associated(mac, resp, network);
  315 + ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network);
  316 + break;
  317 + case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
  318 + if (!network->auth_desynced_once) {
  319 + /* there seem to be a few rare cases where our view of
  320 + * the world is obscured, or buggy APs that don't DEAUTH
  321 + * us properly. So we handle that, but allow it only once.
  322 + */
  323 + printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n");
  324 + network->authenticated = 0;
  325 + /* we don't want to do this more than once ... */
  326 + network->auth_desynced_once = 1;
  327 + queue_work(mac->workqueue, &mac->associnfo.work);
  328 + break;
  329 + }
  330 + default:
  331 + dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
  332 + mac->associnfo.associating = 0;
  333 + mac->associnfo.bssvalid = 0;
  334 + mac->associated = 0;
  335 + ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
  336 + }
  337 +
  338 + spin_unlock_irqrestore(&mac->lock, flags);
  339 + return 0;
  340 +}
  341 +
  342 +int
  343 +ieee80211softmac_handle_disassoc(struct net_device * dev,
  344 + struct ieee80211_disassoc *disassoc)
  345 +{
  346 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  347 + unsigned long flags;
  348 + dprintk(KERN_INFO PFX "got disassoc frame\n");
  349 +
  350 + spin_lock_irqsave(&mac->lock, flags);
  351 + mac->associnfo.bssvalid = 0;
  352 + mac->associated = 0;
  353 + spin_unlock_irqrestore(&mac->lock, flags);
  354 +
  355 + return 0;
  356 +}
net/ieee80211/softmac/ieee80211softmac_auth.c
  1 +#include "ieee80211softmac_priv.h"
  2 +
  3 +static void ieee80211softmac_auth_queue(void *data);
  4 +
  5 +/* Queues an auth request to the desired AP */
  6 +int
  7 +ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
  8 + struct ieee80211softmac_network *net)
  9 +{
  10 + struct ieee80211softmac_auth_queue_item *auth;
  11 + unsigned long flags;
  12 +
  13 + function_enter();
  14 +
  15 + if (net->authenticating)
  16 + return 0;
  17 +
  18 + /* Add the network if it's not already added */
  19 + ieee80211softmac_add_network(mac, net);
  20 +
  21 + dprintk(KERN_NOTICE PFX "Queueing Authentication Request to "MAC_FMT"\n", MAC_ARG(net->bssid));
  22 + /* Queue the auth request */
  23 + auth = (struct ieee80211softmac_auth_queue_item *)
  24 + kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL);
  25 + if(auth == NULL)
  26 + return -ENOMEM;
  27 +
  28 + auth->net = net;
  29 + auth->mac = mac;
  30 + auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
  31 + auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
  32 + INIT_WORK(&auth->work, &ieee80211softmac_auth_queue, (void *)auth);
  33 +
  34 + /* Lock (for list) */
  35 + spin_lock_irqsave(&mac->lock, flags);
  36 +
  37 + /* add to list */
  38 + list_add_tail(&auth->list, &mac->auth_queue);
  39 + queue_work(mac->workqueue, &auth->work);
  40 + spin_unlock_irqrestore(&mac->lock, flags);
  41 +
  42 + return 0;
  43 +}
  44 +
  45 +
  46 +/* Sends an auth request to the desired AP and handles timeouts */
  47 +static void
  48 +ieee80211softmac_auth_queue(void *data)
  49 +{
  50 + struct ieee80211softmac_device *mac;
  51 + struct ieee80211softmac_auth_queue_item *auth;
  52 + struct ieee80211softmac_network *net;
  53 + unsigned long flags;
  54 +
  55 + function_enter();
  56 +
  57 + auth = (struct ieee80211softmac_auth_queue_item *)data;
  58 + net = auth->net;
  59 + mac = auth->mac;
  60 +
  61 + if(auth->retry > 0) {
  62 + /* Switch to correct channel for this network */
  63 + mac->set_channel(mac->dev, net->channel);
  64 +
  65 + /* Lock and set flags */
  66 + spin_lock_irqsave(&mac->lock, flags);
  67 + net->authenticated = 0;
  68 + net->authenticating = 1;
  69 + /* add a timeout call so we eventually give up waiting for an auth reply */
  70 + queue_delayed_work(mac->workqueue, &auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
  71 + auth->retry--;
  72 + spin_unlock_irqrestore(&mac->lock, flags);
  73 + if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state))
  74 + dprintk(KERN_NOTICE PFX "Sending Authentication Request to "MAC_FMT" failed (this shouldn't happen, wait for the timeout).\n", MAC_ARG(net->bssid));
  75 + else
  76 + dprintk(KERN_NOTICE PFX "Sent Authentication Request to "MAC_FMT".\n", MAC_ARG(net->bssid));
  77 + return;
  78 + }
  79 +
  80 + printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid));
  81 + /* Remove this item from the queue */
  82 + spin_lock_irqsave(&mac->lock, flags);
  83 + ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
  84 + cancel_delayed_work(&auth->work); /* just to make sure... */
  85 + list_del(&auth->list);
  86 + spin_unlock_irqrestore(&mac->lock, flags);
  87 + /* Free it */
  88 + kfree(auth);
  89 +}
  90 +
  91 +/* Handle the auth response from the AP
  92 + * This should be registered with ieee80211 as handle_auth
  93 + */
  94 +int
  95 +ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
  96 +{
  97 +
  98 + struct list_head *list_ptr;
  99 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  100 + struct ieee80211softmac_auth_queue_item *aq = NULL;
  101 + struct ieee80211softmac_network *net = NULL;
  102 + unsigned long flags;
  103 + u8 * data;
  104 +
  105 + function_enter();
  106 +
  107 + /* Find correct auth queue item */
  108 + spin_lock_irqsave(&mac->lock, flags);
  109 + list_for_each(list_ptr, &mac->auth_queue) {
  110 + aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
  111 + net = aq->net;
  112 + if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN))
  113 + break;
  114 + else
  115 + aq = NULL;
  116 + }
  117 + spin_unlock_irqrestore(&mac->lock, flags);
  118 +
  119 + /* Make sure that we've got an auth queue item for this request */
  120 + if(aq == NULL)
  121 + {
  122 + printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2));
  123 + /* Error #? */
  124 + return -1;
  125 + }
  126 +
  127 + /* Check for out of order authentication */
  128 + if(!net->authenticating)
  129 + {
  130 + printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2));
  131 + return -1;
  132 + }
  133 +
  134 + /* Parse the auth packet */
  135 + switch(auth->algorithm) {
  136 + case WLAN_AUTH_OPEN:
  137 + /* Check the status code of the response */
  138 +
  139 + switch(auth->status) {
  140 + case WLAN_STATUS_SUCCESS:
  141 + /* Update the status to Authenticated */
  142 + spin_lock_irqsave(&mac->lock, flags);
  143 + net->authenticating = 0;
  144 + net->authenticated = 1;
  145 + spin_unlock_irqrestore(&mac->lock, flags);
  146 +
  147 + /* Send event */
  148 + printkl(KERN_NOTICE PFX "Open Authentication completed with "MAC_FMT"\n", MAC_ARG(net->bssid));
  149 + ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
  150 + break;
  151 + default:
  152 + /* Lock and reset flags */
  153 + spin_lock_irqsave(&mac->lock, flags);
  154 + net->authenticated = 0;
  155 + net->authenticating = 0;
  156 + spin_unlock_irqrestore(&mac->lock, flags);
  157 +
  158 + printkl(KERN_NOTICE PFX "Open Authentication with "MAC_FMT" failed, error code: %i\n",
  159 + MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
  160 + /* Count the error? */
  161 + break;
  162 + }
  163 + goto free_aq;
  164 + break;
  165 + case WLAN_AUTH_SHARED_KEY:
  166 + /* Figure out where we are in the process */
  167 + switch(auth->transaction) {
  168 + case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
  169 + /* Check to make sure we have a challenge IE */
  170 + data = (u8 *)auth->info_element;
  171 + if(*data++ != MFIE_TYPE_CHALLENGE){
  172 + printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
  173 + break;
  174 + }
  175 + /* Save the challenge */
  176 + spin_lock_irqsave(&mac->lock, flags);
  177 + net->challenge_len = *data++;
  178 + if(net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
  179 + net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
  180 + if(net->challenge != NULL)
  181 + kfree(net->challenge);
  182 + net->challenge = kmalloc(net->challenge_len, GFP_ATOMIC);
  183 + memcpy(net->challenge, data, net->challenge_len);
  184 + aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
  185 + spin_unlock_irqrestore(&mac->lock, flags);
  186 +
  187 + /* Switch to correct channel for this network */
  188 + mac->set_channel(mac->dev, net->channel);
  189 +
  190 + /* Send our response (How to encrypt?) */
  191 + ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
  192 + break;
  193 + case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
  194 + /* Check the status code of the response */
  195 + switch(auth->status) {
  196 + case WLAN_STATUS_SUCCESS:
  197 + /* Update the status to Authenticated */
  198 + spin_lock_irqsave(&mac->lock, flags);
  199 + net->authenticating = 0;
  200 + net->authenticated = 1;
  201 + spin_unlock_irqrestore(&mac->lock, flags);
  202 + printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n",
  203 + MAC_ARG(net->bssid));
  204 + break;
  205 + default:
  206 + printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n",
  207 + MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
  208 + /* Lock and reset flags */
  209 + spin_lock_irqsave(&mac->lock, flags);
  210 + net->authenticating = 0;
  211 + net->authenticated = 0;
  212 + spin_unlock_irqrestore(&mac->lock, flags);
  213 + /* Count the error? */
  214 + break;
  215 + }
  216 + goto free_aq;
  217 + break;
  218 + default:
  219 + printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction);
  220 + break;
  221 + }
  222 + goto free_aq;
  223 + break;
  224 + default:
  225 + /* ERROR */
  226 + goto free_aq;
  227 + break;
  228 + }
  229 + return 0;
  230 +free_aq:
  231 + /* Cancel the timeout */
  232 + spin_lock_irqsave(&mac->lock, flags);
  233 + cancel_delayed_work(&aq->work);
  234 + /* Remove this item from the queue */
  235 + list_del(&aq->list);
  236 + spin_unlock_irqrestore(&mac->lock, flags);
  237 +
  238 + /* Free it */
  239 + kfree(aq);
  240 + return 0;
  241 +}
  242 +
  243 +/*
  244 + * Handle deauthorization
  245 + */
  246 +void
  247 +ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
  248 + struct ieee80211softmac_network *net)
  249 +{
  250 + struct ieee80211softmac_auth_queue_item *aq = NULL;
  251 + struct list_head *list_ptr;
  252 + unsigned long flags;
  253 +
  254 + function_enter();
  255 +
  256 + /* Lock and reset status flags */
  257 + spin_lock_irqsave(&mac->lock, flags);
  258 + net->authenticating = 0;
  259 + net->authenticated = 0;
  260 +
  261 + /* Find correct auth queue item, if it exists */
  262 + list_for_each(list_ptr, &mac->auth_queue) {
  263 + aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
  264 + if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN))
  265 + break;
  266 + else
  267 + aq = NULL;
  268 + }
  269 +
  270 + /* Cancel pending work */
  271 + if(aq != NULL)
  272 + /* Not entirely safe? What about running work? */
  273 + cancel_delayed_work(&aq->work);
  274 +
  275 + /* Free our network ref */
  276 + ieee80211softmac_del_network_locked(mac, net);
  277 + if(net->challenge != NULL)
  278 + kfree(net->challenge);
  279 + kfree(net);
  280 +
  281 + /* let's try to re-associate */
  282 + queue_work(mac->workqueue, &mac->associnfo.work);
  283 + spin_unlock_irqrestore(&mac->lock, flags);
  284 +}
  285 +
  286 +/*
  287 + * Sends a deauth request to the desired AP
  288 + */
  289 +int
  290 +ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac,
  291 + struct ieee80211softmac_network *net, int reason)
  292 +{
  293 + int ret;
  294 +
  295 + function_enter();
  296 +
  297 + /* Make sure the network is authenticated */
  298 + if (!net->authenticated)
  299 + {
  300 + printkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
  301 + /* Error okay? */
  302 + return -EPERM;
  303 + }
  304 +
  305 + /* Send the de-auth packet */
  306 + if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason)))
  307 + return ret;
  308 +
  309 + ieee80211softmac_deauth_from_net(mac, net);
  310 + return 0;
  311 +}
  312 +
  313 +/*
  314 + * This should be registered with ieee80211 as handle_deauth
  315 + */
  316 +int
  317 +ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_auth *auth)
  318 +{
  319 +
  320 + struct ieee80211softmac_network *net = NULL;
  321 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  322 +
  323 + function_enter();
  324 +
  325 + if (!auth) {
  326 + dprintk("deauth without deauth packet. eek!\n");
  327 + return 0;
  328 + }
  329 +
  330 + net = ieee80211softmac_get_network_by_bssid(mac, auth->header.addr2);
  331 +
  332 + if (net == NULL) {
  333 + printkl(KERN_DEBUG PFX "Recieved deauthentication packet from "MAC_FMT", but that network is unknown.\n",
  334 + MAC_ARG(auth->header.addr2));
  335 + return 0;
  336 + }
  337 +
  338 + /* Make sure the network is authenticated */
  339 + if(!net->authenticated)
  340 + {
  341 + printkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
  342 + /* Error okay? */
  343 + return -EPERM;
  344 + }
  345 +
  346 + ieee80211softmac_deauth_from_net(mac, net);
  347 + return 0;
  348 +}
net/ieee80211/softmac/ieee80211softmac_event.c
  1 +#include "ieee80211softmac_priv.h"
  2 +
  3 +/*
  4 + * Event system
  5 + * Also see comments in public header file
  6 + *
  7 + * Each event has associated to it
  8 + * - an event type (see constants in public header)
  9 + * - an event context (see below)
  10 + * - the function to be called
  11 + * - a context (extra parameter to call the function with)
  12 + * - and the softmac struct
  13 + *
  14 + * The event context is private and can only be used from
  15 + * within this module. Its meaning varies with the event
  16 + * type:
  17 + * SCAN_FINISHED: no special meaning
  18 + * ASSOCIATED,
  19 + * ASSOCIATE_FAILED,
  20 + * ASSOCIATE_TIMEOUT,
  21 + * AUTHENTICATED,
  22 + * AUTH_FAILED,
  23 + * AUTH_TIMEOUT: a pointer to the network struct
  24 + * ...
  25 + * Code within this module can use the event context to be only
  26 + * called when the event is true for that specific context
  27 + * as per above table.
  28 + * If the event context is NULL, then the notification is always called,
  29 + * regardless of the event context. The event context is not passed to
  30 + * the callback, it is assumed that the context suffices.
  31 + *
  32 + * You can also use the event context only by setting the event type
  33 + * to -1 (private use only), in which case you'll be notified
  34 + * whenever the event context matches.
  35 + */
  36 +
  37 +static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
  38 + "scan finished",
  39 + "associated",
  40 + "associating failed",
  41 + "associating timed out",
  42 + "authenticated",
  43 + "authenticating failed",
  44 + "authenticating timed out",
  45 + "associating failed because no suitable network was found",
  46 +};
  47 +
  48 +
  49 +static void
  50 +ieee80211softmac_notify_callback(void *d)
  51 +{
  52 + struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d;
  53 + kfree(d);
  54 +
  55 + event.fun(event.mac->dev, event.context);
  56 +}
  57 +
  58 +int
  59 +ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
  60 + int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask)
  61 +{
  62 + struct ieee80211softmac_event *eventptr;
  63 + unsigned long flags;
  64 +
  65 + if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST)
  66 + return -ENOSYS;
  67 +
  68 + if (!fun)
  69 + return -EINVAL;
  70 +
  71 + eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask);
  72 + if (!eventptr)
  73 + return -ENOMEM;
  74 +
  75 + eventptr->event_type = event;
  76 + INIT_WORK(&eventptr->work, ieee80211softmac_notify_callback, eventptr);
  77 + eventptr->fun = fun;
  78 + eventptr->context = context;
  79 + eventptr->mac = mac;
  80 + eventptr->event_context = event_context;
  81 +
  82 + spin_lock_irqsave(&mac->lock, flags);
  83 + list_add(&eventptr->list, &mac->events);
  84 + spin_unlock_irqrestore(&mac->lock, flags);
  85 +
  86 + return 0;
  87 +}
  88 +
  89 +int
  90 +ieee80211softmac_notify_gfp(struct net_device *dev,
  91 + int event, notify_function_ptr fun, void *context, gfp_t gfp_mask)
  92 +{
  93 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  94 +
  95 + if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST)
  96 + return -ENOSYS;
  97 +
  98 + return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask);
  99 +}
  100 +EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp);
  101 +
  102 +/* private -- calling all callbacks that were specified */
  103 +void
  104 +ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
  105 +{
  106 + struct ieee80211softmac_event *eventptr, *tmp;
  107 + union iwreq_data wrqu;
  108 + char *msg;
  109 +
  110 + if (event >= 0) {
  111 + msg = event_descriptions[event];
  112 + wrqu.data.length = strlen(msg);
  113 + wireless_send_event(mac->dev, IWEVCUSTOM, &wrqu, msg);
  114 + }
  115 +
  116 + if (!list_empty(&mac->events))
  117 + list_for_each_entry_safe(eventptr, tmp, &mac->events, list) {
  118 + if ((eventptr->event_type == event || eventptr->event_type == -1)
  119 + && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
  120 + list_del(&eventptr->list);
  121 + queue_work(mac->workqueue, &eventptr->work);
  122 + }
  123 + }
  124 +}
  125 +
  126 +void
  127 +ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx)
  128 +{
  129 + unsigned long flags;
  130 +
  131 + spin_lock_irqsave(&mac->lock, flags);
  132 + ieee80211softmac_call_events_locked(mac, event, event_ctx);
  133 +
  134 + spin_unlock_irqrestore(&mac->lock, flags);
  135 +}
net/ieee80211/softmac/ieee80211softmac_io.c
  1 +/*
  2 + * Some parts based on code from net80211
  3 + * Copyright (c) 2001 Atsushi Onoe
  4 + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
  5 + * All rights reserved.
  6 + *
  7 + * Redistribution and use in source and binary forms, with or without
  8 + * modification, are permitted provided that the following conditions
  9 + * are met:
  10 + * 1. Redistributions of source code must retain the above copyright
  11 + * notice, this list of conditions and the following disclaimer.
  12 + * 2. Redistributions in binary form must reproduce the above copyright
  13 + * notice, this list of conditions and the following disclaimer in the
  14 + * documentation and/or other materials provided with the distribution.
  15 + * 3. The name of the author may not be used to endorse or promote products
  16 + * derived from this software without specific prior written permission.
  17 + *
  18 + * Alternatively, this software may be distributed under the terms of the
  19 + * GNU General Public License ("GPL") version 2 as published by the Free
  20 + * Software Foundation.
  21 + *
  22 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  23 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  24 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  25 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  26 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  27 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  31 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32 + *
  33 + */
  34 +
  35 +#include "ieee80211softmac_priv.h"
  36 +
  37 +/* Helper functions for inserting data into the frames */
  38 +
  39 +/*
  40 + * Adds an ESSID element to the frame
  41 + *
  42 + */
  43 +static u8 *
  44 +ieee80211softmac_add_essid(u8 *dst, struct ieee80211softmac_essid *essid)
  45 +{
  46 + if (essid) {
  47 + *dst++ = MFIE_TYPE_SSID;
  48 + *dst++ = essid->len;
  49 + memcpy(dst, essid->data, essid->len);
  50 + return dst+essid->len;
  51 + } else {
  52 + *dst++ = MFIE_TYPE_SSID;
  53 + *dst++ = 0;
  54 + return dst;
  55 + }
  56 +}
  57 +
  58 +/* Adds Supported Rates and if required Extended Rates Information Element
  59 + * to the frame, ASSUMES WE HAVE A SORTED LIST OF RATES */
  60 +static u8 *
  61 +ieee80211softmac_frame_add_rates(u8 *dst, const struct ieee80211softmac_ratesinfo *r)
  62 +{
  63 + int cck_len, ofdm_len;
  64 + *dst++ = MFIE_TYPE_RATES;
  65 +
  66 + for(cck_len=0; ieee80211_is_cck_rate(r->rates[cck_len]) && (cck_len < r->count);cck_len++);
  67 +
  68 + if(cck_len > IEEE80211SOFTMAC_MAX_RATES_LEN)
  69 + cck_len = IEEE80211SOFTMAC_MAX_RATES_LEN;
  70 + *dst++ = cck_len;
  71 + memcpy(dst, r->rates, cck_len);
  72 + dst += cck_len;
  73 +
  74 + if(cck_len < r->count){
  75 + for (ofdm_len=0; ieee80211_is_ofdm_rate(r->rates[ofdm_len + cck_len]) && (ofdm_len + cck_len < r->count); ofdm_len++);
  76 + if (ofdm_len > 0) {
  77 + if (ofdm_len > IEEE80211SOFTMAC_MAX_EX_RATES_LEN)
  78 + ofdm_len = IEEE80211SOFTMAC_MAX_EX_RATES_LEN;
  79 + *dst++ = MFIE_TYPE_RATES_EX;
  80 + *dst++ = ofdm_len;
  81 + memcpy(dst, r->rates + cck_len, ofdm_len);
  82 + dst += ofdm_len;
  83 + }
  84 + }
  85 + return dst;
  86 +}
  87 +
  88 +/* Allocate a management frame */
  89 +static u8 *
  90 +ieee80211softmac_alloc_mgt(u32 size)
  91 +{
  92 + u8 * data;
  93 +
  94 + /* Add the header and FCS to the size */
  95 + size = size + IEEE80211_3ADDR_LEN;
  96 + if(size > IEEE80211_DATA_LEN)
  97 + return NULL;
  98 + /* Allocate the frame */
  99 + data = kmalloc(size, GFP_ATOMIC);
  100 + memset(data, 0, size);
  101 + return data;
  102 +}
  103 +
  104 +/*
  105 + * Add a 2 Address Header
  106 + */
  107 +static void
  108 +ieee80211softmac_hdr_2addr(struct ieee80211softmac_device *mac,
  109 + struct ieee80211_hdr_2addr *header, u32 type, u8 *dest)
  110 +{
  111 + /* Fill in the frame control flags */
  112 + header->frame_ctl = cpu_to_le16(type);
  113 + /* Control packets always have WEP turned off */
  114 + if(type > IEEE80211_STYPE_CFENDACK && type < IEEE80211_STYPE_PSPOLL)
  115 + header->frame_ctl |= mac->ieee->sec.level ? cpu_to_le16(IEEE80211_FCTL_PROTECTED) : 0;
  116 +
  117 + /* Fill in the duration */
  118 + header->duration_id = 0;
  119 + /* FIXME: How do I find this?
  120 + * calculate. But most drivers just fill in 0 (except if it's a station id of course) */
  121 +
  122 + /* Fill in the Destination Address */
  123 + if(dest == NULL)
  124 + memset(header->addr1, 0xFF, ETH_ALEN);
  125 + else
  126 + memcpy(header->addr1, dest, ETH_ALEN);
  127 + /* Fill in the Source Address */
  128 + memcpy(header->addr2, mac->ieee->dev->dev_addr, ETH_ALEN);
  129 +
  130 +}
  131 +
  132 +
  133 +/* Add a 3 Address Header */
  134 +static void
  135 +ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac,
  136 + struct ieee80211_hdr_3addr *header, u32 type, u8 *dest, u8 *bssid)
  137 +{
  138 + /* This is common with 2addr, so use that instead */
  139 + ieee80211softmac_hdr_2addr(mac, (struct ieee80211_hdr_2addr *)header, type, dest);
  140 +
  141 + /* Fill in the BSS ID */
  142 + if(bssid == NULL)
  143 + memset(header->addr3, 0xFF, ETH_ALEN);
  144 + else
  145 + memcpy(header->addr3, bssid, ETH_ALEN);
  146 +
  147 + /* Fill in the sequence # */
  148 + /* FIXME: I need to add this to the softmac struct
  149 + * shouldn't the sequence number be in ieee80211? */
  150 +}
  151 +
  152 +
  153 +/*****************************************************************************
  154 + * Create Management packets
  155 + *****************************************************************************/
  156 +
  157 +/* Creates an association request packet */
  158 +u32
  159 +ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
  160 + struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
  161 +{
  162 + u8 *data;
  163 + (*pkt) = (struct ieee80211_assoc_request *)ieee80211softmac_alloc_mgt(
  164 + 2 + /* Capability Info */
  165 + 2 + /* Listen Interval */
  166 + /* SSID IE */
  167 + 1 + 1 + IW_ESSID_MAX_SIZE +
  168 + /* Rates IE */
  169 + 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
  170 + /* Extended Rates IE */
  171 + 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN +
  172 + /* WPA IE if present */
  173 + mac->wpa.IElen
  174 + /* Other IE's? Optional?
  175 + * Yeah, probably need an extra IE parameter -- lots of vendors like to
  176 + * fill in their own IEs */
  177 + );
  178 + if (unlikely((*pkt) == NULL))
  179 + return 0;
  180 + ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
  181 +
  182 + /* Fill in capability Info */
  183 + (*pkt)->capability = (mac->ieee->iw_mode == IW_MODE_MASTER) || (mac->ieee->iw_mode == IW_MODE_INFRA) ?
  184 + cpu_to_le16(WLAN_CAPABILITY_ESS) :
  185 + cpu_to_le16(WLAN_CAPABILITY_IBSS);
  186 + /* Need to add this
  187 + (*pkt)->capability |= mac->ieee->short_slot ?
  188 + cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0;
  189 + */
  190 + (*pkt)->capability |= mac->ieee->sec.level ? cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
  191 + /* Fill in Listen Interval (?) */
  192 + (*pkt)->listen_interval = cpu_to_le16(10);
  193 +
  194 + data = (u8 *)(*pkt)->info_element;
  195 + /* Add SSID */
  196 + data = ieee80211softmac_add_essid(data, &net->essid);
  197 + /* Add Rates */
  198 + data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
  199 + /* Add WPA IE */
  200 + if (mac->wpa.IElen && mac->wpa.IE) {
  201 + memcpy(data, mac->wpa.IE, mac->wpa.IElen);
  202 + data += mac->wpa.IElen;
  203 + }
  204 + /* Return the number of used bytes */
  205 + return (data - (u8*)(*pkt));
  206 +}
  207 +
  208 +/* Create a reassociation request packet */
  209 +u32
  210 +ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt,
  211 + struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
  212 +{
  213 + u8 *data;
  214 + (*pkt) = (struct ieee80211_reassoc_request *)ieee80211softmac_alloc_mgt(
  215 + 2 + /* Capability Info */
  216 + 2 + /* Listen Interval */
  217 + ETH_ALEN + /* AP MAC */
  218 + /* SSID IE */
  219 + 1 + 1 + IW_ESSID_MAX_SIZE +
  220 + /* Rates IE */
  221 + 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
  222 + /* Extended Rates IE */
  223 + 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
  224 + /* Other IE's? */
  225 + );
  226 + if (unlikely((*pkt) == NULL))
  227 + return 0;
  228 + ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid);
  229 +
  230 + /* Fill in capability Info */
  231 + (*pkt)->capability = mac->ieee->iw_mode == IW_MODE_MASTER ?
  232 + cpu_to_le16(WLAN_CAPABILITY_ESS) :
  233 + cpu_to_le16(WLAN_CAPABILITY_IBSS);
  234 + /*
  235 + (*pkt)->capability |= mac->ieee->short_slot ?
  236 + cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0;
  237 + */
  238 + (*pkt)->capability |= mac->ieee->sec.level ?
  239 + cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
  240 +
  241 + /* Fill in Listen Interval (?) */
  242 + (*pkt)->listen_interval = cpu_to_le16(10);
  243 + /* Fill in the current AP MAC */
  244 + memcpy((*pkt)->current_ap, mac->ieee->bssid, ETH_ALEN);
  245 +
  246 + data = (u8 *)(*pkt)->info_element;
  247 + /* Add SSID */
  248 + data = ieee80211softmac_add_essid(data, &net->essid);
  249 + /* Add Rates */
  250 + data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
  251 + /* Return packet size */
  252 + return (data - (u8 *)(*pkt));
  253 +}
  254 +
  255 +/* Create an authentication packet */
  256 +u32
  257 +ieee80211softmac_auth(struct ieee80211_auth **pkt,
  258 + struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
  259 + u16 transaction, u16 status)
  260 +{
  261 + u8 *data;
  262 + /* Allocate Packet */
  263 + (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt(
  264 + 2 + /* Auth Algorithm */
  265 + 2 + /* Auth Transaction Seq */
  266 + 2 + /* Status Code */
  267 + /* Challenge Text IE */
  268 + mac->ieee->open_wep ? 0 :
  269 + 1 + 1 + WLAN_AUTH_CHALLENGE_LEN
  270 + );
  271 + if (unlikely((*pkt) == NULL))
  272 + return 0;
  273 + ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid);
  274 +
  275 + /* Algorithm */
  276 + (*pkt)->algorithm = mac->ieee->open_wep ?
  277 + cpu_to_le16(WLAN_AUTH_OPEN) :
  278 + cpu_to_le16(WLAN_AUTH_SHARED_KEY);
  279 + /* Transaction */
  280 + (*pkt)->transaction = cpu_to_le16(transaction);
  281 + /* Status */
  282 + (*pkt)->status = cpu_to_le16(status);
  283 +
  284 + data = (u8 *)(*pkt)->info_element;
  285 + /* Challenge Text */
  286 + if(!mac->ieee->open_wep){
  287 + *data = MFIE_TYPE_CHALLENGE;
  288 + data++;
  289 +
  290 + /* Copy the challenge in */
  291 + // *data = challenge length
  292 + // data += sizeof(u16);
  293 + // memcpy(data, challenge, challenge length);
  294 + // data += challenge length;
  295 +
  296 + /* Add the full size to the packet length */
  297 + }
  298 +
  299 + /* Return the packet size */
  300 + return (data - (u8 *)(*pkt));
  301 +}
  302 +
  303 +/* Create a disassocation or deauthentication packet */
  304 +u32
  305 +ieee80211softmac_disassoc_deauth(struct ieee80211_disassoc **pkt,
  306 + struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
  307 + u16 type, u16 reason)
  308 +{
  309 + /* Allocate Packet */
  310 + (*pkt) = (struct ieee80211_disassoc *)ieee80211softmac_alloc_mgt(2);
  311 + if (unlikely(pkt == NULL))
  312 + return 0;
  313 + ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), type, net->bssid, net->bssid);
  314 + /* Reason */
  315 + (*pkt)->reason = cpu_to_le16(reason);
  316 + /* Return the packet size */
  317 + return (2 + IEEE80211_3ADDR_LEN);
  318 +}
  319 +
  320 +/* Create a probe request packet */
  321 +u32
  322 +ieee80211softmac_probe_req(struct ieee80211_probe_request **pkt,
  323 + struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid)
  324 +{
  325 + u8 *data;
  326 + /* Allocate Packet */
  327 + (*pkt) = (struct ieee80211_probe_request *)ieee80211softmac_alloc_mgt(
  328 + /* SSID of requested network */
  329 + 1 + 1 + IW_ESSID_MAX_SIZE +
  330 + /* Rates IE */
  331 + 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
  332 + /* Extended Rates IE */
  333 + 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
  334 + );
  335 + if (unlikely((*pkt) == NULL))
  336 + return 0;
  337 + ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_REQ, NULL, NULL);
  338 +
  339 + data = (u8 *)(*pkt)->info_element;
  340 + /* Add ESSID (can be NULL) */
  341 + data = ieee80211softmac_add_essid(data, essid);
  342 + /* Add Rates */
  343 + data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
  344 + /* Return packet size */
  345 + return (data - (u8 *)(*pkt));
  346 +}
  347 +
  348 +/* Create a probe response packet */
  349 +/* FIXME: Not complete */
  350 +u32
  351 +ieee80211softmac_probe_resp(struct ieee80211_probe_response **pkt,
  352 + struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
  353 +{
  354 + u8 *data;
  355 + /* Allocate Packet */
  356 + (*pkt) = (struct ieee80211_probe_response *)ieee80211softmac_alloc_mgt(
  357 + 8 + /* Timestamp */
  358 + 2 + /* Beacon Interval */
  359 + 2 + /* Capability Info */
  360 + /* SSID IE */
  361 + 1 + 1 + IW_ESSID_MAX_SIZE +
  362 + 7 + /* FH Parameter Set */
  363 + 2 + /* DS Parameter Set */
  364 + 8 + /* CF Parameter Set */
  365 + 4 /* IBSS Parameter Set */
  366 + );
  367 + if (unlikely((*pkt) == NULL))
  368 + return 0;
  369 + ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_RESP, net->bssid, net->bssid);
  370 + data = (u8 *)(*pkt)->info_element;
  371 +
  372 + /* Return the packet size */
  373 + return (data - (u8 *)(*pkt));
  374 +}
  375 +
  376 +
  377 +/* Sends a manangement packet
  378 + * FIXME: document the use of the arg parameter
  379 + * for _AUTH: (transaction #) | (status << 16)
  380 + */
  381 +int
  382 +ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
  383 + void *ptrarg, u32 type, u32 arg)
  384 +{
  385 + void *pkt = NULL;
  386 + u32 pkt_size = 0;
  387 +
  388 + switch(type) {
  389 + case IEEE80211_STYPE_ASSOC_REQ:
  390 + pkt_size = ieee80211softmac_assoc_req((struct ieee80211_assoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
  391 + break;
  392 + case IEEE80211_STYPE_REASSOC_REQ:
  393 + pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
  394 + break;
  395 + case IEEE80211_STYPE_AUTH:
  396 + pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16));
  397 + break;
  398 + case IEEE80211_STYPE_DISASSOC:
  399 + case IEEE80211_STYPE_DEAUTH:
  400 + pkt_size = ieee80211softmac_disassoc_deauth((struct ieee80211_disassoc **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, type, (u16)(arg & 0xFFFF));
  401 + break;
  402 + case IEEE80211_STYPE_PROBE_REQ:
  403 + pkt_size = ieee80211softmac_probe_req((struct ieee80211_probe_request **)(&pkt), mac, (struct ieee80211softmac_essid *)ptrarg);
  404 + break;
  405 + case IEEE80211_STYPE_PROBE_RESP:
  406 + pkt_size = ieee80211softmac_probe_resp((struct ieee80211_probe_response **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
  407 + break;
  408 + default:
  409 + printkl(KERN_DEBUG PFX "Unsupported Management Frame type: %i\n", type);
  410 + return -EINVAL;
  411 + };
  412 +
  413 + if(pkt_size == 0 || pkt == NULL) {
  414 + printkl(KERN_DEBUG PFX "Error, packet is nonexistant or 0 length\n");
  415 + return -ENOMEM;
  416 + }
  417 +
  418 + /* Send the packet to the ieee80211 layer for tx */
  419 + /* we defined softmac->mgmt_xmit for this. Should we keep it
  420 + * as it is (that means we'd need to wrap this into a txb),
  421 + * modify the prototype (so it matches this function),
  422 + * or get rid of it alltogether?
  423 + * Does this work for you now?
  424 + */
  425 + ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt, pkt_size);
  426 +
  427 + kfree(pkt);
  428 + return 0;
  429 +}
  430 +
  431 +
  432 +/* Create an rts/cts frame */
  433 +u32
  434 +ieee80211softmac_rts_cts(struct ieee80211_hdr_2addr **pkt,
  435 + struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
  436 + u32 type)
  437 +{
  438 + /* Allocate Packet */
  439 + (*pkt) = kmalloc(IEEE80211_2ADDR_LEN, GFP_ATOMIC);
  440 + memset(*pkt, 0, IEEE80211_2ADDR_LEN);
  441 + if((*pkt) == NULL)
  442 + return 0;
  443 + ieee80211softmac_hdr_2addr(mac, (*pkt), type, net->bssid);
  444 + return IEEE80211_2ADDR_LEN;
  445 +}
  446 +
  447 +
  448 +/* Sends a control packet */
  449 +static int
  450 +ieee80211softmac_send_ctl_frame(struct ieee80211softmac_device *mac,
  451 + struct ieee80211softmac_network *net, u32 type, u32 arg)
  452 +{
  453 + void *pkt = NULL;
  454 + u32 pkt_size = 0;
  455 +
  456 + switch(type) {
  457 + case IEEE80211_STYPE_RTS:
  458 + case IEEE80211_STYPE_CTS:
  459 + pkt_size = ieee80211softmac_rts_cts((struct ieee80211_hdr_2addr **)(&pkt), mac, net, type);
  460 + break;
  461 + default:
  462 + printkl(KERN_DEBUG PFX "Unsupported Control Frame type: %i\n", type);
  463 + return -EINVAL;
  464 + }
  465 +
  466 + if(pkt_size == 0)
  467 + return -ENOMEM;
  468 +
  469 + /* Send the packet to the ieee80211 layer for tx */
  470 + ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *) pkt, pkt_size);
  471 +
  472 + kfree(pkt);
  473 + return 0;
  474 +}
net/ieee80211/softmac/ieee80211softmac_module.c
  1 +#include "ieee80211softmac_priv.h"
  2 +#include <linux/sort.h>
  3 +
  4 +struct net_device *alloc_ieee80211softmac(int sizeof_priv)
  5 +{
  6 + struct ieee80211softmac_device *softmac;
  7 + struct net_device *dev;
  8 +
  9 + dev = alloc_ieee80211(sizeof(struct ieee80211softmac_device) + sizeof_priv);
  10 + softmac = ieee80211_priv(dev);
  11 + softmac->dev = dev;
  12 + softmac->ieee = netdev_priv(dev);
  13 + spin_lock_init(&softmac->lock);
  14 +
  15 + softmac->ieee->handle_auth = ieee80211softmac_auth_resp;
  16 + softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp;
  17 + softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
  18 + softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
  19 + softmac->scaninfo = NULL;
  20 +
  21 + /* TODO: initialise all the other callbacks in the ieee struct
  22 + * (once they're written)
  23 + */
  24 +
  25 + softmac->workqueue = create_workqueue("80211softmac");
  26 + if (!softmac->workqueue)
  27 + goto err_free_ieee80211;
  28 +
  29 + INIT_LIST_HEAD(&softmac->auth_queue);
  30 + INIT_LIST_HEAD(&softmac->network_list);
  31 + INIT_LIST_HEAD(&softmac->events);
  32 +
  33 + INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
  34 + INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
  35 + softmac->start_scan = ieee80211softmac_start_scan_implementation;
  36 + softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
  37 + softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
  38 +
  39 + //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...)
  40 + // It has to be set to the highest rate all stations in the current network can handle.
  41 + softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB;
  42 + softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB;
  43 + /* This is reassigned in ieee80211softmac_start to sane values. */
  44 + softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB;
  45 + softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB;
  46 +
  47 + /* should we also assign softmac->mgmt_xmit here so
  48 + * that it is always valid? If so, we probably want
  49 + * to define a new function for that which just
  50 + * wraps ieee80211_tx_frame
  51 + */
  52 +
  53 + /* until associated, we're not ready */
  54 + dev->flags &= ~IFF_RUNNING;
  55 +
  56 + return dev;
  57 +
  58 +err_free_ieee80211:
  59 + free_ieee80211(dev);
  60 +
  61 + return NULL;
  62 +}
  63 +
  64 +/* Clears the pending work queue items, stops all scans, etc. */
  65 +void
  66 +ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
  67 +{
  68 + unsigned long flags;
  69 + struct ieee80211softmac_event *eventptr, *eventtmp;
  70 + struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
  71 + struct ieee80211softmac_network *netptr, *nettmp;
  72 +
  73 + ieee80211softmac_stop_scan(sm);
  74 + ieee80211softmac_wait_for_scan(sm);
  75 +
  76 + spin_lock_irqsave(&sm->lock, flags);
  77 + /* Free all pending assoc work items */
  78 + cancel_delayed_work(&sm->associnfo.work);
  79 +
  80 + /* Free all pending scan work items */
  81 + if(sm->scaninfo != NULL)
  82 + cancel_delayed_work(&sm->scaninfo->softmac_scan);
  83 +
  84 + /* Free all pending auth work items */
  85 + list_for_each_entry(authptr, &sm->auth_queue, list)
  86 + cancel_delayed_work(&authptr->work);
  87 +
  88 + /* delete all pending event calls and work items */
  89 + list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
  90 + cancel_delayed_work(&eventptr->work);
  91 +
  92 + spin_unlock_irqrestore(&sm->lock, flags);
  93 + flush_workqueue(sm->workqueue);
  94 +
  95 + // now we should be save and no longer need locking...
  96 + spin_lock_irqsave(&sm->lock, flags);
  97 + /* Free all pending auth work items */
  98 + list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
  99 + list_del(&authptr->list);
  100 + kfree(authptr);
  101 + }
  102 +
  103 + /* delete all pending event calls and work items */
  104 + list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
  105 + list_del(&eventptr->list);
  106 + kfree(eventptr);
  107 + }
  108 +
  109 + /* Free all networks */
  110 + list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
  111 + ieee80211softmac_del_network_locked(sm, netptr);
  112 + if(netptr->challenge != NULL)
  113 + kfree(netptr->challenge);
  114 + kfree(netptr);
  115 + }
  116 +
  117 + spin_unlock_irqrestore(&sm->lock, flags);
  118 +}
  119 +
  120 +void free_ieee80211softmac(struct net_device *dev)
  121 +{
  122 + struct ieee80211softmac_device *sm = ieee80211_priv(dev);
  123 + ieee80211softmac_clear_pending_work(sm);
  124 + destroy_workqueue(sm->workqueue);
  125 + kfree(sm->scaninfo);
  126 + kfree(sm->wpa.IE);
  127 + free_ieee80211(dev);
  128 +}
  129 +
  130 +static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
  131 +{
  132 + struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
  133 + /* I took out the sorting check, we're seperating by modulation now. */
  134 + if (ri->count)
  135 + return;
  136 + /* otherwise assume we hav'em all! */
  137 + if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
  138 + ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
  139 + ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
  140 + ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
  141 + ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
  142 + }
  143 + if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
  144 + ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
  145 + ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
  146 + ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
  147 + ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
  148 + ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
  149 + ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
  150 + ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
  151 + ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
  152 + }
  153 +}
  154 +
  155 +void ieee80211softmac_start(struct net_device *dev)
  156 +{
  157 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  158 + struct ieee80211_device *ieee = mac->ieee;
  159 + u32 change = 0;
  160 + struct ieee80211softmac_txrates oldrates;
  161 +
  162 + ieee80211softmac_start_check_rates(mac);
  163 +
  164 + /* TODO: We need some kind of state machine to lower the default rates
  165 + * if we loose too many packets.
  166 + */
  167 + /* Change the default txrate to the highest possible value.
  168 + * The txrate machine will lower it, if it is too high.
  169 + */
  170 + if (mac->txrates_change)
  171 + oldrates = mac->txrates;
  172 + if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
  173 + mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
  174 + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
  175 + mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
  176 + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
  177 + } else if (ieee->modulation & IEEE80211_CCK_MODULATION) {
  178 + mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB;
  179 + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
  180 + mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
  181 + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
  182 + } else
  183 + assert(0);
  184 + if (mac->txrates_change)
  185 + mac->txrates_change(dev, change, &oldrates);
  186 +}
  187 +
  188 +void ieee80211softmac_stop(struct net_device *dev)
  189 +{
  190 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  191 +
  192 + ieee80211softmac_clear_pending_work(mac);
  193 +}
  194 +
  195 +void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
  196 +{
  197 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  198 + unsigned long flags;
  199 +
  200 + spin_lock_irqsave(&mac->lock, flags);
  201 + memcpy(mac->ratesinfo.rates, rates, count);
  202 + mac->ratesinfo.count = count;
  203 + spin_unlock_irqrestore(&mac->lock, flags);
  204 +}
  205 +
  206 +static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
  207 +{
  208 + int i;
  209 + struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
  210 +
  211 + for (i=0; i<ri->count-1; i++) {
  212 + if (ri->rates[i] == rate)
  213 + return ri->rates[i+1];
  214 + }
  215 + /* I guess we can't go any higher... */
  216 + return ri->rates[ri->count];
  217 +}
  218 +
  219 +u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
  220 +{
  221 + int i;
  222 + struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
  223 +
  224 + for (i=delta; i<ri->count; i++) {
  225 + if (ri->rates[i] == rate)
  226 + return ri->rates[i-delta];
  227 + }
  228 + /* I guess we can't go any lower... */
  229 + return ri->rates[0];
  230 +}
  231 +
  232 +static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
  233 + int amount)
  234 +{
  235 + struct ieee80211softmac_txrates oldrates;
  236 + u8 default_rate = mac->txrates.default_rate;
  237 + u8 default_fallback = mac->txrates.default_fallback;
  238 + u32 changes = 0;
  239 +
  240 + //TODO: This is highly experimental code.
  241 + // Maybe the dynamic rate selection does not work
  242 + // and it has to be removed again.
  243 +
  244 +printk("badness %d\n", mac->txrate_badness);
  245 + mac->txrate_badness += amount;
  246 + if (mac->txrate_badness <= -1000) {
  247 + /* Very small badness. Try a faster bitrate. */
  248 + if (mac->txrates_change)
  249 + memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
  250 + default_rate = raise_rate(mac, default_rate);
  251 + changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
  252 + default_fallback = get_fallback_rate(mac, default_rate);
  253 + changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
  254 + mac->txrate_badness = 0;
  255 +printk("Bitrate raised to %u\n", default_rate);
  256 + } else if (mac->txrate_badness >= 10000) {
  257 + /* Very high badness. Try a slower bitrate. */
  258 + if (mac->txrates_change)
  259 + memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
  260 + default_rate = lower_rate(mac, default_rate);
  261 + changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
  262 + default_fallback = get_fallback_rate(mac, default_rate);
  263 + changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
  264 + mac->txrate_badness = 0;
  265 +printk("Bitrate lowered to %u\n", default_rate);
  266 + }
  267 +
  268 + mac->txrates.default_rate = default_rate;
  269 + mac->txrates.default_fallback = default_fallback;
  270 +
  271 + if (changes && mac->txrates_change)
  272 + mac->txrates_change(mac->dev, changes, &oldrates);
  273 +}
  274 +
  275 +void ieee80211softmac_fragment_lost(struct net_device *dev,
  276 + u16 wl_seq)
  277 +{
  278 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  279 + unsigned long flags;
  280 +
  281 + spin_lock_irqsave(&mac->lock, flags);
  282 + ieee80211softmac_add_txrates_badness(mac, 1000);
  283 + //TODO
  284 +
  285 + spin_unlock_irqrestore(&mac->lock, flags);
  286 +}
  287 +
  288 +static int rate_cmp(const void *a_, const void *b_) {
  289 + u8 *a, *b;
  290 + a = (u8*)a_;
  291 + b = (u8*)b_;
  292 + return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
  293 +}
  294 +
  295 +/* Allocate a softmac network struct and fill it from a network */
  296 +struct ieee80211softmac_network *
  297 +ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
  298 + struct ieee80211_network *net)
  299 +{
  300 + struct ieee80211softmac_network *softnet;
  301 + softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
  302 + if(softnet == NULL)
  303 + return NULL;
  304 + memcpy(softnet->bssid, net->bssid, ETH_ALEN);
  305 + softnet->channel = net->channel;
  306 + softnet->essid.len = net->ssid_len;
  307 + memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
  308 +
  309 + /* copy rates over */
  310 + softnet->supported_rates.count = net->rates_len;
  311 + memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
  312 + memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
  313 + softnet->supported_rates.count += net->rates_ex_len;
  314 + sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
  315 +
  316 + softnet->capabilities = net->capability;
  317 + return softnet;
  318 +}
  319 +
  320 +
  321 +/* Add a network to the list, while locked */
  322 +void
  323 +ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
  324 + struct ieee80211softmac_network *add_net)
  325 +{
  326 + struct list_head *list_ptr;
  327 + struct ieee80211softmac_network *softmac_net = NULL;
  328 +
  329 + list_for_each(list_ptr, &mac->network_list) {
  330 + softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
  331 + if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
  332 + break;
  333 + else
  334 + softmac_net = NULL;
  335 + }
  336 + if(softmac_net == NULL)
  337 + list_add(&(add_net->list), &mac->network_list);
  338 +}
  339 +
  340 +/* Add a network to the list, with locking */
  341 +void
  342 +ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
  343 + struct ieee80211softmac_network *add_net)
  344 +{
  345 + unsigned long flags;
  346 + spin_lock_irqsave(&mac->lock, flags);
  347 + ieee80211softmac_add_network_locked(mac, add_net);
  348 + spin_unlock_irqrestore(&mac->lock, flags);
  349 +}
  350 +
  351 +
  352 +/* Delete a network from the list, while locked*/
  353 +void
  354 +ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
  355 + struct ieee80211softmac_network *del_net)
  356 +{
  357 + list_del(&(del_net->list));
  358 +}
  359 +
  360 +/* Delete a network from the list with locking */
  361 +void
  362 +ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
  363 + struct ieee80211softmac_network *del_net)
  364 +{
  365 + unsigned long flags;
  366 + spin_lock_irqsave(&mac->lock, flags);
  367 + ieee80211softmac_del_network_locked(mac, del_net);
  368 + spin_unlock_irqrestore(&mac->lock, flags);
  369 +}
  370 +
  371 +/* Get a network from the list by MAC while locked */
  372 +struct ieee80211softmac_network *
  373 +ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
  374 + u8 *bssid)
  375 +{
  376 + struct list_head *list_ptr;
  377 + struct ieee80211softmac_network *softmac_net = NULL;
  378 + list_for_each(list_ptr, &mac->network_list) {
  379 + softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
  380 + if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
  381 + break;
  382 + else
  383 + softmac_net = NULL;
  384 + }
  385 + return softmac_net;
  386 +}
  387 +
  388 +/* Get a network from the list by BSSID with locking */
  389 +struct ieee80211softmac_network *
  390 +ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
  391 + u8 *bssid)
  392 +{
  393 + unsigned long flags;
  394 + struct ieee80211softmac_network *softmac_net;
  395 +
  396 + spin_lock_irqsave(&mac->lock, flags);
  397 + softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
  398 + spin_unlock_irqrestore(&mac->lock, flags);
  399 + return softmac_net;
  400 +}
  401 +
  402 +/* Get a network from the list by ESSID while locked */
  403 +struct ieee80211softmac_network *
  404 +ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
  405 + struct ieee80211softmac_essid *essid)
  406 +{
  407 + struct list_head *list_ptr;
  408 + struct ieee80211softmac_network *softmac_net = NULL;
  409 +
  410 + list_for_each(list_ptr, &mac->network_list) {
  411 + softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
  412 + if (softmac_net->essid.len == essid->len &&
  413 + !memcmp(softmac_net->essid.data, essid->data, essid->len))
  414 + return softmac_net;
  415 + }
  416 + return NULL;
  417 +}
  418 +
  419 +/* Get a network from the list by ESSID with locking */
  420 +struct ieee80211softmac_network *
  421 +ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
  422 + struct ieee80211softmac_essid *essid)
  423 +{
  424 + unsigned long flags;
  425 + struct ieee80211softmac_network *softmac_net = NULL;
  426 +
  427 + spin_lock_irqsave(&mac->lock, flags);
  428 + softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
  429 + spin_unlock_irqrestore(&mac->lock, flags);
  430 + return softmac_net;
  431 +}
  432 +
  433 +MODULE_LICENSE("GPL");
  434 +
  435 +EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
  436 +EXPORT_SYMBOL_GPL(free_ieee80211softmac);
  437 +EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
  438 +EXPORT_SYMBOL_GPL(ieee80211softmac_start);
  439 +EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
  440 +EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
  441 +EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
net/ieee80211/softmac/ieee80211softmac_priv.h
  1 +#ifndef IEEE80211SOFTMAC_PRIV_H_
  2 +#define IEEE80211SOFTMAC_PRIV_H_
  3 +
  4 +#include <net/ieee80211softmac.h>
  5 +#include <net/ieee80211softmac_wx.h>
  6 +#include <linux/kernel.h>
  7 +#include <linux/stringify.h>
  8 +
  9 +
  10 +#define PFX "SoftMAC: "
  11 +
  12 +#ifdef assert
  13 +# undef assert
  14 +#endif
  15 +#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
  16 +#define assert(expr) \
  17 + do { \
  18 + if (unlikely(!(expr))) { \
  19 + printkl(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", #expr, \
  20 + __FILE__, __LINE__, __FUNCTION__); \
  21 + } \
  22 + } while (0)
  23 +#else
  24 +#define assert(expr) do {} while (0)
  25 +#endif
  26 +
  27 +/* rate limited printk(). */
  28 +#ifdef printkl
  29 +# undef printkl
  30 +#endif
  31 +#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0)
  32 +/* rate limited printk() for debugging */
  33 +#ifdef dprintkl
  34 +# undef dprintkl
  35 +#endif
  36 +#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
  37 +# define dprintkl printkl
  38 +#else
  39 +# define dprintkl(f, x...) do { /* nothing */ } while (0)
  40 +#endif
  41 +
  42 +/* debugging printk() */
  43 +#ifdef dprintk
  44 +# undef dprintk
  45 +#endif
  46 +#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
  47 +# define dprintk(f, x...) do { printk(f ,##x); } while (0)
  48 +#else
  49 +# define dprintk(f, x...) do { /* nothing */ } while (0)
  50 +#endif
  51 +
  52 +#ifdef function_enter
  53 +# undef function_enter
  54 +#endif
  55 +#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
  56 +# define function_enter() do { printk(KERN_DEBUG PFX "%s:%d:%s()\n", __FILE__, __LINE__, __FUNCTION__); } while (0)
  57 +#else
  58 +# define function_enter() do { /* nothing */ } while (0)
  59 +#endif
  60 +
  61 +/* private definitions and prototypes */
  62 +
  63 +/*** prototypes from _scan.c */
  64 +void ieee80211softmac_scan(void *sm);
  65 +/* for internal use if scanning is needed */
  66 +int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac);
  67 +void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac);
  68 +void ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *mac);
  69 +
  70 +/* for use by _module.c to assign to the callbacks */
  71 +int ieee80211softmac_start_scan_implementation(struct net_device *dev);
  72 +void ieee80211softmac_stop_scan_implementation(struct net_device *dev);
  73 +void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev);
  74 +
  75 +/*** Network prototypes from _module.c */
  76 +struct ieee80211softmac_network * ieee80211softmac_create_network(
  77 + struct ieee80211softmac_device *mac, struct ieee80211_network *net);
  78 +void ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
  79 + struct ieee80211softmac_network *net);
  80 +void ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
  81 + struct ieee80211softmac_network *net);
  82 +void ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
  83 + struct ieee80211softmac_network *net);
  84 +void ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
  85 + struct ieee80211softmac_network *net);
  86 +struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid_locked(
  87 + struct ieee80211softmac_device *mac, u8 *ea);
  88 +struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid(
  89 + struct ieee80211softmac_device *mac, u8 *ea);
  90 +struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid_locked(
  91 + struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
  92 +struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid(
  93 + struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
  94 +
  95 +
  96 +/* Rates related */
  97 +u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
  98 +static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
  99 + return ieee80211softmac_lower_rate_delta(mac, rate, 1);
  100 +}
  101 +
  102 +static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
  103 +{
  104 + return ieee80211softmac_lower_rate_delta(mac, rate, 2);
  105 +}
  106 +
  107 +
  108 +/*** prototypes from _io.c */
  109 +int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
  110 + void* ptrarg, u32 type, u32 arg);
  111 +
  112 +/*** prototypes from _auth.c */
  113 +/* do these have to go into the public header? */
  114 +int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net);
  115 +int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason);
  116 +
  117 +/* for use by _module.c to assign to the callbacks */
  118 +int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth);
  119 +int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_auth *auth);
  120 +
  121 +/*** prototypes from _assoc.c */
  122 +void ieee80211softmac_assoc_work(void *d);
  123 +int ieee80211softmac_handle_assoc_response(struct net_device * dev,
  124 + struct ieee80211_assoc_response * resp,
  125 + struct ieee80211_network * network);
  126 +int ieee80211softmac_handle_disassoc(struct net_device * dev,
  127 + struct ieee80211_disassoc * disassoc);
  128 +void ieee80211softmac_assoc_timeout(void *d);
  129 +
  130 +/* some helper functions */
  131 +static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
  132 +{
  133 + return (sm->start_scan == ieee80211softmac_start_scan_implementation) &&
  134 + (sm->stop_scan == ieee80211softmac_stop_scan_implementation) &&
  135 + (sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation);
  136 +}
  137 +
  138 +static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm)
  139 +{
  140 + return ((sm->start_scan != ieee80211softmac_start_scan_implementation) &&
  141 + (sm->stop_scan != ieee80211softmac_stop_scan_implementation) &&
  142 + (sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation)
  143 + ) || ieee80211softmac_scan_handlers_check_self(sm);
  144 +}
  145 +
  146 +#define IEEE80211SOFTMAC_PROBE_DELAY HZ/2
  147 +#define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ)
  148 +
  149 +struct ieee80211softmac_network {
  150 + struct list_head list; /* List */
  151 + /* Network information copied from ieee80211_network */
  152 + u8 bssid[ETH_ALEN];
  153 + u8 channel;
  154 + struct ieee80211softmac_essid essid;
  155 +
  156 + struct ieee80211softmac_ratesinfo supported_rates;
  157 +
  158 + /* SoftMAC specific */
  159 + u16 authenticating:1, /* Status Flags */
  160 + authenticated:1,
  161 + auth_desynced_once:1;
  162 +
  163 + u16 capabilities; /* Capabilities bitfield */
  164 + u8 challenge_len; /* Auth Challenge length */
  165 + char *challenge; /* Challenge Text */
  166 +};
  167 +
  168 +/* structure used to keep track of networks we're auth'ing to */
  169 +struct ieee80211softmac_auth_queue_item {
  170 + struct list_head list; /* List head */
  171 + struct ieee80211softmac_network *net; /* Network to auth */
  172 + struct ieee80211softmac_device *mac; /* SoftMAC device */
  173 + u8 retry; /* Retry limit */
  174 + u8 state; /* Auth State */
  175 + struct work_struct work; /* Work queue */
  176 +};
  177 +
  178 +/* scanning information */
  179 +struct ieee80211softmac_scaninfo {
  180 + u8 current_channel_idx,
  181 + number_channels;
  182 + struct ieee80211_channel *channels;
  183 + u8 started:1,
  184 + stop:1;
  185 + u8 skip_flags;
  186 + struct completion finished;
  187 + struct work_struct softmac_scan;
  188 +};
  189 +
  190 +/* private event struct */
  191 +struct ieee80211softmac_event {
  192 + struct list_head list;
  193 + int event_type;
  194 + void *event_context;
  195 + struct work_struct work;
  196 + notify_function_ptr fun;
  197 + void *context;
  198 + struct ieee80211softmac_device *mac;
  199 +};
  200 +
  201 +void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context);
  202 +void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context);
  203 +int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
  204 + int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
  205 +
  206 +#endif /* IEEE80211SOFTMAC_PRIV_H_ */
net/ieee80211/softmac/ieee80211softmac_scan.c
  1 +/*
  2 + * Scanning routines.
  3 + *
  4 + * These are not exported because they're assigned to the function pointers.
  5 + */
  6 +
  7 +#include <linux/completion.h>
  8 +#include "ieee80211softmac_priv.h"
  9 +
  10 +/* internal, use to trigger scanning if needed.
  11 + * Returns -EBUSY if already scanning,
  12 + * result of start_scan otherwise */
  13 +int
  14 +ieee80211softmac_start_scan(struct ieee80211softmac_device *sm)
  15 +{
  16 + unsigned long flags;
  17 + int ret;
  18 +
  19 + spin_lock_irqsave(&sm->lock, flags);
  20 + if (sm->scanning)
  21 + {
  22 + spin_unlock_irqrestore(&sm->lock, flags);
  23 + return -EINPROGRESS;
  24 + }
  25 + sm->scanning = 1;
  26 + spin_unlock_irqrestore(&sm->lock, flags);
  27 +
  28 + ret = sm->start_scan(sm->dev);
  29 + if (ret) {
  30 + spin_lock_irqsave(&sm->lock, flags);
  31 + sm->scanning = 0;
  32 + spin_unlock_irqrestore(&sm->lock, flags);
  33 + }
  34 + return ret;
  35 +}
  36 +
  37 +void
  38 +ieee80211softmac_stop_scan(struct ieee80211softmac_device *sm)
  39 +{
  40 + unsigned long flags;
  41 +
  42 + spin_lock_irqsave(&sm->lock, flags);
  43 +
  44 + if (!sm->scanning) {
  45 + spin_unlock_irqrestore(&sm->lock, flags);
  46 + return;
  47 + }
  48 +
  49 + spin_unlock_irqrestore(&sm->lock, flags);
  50 + sm->stop_scan(sm->dev);
  51 +}
  52 +
  53 +void
  54 +ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm)
  55 +{
  56 + unsigned long flags;
  57 +
  58 + spin_lock_irqsave(&sm->lock, flags);
  59 +
  60 + if (!sm->scanning) {
  61 + spin_unlock_irqrestore(&sm->lock, flags);
  62 + return;
  63 + }
  64 +
  65 + spin_unlock_irqrestore(&sm->lock, flags);
  66 + sm->wait_for_scan(sm->dev);
  67 +}
  68 +
  69 +
  70 +/* internal scanning implementation follows */
  71 +void ieee80211softmac_scan(void *d)
  72 +{
  73 + int invalid_channel;
  74 + u8 current_channel_idx;
  75 + struct ieee80211softmac_device *sm = (struct ieee80211softmac_device *)d;
  76 + struct ieee80211softmac_scaninfo *si = sm->scaninfo;
  77 + unsigned long flags;
  78 +
  79 + while (!(si->stop) && (si->current_channel_idx < si->number_channels)) {
  80 + current_channel_idx = si->current_channel_idx;
  81 + si->current_channel_idx++; /* go to the next channel */
  82 +
  83 + invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags);
  84 +
  85 + if (!invalid_channel) {
  86 + sm->set_channel(sm->dev, si->channels[current_channel_idx].channel);
  87 + //TODO: Probe the channel
  88 + // FIXME make this user configurable (active/passive)
  89 + if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0))
  90 + printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n");
  91 +
  92 + /* also send directed management frame for the network we're looking for */
  93 + // TODO: is this if correct, or should we do this only if scanning from assoc request?
  94 + if (sm->associnfo.req_essid.len)
  95 + ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0);
  96 + queue_delayed_work(sm->workqueue, &si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
  97 + return;
  98 + } else {
  99 + dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel);
  100 + }
  101 + }
  102 +
  103 + spin_lock_irqsave(&sm->lock, flags);
  104 + cancel_delayed_work(&si->softmac_scan);
  105 + si->started = 0;
  106 + spin_unlock_irqrestore(&sm->lock, flags);
  107 +
  108 + dprintk(PFX "Scanning finished\n");
  109 + ieee80211softmac_scan_finished(sm);
  110 + complete_all(&sm->scaninfo->finished);
  111 +}
  112 +
  113 +static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac)
  114 +{
  115 + /* ugh. can we call this without having the spinlock held? */
  116 + struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC);
  117 + if (unlikely(!info))
  118 + return NULL;
  119 + INIT_WORK(&info->softmac_scan, ieee80211softmac_scan, mac);
  120 + init_completion(&info->finished);
  121 + return info;
  122 +}
  123 +
  124 +int ieee80211softmac_start_scan_implementation(struct net_device *dev)
  125 +{
  126 + struct ieee80211softmac_device *sm = ieee80211_priv(dev);
  127 + unsigned long flags;
  128 +
  129 + if (!(dev->flags & IFF_UP))
  130 + return -ENODEV;
  131 +
  132 + assert(ieee80211softmac_scan_handlers_check_self(sm));
  133 + if (!ieee80211softmac_scan_handlers_check_self(sm))
  134 + return -EINVAL;
  135 +
  136 + spin_lock_irqsave(&sm->lock, flags);
  137 + /* it looks like we need to hold the lock here
  138 + * to make sure we don't allocate two of these... */
  139 + if (unlikely(!sm->scaninfo))
  140 + sm->scaninfo = allocate_scaninfo(sm);
  141 + if (unlikely(!sm->scaninfo)) {
  142 + spin_unlock_irqrestore(&sm->lock, flags);
  143 + return -ENOMEM;
  144 + }
  145 +
  146 + sm->scaninfo->skip_flags = IEEE80211_CH_INVALID;
  147 + if (0 /* not scanning in IEEE802.11b */)//TODO
  148 + sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY;
  149 + if (0 /* IEEE802.11a */) {//TODO
  150 + sm->scaninfo->channels = sm->ieee->geo.a;
  151 + sm->scaninfo->number_channels = sm->ieee->geo.a_channels;
  152 + } else {
  153 + sm->scaninfo->channels = sm->ieee->geo.bg;
  154 + sm->scaninfo->number_channels = sm->ieee->geo.bg_channels;
  155 + }
  156 + dprintk(PFX "Start scanning with channel: %d\n", sm->scaninfo->channels[0].channel);
  157 + dprintk(PFX "Scanning %d channels\n", sm->scaninfo->number_channels);
  158 + sm->scaninfo->current_channel_idx = 0;
  159 + sm->scaninfo->started = 1;
  160 + INIT_COMPLETION(sm->scaninfo->finished);
  161 + queue_work(sm->workqueue, &sm->scaninfo->softmac_scan);
  162 + spin_unlock_irqrestore(&sm->lock, flags);
  163 + return 0;
  164 +}
  165 +
  166 +void ieee80211softmac_stop_scan_implementation(struct net_device *dev)
  167 +{
  168 + struct ieee80211softmac_device *sm = ieee80211_priv(dev);
  169 + unsigned long flags;
  170 +
  171 + assert(ieee80211softmac_scan_handlers_check_self(sm));
  172 + if (!ieee80211softmac_scan_handlers_check_self(sm))
  173 + return;
  174 +
  175 + spin_lock_irqsave(&sm->lock, flags);
  176 + assert(sm->scaninfo != NULL);
  177 + if (sm->scaninfo) {
  178 + if (sm->scaninfo->started)
  179 + sm->scaninfo->stop = 1;
  180 + else
  181 + complete_all(&sm->scaninfo->finished);
  182 + }
  183 + spin_unlock_irqrestore(&sm->lock, flags);
  184 +}
  185 +
  186 +void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev)
  187 +{
  188 + struct ieee80211softmac_device *sm = ieee80211_priv(dev);
  189 + unsigned long flags;
  190 +
  191 + assert(ieee80211softmac_scan_handlers_check_self(sm));
  192 + if (!ieee80211softmac_scan_handlers_check_self(sm))
  193 + return;
  194 +
  195 + spin_lock_irqsave(&sm->lock, flags);
  196 + if (!sm->scaninfo->started) {
  197 + spin_unlock_irqrestore(&sm->lock, flags);
  198 + return;
  199 + }
  200 + spin_unlock_irqrestore(&sm->lock, flags);
  201 + wait_for_completion(&sm->scaninfo->finished);
  202 +}
  203 +
  204 +/* this is what drivers (that do scanning) call when they're done */
  205 +void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
  206 +{
  207 + unsigned long flags;
  208 +
  209 + spin_lock_irqsave(&sm->lock, flags);
  210 + sm->scanning = 0;
  211 + spin_unlock_irqrestore(&sm->lock, flags);
  212 +
  213 + ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
  214 +}
  215 +
  216 +EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);
net/ieee80211/softmac/ieee80211softmac_wx.c
  1 +/*
  2 + * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
  3 + */
  4 +
  5 +#include "ieee80211softmac_priv.h"
  6 +
  7 +#include <net/iw_handler.h>
  8 +
  9 +
  10 +int
  11 +ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
  12 + struct iw_request_info *info,
  13 + union iwreq_data *data,
  14 + char *extra)
  15 +{
  16 + struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
  17 + return ieee80211softmac_start_scan(sm);
  18 +}
  19 +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
  20 +
  21 +
  22 +int
  23 +ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
  24 + struct iw_request_info *info,
  25 + union iwreq_data *data,
  26 + char *extra)
  27 +{
  28 + struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
  29 + return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
  30 +}
  31 +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
  32 +
  33 +int
  34 +ieee80211softmac_wx_set_essid(struct net_device *net_dev,
  35 + struct iw_request_info *info,
  36 + union iwreq_data *data,
  37 + char *extra)
  38 +{
  39 + struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
  40 + int length = 0;
  41 + unsigned long flags;
  42 +
  43 + spin_lock_irqsave(&sm->lock, flags);
  44 +
  45 + sm->associnfo.static_essid = 0;
  46 +
  47 + if (data->essid.flags && data->essid.length && extra /*required?*/) {
  48 + length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
  49 + if (length) {
  50 + memcpy(sm->associnfo.req_essid.data, extra, length);
  51 + sm->associnfo.static_essid = 1;
  52 + }
  53 + }
  54 + sm->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
  55 +
  56 + /* set our requested ESSID length.
  57 + * If applicable, we have already copied the data in */
  58 + sm->associnfo.req_essid.len = length;
  59 +
  60 + /* queue lower level code to do work (if necessary) */
  61 + queue_work(sm->workqueue, &sm->associnfo.work);
  62 +
  63 + spin_unlock_irqrestore(&sm->lock, flags);
  64 + return 0;
  65 +}
  66 +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
  67 +
  68 +int
  69 +ieee80211softmac_wx_get_essid(struct net_device *net_dev,
  70 + struct iw_request_info *info,
  71 + union iwreq_data *data,
  72 + char *extra)
  73 +{
  74 + struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
  75 + unsigned long flags;
  76 +
  77 + /* avoid getting inconsistent information */
  78 + spin_lock_irqsave(&sm->lock, flags);
  79 + /* If all fails, return ANY (empty) */
  80 + data->essid.length = 0;
  81 + data->essid.flags = 0; /* active */
  82 +
  83 + /* If we have a statically configured ESSID then return it */
  84 + if (sm->associnfo.static_essid) {
  85 + data->essid.length = sm->associnfo.req_essid.len;
  86 + data->essid.flags = 1; /* active */
  87 + memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
  88 + }
  89 +
  90 + /* If we're associating/associated, return that */
  91 + if (sm->associated || sm->associnfo.associating) {
  92 + data->essid.length = sm->associnfo.associate_essid.len;
  93 + data->essid.flags = 1; /* active */
  94 + memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
  95 + }
  96 + spin_unlock_irqrestore(&sm->lock, flags);
  97 + return 0;
  98 +}
  99 +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
  100 +
  101 +int
  102 +ieee80211softmac_wx_set_rate(struct net_device *net_dev,
  103 + struct iw_request_info *info,
  104 + union iwreq_data *data,
  105 + char *extra)
  106 +{
  107 + struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
  108 + struct ieee80211_device *ieee = mac->ieee;
  109 + unsigned long flags;
  110 + s32 in_rate = data->bitrate.value;
  111 + u8 rate;
  112 + int is_ofdm = 0;
  113 + int err = -EINVAL;
  114 +
  115 + if (in_rate == -1) {
  116 + /* automatic detect */
  117 + if (ieee->modulation & IEEE80211_OFDM_MODULATION)
  118 + in_rate = 54000000;
  119 + else
  120 + in_rate = 11000000;
  121 + }
  122 +
  123 + switch (in_rate) {
  124 + case 1000000:
  125 + rate = IEEE80211_CCK_RATE_1MB;
  126 + break;
  127 + case 2000000:
  128 + rate = IEEE80211_CCK_RATE_2MB;
  129 + break;
  130 + case 5500000:
  131 + rate = IEEE80211_CCK_RATE_5MB;
  132 + break;
  133 + case 11000000:
  134 + rate = IEEE80211_CCK_RATE_11MB;
  135 + break;
  136 + case 6000000:
  137 + rate = IEEE80211_OFDM_RATE_6MB;
  138 + is_ofdm = 1;
  139 + break;
  140 + case 9000000:
  141 + rate = IEEE80211_OFDM_RATE_9MB;
  142 + is_ofdm = 1;
  143 + break;
  144 + case 12000000:
  145 + rate = IEEE80211_OFDM_RATE_12MB;
  146 + is_ofdm = 1;
  147 + break;
  148 + case 18000000:
  149 + rate = IEEE80211_OFDM_RATE_18MB;
  150 + is_ofdm = 1;
  151 + break;
  152 + case 24000000:
  153 + rate = IEEE80211_OFDM_RATE_24MB;
  154 + is_ofdm = 1;
  155 + break;
  156 + case 36000000:
  157 + rate = IEEE80211_OFDM_RATE_36MB;
  158 + is_ofdm = 1;
  159 + break;
  160 + case 48000000:
  161 + rate = IEEE80211_OFDM_RATE_48MB;
  162 + is_ofdm = 1;
  163 + break;
  164 + case 54000000:
  165 + rate = IEEE80211_OFDM_RATE_54MB;
  166 + is_ofdm = 1;
  167 + break;
  168 + default:
  169 + goto out;
  170 + }
  171 +
  172 + spin_lock_irqsave(&mac->lock, flags);
  173 +
  174 + /* Check if correct modulation for this PHY. */
  175 + if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
  176 + goto out_unlock;
  177 +
  178 + mac->txrates.default_rate = rate;
  179 + mac->txrates.default_fallback = lower_rate(mac, rate);
  180 + err = 0;
  181 +
  182 +out_unlock:
  183 + spin_unlock_irqrestore(&mac->lock, flags);
  184 +out:
  185 + return err;
  186 +}
  187 +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
  188 +
  189 +int
  190 +ieee80211softmac_wx_get_rate(struct net_device *net_dev,
  191 + struct iw_request_info *info,
  192 + union iwreq_data *data,
  193 + char *extra)
  194 +{
  195 + struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
  196 + unsigned long flags;
  197 + int err = -EINVAL;
  198 +
  199 + spin_lock_irqsave(&mac->lock, flags);
  200 + switch (mac->txrates.default_rate) {
  201 + case IEEE80211_CCK_RATE_1MB:
  202 + data->bitrate.value = 1000000;
  203 + break;
  204 + case IEEE80211_CCK_RATE_2MB:
  205 + data->bitrate.value = 2000000;
  206 + break;
  207 + case IEEE80211_CCK_RATE_5MB:
  208 + data->bitrate.value = 5500000;
  209 + break;
  210 + case IEEE80211_CCK_RATE_11MB:
  211 + data->bitrate.value = 11000000;
  212 + break;
  213 + case IEEE80211_OFDM_RATE_6MB:
  214 + data->bitrate.value = 6000000;
  215 + break;
  216 + case IEEE80211_OFDM_RATE_9MB:
  217 + data->bitrate.value = 9000000;
  218 + break;
  219 + case IEEE80211_OFDM_RATE_12MB:
  220 + data->bitrate.value = 12000000;
  221 + break;
  222 + case IEEE80211_OFDM_RATE_18MB:
  223 + data->bitrate.value = 18000000;
  224 + break;
  225 + case IEEE80211_OFDM_RATE_24MB:
  226 + data->bitrate.value = 24000000;
  227 + break;
  228 + case IEEE80211_OFDM_RATE_36MB:
  229 + data->bitrate.value = 36000000;
  230 + break;
  231 + case IEEE80211_OFDM_RATE_48MB:
  232 + data->bitrate.value = 48000000;
  233 + break;
  234 + case IEEE80211_OFDM_RATE_54MB:
  235 + data->bitrate.value = 54000000;
  236 + break;
  237 + default:
  238 + assert(0);
  239 + goto out_unlock;
  240 + }
  241 + err = 0;
  242 +out_unlock:
  243 + spin_unlock_irqrestore(&mac->lock, flags);
  244 +
  245 + return err;
  246 +}
  247 +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
  248 +
  249 +int
  250 +ieee80211softmac_wx_get_wap(struct net_device *net_dev,
  251 + struct iw_request_info *info,
  252 + union iwreq_data *data,
  253 + char *extra)
  254 +{
  255 + struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
  256 + int err = 0;
  257 + unsigned long flags;
  258 +
  259 + spin_lock_irqsave(&mac->lock, flags);
  260 + if (mac->associnfo.bssvalid)
  261 + memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
  262 + else
  263 + memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
  264 + data->ap_addr.sa_family = ARPHRD_ETHER;
  265 + spin_unlock_irqrestore(&mac->lock, flags);
  266 + return err;
  267 +}
  268 +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
  269 +
  270 +int
  271 +ieee80211softmac_wx_set_wap(struct net_device *net_dev,
  272 + struct iw_request_info *info,
  273 + union iwreq_data *data,
  274 + char *extra)
  275 +{
  276 + struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
  277 + static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  278 + static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  279 + unsigned long flags;
  280 +
  281 + /* sanity check */
  282 + if (data->ap_addr.sa_family != ARPHRD_ETHER) {
  283 + return -EINVAL;
  284 + }
  285 +
  286 + spin_lock_irqsave(&mac->lock, flags);
  287 + if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) ||
  288 + !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) {
  289 + queue_work(mac->workqueue, &mac->associnfo.work);
  290 + goto out;
  291 + } else {
  292 + if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
  293 + if (mac->associnfo.associating || mac->associated) {
  294 + /* bssid unchanged and associated or associating - just return */
  295 + goto out;
  296 + }
  297 + } else {
  298 + /* copy new value in data->ap_addr.sa_data to bssid */
  299 + memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
  300 + }
  301 + /* queue associate if new bssid or (old one again and not associated) */
  302 + queue_work(mac->workqueue,&mac->associnfo.work);
  303 + }
  304 +
  305 +out:
  306 + spin_unlock_irqrestore(&mac->lock, flags);
  307 + return 0;
  308 +}
  309 +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
  310 +
  311 +int
  312 +ieee80211softmac_wx_set_genie(struct net_device *dev,
  313 + struct iw_request_info *info,
  314 + union iwreq_data *wrqu,
  315 + char *extra)
  316 +{
  317 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  318 + unsigned long flags;
  319 + int err = 0;
  320 + char *buf;
  321 + int i;
  322 +
  323 + spin_lock_irqsave(&mac->lock, flags);
  324 + /* bleh. shouldn't be locked for that kmalloc... */
  325 +
  326 + if (wrqu->data.length) {
  327 + if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
  328 + /* this is an IE, so the length must be
  329 + * correct. Is it possible though that
  330 + * more than one IE is passed in?
  331 + */
  332 + err = -EINVAL;
  333 + goto out;
  334 + }
  335 + if (mac->wpa.IEbuflen <= wrqu->data.length) {
  336 + buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
  337 + if (!buf) {
  338 + err = -ENOMEM;
  339 + goto out;
  340 + }
  341 + kfree(mac->wpa.IE);
  342 + mac->wpa.IE = buf;
  343 + mac->wpa.IEbuflen = wrqu->data.length;
  344 + }
  345 + memcpy(mac->wpa.IE, extra, wrqu->data.length);
  346 + dprintk(KERN_INFO PFX "generic IE set to ");
  347 + for (i=0;i<wrqu->data.length;i++)
  348 + dprintk("%.2x", mac->wpa.IE[i]);
  349 + dprintk("\n");
  350 + mac->wpa.IElen = wrqu->data.length;
  351 + } else {
  352 + kfree(mac->wpa.IE);
  353 + mac->wpa.IE = NULL;
  354 + mac->wpa.IElen = 0;
  355 + mac->wpa.IEbuflen = 0;
  356 + }
  357 +
  358 + out:
  359 + spin_unlock_irqrestore(&mac->lock, flags);
  360 + return err;
  361 +}
  362 +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
  363 +
  364 +int
  365 +ieee80211softmac_wx_get_genie(struct net_device *dev,
  366 + struct iw_request_info *info,
  367 + union iwreq_data *wrqu,
  368 + char *extra)
  369 +{
  370 + struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  371 + unsigned long flags;
  372 + int err = 0;
  373 + int space = wrqu->data.length;
  374 +
  375 + spin_lock_irqsave(&mac->lock, flags);
  376 +
  377 + wrqu->data.length = 0;
  378 +
  379 + if (mac->wpa.IE && mac->wpa.IElen) {
  380 + wrqu->data.length = mac->wpa.IElen;
  381 + if (mac->wpa.IElen <= space)
  382 + memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
  383 + else
  384 + err = -E2BIG;
  385 + }
  386 + spin_unlock_irqrestore(&mac->lock, flags);
  387 + return err;
  388 +}
  389 +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);