aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee80211/softmac/ieee80211softmac_wx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ieee80211/softmac/ieee80211softmac_wx.c')
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c412
1 files changed, 412 insertions, 0 deletions
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
new file mode 100644
index 0000000..e1a9bc6
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -0,0 +1,412 @@
+/*
+ * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
+ *
+ * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Joseph Jezak <josejx@gentoo.org>
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ * Danny van Dyk <kugelfang@gentoo.org>
+ * Michael Buesch <mbuesch@freenet.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+
+#include "ieee80211softmac_priv.h"
+
+#include <net/iw_handler.h>
+
+
+int
+ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
+ return ieee80211softmac_start_scan(sm);
+}
+EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
+
+
+int
+ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
+ return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
+}
+EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
+
+int
+ieee80211softmac_wx_set_essid(struct net_device *net_dev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
+ int length = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sm->lock, flags);
+
+ sm->associnfo.static_essid = 0;
+
+ if (data->essid.flags && data->essid.length && extra /*required?*/) {
+ length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
+ if (length) {
+ memcpy(sm->associnfo.req_essid.data, extra, length);
+ sm->associnfo.static_essid = 1;
+ }
+ }
+ sm->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
+
+ /* set our requested ESSID length.
+ * If applicable, we have already copied the data in */
+ sm->associnfo.req_essid.len = length;
+
+ /* queue lower level code to do work (if necessary) */
+ schedule_work(&sm->associnfo.work);
+
+ spin_unlock_irqrestore(&sm->lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
+
+int
+ieee80211softmac_wx_get_essid(struct net_device *net_dev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
+ unsigned long flags;
+
+ /* avoid getting inconsistent information */
+ spin_lock_irqsave(&sm->lock, flags);
+ /* If all fails, return ANY (empty) */
+ data->essid.length = 0;
+ data->essid.flags = 0; /* active */
+
+ /* If we have a statically configured ESSID then return it */
+ if (sm->associnfo.static_essid) {
+ data->essid.length = sm->associnfo.req_essid.len;
+ data->essid.flags = 1; /* active */
+ memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
+ }
+
+ /* If we're associating/associated, return that */
+ if (sm->associated || sm->associnfo.associating) {
+ data->essid.length = sm->associnfo.associate_essid.len;
+ data->essid.flags = 1; /* active */
+ memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
+ }
+ spin_unlock_irqrestore(&sm->lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
+
+int
+ieee80211softmac_wx_set_rate(struct net_device *net_dev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
+ struct ieee80211_device *ieee = mac->ieee;
+ unsigned long flags;
+ s32 in_rate = data->bitrate.value;
+ u8 rate;
+ int is_ofdm = 0;
+ int err = -EINVAL;
+
+ if (in_rate == -1) {
+ /* automatic detect */
+ if (ieee->modulation & IEEE80211_OFDM_MODULATION)
+ in_rate = 54000000;
+ else
+ in_rate = 11000000;
+ }
+
+ switch (in_rate) {
+ case 1000000:
+ rate = IEEE80211_CCK_RATE_1MB;
+ break;
+ case 2000000:
+ rate = IEEE80211_CCK_RATE_2MB;
+ break;
+ case 5500000:
+ rate = IEEE80211_CCK_RATE_5MB;
+ break;
+ case 11000000:
+ rate = IEEE80211_CCK_RATE_11MB;
+ break;
+ case 6000000:
+ rate = IEEE80211_OFDM_RATE_6MB;
+ is_ofdm = 1;
+ break;
+ case 9000000:
+ rate = IEEE80211_OFDM_RATE_9MB;
+ is_ofdm = 1;
+ break;
+ case 12000000:
+ rate = IEEE80211_OFDM_RATE_12MB;
+ is_ofdm = 1;
+ break;
+ case 18000000:
+ rate = IEEE80211_OFDM_RATE_18MB;
+ is_ofdm = 1;
+ break;
+ case 24000000:
+ rate = IEEE80211_OFDM_RATE_24MB;
+ is_ofdm = 1;
+ break;
+ case 36000000:
+ rate = IEEE80211_OFDM_RATE_36MB;
+ is_ofdm = 1;
+ break;
+ case 48000000:
+ rate = IEEE80211_OFDM_RATE_48MB;
+ is_ofdm = 1;
+ break;
+ case 54000000:
+ rate = IEEE80211_OFDM_RATE_54MB;
+ is_ofdm = 1;
+ break;
+ default:
+ goto out;
+ }
+
+ spin_lock_irqsave(&mac->lock, flags);
+
+ /* Check if correct modulation for this PHY. */
+ if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
+ goto out_unlock;
+
+ mac->txrates.default_rate = rate;
+ mac->txrates.default_fallback = lower_rate(mac, rate);
+ err = 0;
+
+out_unlock:
+ spin_unlock_irqrestore(&mac->lock, flags);
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
+
+int
+ieee80211softmac_wx_get_rate(struct net_device *net_dev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
+ unsigned long flags;
+ int err = -EINVAL;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ switch (mac->txrates.default_rate) {
+ case IEEE80211_CCK_RATE_1MB:
+ data->bitrate.value = 1000000;
+ break;
+ case IEEE80211_CCK_RATE_2MB:
+ data->bitrate.value = 2000000;
+ break;
+ case IEEE80211_CCK_RATE_5MB:
+ data->bitrate.value = 5500000;
+ break;
+ case IEEE80211_CCK_RATE_11MB:
+ data->bitrate.value = 11000000;
+ break;
+ case IEEE80211_OFDM_RATE_6MB:
+ data->bitrate.value = 6000000;
+ break;
+ case IEEE80211_OFDM_RATE_9MB:
+ data->bitrate.value = 9000000;
+ break;
+ case IEEE80211_OFDM_RATE_12MB:
+ data->bitrate.value = 12000000;
+ break;
+ case IEEE80211_OFDM_RATE_18MB:
+ data->bitrate.value = 18000000;
+ break;
+ case IEEE80211_OFDM_RATE_24MB:
+ data->bitrate.value = 24000000;
+ break;
+ case IEEE80211_OFDM_RATE_36MB:
+ data->bitrate.value = 36000000;
+ break;
+ case IEEE80211_OFDM_RATE_48MB:
+ data->bitrate.value = 48000000;
+ break;
+ case IEEE80211_OFDM_RATE_54MB:
+ data->bitrate.value = 54000000;
+ break;
+ default:
+ assert(0);
+ goto out_unlock;
+ }
+ err = 0;
+out_unlock:
+ spin_unlock_irqrestore(&mac->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
+
+int
+ieee80211softmac_wx_get_wap(struct net_device *net_dev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
+ int err = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ if (mac->associnfo.bssvalid)
+ memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
+ else
+ memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
+ data->ap_addr.sa_family = ARPHRD_ETHER;
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return err;
+}
+EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
+
+int
+ieee80211softmac_wx_set_wap(struct net_device *net_dev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
+ static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ unsigned long flags;
+
+ /* sanity check */
+ if (data->ap_addr.sa_family != ARPHRD_ETHER) {
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&mac->lock, flags);
+ if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) ||
+ !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) {
+ schedule_work(&mac->associnfo.work);
+ goto out;
+ } else {
+ if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
+ if (mac->associnfo.associating || mac->associated) {
+ /* bssid unchanged and associated or associating - just return */
+ goto out;
+ }
+ } else {
+ /* copy new value in data->ap_addr.sa_data to bssid */
+ memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
+ }
+ /* queue associate if new bssid or (old one again and not associated) */
+ schedule_work(&mac->associnfo.work);
+ }
+
+out:
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
+
+int
+ieee80211softmac_wx_set_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ struct ieee80211softmac_device *mac = ieee80211_priv(dev);
+ unsigned long flags;
+ int err = 0;
+ char *buf;
+ int i;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ /* bleh. shouldn't be locked for that kmalloc... */
+
+ if (wrqu->data.length) {
+ if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
+ /* this is an IE, so the length must be
+ * correct. Is it possible though that
+ * more than one IE is passed in?
+ */
+ err = -EINVAL;
+ goto out;
+ }
+ if (mac->wpa.IEbuflen <= wrqu->data.length) {
+ buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out;
+ }
+ kfree(mac->wpa.IE);
+ mac->wpa.IE = buf;
+ mac->wpa.IEbuflen = wrqu->data.length;
+ }
+ memcpy(mac->wpa.IE, extra, wrqu->data.length);
+ dprintk(KERN_INFO PFX "generic IE set to ");
+ for (i=0;i<wrqu->data.length;i++)
+ dprintk("%.2x", mac->wpa.IE[i]);
+ dprintk("\n");
+ mac->wpa.IElen = wrqu->data.length;
+ } else {
+ kfree(mac->wpa.IE);
+ mac->wpa.IE = NULL;
+ mac->wpa.IElen = 0;
+ mac->wpa.IEbuflen = 0;
+ }
+
+ out:
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return err;
+}
+EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
+
+int
+ieee80211softmac_wx_get_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ struct ieee80211softmac_device *mac = ieee80211_priv(dev);
+ unsigned long flags;
+ int err = 0;
+ int space = wrqu->data.length;
+
+ spin_lock_irqsave(&mac->lock, flags);
+
+ wrqu->data.length = 0;
+
+ if (mac->wpa.IE && mac->wpa.IElen) {
+ wrqu->data.length = mac->wpa.IElen;
+ if (mac->wpa.IElen <= space)
+ memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
+ else
+ err = -E2BIG;
+ }
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return err;
+}
+EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
+