aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/wlan-ng/p80211wext.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/wlan-ng/p80211wext.c')
-rw-r--r--drivers/staging/wlan-ng/p80211wext.c2048
1 files changed, 2048 insertions, 0 deletions
diff --git a/drivers/staging/wlan-ng/p80211wext.c b/drivers/staging/wlan-ng/p80211wext.c
new file mode 100644
index 00000000000..906ba439237
--- /dev/null
+++ b/drivers/staging/wlan-ng/p80211wext.c
@@ -0,0 +1,2048 @@
+/* src/p80211/p80211wext.c
+*
+* Glue code to make linux-wlan-ng a happy wireless extension camper.
+*
+* original author: Reyk Floeter <reyk@synack.de>
+* Completely re-written by Solomon Peachy <solomon@linux-wlan.com>
+*
+* Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved.
+* --------------------------------------------------------------------
+*
+* linux-wlan
+*
+* The contents of this file are subject to the Mozilla Public
+* License Version 1.1 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.mozilla.org/MPL/
+*
+* Software distributed under the License is distributed on an "AS
+* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* Alternatively, the contents of this file may be used under the
+* terms of the GNU Public License version 2 (the "GPL"), in which
+* case the provisions of the GPL are applicable instead of the
+* above. If you wish to allow the use of your version of this file
+* only under the terms of the GPL and not to allow others to use
+* your version of this file under the MPL, indicate your decision
+* by deleting the provisions above and replace them with the notice
+* and other provisions required by the GPL. If you do not delete
+* the provisions above, a recipient may use your version of this
+* file under either the MPL or the GPL.
+*
+* --------------------------------------------------------------------
+*/
+
+/*================================================================*/
+/* System Includes */
+
+
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#if WIRELESS_EXT > 12
+#include <net/iw_handler.h>
+#endif
+#include <linux/if_arp.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+/*================================================================*/
+/* Project Includes */
+
+#include "version.h"
+#include "wlan_compat.h"
+
+#include "p80211types.h"
+#include "p80211hdr.h"
+#include "p80211conv.h"
+#include "p80211mgmt.h"
+#include "p80211msg.h"
+#include "p80211metastruct.h"
+#include "p80211metadef.h"
+#include "p80211netdev.h"
+#include "p80211ioctl.h"
+#include "p80211req.h"
+
+static int p80211wext_giwrate(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra);
+static int p80211wext_giwessid(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *essid);
+/* compatibility to wireless extensions */
+#ifdef WIRELESS_EXT
+
+static UINT8 p80211_mhz_to_channel(UINT16 mhz)
+{
+ if (mhz >= 5000) {
+ return ((mhz - 5000) / 5);
+ }
+
+ if (mhz == 2482)
+ return 14;
+
+ if (mhz >= 2407) {
+ return ((mhz - 2407) / 5);
+ }
+
+ return 0;
+}
+
+static UINT16 p80211_channel_to_mhz(UINT8 ch, int dot11a)
+{
+
+ if (ch == 0)
+ return 0;
+ if (ch > 200)
+ return 0;
+
+ /* 5G */
+
+ if (dot11a) {
+ return (5000 + (5 * ch));
+ }
+
+ /* 2.4G */
+
+ if (ch == 14)
+ return 2484;
+
+ if ((ch < 14) && (ch > 0)) {
+ return (2407 + (5 * ch));
+ }
+
+ return 0;
+}
+
+/* taken from orinoco.c ;-) */
+static const long p80211wext_channel_freq[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+#define NUM_CHANNELS (sizeof(p80211wext_channel_freq) / sizeof(p80211wext_channel_freq[0]))
+
+/* steal a spare bit to store the shared/opensystems state. should default to open if not set */
+#define HOSTWEP_SHAREDKEY BIT3
+
+
+/** function declarations =============== */
+
+static int qual_as_percent(int snr ) {
+ if ( snr <= 0 )
+ return 0;
+ if ( snr <= 40 )
+ return snr*5/2;
+ return 100;
+}
+
+
+
+
+static int p80211wext_dorequest(wlandevice_t *wlandev, UINT32 did, UINT32 data)
+{
+ p80211msg_dot11req_mibset_t msg;
+ p80211item_uint32_t mibitem;
+ int result;
+
+ DBFENTER;
+
+ msg.msgcode = DIDmsg_dot11req_mibset;
+ mibitem.did = did;
+ mibitem.data = data;
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ DBFEXIT;
+ return result;
+}
+
+static int p80211wext_autojoin(wlandevice_t *wlandev)
+{
+ p80211msg_lnxreq_autojoin_t msg;
+ struct iw_point data;
+ char ssid[IW_ESSID_MAX_SIZE];
+
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ /* Get ESSID */
+ result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if ( wlandev->hostwep & HOSTWEP_SHAREDKEY )
+ msg.authtype.data = P80211ENUM_authalg_sharedkey;
+ else
+ msg.authtype.data = P80211ENUM_authalg_opensystem;
+
+ msg.msgcode = DIDmsg_lnxreq_autojoin;
+
+ /* Trim the last '\0' to fit the SSID format */
+
+ if (data.length && ssid[data.length-1] == '\0') {
+ data.length = data.length - 1;
+ }
+
+ memcpy(msg.ssid.data.data, ssid, data.length);
+ msg.ssid.data.len = data.length;
+
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+exit:
+
+ DBFEXIT;
+ return err;
+
+}
+
+/* called by /proc/net/wireless */
+struct iw_statistics* p80211wext_get_wireless_stats (netdevice_t *dev)
+{
+ p80211msg_lnxreq_commsquality_t quality;
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ struct iw_statistics* wstats = &wlandev->wstats;
+ int retval;
+
+ DBFENTER;
+ /* Check */
+ if ( (wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING) )
+ return NULL;
+
+ /* XXX Only valid in station mode */
+ wstats->status = 0;
+
+ /* build request message */
+ quality.msgcode = DIDmsg_lnxreq_commsquality;
+ quality.dbm.data = P80211ENUM_truth_true;
+ quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
+
+ /* send message to nsd */
+ if ( wlandev->mlmerequest == NULL )
+ return NULL;
+
+ retval = wlandev->mlmerequest(wlandev, (p80211msg_t*) &quality);
+
+ wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */
+ wstats->qual.level = quality.level.data; /* instant signal level */
+ wstats->qual.noise = quality.noise.data; /* instant noise level */
+
+#if WIRELESS_EXT > 18
+ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+#else
+ wstats->qual.updated = 7;
+#endif
+ wstats->discard.code = wlandev->rx.decrypt_err;
+ wstats->discard.nwid = 0;
+ wstats->discard.misc = 0;
+
+#if WIRELESS_EXT > 11
+ wstats->discard.fragment = 0; // incomplete fragments
+ wstats->discard.retries = 0; // tx retries.
+ wstats->miss.beacon = 0;
+#endif
+
+ DBFEXIT;
+
+ return wstats;
+}
+
+static int p80211wext_giwname(netdevice_t *dev,
+ struct iw_request_info *info,
+ char *name, char *extra)
+{
+ struct iw_param rate;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ result = p80211wext_giwrate(dev, NULL, &rate, NULL);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ switch (rate.value) {
+ case 1000000:
+ case 2000000:
+ strcpy(name, "IEEE 802.11-DS");
+ break;
+ case 5500000:
+ case 11000000:
+ strcpy(name, "IEEE 802.11-b");
+ break;
+ }
+exit:
+ DBFEXIT;
+ return err;
+}
+
+static int p80211wext_giwfreq(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ msg.msgcode = DIDmsg_dot11req_mibget;
+ mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
+
+ if (mibitem.data > NUM_CHANNELS) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ /* convert into frequency instead of a channel */
+ freq->e = 1;
+ freq->m = p80211_channel_to_mhz(mibitem.data, 0) * 100000;
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+static int p80211wext_siwfreq(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ if (!wlan_wext_write) {
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+ msg.msgcode = DIDmsg_dot11req_mibset;
+ mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
+ mibitem.status = P80211ENUM_msgitem_status_data_ok;
+
+ if ( (freq->e == 0) && (freq->m <= 1000) )
+ mibitem.data = freq->m;
+ else
+ mibitem.data = p80211_mhz_to_channel(freq->m);
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+#if WIRELESS_EXT > 8
+
+static int p80211wext_giwmode(netdevice_t *dev,
+ struct iw_request_info *info,
+ __u32 *mode, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+
+ DBFENTER;
+
+ switch (wlandev->macmode) {
+ case WLAN_MACMODE_IBSS_STA:
+ *mode = IW_MODE_ADHOC;
+ break;
+ case WLAN_MACMODE_ESS_STA:
+ *mode = IW_MODE_INFRA;
+ break;
+ case WLAN_MACMODE_ESS_AP:
+ *mode = IW_MODE_MASTER;
+ break;
+ default:
+ /* Not set yet. */
+ *mode = IW_MODE_AUTO;
+ }
+
+ DBFEXIT;
+ return 0;
+}
+
+static int p80211wext_siwmode(netdevice_t *dev,
+ struct iw_request_info *info,
+ __u32 *mode, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ if (!wlan_wext_write) {
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+ if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
+ *mode != IW_MODE_MASTER) {
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+ /* Operation mode is the same with current mode */
+ if (*mode == wlandev->macmode)
+ goto exit;
+
+ switch (*mode) {
+ case IW_MODE_ADHOC:
+ wlandev->macmode = WLAN_MACMODE_IBSS_STA;
+ break;
+ case IW_MODE_INFRA:
+ wlandev->macmode = WLAN_MACMODE_ESS_STA;
+ break;
+ case IW_MODE_MASTER:
+ wlandev->macmode = WLAN_MACMODE_ESS_AP;
+ break;
+ default:
+ /* Not set yet. */
+ WLAN_LOG_INFO("Operation mode: %d not support\n", *mode);
+ return -EOPNOTSUPP;
+ }
+
+ /* Set Operation mode to the PORT TYPE RID */
+
+#warning "get rid of p2mib here"
+
+ msg.msgcode = DIDmsg_dot11req_mibset;
+ mibitem.did = DIDmib_p2_p2Static_p2CnfPortType;
+ mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1;
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result)
+ err = -EFAULT;
+
+ exit:
+ DBFEXIT;
+
+ return err;
+}
+
+
+static int p80211wext_giwrange(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct iw_range *range = (struct iw_range *) extra;
+ int i, val;
+
+ DBFENTER;
+
+ // for backward compatability set size & zero everything we don't understand
+ data->length = sizeof(*range);
+ memset(range,0,sizeof(*range));
+
+#if WIRELESS_EXT > 9
+ range->txpower_capa = IW_TXPOW_DBM;
+ // XXX what about min/max_pmp, min/max_pmt, etc.
+#endif
+
+#if WIRELESS_EXT > 10
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 13;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT;
+ range->min_retry = 0;
+ range->max_retry = 255;
+#endif /* WIRELESS_EXT > 10 */
+
+#if WIRELESS_EXT > 16
+ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | //mode/freq/ssid
+ IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+ IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+ range->event_capa[1] = IW_EVENT_CAPA_K_1; //encode
+ range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) |
+ IW_EVENT_CAPA_MASK(IWEVCUSTOM) );
+#endif
+
+ range->num_channels = NUM_CHANNELS;
+
+ /* XXX need to filter against the regulatory domain &| active set */
+ val = 0;
+ for (i = 0; i < NUM_CHANNELS ; i++) {
+ range->freq[val].i = i + 1;
+ range->freq[val].m = p80211wext_channel_freq[i] * 100000;
+ range->freq[val].e = 1;
+ val++;
+ }
+
+ range->num_frequency = val;
+
+ /* Max of /proc/net/wireless */
+ range->max_qual.qual = 100;
+ range->max_qual.level = 0;
+ range->max_qual.noise = 0;
+ range->sensitivity = 3;
+ // XXX these need to be nsd-specific!
+
+ range->min_rts = 0;
+ range->max_rts = 2347;
+ range->min_frag = 256;
+ range->max_frag = 2346;
+
+ range->max_encoding_tokens = NUM_WEPKEYS;
+ range->num_encoding_sizes = 2;
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+
+ // XXX what about num_bitrates/throughput?
+ range->num_bitrates = 0;
+
+ /* estimated max throughput */
+ // XXX need to cap it if we're running at ~2Mbps..
+ range->throughput = 5500000;
+
+ DBFEXIT;
+ return 0;
+}
+#endif
+
+static int p80211wext_giwap(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+
+ DBFENTER;
+
+ memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN);
+ ap_addr->sa_family = ARPHRD_ETHER;
+
+ DBFEXIT;
+ return 0;
+}
+
+#if WIRELESS_EXT > 8
+static int p80211wext_giwencode(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *key)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ int err = 0;
+ int i;
+
+ DBFENTER;
+
+ if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
+ erq->flags = IW_ENCODE_ENABLED;
+ else
+ erq->flags = IW_ENCODE_DISABLED;
+
+ if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED)
+ erq->flags |= IW_ENCODE_RESTRICTED;
+ else
+ erq->flags |= IW_ENCODE_OPEN;
+
+ i = (erq->flags & IW_ENCODE_INDEX) - 1;
+
+ if (i == -1)
+ i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
+
+ if ((i < 0) || (i >= NUM_WEPKEYS)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ erq->flags |= i + 1;
+
+ /* copy the key from the driver cache as the keys are read-only MIBs */
+ erq->length = wlandev->wep_keylens[i];
+ memcpy(key, wlandev->wep_keys[i], erq->length);
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+static int p80211wext_siwencode(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *key)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211msg_dot11req_mibset_t msg;
+ p80211item_pstr32_t pstr;
+
+ int err = 0;
+ int result = 0;
+ int enable = 0;
+ int i;
+
+ DBFENTER;
+ if (!wlan_wext_write) {
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+ /* Check the Key index first. */
+ if((i = (erq->flags & IW_ENCODE_INDEX))) {
+
+ if ((i < 1) || (i > NUM_WEPKEYS)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ else
+ i--;
+
+ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, i);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+ else {
+ enable = 1;
+ }
+
+ }
+ else {
+ // Do not thing when no Key Index
+ }
+
+ /* Check if there is no key information in the iwconfig request */
+ if((erq->flags & IW_ENCODE_NOKEY) == 0 && enable == 1) {
+
+ /*------------------------------------------------------------
+ * If there is WEP Key for setting, check the Key Information
+ * and then set it to the firmware.
+ -------------------------------------------------------------*/
+
+ if (erq->length > 0) {
+
+ /* copy the key from the driver cache as the keys are read-only MIBs */
+ wlandev->wep_keylens[i] = erq->length;
+ memcpy(wlandev->wep_keys[i], key, erq->length);
+
+ /* Prepare data struture for p80211req_dorequest. */
+ memcpy(pstr.data.data, key, erq->length);
+ pstr.data.len = erq->length;
+
+ switch(i)
+ {
+ case 0:
+ pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
+ break;
+
+ case 1:
+ pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
+ break;
+
+ case 2:
+ pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
+ break;
+
+ case 3:
+ pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
+ break;
+
+ default:
+ err = -EINVAL;
+ goto exit;
+ }
+
+ msg.msgcode = DIDmsg_dot11req_mibset;
+ memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+ }
+
+ }
+
+ /* Check the PrivacyInvoked flag */
+ if (erq->flags & IW_ENCODE_DISABLED) {
+ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false);
+ }
+ else if((erq->flags & IW_ENCODE_ENABLED) || enable == 1) {
+ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true);
+ }
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ /* Check the ExcludeUnencrypted flag */
+ if (erq->flags & IW_ENCODE_RESTRICTED) {
+ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true);
+ }
+ else if (erq->flags & IW_ENCODE_OPEN) {
+ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false);
+ }
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ exit:
+
+ DBFEXIT;
+ return err;
+}
+
+static int p80211wext_giwessid(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *essid)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+
+ DBFENTER;
+
+ if (wlandev->ssid.len) {
+ data->length = wlandev->ssid.len;
+ data->flags = 1;
+ memcpy(essid, wlandev->ssid.data, data->length);
+ essid[data->length] = 0;
+#if (WIRELESS_EXT < 21)
+ data->length++;
+#endif
+ } else {
+ memset(essid, 0, sizeof(wlandev->ssid.data));
+ data->length = 0;
+ data->flags = 0;
+ }
+
+ DBFEXIT;
+ return 0;
+}
+
+static int p80211wext_siwessid(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *essid)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211msg_lnxreq_autojoin_t msg;
+
+ int result;
+ int err = 0;
+ int length = data->length;
+
+ DBFENTER;
+
+ if (!wlan_wext_write) {
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+
+ if ( wlandev->hostwep & HOSTWEP_SHAREDKEY )
+ msg.authtype.data = P80211ENUM_authalg_sharedkey;
+ else
+ msg.authtype.data = P80211ENUM_authalg_opensystem;
+
+ msg.msgcode = DIDmsg_lnxreq_autojoin;
+
+#if (WIRELESS_EXT < 21)
+ if (length) length--;
+#endif
+
+ /* Trim the last '\0' to fit the SSID format */
+
+ if (length && essid[length-1] == '\0') {
+ length--;
+ }
+
+ memcpy(msg.ssid.data.data, essid, length);
+ msg.ssid.data.len = length;
+
+ WLAN_LOG_DEBUG(1,"autojoin_ssid for %s \n",essid);
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+ WLAN_LOG_DEBUG(1,"autojoin_ssid %d\n",result);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+
+static int p80211wext_siwcommit(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *essid)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ int err = 0;
+
+ DBFENTER;
+
+ if (!wlan_wext_write) {
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+ /* Auto Join */
+ err = p80211wext_autojoin(wlandev);
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+
+static int p80211wext_giwrate(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ msg.msgcode = DIDmsg_dot11req_mibget;
+ mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate;
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
+
+ rrq->fixed = 0; /* can it change? */
+ rrq->disabled = 0;
+ rrq->value = 0;
+
+#define HFA384x_RATEBIT_1 ((UINT16)1)
+#define HFA384x_RATEBIT_2 ((UINT16)2)
+#define HFA384x_RATEBIT_5dot5 ((UINT16)4)
+#define HFA384x_RATEBIT_11 ((UINT16)8)
+
+ switch (mibitem.data) {
+ case HFA384x_RATEBIT_1:
+ rrq->value = 1000000;
+ break;
+ case HFA384x_RATEBIT_2:
+ rrq->value = 2000000;
+ break;
+ case HFA384x_RATEBIT_5dot5:
+ rrq->value = 5500000;
+ break;
+ case HFA384x_RATEBIT_11:
+ rrq->value = 11000000;
+ break;
+ default:
+ err = -EINVAL;
+ }
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+static int p80211wext_giwrts(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ msg.msgcode = DIDmsg_dot11req_mibget;
+ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
+
+ rts->value = mibitem.data;
+ rts->disabled = (rts->value == 2347);
+ rts->fixed = 1;
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+
+static int p80211wext_siwrts(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ if (!wlan_wext_write) {
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+ msg.msgcode = DIDmsg_dot11req_mibget;
+ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
+ if (rts->disabled)
+ mibitem.data = 2347;
+ else
+ mibitem.data = rts->value;
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+static int p80211wext_giwfrag(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ msg.msgcode = DIDmsg_dot11req_mibget;
+ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
+
+ frag->value = mibitem.data;
+ frag->disabled = (frag->value == 2346);
+ frag->fixed = 1;
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+static int p80211wext_siwfrag(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ if (!wlan_wext_write) {
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+ msg.msgcode = DIDmsg_dot11req_mibset;
+ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
+
+ if (frag->disabled)
+ mibitem.data = 2346;
+ else
+ mibitem.data = frag->value;
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+#endif /* WIRELESS_EXT > 8 */
+
+#if WIRELESS_EXT > 10
+
+#ifndef IW_RETRY_LONG
+#define IW_RETRY_LONG IW_RETRY_MAX
+#endif
+
+#ifndef IW_RETRY_SHORT
+#define IW_RETRY_SHORT IW_RETRY_MIN
+#endif
+
+static int p80211wext_giwretry(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+ UINT16 shortretry, longretry, lifetime;
+
+ DBFENTER;
+
+ msg.msgcode = DIDmsg_dot11req_mibget;
+ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
+
+ shortretry = mibitem.data;
+
+ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
+
+ longretry = mibitem.data;
+
+ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
+
+ lifetime = mibitem.data;
+
+ rrq->disabled = 0;
+
+ if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+ rrq->flags = IW_RETRY_LIFETIME;
+ rrq->value = lifetime * 1024;
+ } else {
+ if (rrq->flags & IW_RETRY_LONG) {
+ rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ rrq->value = longretry;
+ } else {
+ rrq->flags = IW_RETRY_LIMIT;
+ rrq->value = shortretry;
+ if (shortretry != longretry)
+ rrq->flags |= IW_RETRY_SHORT;
+ }
+ }
+
+ exit:
+ DBFEXIT;
+ return err;
+
+}
+
+static int p80211wext_siwretry(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ if (!wlan_wext_write) {
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+ if (rrq->disabled) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ msg.msgcode = DIDmsg_dot11req_mibset;
+
+ if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
+ mibitem.data = rrq->value /= 1024;
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+ } else {
+ if (rrq->flags & IW_RETRY_LONG) {
+ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
+ mibitem.data = rrq->value;
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+ }
+
+ if (rrq->flags & IW_RETRY_SHORT) {
+ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
+ mibitem.data = rrq->value;
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+ }
+ }
+
+ exit:
+ DBFEXIT;
+ return err;
+
+}
+
+#endif /* WIRELESS_EXT > 10 */
+
+#if WIRELESS_EXT > 9
+static int p80211wext_siwtxpow(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ if (!wlan_wext_write) {
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+ msg.msgcode = DIDmsg_dot11req_mibset;
+
+ switch (rrq->value) {
+
+ case 1 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel1; break;
+ case 2 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel2; break;
+ case 3 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel3; break;
+ case 4 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel4; break;
+ case 5 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel5; break;
+ case 6 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel6; break;
+ case 7 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel7; break;
+ case 8 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8; break;
+ default: mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8; break;
+ }
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+static int p80211wext_giwtxpow(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211item_uint32_t mibitem;
+ p80211msg_dot11req_mibset_t msg;
+ int result;
+ int err = 0;
+
+ DBFENTER;
+
+ msg.msgcode = DIDmsg_dot11req_mibget;
+ mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
+
+ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem));
+
+ // XXX handle OFF by setting disabled = 1;
+
+ rrq->flags = 0; // IW_TXPOW_DBM;
+ rrq->disabled = 0;
+ rrq->fixed = 0;
+ rrq->value = mibitem.data;
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+#endif /* WIRELESS_EXT > 9 */
+
+static int p80211wext_siwspy(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *srq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ struct sockaddr address[IW_MAX_SPY];
+ int number = srq->length;
+ int i;
+
+ DBFENTER;
+
+ /* Copy the data from the input buffer */
+ memcpy(address, extra, sizeof(struct sockaddr)*number);
+
+ wlandev->spy_number = 0;
+
+ if (number > 0) {
+
+ /* extract the addresses */
+ for (i = 0; i < number; i++) {
+
+ memcpy(wlandev->spy_address[i], address[i].sa_data, ETH_ALEN);
+ }
+
+ /* reset stats */
+ memset(wlandev->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY);
+
+ /* set number of addresses */
+ wlandev->spy_number = number;
+ }
+
+ DBFEXIT;
+ return 0;
+}
+
+/* jkriegl: from orinoco, modified */
+static int p80211wext_giwspy(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *srq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+
+ struct sockaddr address[IW_MAX_SPY];
+ struct iw_quality spy_stat[IW_MAX_SPY];
+ int number;
+ int i;
+
+ DBFENTER;
+
+ number = wlandev->spy_number;
+
+ if (number > 0) {
+
+ /* populate address and spy struct's */
+ for (i = 0; i < number; i++) {
+ memcpy(address[i].sa_data, wlandev->spy_address[i], ETH_ALEN);
+ address[i].sa_family = AF_UNIX;
+ memcpy(&spy_stat[i], &wlandev->spy_stat[i], sizeof(struct iw_quality));
+ }
+
+ /* reset update flag */
+ for (i=0; i < number; i++)
+ wlandev->spy_stat[i].updated = 0;
+ }
+
+ /* push stuff to user space */
+ srq->length = number;
+ memcpy(extra, address, sizeof(struct sockaddr)*number);
+ memcpy(extra+sizeof(struct sockaddr)*number, spy_stat, sizeof(struct iw_quality)*number);
+
+ DBFEXIT;
+ return 0;
+}
+
+static int prism2_result2err (int prism2_result)
+{
+ int err = 0;
+
+ switch (prism2_result) {
+ case P80211ENUM_resultcode_invalid_parameters:
+ err = -EINVAL;
+ break;
+ case P80211ENUM_resultcode_implementation_failure:
+ err = -EIO;
+ break;
+ case P80211ENUM_resultcode_not_supported:
+ err = -EOPNOTSUPP;
+ break;
+ default:
+ err = 0;
+ break;
+ }
+
+ return err;
+}
+
+#if WIRELESS_EXT > 13
+static int p80211wext_siwscan(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *srq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211msg_dot11req_scan_t msg;
+ int result;
+ int err = 0;
+ int i = 0;
+
+ DBFENTER;
+
+ if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
+ WLAN_LOG_ERROR("Can't scan in AP mode\n");
+ err = (-EOPNOTSUPP);
+ goto exit;
+ }
+
+ memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t));
+ msg.msgcode = DIDmsg_dot11req_scan;
+ msg.bsstype.data = P80211ENUM_bsstype_any;
+
+ memset(&(msg.bssid.data), 0xFF, sizeof (p80211item_pstr6_t));
+ msg.bssid.data.len = 6;
+
+ msg.scantype.data = P80211ENUM_scantype_active;
+ msg.probedelay.data = 0;
+
+ for (i = 1; i <= 14; i++)
+ msg.channellist.data.data[i-1] = i;
+ msg.channellist.data.len = 14;
+
+ msg.maxchanneltime.data = 250;
+ msg.minchanneltime.data = 200;
+
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+ if (result)
+ err = prism2_result2err (msg.resultcode.data);
+
+ exit:
+ DBFEXIT;
+ return err;
+}
+
+
+/* Helper to translate scan into Wireless Extensions scan results.
+ * Inspired by the prism54 code, which was in turn inspired by the
+ * airo driver code.
+ */
+static char *
+wext_translate_bss(struct iw_request_info *info, char *current_ev,
+ char *end_buf, p80211msg_dot11req_scan_results_t *bss)
+{
+ struct iw_event iwe; /* Temporary buffer */
+
+ /* The first entry must be the MAC address */
+ memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN);
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ iwe.cmd = SIOCGIWAP;
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+ /* The following entries will be displayed in the same order we give them */
+
+ /* The ESSID. */
+ if (bss->ssid.data.len > 0) {
+ char essid[IW_ESSID_MAX_SIZE + 1];
+ int size;
+
+ size = wlan_min(IW_ESSID_MAX_SIZE, bss->ssid.data.len);
+ memset(&essid, 0, sizeof (essid));
+ memcpy(&essid, bss->ssid.data.data, size);
+ WLAN_LOG_DEBUG(1, " essid size = %d\n", size);
+ iwe.u.data.length = size;
+ iwe.u.data.flags = 1;
+ iwe.cmd = SIOCGIWESSID;
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, &essid[0]);
+ WLAN_LOG_DEBUG(1, " essid size OK.\n");
+ }
+
+ switch (bss->bsstype.data) {
+ case P80211ENUM_bsstype_infrastructure:
+ iwe.u.mode = IW_MODE_MASTER;
+ break;
+
+ case P80211ENUM_bsstype_independent:
+ iwe.u.mode = IW_MODE_ADHOC;
+ break;
+
+ default:
+ iwe.u.mode = 0;
+ break;
+ }
+ iwe.cmd = SIOCGIWMODE;
+ if (iwe.u.mode)
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+
+ /* Encryption capability */
+ if (bss->privacy.data == P80211ENUM_truth_true)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ iwe.cmd = SIOCGIWENCODE;
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL);
+
+ /* Add frequency. (short) bss->channel is the frequency in MHz */
+ iwe.u.freq.m = bss->dschannel.data;
+ iwe.u.freq.e = 0;
+ iwe.cmd = SIOCGIWFREQ;
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
+
+ /* Add quality statistics */
+ iwe.u.qual.level = bss->signal.data;
+ iwe.u.qual.noise = bss->noise.data;
+ /* do a simple SNR for quality */
+ iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data);
+ iwe.cmd = IWEVQUAL;
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+
+ return current_ev;
+}
+
+
+static int p80211wext_giwscan(netdevice_t *dev,
+ struct iw_request_info *info,
+ struct iw_point *srq, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ p80211msg_dot11req_scan_results_t msg;
+ int result = 0;
+ int err = 0;
+ int i = 0;
+ int scan_good = 0;
+ char *current_ev = extra;
+
+ DBFENTER;
+
+ /* Since wireless tools doesn't really have a way of passing how
+ * many scan results results there were back here, keep grabbing them
+ * until we fail.
+ */
+ do {
+ memset(&msg, 0, sizeof(msg));
+ msg.msgcode = DIDmsg_dot11req_scan_results;
+ msg.bssindex.data = i;
+
+ result = p80211req_dorequest(wlandev, (UINT8*)&msg);
+ if ((result != 0) ||
+ (msg.resultcode.data != P80211ENUM_resultcode_success)) {
+ break;
+ }
+
+ current_ev = wext_translate_bss(info, current_ev, extra + IW_SCAN_MAX_DATA, &msg);
+ scan_good = 1;
+ i++;
+ } while (i < IW_MAX_AP);
+
+ srq->length = (current_ev - extra);
+ srq->flags = 0; /* todo */
+
+ if (result && !scan_good)
+ err = prism2_result2err (msg.resultcode.data);
+
+ DBFEXIT;
+ return err;
+}
+#endif
+
+/*****************************************************/
+//extra wireless extensions stuff to support NetworkManager (I hope)
+
+#if WIRELESS_EXT > 17
+/* SIOCSIWENCODEEXT */
+static int p80211wext_set_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ p80211msg_dot11req_mibset_t msg;
+ p80211item_pstr32_t *pstr;
+
+ int result = 0;
+ struct iw_point *encoding = &wrqu->encoding;
+ int idx = encoding->flags & IW_ENCODE_INDEX;
+
+ WLAN_LOG_DEBUG(1,"set_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len);
+
+
+ if ( ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY ) {
+ // set default key ? I'm not sure if this the the correct thing to do here
+
+ if ( idx ) {
+ if (idx < 1 || idx > NUM_WEPKEYS) {
+ return -EINVAL;
+ } else
+ idx--;
+ }
+ WLAN_LOG_DEBUG(1,"setting default key (%d)\n",idx);
+ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, idx);
+ if ( result )
+ return -EFAULT;
+ }
+
+
+ if ( ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY ) {
+ if ( ! ext->alg & IW_ENCODE_ALG_WEP) {
+ WLAN_LOG_DEBUG(1,"asked to set a non wep key :(");
+ return -EINVAL;
+ }
+ if (idx) {
+ if (idx <1 || idx > NUM_WEPKEYS)
+ return -EINVAL;
+ else
+ idx--;
+ }
+ WLAN_LOG_DEBUG(1,"Set WEP key (%d)\n",idx);
+ wlandev->wep_keylens[idx] = ext->key_len;
+ memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len);
+
+ memset( &msg,0,sizeof(msg));
+ pstr = (p80211item_pstr32_t*)&msg.mibattribute.data;
+ memcpy(pstr->data.data, ext->key,ext->key_len);
+ pstr->data.len = ext->key_len;
+ switch (idx) {
+ case 0:
+ pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
+ break;
+ case 1:
+ pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
+ break;
+ case 2:
+ pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
+ break;
+ case 3:
+ pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
+ break;
+ default:
+ break;
+ }
+ msg.msgcode = DIDmsg_dot11req_mibset;
+ result = p80211req_dorequest(wlandev,(UINT8*)&msg);
+ WLAN_LOG_DEBUG(1,"result (%d)\n",result);
+ }
+ return result;
+}
+
+/* SIOCGIWENCODEEXT */
+static int p80211wext_get_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+
+ struct iw_point *encoding = &wrqu->encoding;
+ int result = 0;
+ int max_len;
+ int idx;
+
+ DBFENTER;
+
+ WLAN_LOG_DEBUG(1,"get_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len);
+
+
+ max_len = encoding->length - sizeof(*ext);
+ if ( max_len <= 0) {
+ WLAN_LOG_DEBUG(1,"get_encodeext max_len [%d] invalid\n",max_len);
+ result = -EINVAL;
+ goto exit;
+ }
+ idx = encoding->flags & IW_ENCODE_INDEX;
+
+ WLAN_LOG_DEBUG(1,"get_encode_ext index [%d]\n",idx);
+
+ if (idx) {
+ if (idx < 1 || idx > NUM_WEPKEYS ) {
+ WLAN_LOG_DEBUG(1,"get_encode_ext invalid key index [%d]\n",idx);
+ result = -EINVAL;
+ goto exit;
+ }
+ idx--;
+ } else {
+ /* default key ? not sure what to do */
+ /* will just use key[0] for now ! FIX ME */
+ }
+
+ encoding->flags = idx + 1;
+ memset(ext,0,sizeof(*ext));
+
+ ext->alg = IW_ENCODE_ALG_WEP;
+ ext->key_len = wlandev->wep_keylens[idx];
+ memcpy( ext->key, wlandev->wep_keys[idx] , ext->key_len );
+
+ encoding->flags |= IW_ENCODE_ENABLED;
+exit:
+ DBFEXIT;
+
+ return result;
+}
+
+
+/* SIOCSIWAUTH */
+static int p80211_wext_set_iwauth (struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ struct iw_param *param = &wrqu->param;
+ int result =0;
+
+ WLAN_LOG_DEBUG(1,"set_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX );
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_DROP_UNENCRYPTED:
+ WLAN_LOG_DEBUG(1,"drop_unencrypted %d\n",param->value);
+ if (param->value)
+ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true);
+ else
+ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false);
+ break;
+
+ case IW_AUTH_PRIVACY_INVOKED:
+ WLAN_LOG_DEBUG(1,"privacy invoked %d\n",param->value);
+ if ( param->value)
+ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true);
+ else
+ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false);
+
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ if ( param->value & IW_AUTH_ALG_OPEN_SYSTEM ) {
+ WLAN_LOG_DEBUG(1,"set open_system\n");
+ wlandev->hostwep &= ~HOSTWEP_SHAREDKEY;
+ } else if ( param->value & IW_AUTH_ALG_SHARED_KEY) {
+ WLAN_LOG_DEBUG(1,"set shared key\n");
+ wlandev->hostwep |= HOSTWEP_SHAREDKEY;
+ } else {
+ /* don't know what to do know :( */
+ WLAN_LOG_DEBUG(1,"unknown AUTH_ALG (%d)\n",param->value);
+ result = -EINVAL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+
+
+ return result;
+}
+
+/* SIOCSIWAUTH */
+static int p80211_wext_get_iwauth (struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+ struct iw_param *param = &wrqu->param;
+ int result =0;
+
+ WLAN_LOG_DEBUG(1,"get_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX );
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_DROP_UNENCRYPTED:
+ param->value = wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED?1:0;
+ break;
+
+ case IW_AUTH_PRIVACY_INVOKED:
+ param->value = wlandev->hostwep & HOSTWEP_PRIVACYINVOKED?1:0;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ param->value = wlandev->hostwep & HOSTWEP_SHAREDKEY?IW_AUTH_ALG_SHARED_KEY:IW_AUTH_ALG_OPEN_SYSTEM;
+ break;
+
+
+ default:
+ break;
+ }
+
+
+
+ return result;
+}
+
+
+#endif
+
+
+
+
+
+
+/*****************************************************/
+
+
+
+
+
+/*
+typedef int (*iw_handler)(netdevice_t *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+*/
+
+#if WIRELESS_EXT > 12
+static iw_handler p80211wext_handlers[] = {
+ (iw_handler) p80211wext_siwcommit, /* SIOCSIWCOMMIT */
+ (iw_handler) p80211wext_giwname, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) p80211wext_siwfreq, /* SIOCSIWFREQ */
+ (iw_handler) p80211wext_giwfreq, /* SIOCGIWFREQ */
+ (iw_handler) p80211wext_siwmode, /* SIOCSIWMODE */
+ (iw_handler) p80211wext_giwmode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* not used */ /* SIOCSIWRANGE */
+ (iw_handler) p80211wext_giwrange, /* SIOCGIWRANGE */
+ (iw_handler) NULL, /* not used */ /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* kernel code */ /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* not used */ /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* kernel code */ /* SIOCGIWSTATS */
+ (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */
+ (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* SIOCSIWAP */
+ (iw_handler) p80211wext_giwap, /* SIOCGIWAP */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+ (iw_handler) p80211wext_siwscan, /* SIOCSIWSCAN */
+ (iw_handler) p80211wext_giwscan, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+ (iw_handler) NULL, /* null */ /* SIOCSIWSCAN */
+ (iw_handler) NULL, /* null */ /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+ (iw_handler) p80211wext_siwessid, /* SIOCSIWESSID */
+ (iw_handler) p80211wext_giwessid, /* SIOCGIWESSID */
+ (iw_handler) NULL, /* SIOCSIWNICKN */
+ (iw_handler) p80211wext_giwessid, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* SIOCSIWRATE */
+ (iw_handler) p80211wext_giwrate, /* SIOCGIWRATE */
+ (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */
+ (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */
+ (iw_handler) p80211wext_siwfrag, /* SIOCSIWFRAG */
+ (iw_handler) p80211wext_giwfrag, /* SIOCGIWFRAG */
+ (iw_handler) p80211wext_siwtxpow, /* SIOCSIWTXPOW */
+ (iw_handler) p80211wext_giwtxpow, /* SIOCGIWTXPOW */
+ (iw_handler) p80211wext_siwretry, /* SIOCSIWRETRY */
+ (iw_handler) p80211wext_giwretry, /* SIOCGIWRETRY */
+ (iw_handler) p80211wext_siwencode, /* SIOCSIWENCODE */
+ (iw_handler) p80211wext_giwencode, /* SIOCGIWENCODE */
+ (iw_handler) NULL, /* SIOCSIWPOWER */
+ (iw_handler) NULL, /* SIOCGIWPOWER */
+#if WIRELESS_EXT > 17
+/* WPA operations */
+
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* SIOCSIWGENIE set generic IE */
+ (iw_handler) NULL, /* SIOCGIWGENIE get generic IE */
+ (iw_handler) p80211_wext_set_iwauth, /* SIOCSIWAUTH set authentication mode params */
+ (iw_handler) p80211_wext_get_iwauth, /* SIOCGIWAUTH get authentication mode params */
+
+ (iw_handler) p80211wext_set_encodeext, /* SIOCSIWENCODEEXT set encoding token & mode */
+ (iw_handler) p80211wext_get_encodeext, /* SIOCGIWENCODEEXT get encoding token & mode */
+ (iw_handler) NULL, /* SIOCSIWPMKSA PMKSA cache operation */
+#endif
+};
+
+struct iw_handler_def p80211wext_handler_def = {
+ .num_standard = sizeof(p80211wext_handlers) / sizeof(iw_handler),
+ .num_private = 0,
+ .num_private_args = 0,
+ .standard = p80211wext_handlers,
+ .private = NULL,
+ .private_args = NULL,
+#if WIRELESS_EXT > 16
+ .get_wireless_stats = p80211wext_get_wireless_stats
+#endif
+};
+
+#endif
+
+/* wireless extensions' ioctls */
+int p80211wext_support_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd)
+{
+ wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+
+#if WIRELESS_EXT < 13
+ struct iwreq *iwr = (struct iwreq*)ifr;
+#endif
+
+ p80211item_uint32_t mibitem;
+ int err = 0;
+
+ DBFENTER;
+
+ mibitem.status = P80211ENUM_msgitem_status_data_ok;
+
+ if ( wlandev->msdstate != WLAN_MSD_RUNNING ) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ WLAN_LOG_DEBUG(1, "Received wireless extension ioctl #%d.\n", cmd);
+
+ switch (cmd) {
+#if WIRELESS_EXT < 13
+ case SIOCSIWNAME: /* unused */
+ err = (-EOPNOTSUPP);
+ break;
+ case SIOCGIWNAME: /* get name == wireless protocol */
+ err = p80211wext_giwname(dev, NULL, (char *) &iwr->u, NULL);
+ break;
+ case SIOCSIWNWID:
+ case SIOCGIWNWID:
+ err = (-EOPNOTSUPP);
+ break;
+ case SIOCSIWFREQ: /* set channel */
+ err = p80211wext_siwfreq(dev, NULL, &(iwr->u.freq), NULL);
+ break;
+ case SIOCGIWFREQ: /* get channel */
+ err = p80211wext_giwfreq(dev, NULL, &(iwr->u.freq), NULL);
+ break;
+ case SIOCSIWRANGE:
+ case SIOCSIWPRIV:
+ case SIOCSIWAP: /* set access point MAC addresses (BSSID) */
+ err = (-EOPNOTSUPP);
+ break;
+
+ case SIOCGIWAP: /* get access point MAC addresses (BSSID) */
+ err = p80211wext_giwap(dev, NULL, &(iwr->u.ap_addr), NULL);
+ break;
+
+#if WIRELESS_EXT > 8
+ case SIOCSIWMODE: /* set operation mode */
+ case SIOCSIWESSID: /* set SSID (network name) */
+ case SIOCSIWRATE: /* set default bit rate (bps) */
+ err = (-EOPNOTSUPP);
+ break;
+
+ case SIOCGIWMODE: /* get operation mode */
+ err = p80211wext_giwmode(dev, NULL, &iwr->u.mode, NULL);
+
+ break;
+ case SIOCGIWNICKN: /* get node name/nickname */
+ case SIOCGIWESSID: /* get SSID */
+ if(iwr->u.essid.pointer) {
+ char ssid[IW_ESSID_MAX_SIZE+1];
+ memset(ssid, 0, sizeof(ssid));
+
+ err = p80211wext_giwessid(dev, NULL, &iwr->u.essid, ssid);
+ if(copy_to_user(iwr->u.essid.pointer, ssid, sizeof(ssid)))
+ err = (-EFAULT);
+ }
+ break;
+ case SIOCGIWRATE:
+ err = p80211wext_giwrate(dev, NULL, &iwr->u.bitrate, NULL);
+ break;
+ case SIOCGIWRTS:
+ err = p80211wext_giwrts(dev, NULL, &iwr->u.rts, NULL);
+ break;
+ case SIOCGIWFRAG:
+ err = p80211wext_giwfrag(dev, NULL, &iwr->u.rts, NULL);
+ break;
+ case SIOCGIWENCODE:
+ if (!capable(CAP_NET_ADMIN))
+ err = -EPERM;
+ else if (iwr->u.encoding.pointer) {
+ char keybuf[MAX_KEYLEN];
+ err = p80211wext_giwencode(dev, NULL,
+ &iwr->u.encoding, keybuf);
+ if (copy_to_user(iwr->u.encoding.pointer, keybuf,
+ iwr->u.encoding.length))
+ err = -EFAULT;
+ }
+ break;
+ case SIOCGIWAPLIST:
+ case SIOCSIWRTS:
+ case SIOCSIWFRAG:
+ case SIOCSIWSENS:
+ case SIOCGIWSENS:
+ case SIOCSIWNICKN: /* set node name/nickname */
+ case SIOCSIWENCODE: /* set encoding token & mode */
+ case SIOCSIWSPY:
+ case SIOCGIWSPY:
+ case SIOCSIWPOWER:
+ case SIOCGIWPOWER:
+ case SIOCGIWPRIV:
+ err = (-EOPNOTSUPP);
+ break;
+ case SIOCGIWRANGE:
+ if(iwr->u.data.pointer != NULL) {
+ struct iw_range range;
+ err = p80211wext_giwrange(dev, NULL, &iwr->u.data,
+ (char *) &range);
+ /* Push that up to the caller */
+ if (copy_to_user(iwr->u.data.pointer, &range, sizeof(range)))
+ err = -EFAULT;
+ }
+ break;
+#endif /* WIRELESS_EXT > 8 */
+#if WIRELESS_EXT > 9
+ case SIOCSIWTXPOW:
+ err = (-EOPNOTSUPP);
+ break;
+ case SIOCGIWTXPOW:
+ err = p80211wext_giwtxpow(dev, NULL, &iwr->u.txpower, NULL);
+ break;
+#endif /* WIRELESS_EXT > 9 */
+#if WIRELESS_EXT > 10
+ case SIOCSIWRETRY:
+ err = (-EOPNOTSUPP);
+ break;
+ case SIOCGIWRETRY:
+ err = p80211wext_giwretry(dev, NULL, &iwr->u.retry, NULL);
+ break;
+#endif /* WIRELESS_EXT > 10 */
+
+#endif /* WIRELESS_EXT <= 12 */
+
+ default:
+ err = (-EOPNOTSUPP);
+ break;
+ }
+
+ exit:
+ DBFEXIT;
+ return (err);
+}
+
+int p80211wext_event_associated(wlandevice_t *wlandev, int assoc)
+{
+ union iwreq_data data;
+
+ DBFENTER;
+
+#if WIRELESS_EXT > 13
+ /* Send the association state first */
+ data.ap_addr.sa_family = ARPHRD_ETHER;
+ if (assoc) {
+ memcpy(data.ap_addr.sa_data, wlandev->bssid, WLAN_ADDR_LEN);
+ } else {
+ memset(data.ap_addr.sa_data, 0, WLAN_ADDR_LEN);
+ }
+
+ if (wlan_wext_write)
+ wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL);
+
+ if (!assoc) goto done;
+
+ // XXX send association data, like IEs, etc etc.
+#endif
+ done:
+ DBFEXIT;
+ return 0;
+}
+
+
+#endif /* compatibility to wireless extensions */
+
+
+
+