Back to home page

OSCL-LXR

 
 

    


0001 /* Wireless extensions support.
0002  *
0003  * See copyright notice in main.c
0004  */
0005 #include <linux/slab.h>
0006 #include <linux/kernel.h>
0007 #include <linux/if_arp.h>
0008 #include <linux/wireless.h>
0009 #include <linux/ieee80211.h>
0010 #include <linux/etherdevice.h>
0011 #include <net/iw_handler.h>
0012 #include <net/cfg80211.h>
0013 #include <net/cfg80211-wext.h>
0014 
0015 #include "hermes.h"
0016 #include "hermes_rid.h"
0017 #include "orinoco.h"
0018 
0019 #include "hw.h"
0020 #include "mic.h"
0021 #include "scan.h"
0022 #include "main.h"
0023 
0024 #include "wext.h"
0025 
0026 #define MAX_RID_LEN 1024
0027 
0028 /* Helper routine to record keys
0029  * It is called under orinoco_lock so it may not sleep */
0030 static int orinoco_set_key(struct orinoco_private *priv, int index,
0031                enum orinoco_alg alg, const u8 *key, int key_len,
0032                const u8 *seq, int seq_len)
0033 {
0034     kfree_sensitive(priv->keys[index].key);
0035     kfree_sensitive(priv->keys[index].seq);
0036 
0037     if (key_len) {
0038         priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC);
0039         if (!priv->keys[index].key)
0040             goto nomem;
0041     } else
0042         priv->keys[index].key = NULL;
0043 
0044     if (seq_len) {
0045         priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC);
0046         if (!priv->keys[index].seq)
0047             goto free_key;
0048     } else
0049         priv->keys[index].seq = NULL;
0050 
0051     priv->keys[index].key_len = key_len;
0052     priv->keys[index].seq_len = seq_len;
0053 
0054     if (key_len)
0055         memcpy((void *)priv->keys[index].key, key, key_len);
0056     if (seq_len)
0057         memcpy((void *)priv->keys[index].seq, seq, seq_len);
0058 
0059     switch (alg) {
0060     case ORINOCO_ALG_TKIP:
0061         priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
0062         break;
0063 
0064     case ORINOCO_ALG_WEP:
0065         priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
0066             WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
0067         break;
0068 
0069     case ORINOCO_ALG_NONE:
0070     default:
0071         priv->keys[index].cipher = 0;
0072         break;
0073     }
0074 
0075     return 0;
0076 
0077 free_key:
0078     kfree(priv->keys[index].key);
0079     priv->keys[index].key = NULL;
0080 
0081 nomem:
0082     priv->keys[index].key_len = 0;
0083     priv->keys[index].seq_len = 0;
0084     priv->keys[index].cipher = 0;
0085 
0086     return -ENOMEM;
0087 }
0088 
0089 static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
0090 {
0091     struct orinoco_private *priv = ndev_priv(dev);
0092     struct hermes *hw = &priv->hw;
0093     struct iw_statistics *wstats = &priv->wstats;
0094     int err;
0095     unsigned long flags;
0096 
0097     if (!netif_device_present(dev)) {
0098         printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
0099                dev->name);
0100         return NULL; /* FIXME: Can we do better than this? */
0101     }
0102 
0103     /* If busy, return the old stats.  Returning NULL may cause
0104      * the interface to disappear from /proc/net/wireless */
0105     if (orinoco_lock(priv, &flags) != 0)
0106         return wstats;
0107 
0108     /* We can't really wait for the tallies inquiry command to
0109      * complete, so we just use the previous results and trigger
0110      * a new tallies inquiry command for next time - Jean II */
0111     /* FIXME: Really we should wait for the inquiry to come back -
0112      * as it is the stats we give don't make a whole lot of sense.
0113      * Unfortunately, it's not clear how to do that within the
0114      * wireless extensions framework: I think we're in user
0115      * context, but a lock seems to be held by the time we get in
0116      * here so we're not safe to sleep here. */
0117     hermes_inquire(hw, HERMES_INQ_TALLIES);
0118 
0119     if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
0120         memset(&wstats->qual, 0, sizeof(wstats->qual));
0121         /* If a spy address is defined, we report stats of the
0122          * first spy address - Jean II */
0123         if (SPY_NUMBER(priv)) {
0124             wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
0125             wstats->qual.level = priv->spy_data.spy_stat[0].level;
0126             wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
0127             wstats->qual.updated =
0128                 priv->spy_data.spy_stat[0].updated;
0129         }
0130     } else {
0131         struct {
0132             __le16 qual, signal, noise, unused;
0133         } __packed cq;
0134 
0135         err = HERMES_READ_RECORD(hw, USER_BAP,
0136                      HERMES_RID_COMMSQUALITY, &cq);
0137 
0138         if (!err) {
0139             wstats->qual.qual = (int)le16_to_cpu(cq.qual);
0140             wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
0141             wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
0142             wstats->qual.updated =
0143                 IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
0144         }
0145     }
0146 
0147     orinoco_unlock(priv, &flags);
0148     return wstats;
0149 }
0150 
0151 /********************************************************************/
0152 /* Wireless extensions                                              */
0153 /********************************************************************/
0154 
0155 static int orinoco_ioctl_setwap(struct net_device *dev,
0156                 struct iw_request_info *info,
0157                 struct sockaddr *ap_addr,
0158                 char *extra)
0159 {
0160     struct orinoco_private *priv = ndev_priv(dev);
0161     int err = -EINPROGRESS;     /* Call commit handler */
0162     unsigned long flags;
0163 
0164     if (orinoco_lock(priv, &flags) != 0)
0165         return -EBUSY;
0166 
0167     /* Enable automatic roaming - no sanity checks are needed */
0168     if (is_zero_ether_addr(ap_addr->sa_data) ||
0169         is_broadcast_ether_addr(ap_addr->sa_data)) {
0170         priv->bssid_fixed = 0;
0171         eth_zero_addr(priv->desired_bssid);
0172 
0173         /* "off" means keep existing connection */
0174         if (ap_addr->sa_data[0] == 0) {
0175             __orinoco_hw_set_wap(priv);
0176             err = 0;
0177         }
0178         goto out;
0179     }
0180 
0181     if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
0182         printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
0183                "support manual roaming\n",
0184                dev->name);
0185         err = -EOPNOTSUPP;
0186         goto out;
0187     }
0188 
0189     if (priv->iw_mode != NL80211_IFTYPE_STATION) {
0190         printk(KERN_WARNING "%s: Manual roaming supported only in "
0191                "managed mode\n", dev->name);
0192         err = -EOPNOTSUPP;
0193         goto out;
0194     }
0195 
0196     /* Intersil firmware hangs without Desired ESSID */
0197     if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
0198         strlen(priv->desired_essid) == 0) {
0199         printk(KERN_WARNING "%s: Desired ESSID must be set for "
0200                "manual roaming\n", dev->name);
0201         err = -EOPNOTSUPP;
0202         goto out;
0203     }
0204 
0205     /* Finally, enable manual roaming */
0206     priv->bssid_fixed = 1;
0207     memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
0208 
0209  out:
0210     orinoco_unlock(priv, &flags);
0211     return err;
0212 }
0213 
0214 static int orinoco_ioctl_getwap(struct net_device *dev,
0215                 struct iw_request_info *info,
0216                 struct sockaddr *ap_addr,
0217                 char *extra)
0218 {
0219     struct orinoco_private *priv = ndev_priv(dev);
0220 
0221     int err = 0;
0222     unsigned long flags;
0223 
0224     if (orinoco_lock(priv, &flags) != 0)
0225         return -EBUSY;
0226 
0227     ap_addr->sa_family = ARPHRD_ETHER;
0228     err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
0229 
0230     orinoco_unlock(priv, &flags);
0231 
0232     return err;
0233 }
0234 
0235 static int orinoco_ioctl_setiwencode(struct net_device *dev,
0236                      struct iw_request_info *info,
0237                      struct iw_point *erq,
0238                      char *keybuf)
0239 {
0240     struct orinoco_private *priv = ndev_priv(dev);
0241     int index = (erq->flags & IW_ENCODE_INDEX) - 1;
0242     int setindex = priv->tx_key;
0243     enum orinoco_alg encode_alg = priv->encode_alg;
0244     int restricted = priv->wep_restrict;
0245     int err = -EINPROGRESS;     /* Call commit handler */
0246     unsigned long flags;
0247 
0248     if (!priv->has_wep)
0249         return -EOPNOTSUPP;
0250 
0251     if (erq->pointer) {
0252         /* We actually have a key to set - check its length */
0253         if (erq->length > LARGE_KEY_SIZE)
0254             return -E2BIG;
0255 
0256         if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep)
0257             return -E2BIG;
0258     }
0259 
0260     if (orinoco_lock(priv, &flags) != 0)
0261         return -EBUSY;
0262 
0263     /* Clear any TKIP key we have */
0264     if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
0265         (void) orinoco_clear_tkip_key(priv, setindex);
0266 
0267     if (erq->length > 0) {
0268         if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
0269             index = priv->tx_key;
0270 
0271         /* Switch on WEP if off */
0272         if (encode_alg != ORINOCO_ALG_WEP) {
0273             setindex = index;
0274             encode_alg = ORINOCO_ALG_WEP;
0275         }
0276     } else {
0277         /* Important note : if the user do "iwconfig eth0 enc off",
0278          * we will arrive there with an index of -1. This is valid
0279          * but need to be taken care off... Jean II */
0280         if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
0281             if ((index != -1) || (erq->flags == 0)) {
0282                 err = -EINVAL;
0283                 goto out;
0284             }
0285         } else {
0286             /* Set the index : Check that the key is valid */
0287             if (priv->keys[index].key_len == 0) {
0288                 err = -EINVAL;
0289                 goto out;
0290             }
0291             setindex = index;
0292         }
0293     }
0294 
0295     if (erq->flags & IW_ENCODE_DISABLED)
0296         encode_alg = ORINOCO_ALG_NONE;
0297     if (erq->flags & IW_ENCODE_OPEN)
0298         restricted = 0;
0299     if (erq->flags & IW_ENCODE_RESTRICTED)
0300         restricted = 1;
0301 
0302     if (erq->pointer && erq->length > 0) {
0303         err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
0304                       erq->length, NULL, 0);
0305     }
0306     priv->tx_key = setindex;
0307 
0308     /* Try fast key change if connected and only keys are changed */
0309     if ((priv->encode_alg == encode_alg) &&
0310         (priv->wep_restrict == restricted) &&
0311         netif_carrier_ok(dev)) {
0312         err = __orinoco_hw_setup_wepkeys(priv);
0313         /* No need to commit if successful */
0314         goto out;
0315     }
0316 
0317     priv->encode_alg = encode_alg;
0318     priv->wep_restrict = restricted;
0319 
0320  out:
0321     orinoco_unlock(priv, &flags);
0322 
0323     return err;
0324 }
0325 
0326 static int orinoco_ioctl_getiwencode(struct net_device *dev,
0327                      struct iw_request_info *info,
0328                      struct iw_point *erq,
0329                      char *keybuf)
0330 {
0331     struct orinoco_private *priv = ndev_priv(dev);
0332     int index = (erq->flags & IW_ENCODE_INDEX) - 1;
0333     unsigned long flags;
0334 
0335     if (!priv->has_wep)
0336         return -EOPNOTSUPP;
0337 
0338     if (orinoco_lock(priv, &flags) != 0)
0339         return -EBUSY;
0340 
0341     if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
0342         index = priv->tx_key;
0343 
0344     erq->flags = 0;
0345     if (!priv->encode_alg)
0346         erq->flags |= IW_ENCODE_DISABLED;
0347     erq->flags |= index + 1;
0348 
0349     if (priv->wep_restrict)
0350         erq->flags |= IW_ENCODE_RESTRICTED;
0351     else
0352         erq->flags |= IW_ENCODE_OPEN;
0353 
0354     erq->length = priv->keys[index].key_len;
0355 
0356     memcpy(keybuf, priv->keys[index].key, erq->length);
0357 
0358     orinoco_unlock(priv, &flags);
0359     return 0;
0360 }
0361 
0362 static int orinoco_ioctl_setessid(struct net_device *dev,
0363                   struct iw_request_info *info,
0364                   struct iw_point *erq,
0365                   char *essidbuf)
0366 {
0367     struct orinoco_private *priv = ndev_priv(dev);
0368     unsigned long flags;
0369 
0370     /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
0371      * anyway... - Jean II */
0372 
0373     /* Hum... Should not use Wireless Extension constant (may change),
0374      * should use our own... - Jean II */
0375     if (erq->length > IW_ESSID_MAX_SIZE)
0376         return -E2BIG;
0377 
0378     if (orinoco_lock(priv, &flags) != 0)
0379         return -EBUSY;
0380 
0381     /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
0382     memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
0383 
0384     /* If not ANY, get the new ESSID */
0385     if (erq->flags)
0386         memcpy(priv->desired_essid, essidbuf, erq->length);
0387 
0388     orinoco_unlock(priv, &flags);
0389 
0390     return -EINPROGRESS;        /* Call commit handler */
0391 }
0392 
0393 static int orinoco_ioctl_getessid(struct net_device *dev,
0394                   struct iw_request_info *info,
0395                   struct iw_point *erq,
0396                   char *essidbuf)
0397 {
0398     struct orinoco_private *priv = ndev_priv(dev);
0399     int active;
0400     int err = 0;
0401     unsigned long flags;
0402 
0403     if (netif_running(dev)) {
0404         err = orinoco_hw_get_essid(priv, &active, essidbuf);
0405         if (err < 0)
0406             return err;
0407         erq->length = err;
0408     } else {
0409         if (orinoco_lock(priv, &flags) != 0)
0410             return -EBUSY;
0411         memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
0412         erq->length = strlen(priv->desired_essid);
0413         orinoco_unlock(priv, &flags);
0414     }
0415 
0416     erq->flags = 1;
0417 
0418     return 0;
0419 }
0420 
0421 static int orinoco_ioctl_setfreq(struct net_device *dev,
0422                  struct iw_request_info *info,
0423                  struct iw_freq *frq,
0424                  char *extra)
0425 {
0426     struct orinoco_private *priv = ndev_priv(dev);
0427     int chan = -1;
0428     unsigned long flags;
0429     int err = -EINPROGRESS;     /* Call commit handler */
0430 
0431     /* In infrastructure mode the AP sets the channel */
0432     if (priv->iw_mode == NL80211_IFTYPE_STATION)
0433         return -EBUSY;
0434 
0435     if ((frq->e == 0) && (frq->m <= 1000)) {
0436         /* Setting by channel number */
0437         chan = frq->m;
0438     } else {
0439         /* Setting by frequency */
0440         int denom = 1;
0441         int i;
0442 
0443         /* Calculate denominator to rescale to MHz */
0444         for (i = 0; i < (6 - frq->e); i++)
0445             denom *= 10;
0446 
0447         chan = ieee80211_frequency_to_channel(frq->m / denom);
0448     }
0449 
0450     if ((chan < 1) || (chan > NUM_CHANNELS) ||
0451          !(priv->channel_mask & (1 << (chan - 1))))
0452         return -EINVAL;
0453 
0454     if (orinoco_lock(priv, &flags) != 0)
0455         return -EBUSY;
0456 
0457     priv->channel = chan;
0458     if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
0459         /* Fast channel change - no commit if successful */
0460         struct hermes *hw = &priv->hw;
0461         err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
0462                         HERMES_TEST_SET_CHANNEL,
0463                     chan, NULL);
0464     }
0465     orinoco_unlock(priv, &flags);
0466 
0467     return err;
0468 }
0469 
0470 static int orinoco_ioctl_getfreq(struct net_device *dev,
0471                  struct iw_request_info *info,
0472                  struct iw_freq *frq,
0473                  char *extra)
0474 {
0475     struct orinoco_private *priv = ndev_priv(dev);
0476     int tmp;
0477 
0478     /* Locking done in there */
0479     tmp = orinoco_hw_get_freq(priv);
0480     if (tmp < 0)
0481         return tmp;
0482 
0483     frq->m = tmp * 100000;
0484     frq->e = 1;
0485 
0486     return 0;
0487 }
0488 
0489 static int orinoco_ioctl_getsens(struct net_device *dev,
0490                  struct iw_request_info *info,
0491                  struct iw_param *srq,
0492                  char *extra)
0493 {
0494     struct orinoco_private *priv = ndev_priv(dev);
0495     struct hermes *hw = &priv->hw;
0496     u16 val;
0497     int err;
0498     unsigned long flags;
0499 
0500     if (!priv->has_sensitivity)
0501         return -EOPNOTSUPP;
0502 
0503     if (orinoco_lock(priv, &flags) != 0)
0504         return -EBUSY;
0505     err = hermes_read_wordrec(hw, USER_BAP,
0506                   HERMES_RID_CNFSYSTEMSCALE, &val);
0507     orinoco_unlock(priv, &flags);
0508 
0509     if (err)
0510         return err;
0511 
0512     srq->value = val;
0513     srq->fixed = 0; /* auto */
0514 
0515     return 0;
0516 }
0517 
0518 static int orinoco_ioctl_setsens(struct net_device *dev,
0519                  struct iw_request_info *info,
0520                  struct iw_param *srq,
0521                  char *extra)
0522 {
0523     struct orinoco_private *priv = ndev_priv(dev);
0524     int val = srq->value;
0525     unsigned long flags;
0526 
0527     if (!priv->has_sensitivity)
0528         return -EOPNOTSUPP;
0529 
0530     if ((val < 1) || (val > 3))
0531         return -EINVAL;
0532 
0533     if (orinoco_lock(priv, &flags) != 0)
0534         return -EBUSY;
0535     priv->ap_density = val;
0536     orinoco_unlock(priv, &flags);
0537 
0538     return -EINPROGRESS;        /* Call commit handler */
0539 }
0540 
0541 static int orinoco_ioctl_setrate(struct net_device *dev,
0542                  struct iw_request_info *info,
0543                  struct iw_param *rrq,
0544                  char *extra)
0545 {
0546     struct orinoco_private *priv = ndev_priv(dev);
0547     int ratemode;
0548     int bitrate; /* 100s of kilobits */
0549     unsigned long flags;
0550 
0551     /* As the user space doesn't know our highest rate, it uses -1
0552      * to ask us to set the highest rate.  Test it using "iwconfig
0553      * ethX rate auto" - Jean II */
0554     if (rrq->value == -1)
0555         bitrate = 110;
0556     else {
0557         if (rrq->value % 100000)
0558             return -EINVAL;
0559         bitrate = rrq->value / 100000;
0560     }
0561 
0562     ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed);
0563 
0564     if (ratemode == -1)
0565         return -EINVAL;
0566 
0567     if (orinoco_lock(priv, &flags) != 0)
0568         return -EBUSY;
0569     priv->bitratemode = ratemode;
0570     orinoco_unlock(priv, &flags);
0571 
0572     return -EINPROGRESS;
0573 }
0574 
0575 static int orinoco_ioctl_getrate(struct net_device *dev,
0576                  struct iw_request_info *info,
0577                  struct iw_param *rrq,
0578                  char *extra)
0579 {
0580     struct orinoco_private *priv = ndev_priv(dev);
0581     int err = 0;
0582     int bitrate, automatic;
0583     unsigned long flags;
0584 
0585     if (orinoco_lock(priv, &flags) != 0)
0586         return -EBUSY;
0587 
0588     orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic);
0589 
0590     /* If the interface is running we try to find more about the
0591        current mode */
0592     if (netif_running(dev)) {
0593         int act_bitrate;
0594         int lerr;
0595 
0596         /* Ignore errors if we can't get the actual bitrate */
0597         lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate);
0598         if (!lerr)
0599             bitrate = act_bitrate;
0600     }
0601 
0602     orinoco_unlock(priv, &flags);
0603 
0604     rrq->value = bitrate;
0605     rrq->fixed = !automatic;
0606     rrq->disabled = 0;
0607 
0608     return err;
0609 }
0610 
0611 static int orinoco_ioctl_setpower(struct net_device *dev,
0612                   struct iw_request_info *info,
0613                   struct iw_param *prq,
0614                   char *extra)
0615 {
0616     struct orinoco_private *priv = ndev_priv(dev);
0617     int err = -EINPROGRESS;     /* Call commit handler */
0618     unsigned long flags;
0619 
0620     if (orinoco_lock(priv, &flags) != 0)
0621         return -EBUSY;
0622 
0623     if (prq->disabled) {
0624         priv->pm_on = 0;
0625     } else {
0626         switch (prq->flags & IW_POWER_MODE) {
0627         case IW_POWER_UNICAST_R:
0628             priv->pm_mcast = 0;
0629             priv->pm_on = 1;
0630             break;
0631         case IW_POWER_ALL_R:
0632             priv->pm_mcast = 1;
0633             priv->pm_on = 1;
0634             break;
0635         case IW_POWER_ON:
0636             /* No flags : but we may have a value - Jean II */
0637             break;
0638         default:
0639             err = -EINVAL;
0640             goto out;
0641         }
0642 
0643         if (prq->flags & IW_POWER_TIMEOUT) {
0644             priv->pm_on = 1;
0645             priv->pm_timeout = prq->value / 1000;
0646         }
0647         if (prq->flags & IW_POWER_PERIOD) {
0648             priv->pm_on = 1;
0649             priv->pm_period = prq->value / 1000;
0650         }
0651         /* It's valid to not have a value if we are just toggling
0652          * the flags... Jean II */
0653         if (!priv->pm_on) {
0654             err = -EINVAL;
0655             goto out;
0656         }
0657     }
0658 
0659  out:
0660     orinoco_unlock(priv, &flags);
0661 
0662     return err;
0663 }
0664 
0665 static int orinoco_ioctl_getpower(struct net_device *dev,
0666                   struct iw_request_info *info,
0667                   struct iw_param *prq,
0668                   char *extra)
0669 {
0670     struct orinoco_private *priv = ndev_priv(dev);
0671     struct hermes *hw = &priv->hw;
0672     int err = 0;
0673     u16 enable, period, timeout, mcast;
0674     unsigned long flags;
0675 
0676     if (orinoco_lock(priv, &flags) != 0)
0677         return -EBUSY;
0678 
0679     err = hermes_read_wordrec(hw, USER_BAP,
0680                   HERMES_RID_CNFPMENABLED, &enable);
0681     if (err)
0682         goto out;
0683 
0684     err = hermes_read_wordrec(hw, USER_BAP,
0685                   HERMES_RID_CNFMAXSLEEPDURATION, &period);
0686     if (err)
0687         goto out;
0688 
0689     err = hermes_read_wordrec(hw, USER_BAP,
0690                   HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
0691     if (err)
0692         goto out;
0693 
0694     err = hermes_read_wordrec(hw, USER_BAP,
0695                   HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
0696     if (err)
0697         goto out;
0698 
0699     prq->disabled = !enable;
0700     /* Note : by default, display the period */
0701     if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
0702         prq->flags = IW_POWER_TIMEOUT;
0703         prq->value = timeout * 1000;
0704     } else {
0705         prq->flags = IW_POWER_PERIOD;
0706         prq->value = period * 1000;
0707     }
0708     if (mcast)
0709         prq->flags |= IW_POWER_ALL_R;
0710     else
0711         prq->flags |= IW_POWER_UNICAST_R;
0712 
0713  out:
0714     orinoco_unlock(priv, &flags);
0715 
0716     return err;
0717 }
0718 
0719 static int orinoco_ioctl_set_encodeext(struct net_device *dev,
0720                        struct iw_request_info *info,
0721                        union iwreq_data *wrqu,
0722                        char *extra)
0723 {
0724     struct orinoco_private *priv = ndev_priv(dev);
0725     struct iw_point *encoding = &wrqu->encoding;
0726     struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
0727     int idx, alg = ext->alg, set_key = 1;
0728     unsigned long flags;
0729     int err = -EINVAL;
0730 
0731     if (orinoco_lock(priv, &flags) != 0)
0732         return -EBUSY;
0733 
0734     /* Determine and validate the key index */
0735     idx = encoding->flags & IW_ENCODE_INDEX;
0736     if (idx) {
0737         if ((idx < 1) || (idx > 4))
0738             goto out;
0739         idx--;
0740     } else
0741         idx = priv->tx_key;
0742 
0743     if (encoding->flags & IW_ENCODE_DISABLED)
0744         alg = IW_ENCODE_ALG_NONE;
0745 
0746     if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
0747         /* Clear any TKIP TX key we had */
0748         (void) orinoco_clear_tkip_key(priv, priv->tx_key);
0749     }
0750 
0751     if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
0752         priv->tx_key = idx;
0753         set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
0754                (ext->key_len > 0)) ? 1 : 0;
0755     }
0756 
0757     if (set_key) {
0758         /* Set the requested key first */
0759         switch (alg) {
0760         case IW_ENCODE_ALG_NONE:
0761             priv->encode_alg = ORINOCO_ALG_NONE;
0762             err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
0763                           NULL, 0, NULL, 0);
0764             break;
0765 
0766         case IW_ENCODE_ALG_WEP:
0767             if (ext->key_len <= 0)
0768                 goto out;
0769 
0770             priv->encode_alg = ORINOCO_ALG_WEP;
0771             err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
0772                           ext->key, ext->key_len, NULL, 0);
0773             break;
0774 
0775         case IW_ENCODE_ALG_TKIP:
0776         {
0777             u8 *tkip_iv = NULL;
0778 
0779             if (!priv->has_wpa ||
0780                 (ext->key_len > sizeof(struct orinoco_tkip_key)))
0781                 goto out;
0782 
0783             priv->encode_alg = ORINOCO_ALG_TKIP;
0784 
0785             if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
0786                 tkip_iv = &ext->rx_seq[0];
0787 
0788             err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
0789                           ext->key, ext->key_len, tkip_iv,
0790                           ORINOCO_SEQ_LEN);
0791 
0792             err = __orinoco_hw_set_tkip_key(priv, idx,
0793                  ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
0794                  priv->keys[idx].key, priv->keys[idx].key_len,
0795                  tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
0796             if (err)
0797                 printk(KERN_ERR "%s: Error %d setting TKIP key"
0798                        "\n", dev->name, err);
0799 
0800             goto out;
0801         }
0802         default:
0803             goto out;
0804         }
0805     }
0806     err = -EINPROGRESS;
0807  out:
0808     orinoco_unlock(priv, &flags);
0809 
0810     return err;
0811 }
0812 
0813 static int orinoco_ioctl_get_encodeext(struct net_device *dev,
0814                        struct iw_request_info *info,
0815                        union iwreq_data *wrqu,
0816                        char *extra)
0817 {
0818     struct orinoco_private *priv = ndev_priv(dev);
0819     struct iw_point *encoding = &wrqu->encoding;
0820     struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
0821     int idx, max_key_len;
0822     unsigned long flags;
0823     int err;
0824 
0825     if (orinoco_lock(priv, &flags) != 0)
0826         return -EBUSY;
0827 
0828     err = -EINVAL;
0829     max_key_len = encoding->length - sizeof(*ext);
0830     if (max_key_len < 0)
0831         goto out;
0832 
0833     idx = encoding->flags & IW_ENCODE_INDEX;
0834     if (idx) {
0835         if ((idx < 1) || (idx > 4))
0836             goto out;
0837         idx--;
0838     } else
0839         idx = priv->tx_key;
0840 
0841     encoding->flags = idx + 1;
0842     memset(ext, 0, sizeof(*ext));
0843 
0844     switch (priv->encode_alg) {
0845     case ORINOCO_ALG_NONE:
0846         ext->alg = IW_ENCODE_ALG_NONE;
0847         ext->key_len = 0;
0848         encoding->flags |= IW_ENCODE_DISABLED;
0849         break;
0850     case ORINOCO_ALG_WEP:
0851         ext->alg = IW_ENCODE_ALG_WEP;
0852         ext->key_len = min(priv->keys[idx].key_len, max_key_len);
0853         memcpy(ext->key, priv->keys[idx].key, ext->key_len);
0854         encoding->flags |= IW_ENCODE_ENABLED;
0855         break;
0856     case ORINOCO_ALG_TKIP:
0857         ext->alg = IW_ENCODE_ALG_TKIP;
0858         ext->key_len = min(priv->keys[idx].key_len, max_key_len);
0859         memcpy(ext->key, priv->keys[idx].key, ext->key_len);
0860         encoding->flags |= IW_ENCODE_ENABLED;
0861         break;
0862     }
0863 
0864     err = 0;
0865  out:
0866     orinoco_unlock(priv, &flags);
0867 
0868     return err;
0869 }
0870 
0871 static int orinoco_ioctl_set_auth(struct net_device *dev,
0872                   struct iw_request_info *info,
0873                   union iwreq_data *wrqu, char *extra)
0874 {
0875     struct orinoco_private *priv = ndev_priv(dev);
0876     struct hermes *hw = &priv->hw;
0877     struct iw_param *param = &wrqu->param;
0878     unsigned long flags;
0879     int ret = -EINPROGRESS;
0880 
0881     if (orinoco_lock(priv, &flags) != 0)
0882         return -EBUSY;
0883 
0884     switch (param->flags & IW_AUTH_INDEX) {
0885     case IW_AUTH_WPA_VERSION:
0886     case IW_AUTH_CIPHER_PAIRWISE:
0887     case IW_AUTH_CIPHER_GROUP:
0888     case IW_AUTH_RX_UNENCRYPTED_EAPOL:
0889     case IW_AUTH_PRIVACY_INVOKED:
0890     case IW_AUTH_DROP_UNENCRYPTED:
0891         /*
0892          * orinoco does not use these parameters
0893          */
0894         break;
0895 
0896     case IW_AUTH_MFP:
0897         /* Management Frame Protection not supported.
0898          * Only fail if set to required.
0899          */
0900         if (param->value == IW_AUTH_MFP_REQUIRED)
0901             ret = -EINVAL;
0902         break;
0903 
0904     case IW_AUTH_KEY_MGMT:
0905         /* wl_lkm implies value 2 == PSK for Hermes I
0906          * which ties in with WEXT
0907          * no other hints tho :(
0908          */
0909         priv->key_mgmt = param->value;
0910         break;
0911 
0912     case IW_AUTH_TKIP_COUNTERMEASURES:
0913         /* When countermeasures are enabled, shut down the
0914          * card; when disabled, re-enable the card. This must
0915          * take effect immediately.
0916          *
0917          * TODO: Make sure that the EAPOL message is getting
0918          *       out before card disabled
0919          */
0920         if (param->value) {
0921             priv->tkip_cm_active = 1;
0922             ret = hermes_disable_port(hw, 0);
0923         } else {
0924             priv->tkip_cm_active = 0;
0925             ret = hermes_enable_port(hw, 0);
0926         }
0927         break;
0928 
0929     case IW_AUTH_80211_AUTH_ALG:
0930         if (param->value & IW_AUTH_ALG_SHARED_KEY)
0931             priv->wep_restrict = 1;
0932         else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
0933             priv->wep_restrict = 0;
0934         else
0935             ret = -EINVAL;
0936         break;
0937 
0938     case IW_AUTH_WPA_ENABLED:
0939         if (priv->has_wpa) {
0940             priv->wpa_enabled = param->value ? 1 : 0;
0941         } else {
0942             if (param->value)
0943                 ret = -EOPNOTSUPP;
0944             /* else silently accept disable of WPA */
0945             priv->wpa_enabled = 0;
0946         }
0947         break;
0948 
0949     default:
0950         ret = -EOPNOTSUPP;
0951     }
0952 
0953     orinoco_unlock(priv, &flags);
0954     return ret;
0955 }
0956 
0957 static int orinoco_ioctl_get_auth(struct net_device *dev,
0958                   struct iw_request_info *info,
0959                   union iwreq_data *wrqu, char *extra)
0960 {
0961     struct orinoco_private *priv = ndev_priv(dev);
0962     struct iw_param *param = &wrqu->param;
0963     unsigned long flags;
0964     int ret = 0;
0965 
0966     if (orinoco_lock(priv, &flags) != 0)
0967         return -EBUSY;
0968 
0969     switch (param->flags & IW_AUTH_INDEX) {
0970     case IW_AUTH_KEY_MGMT:
0971         param->value = priv->key_mgmt;
0972         break;
0973 
0974     case IW_AUTH_TKIP_COUNTERMEASURES:
0975         param->value = priv->tkip_cm_active;
0976         break;
0977 
0978     case IW_AUTH_80211_AUTH_ALG:
0979         if (priv->wep_restrict)
0980             param->value = IW_AUTH_ALG_SHARED_KEY;
0981         else
0982             param->value = IW_AUTH_ALG_OPEN_SYSTEM;
0983         break;
0984 
0985     case IW_AUTH_WPA_ENABLED:
0986         param->value = priv->wpa_enabled;
0987         break;
0988 
0989     default:
0990         ret = -EOPNOTSUPP;
0991     }
0992 
0993     orinoco_unlock(priv, &flags);
0994     return ret;
0995 }
0996 
0997 static int orinoco_ioctl_set_genie(struct net_device *dev,
0998                    struct iw_request_info *info,
0999                    union iwreq_data *wrqu, char *extra)
1000 {
1001     struct orinoco_private *priv = ndev_priv(dev);
1002     u8 *buf;
1003     unsigned long flags;
1004 
1005     /* cut off at IEEE80211_MAX_DATA_LEN */
1006     if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
1007         (wrqu->data.length && (extra == NULL)))
1008         return -EINVAL;
1009 
1010     if (wrqu->data.length) {
1011         buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
1012         if (buf == NULL)
1013             return -ENOMEM;
1014     } else
1015         buf = NULL;
1016 
1017     if (orinoco_lock(priv, &flags) != 0) {
1018         kfree(buf);
1019         return -EBUSY;
1020     }
1021 
1022     kfree(priv->wpa_ie);
1023     priv->wpa_ie = buf;
1024     priv->wpa_ie_len = wrqu->data.length;
1025 
1026     if (priv->wpa_ie) {
1027         /* Looks like wl_lkm wants to check the auth alg, and
1028          * somehow pass it to the firmware.
1029          * Instead it just calls the key mgmt rid
1030          *   - we do this in set auth.
1031          */
1032     }
1033 
1034     orinoco_unlock(priv, &flags);
1035     return 0;
1036 }
1037 
1038 static int orinoco_ioctl_get_genie(struct net_device *dev,
1039                    struct iw_request_info *info,
1040                    union iwreq_data *wrqu, char *extra)
1041 {
1042     struct orinoco_private *priv = ndev_priv(dev);
1043     unsigned long flags;
1044     int err = 0;
1045 
1046     if (orinoco_lock(priv, &flags) != 0)
1047         return -EBUSY;
1048 
1049     if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
1050         wrqu->data.length = 0;
1051         goto out;
1052     }
1053 
1054     if (wrqu->data.length < priv->wpa_ie_len) {
1055         err = -E2BIG;
1056         goto out;
1057     }
1058 
1059     wrqu->data.length = priv->wpa_ie_len;
1060     memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
1061 
1062 out:
1063     orinoco_unlock(priv, &flags);
1064     return err;
1065 }
1066 
1067 static int orinoco_ioctl_set_mlme(struct net_device *dev,
1068                   struct iw_request_info *info,
1069                   union iwreq_data *wrqu, char *extra)
1070 {
1071     struct orinoco_private *priv = ndev_priv(dev);
1072     struct iw_mlme *mlme = (struct iw_mlme *)extra;
1073     unsigned long flags;
1074     int ret = 0;
1075 
1076     if (orinoco_lock(priv, &flags) != 0)
1077         return -EBUSY;
1078 
1079     switch (mlme->cmd) {
1080     case IW_MLME_DEAUTH:
1081         /* silently ignore */
1082         break;
1083 
1084     case IW_MLME_DISASSOC:
1085 
1086         ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
1087                           mlme->reason_code);
1088         break;
1089 
1090     default:
1091         ret = -EOPNOTSUPP;
1092     }
1093 
1094     orinoco_unlock(priv, &flags);
1095     return ret;
1096 }
1097 
1098 static int orinoco_ioctl_reset(struct net_device *dev,
1099                    struct iw_request_info *info,
1100                    void *wrqu,
1101                    char *extra)
1102 {
1103     struct orinoco_private *priv = ndev_priv(dev);
1104 
1105     if (!capable(CAP_NET_ADMIN))
1106         return -EPERM;
1107 
1108     if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
1109         printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
1110 
1111         /* Firmware reset */
1112         orinoco_reset(&priv->reset_work);
1113     } else {
1114         printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
1115 
1116         schedule_work(&priv->reset_work);
1117     }
1118 
1119     return 0;
1120 }
1121 
1122 static int orinoco_ioctl_setibssport(struct net_device *dev,
1123                      struct iw_request_info *info,
1124                      void *wrqu,
1125                      char *extra)
1126 
1127 {
1128     struct orinoco_private *priv = ndev_priv(dev);
1129     int val = *((int *) extra);
1130     unsigned long flags;
1131 
1132     if (orinoco_lock(priv, &flags) != 0)
1133         return -EBUSY;
1134 
1135     priv->ibss_port = val;
1136 
1137     /* Actually update the mode we are using */
1138     set_port_type(priv);
1139 
1140     orinoco_unlock(priv, &flags);
1141     return -EINPROGRESS;        /* Call commit handler */
1142 }
1143 
1144 static int orinoco_ioctl_getibssport(struct net_device *dev,
1145                      struct iw_request_info *info,
1146                      void *wrqu,
1147                      char *extra)
1148 {
1149     struct orinoco_private *priv = ndev_priv(dev);
1150     int *val = (int *) extra;
1151 
1152     *val = priv->ibss_port;
1153     return 0;
1154 }
1155 
1156 static int orinoco_ioctl_setport3(struct net_device *dev,
1157                   struct iw_request_info *info,
1158                   void *wrqu,
1159                   char *extra)
1160 {
1161     struct orinoco_private *priv = ndev_priv(dev);
1162     int val = *((int *) extra);
1163     int err = 0;
1164     unsigned long flags;
1165 
1166     if (orinoco_lock(priv, &flags) != 0)
1167         return -EBUSY;
1168 
1169     switch (val) {
1170     case 0: /* Try to do IEEE ad-hoc mode */
1171         if (!priv->has_ibss) {
1172             err = -EINVAL;
1173             break;
1174         }
1175         priv->prefer_port3 = 0;
1176 
1177         break;
1178 
1179     case 1: /* Try to do Lucent proprietary ad-hoc mode */
1180         if (!priv->has_port3) {
1181             err = -EINVAL;
1182             break;
1183         }
1184         priv->prefer_port3 = 1;
1185         break;
1186 
1187     default:
1188         err = -EINVAL;
1189     }
1190 
1191     if (!err) {
1192         /* Actually update the mode we are using */
1193         set_port_type(priv);
1194         err = -EINPROGRESS;
1195     }
1196 
1197     orinoco_unlock(priv, &flags);
1198 
1199     return err;
1200 }
1201 
1202 static int orinoco_ioctl_getport3(struct net_device *dev,
1203                   struct iw_request_info *info,
1204                   void *wrqu,
1205                   char *extra)
1206 {
1207     struct orinoco_private *priv = ndev_priv(dev);
1208     int *val = (int *) extra;
1209 
1210     *val = priv->prefer_port3;
1211     return 0;
1212 }
1213 
1214 static int orinoco_ioctl_setpreamble(struct net_device *dev,
1215                      struct iw_request_info *info,
1216                      void *wrqu,
1217                      char *extra)
1218 {
1219     struct orinoco_private *priv = ndev_priv(dev);
1220     unsigned long flags;
1221     int val;
1222 
1223     if (!priv->has_preamble)
1224         return -EOPNOTSUPP;
1225 
1226     /* 802.11b has recently defined some short preamble.
1227      * Basically, the Phy header has been reduced in size.
1228      * This increase performance, especially at high rates
1229      * (the preamble is transmitted at 1Mb/s), unfortunately
1230      * this give compatibility troubles... - Jean II */
1231     val = *((int *) extra);
1232 
1233     if (orinoco_lock(priv, &flags) != 0)
1234         return -EBUSY;
1235 
1236     if (val)
1237         priv->preamble = 1;
1238     else
1239         priv->preamble = 0;
1240 
1241     orinoco_unlock(priv, &flags);
1242 
1243     return -EINPROGRESS;        /* Call commit handler */
1244 }
1245 
1246 static int orinoco_ioctl_getpreamble(struct net_device *dev,
1247                      struct iw_request_info *info,
1248                      void *wrqu,
1249                      char *extra)
1250 {
1251     struct orinoco_private *priv = ndev_priv(dev);
1252     int *val = (int *) extra;
1253 
1254     if (!priv->has_preamble)
1255         return -EOPNOTSUPP;
1256 
1257     *val = priv->preamble;
1258     return 0;
1259 }
1260 
1261 /* ioctl interface to hermes_read_ltv()
1262  * To use with iwpriv, pass the RID as the token argument, e.g.
1263  * iwpriv get_rid [0xfc00]
1264  * At least Wireless Tools 25 is required to use iwpriv.
1265  * For Wireless Tools 25 and 26 append "dummy" are the end. */
1266 static int orinoco_ioctl_getrid(struct net_device *dev,
1267                 struct iw_request_info *info,
1268                 struct iw_point *data,
1269                 char *extra)
1270 {
1271     struct orinoco_private *priv = ndev_priv(dev);
1272     struct hermes *hw = &priv->hw;
1273     int rid = data->flags;
1274     u16 length;
1275     int err;
1276     unsigned long flags;
1277 
1278     /* It's a "get" function, but we don't want users to access the
1279      * WEP key and other raw firmware data */
1280     if (!capable(CAP_NET_ADMIN))
1281         return -EPERM;
1282 
1283     if (rid < 0xfc00 || rid > 0xffff)
1284         return -EINVAL;
1285 
1286     if (orinoco_lock(priv, &flags) != 0)
1287         return -EBUSY;
1288 
1289     err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
1290                 extra);
1291     if (err)
1292         goto out;
1293 
1294     data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
1295                  MAX_RID_LEN);
1296 
1297  out:
1298     orinoco_unlock(priv, &flags);
1299     return err;
1300 }
1301 
1302 
1303 /* Commit handler, called after set operations */
1304 static int orinoco_ioctl_commit(struct net_device *dev,
1305                 struct iw_request_info *info,
1306                 void *wrqu,
1307                 char *extra)
1308 {
1309     struct orinoco_private *priv = ndev_priv(dev);
1310     unsigned long flags;
1311     int err = 0;
1312 
1313     if (!priv->open)
1314         return 0;
1315 
1316     if (orinoco_lock(priv, &flags) != 0)
1317         return err;
1318 
1319     err = orinoco_commit(priv);
1320 
1321     orinoco_unlock(priv, &flags);
1322     return err;
1323 }
1324 
1325 static const struct iw_priv_args orinoco_privtab[] = {
1326     { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
1327     { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
1328     { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1329       0, "set_port3" },
1330     { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1331       "get_port3" },
1332     { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1333       0, "set_preamble" },
1334     { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1335       "get_preamble" },
1336     { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1337       0, "set_ibssport" },
1338     { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1339       "get_ibssport" },
1340     { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
1341       "get_rid" },
1342 };
1343 
1344 
1345 /*
1346  * Structures to export the Wireless Handlers
1347  */
1348 
1349 static const iw_handler orinoco_handler[] = {
1350     IW_HANDLER(SIOCSIWCOMMIT,   (iw_handler)orinoco_ioctl_commit),
1351     IW_HANDLER(SIOCGIWNAME,     (iw_handler)cfg80211_wext_giwname),
1352     IW_HANDLER(SIOCSIWFREQ,     (iw_handler)orinoco_ioctl_setfreq),
1353     IW_HANDLER(SIOCGIWFREQ,     (iw_handler)orinoco_ioctl_getfreq),
1354     IW_HANDLER(SIOCSIWMODE,     (iw_handler)cfg80211_wext_siwmode),
1355     IW_HANDLER(SIOCGIWMODE,     (iw_handler)cfg80211_wext_giwmode),
1356     IW_HANDLER(SIOCSIWSENS,     (iw_handler)orinoco_ioctl_setsens),
1357     IW_HANDLER(SIOCGIWSENS,     (iw_handler)orinoco_ioctl_getsens),
1358     IW_HANDLER(SIOCGIWRANGE,    (iw_handler)cfg80211_wext_giwrange),
1359     IW_HANDLER(SIOCSIWSPY,      iw_handler_set_spy),
1360     IW_HANDLER(SIOCGIWSPY,      iw_handler_get_spy),
1361     IW_HANDLER(SIOCSIWTHRSPY,   iw_handler_set_thrspy),
1362     IW_HANDLER(SIOCGIWTHRSPY,   iw_handler_get_thrspy),
1363     IW_HANDLER(SIOCSIWAP,       (iw_handler)orinoco_ioctl_setwap),
1364     IW_HANDLER(SIOCGIWAP,       (iw_handler)orinoco_ioctl_getwap),
1365     IW_HANDLER(SIOCSIWSCAN,     (iw_handler)cfg80211_wext_siwscan),
1366     IW_HANDLER(SIOCGIWSCAN,     (iw_handler)cfg80211_wext_giwscan),
1367     IW_HANDLER(SIOCSIWESSID,    (iw_handler)orinoco_ioctl_setessid),
1368     IW_HANDLER(SIOCGIWESSID,    (iw_handler)orinoco_ioctl_getessid),
1369     IW_HANDLER(SIOCSIWRATE,     (iw_handler)orinoco_ioctl_setrate),
1370     IW_HANDLER(SIOCGIWRATE,     (iw_handler)orinoco_ioctl_getrate),
1371     IW_HANDLER(SIOCSIWRTS,      (iw_handler)cfg80211_wext_siwrts),
1372     IW_HANDLER(SIOCGIWRTS,      (iw_handler)cfg80211_wext_giwrts),
1373     IW_HANDLER(SIOCSIWFRAG,     (iw_handler)cfg80211_wext_siwfrag),
1374     IW_HANDLER(SIOCGIWFRAG,     (iw_handler)cfg80211_wext_giwfrag),
1375     IW_HANDLER(SIOCGIWRETRY,    (iw_handler)cfg80211_wext_giwretry),
1376     IW_HANDLER(SIOCSIWENCODE,   (iw_handler)orinoco_ioctl_setiwencode),
1377     IW_HANDLER(SIOCGIWENCODE,   (iw_handler)orinoco_ioctl_getiwencode),
1378     IW_HANDLER(SIOCSIWPOWER,    (iw_handler)orinoco_ioctl_setpower),
1379     IW_HANDLER(SIOCGIWPOWER,    (iw_handler)orinoco_ioctl_getpower),
1380     IW_HANDLER(SIOCSIWGENIE,    orinoco_ioctl_set_genie),
1381     IW_HANDLER(SIOCGIWGENIE,    orinoco_ioctl_get_genie),
1382     IW_HANDLER(SIOCSIWMLME,     orinoco_ioctl_set_mlme),
1383     IW_HANDLER(SIOCSIWAUTH,     orinoco_ioctl_set_auth),
1384     IW_HANDLER(SIOCGIWAUTH,     orinoco_ioctl_get_auth),
1385     IW_HANDLER(SIOCSIWENCODEEXT,    orinoco_ioctl_set_encodeext),
1386     IW_HANDLER(SIOCGIWENCODEEXT,    orinoco_ioctl_get_encodeext),
1387 };
1388 
1389 
1390 /*
1391   Added typecasting since we no longer use iwreq_data -- Moustafa
1392  */
1393 static const iw_handler orinoco_private_handler[] = {
1394     [0] = (iw_handler)orinoco_ioctl_reset,
1395     [1] = (iw_handler)orinoco_ioctl_reset,
1396     [2] = (iw_handler)orinoco_ioctl_setport3,
1397     [3] = (iw_handler)orinoco_ioctl_getport3,
1398     [4] = (iw_handler)orinoco_ioctl_setpreamble,
1399     [5] = (iw_handler)orinoco_ioctl_getpreamble,
1400     [6] = (iw_handler)orinoco_ioctl_setibssport,
1401     [7] = (iw_handler)orinoco_ioctl_getibssport,
1402     [9] = (iw_handler)orinoco_ioctl_getrid,
1403 };
1404 
1405 const struct iw_handler_def orinoco_handler_def = {
1406     .num_standard = ARRAY_SIZE(orinoco_handler),
1407     .num_private = ARRAY_SIZE(orinoco_private_handler),
1408     .num_private_args = ARRAY_SIZE(orinoco_privtab),
1409     .standard = orinoco_handler,
1410     .private = orinoco_private_handler,
1411     .private_args = orinoco_privtab,
1412     .get_wireless_stats = orinoco_get_wireless_stats,
1413 };