This patch addd Linux Wireless Extensions version 18 support into the
Devicescape 802.11 stack by converting the WE ioctl registration to use
the new dev->wireless_handlers mechanism and by adding support for the
ioctls that are needed for WPA/WPA2 in client mode. The private ioctl
versions of key configuration and MLME functions were not removed since
there are still user space programs using these. The old versions can be
removed from here once user space programs get updated to WE-18 (both
client and AP functionality).

I tested this version quickly with bcm43xx driver in dscape-all branch.
Both the patched wpa_supplicant 0.4.7 with driver_dscape.c and the default
driver_wext.c (WE-18) allowed WPA handshake to be completed. The goal is
to make it unnecessary to patch wpa_supplicant with a new driver
interface code (driver_dscape.c).

Please apply into the dscape-all branch (or whatever branch is
appropriate for this kind of change) of the wireless-2.6 tree.

Signed-off-by: Jouni Malinen <[EMAIL PROTECTED]>


Index: wireless-2.6/net/d80211/ieee80211.c
===================================================================
--- wireless-2.6.orig/net/d80211/ieee80211.c
+++ wireless-2.6/net/d80211/ieee80211.c
@@ -1,6 +1,6 @@
 /*
  * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -3874,6 +3874,8 @@ static struct net_device *ieee80211_if_a
 
        memcpy(wds_dev->dev_addr, dev->dev_addr, ETH_ALEN);
        wds_dev->hard_start_xmit = ieee80211_subif_start_xmit;
+       wds_dev->wireless_handlers =
+               (struct iw_handler_def *) &ieee80211_iw_handler_def;
         wds_dev->do_ioctl = ieee80211_ioctl;
        wds_dev->change_mtu = ieee80211_change_mtu;
         wds_dev->tx_timeout = ieee80211_tx_timeout;
@@ -4421,6 +4423,8 @@ struct net_device *ieee80211_alloc_hw(si
        memcpy(dev->name, "wlan%d", 7);
 
         dev->hard_start_xmit = ieee80211_subif_start_xmit;
+       dev->wireless_handlers =
+               (struct iw_handler_def *) &ieee80211_iw_handler_def;
         dev->do_ioctl = ieee80211_ioctl;
        dev->change_mtu = ieee80211_change_mtu;
         dev->tx_timeout = ieee80211_tx_timeout;
@@ -4510,6 +4514,8 @@ struct net_device *ieee80211_alloc_hw(si
 
        ether_setup(mdev);
        mdev->hard_start_xmit = ieee80211_master_start_xmit;
+       mdev->wireless_handlers =
+               (struct iw_handler_def *) &ieee80211_iw_handler_def;
         mdev->do_ioctl = ieee80211_ioctl;
        mdev->change_mtu = ieee80211_change_mtu;
         mdev->tx_timeout = ieee80211_tx_timeout;
Index: wireless-2.6/net/d80211/ieee80211_i.h
===================================================================
--- wireless-2.6.orig/net/d80211/ieee80211_i.h
+++ wireless-2.6/net/d80211/ieee80211_i.h
@@ -515,6 +515,8 @@ int ieee80211_if_update_wds(struct net_d
 
 /* ieee80211_ioctl.c */
 int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+extern const struct iw_handler_def ieee80211_iw_handler_def;
+
 /* Set hw encryption from ieee80211 */
 int ieee80211_set_hw_encryption(struct net_device *dev,
                                struct sta_info *sta, u8 addr[ETH_ALEN],
Index: wireless-2.6/net/d80211/ieee80211_ioctl.c
===================================================================
--- wireless-2.6.orig/net/d80211/ieee80211_ioctl.c
+++ wireless-2.6/net/d80211/ieee80211_ioctl.c
@@ -1,6 +1,6 @@
 /*
  * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -466,43 +466,30 @@ int ieee80211_set_hw_encryption(struct n
 }
 
 
-static int ieee80211_ioctl_set_encryption(struct net_device *dev,
-                                         struct prism2_hostapd_param *param,
-                                         int param_len)
+static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
+                                   int idx, int alg, int set_tx_key, int *err,
+                                   const u8 *_key, size_t key_len)
 {
        struct ieee80211_local *local = dev->priv;
-       int alg, ret = 0;
+       int ret = 0;
        struct sta_info *sta;
        struct ieee80211_key **key;
-       int set_tx_key = 0, try_hwaccel = 1;
+       int try_hwaccel = 1;
         struct ieee80211_key_conf *keyconf;
         struct ieee80211_sub_if_data *sdata;
 
         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       param->u.crypt.err = 0;
-       param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0';
-
-       if (param_len <
-           (int) ((char *) param->u.crypt.key - (char *) param) +
-           param->u.crypt.key_len) {
-               printk(KERN_DEBUG "%s: set_encrypt - invalid param_lem\n",
-                      dev->name);
-               return -EINVAL;
-        }
-
-       if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
-           param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
-           param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+       if (sta_addr[0] == 0xff && sta_addr[1] == 0xff &&
+           sta_addr[2] == 0xff && sta_addr[3] == 0xff &&
+           sta_addr[4] == 0xff && sta_addr[5] == 0xff) {
                sta = NULL;
-               if (param->u.crypt.idx >= NUM_DEFAULT_KEYS) {
+               if (idx >= NUM_DEFAULT_KEYS) {
                        printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
-                              dev->name, param->u.crypt.idx);
+                              dev->name, idx);
                        return -EINVAL;
                }
-               key = &sdata->keys[param->u.crypt.idx];
-               if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY)
-                       set_tx_key = 1;
+               key = &sdata->keys[idx];
 
                /* Disable hwaccel for default keys when the interface is not
                 * the default one.
@@ -523,19 +510,21 @@ static int ieee80211_ioctl_set_encryptio
                    dev != local->wdev)
                        try_hwaccel = 0;
        } else {
-               if (param->u.crypt.idx != 0) {
+               set_tx_key = 0;
+               if (idx != 0) {
                        printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
                               "individual key\n", dev->name);
                        return -EINVAL;
                }
 
-               sta = sta_info_get(local, param->sta_addr);
+               sta = sta_info_get(local, sta_addr);
                if (sta == NULL) {
-                       param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
+                       if (err)
+                               *err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
 #ifdef CONFIG_D80211_VERBOSE_DEBUG
                        printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
                               MACSTR "\n",
-                              dev->name, MAC2STR(param->sta_addr));
+                              dev->name, MAC2STR(sta_addr));
 #endif /* CONFIG_D80211_VERBOSE_DEBUG */
 
                        return -ENOENT;
@@ -544,36 +533,6 @@ static int ieee80211_ioctl_set_encryptio
                key = &sta->key;
        }
 
-       if (strcmp(param->u.crypt.alg, "none") == 0) {
-               alg = ALG_NONE;
-       } else if (strcmp(param->u.crypt.alg, "WEP") == 0) {
-               alg = ALG_WEP;
-       } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
-               if (param->u.crypt.key_len != ALG_TKIP_KEY_LEN) {
-                       printk(KERN_DEBUG "%s: set_encrypt - invalid TKIP key "
-                              "length %d\n", dev->name,
-                              param->u.crypt.key_len);
-                       ret = -EINVAL;
-                       goto done;
-               }
-               alg = ALG_TKIP;
-       } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
-               if (param->u.crypt.key_len != ALG_CCMP_KEY_LEN) {
-                       printk(KERN_DEBUG "%s: set_encrypt - invalid CCMP key "
-                              "length %d\n", dev->name,
-                              param->u.crypt.key_len);
-                       ret = -EINVAL;
-                       goto done;
-               }
-               alg = ALG_CCMP;
-       } else {
-               param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG;
-               printk(KERN_DEBUG "%s: set_encrypt - unknown alg\n",
-                      dev->name);
-               ret = -EINVAL;
-               goto done;
-       }
-
        /* FIX:
         * Cannot configure default hwaccel keys with WEP algorithm, if
         * any of the virtual interfaces is using static WEP
@@ -620,9 +579,10 @@ static int ieee80211_ioctl_set_encryptio
                keyconf = NULL;
                if (try_hwaccel && *key && local->hw->set_key &&
                    (keyconf = ieee80211_key_data2conf(local, *key)) != NULL &&
-                   local->hw->set_key(dev, DISABLE_KEY, param->sta_addr,
+                   local->hw->set_key(dev, DISABLE_KEY, sta_addr,
                                       keyconf, sta ? sta->aid : 0)) {
-                       param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
+                       if (err)
+                               *err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
                        printk(KERN_DEBUG "%s: set_encrypt - low-level disable"
                               " failed\n", dev->name);
                        ret = -EINVAL;
@@ -634,27 +594,25 @@ static int ieee80211_ioctl_set_encryptio
                kfree(*key);
                *key = NULL;
        } else {
-               if (*key == NULL || (*key)->keylen < param->u.crypt.key_len) {
+               if (*key == NULL || (*key)->keylen < key_len) {
                        kfree(*key);
                        *key = kmalloc(sizeof(struct ieee80211_key) +
-                                      param->u.crypt.key_len, GFP_ATOMIC);
+                                      key_len, GFP_ATOMIC);
                        if (*key == NULL) {
                                ret = -ENOMEM;
                                goto done;
                        }
                }
-               memset(*key, 0, sizeof(struct ieee80211_key) +
-                      param->u.crypt.key_len);
+               memset(*key, 0, sizeof(struct ieee80211_key) + key_len);
                /* default to sw encryption; low-level driver sets these if the
                 * requested encryption is supported */
                (*key)->hw_key_idx = HW_KEY_IDX_INVALID;
                (*key)->force_sw_encrypt = 1;
 
                (*key)->alg = alg;
-               (*key)->keyidx = param->u.crypt.idx;
-               (*key)->keylen = param->u.crypt.key_len;
-               memcpy((*key)->key, param->u.crypt.key,
-                      param->u.crypt.key_len);
+               (*key)->keyidx = idx;
+               (*key)->keylen = key_len;
+               memcpy((*key)->key, _key, key_len);
                if (set_tx_key)
                        (*key)->default_tx_key = 1;
 
@@ -667,15 +625,18 @@ static int ieee80211_ioctl_set_encryptio
                }
 
                if (try_hwaccel &&
-                   (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP))
-                       param->u.crypt.err = ieee80211_set_hw_encryption(
-                               dev, sta, param->sta_addr, *key);
+                   (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP)) {
+                       int e = ieee80211_set_hw_encryption(dev, sta, sta_addr,
+                                                           *key);
+                       if (err)
+                               *err = e;
+               }
        }
 
        if (set_tx_key || (sta == NULL && sdata->default_key == NULL)) {
                 sdata->default_key = *key;
                if (local->hw->set_key_idx &&
-                   local->hw->set_key_idx(dev, param->u.crypt.idx))
+                   local->hw->set_key_idx(dev, idx))
                        printk(KERN_DEBUG "%s: failed to set TX key idx for "
                               "low-level driver\n", dev->name);
        }
@@ -687,6 +648,60 @@ static int ieee80211_ioctl_set_encryptio
        return ret;
 }
 
+
+static int ieee80211_ioctl_set_encryption(struct net_device *dev,
+                                         struct prism2_hostapd_param *param,
+                                         int param_len)
+{
+       int alg;
+
+       param->u.crypt.err = 0;
+       param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+       if (param_len <
+           (int) ((char *) param->u.crypt.key - (char *) param) +
+           param->u.crypt.key_len) {
+               printk(KERN_DEBUG "%s: set_encrypt - invalid param_lem\n",
+                      dev->name);
+               return -EINVAL;
+        }
+
+       if (strcmp(param->u.crypt.alg, "none") == 0)
+               alg = ALG_NONE;
+       else if (strcmp(param->u.crypt.alg, "WEP") == 0)
+               alg = ALG_WEP;
+       else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+               if (param->u.crypt.key_len != ALG_TKIP_KEY_LEN) {
+                       printk(KERN_DEBUG "%s: set_encrypt - invalid TKIP key "
+                              "length %d\n", dev->name,
+                              param->u.crypt.key_len);
+                       return -EINVAL;
+               }
+               alg = ALG_TKIP;
+       } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+               if (param->u.crypt.key_len != ALG_CCMP_KEY_LEN) {
+                       printk(KERN_DEBUG "%s: set_encrypt - invalid CCMP key "
+                              "length %d\n", dev->name,
+                              param->u.crypt.key_len);
+                       return -EINVAL;
+               }
+               alg = ALG_CCMP;
+       } else {
+               param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG;
+               printk(KERN_DEBUG "%s: set_encrypt - unknown alg\n",
+                      dev->name);
+               return -EINVAL;
+       }
+
+       return ieee80211_set_encryption(
+               dev, param->sta_addr,
+               param->u.crypt.idx, alg,
+               param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY,
+               &param->u.crypt.err, param->u.crypt.key,
+               param->u.crypt.key_len);
+}
+
+
 static int ieee80211_ioctl_get_encryption(struct net_device *dev,
                                          struct prism2_hostapd_param *param,
                                          int param_len)
@@ -1094,12 +1109,31 @@ static int ieee80211_ioctl_set_sta_vlan(
 }
 
 
+static int ieee80211_set_gen_ie(struct net_device *dev, u8 *ie, size_t len)
+{
+       struct ieee80211_local *local = dev->priv;
+       struct ieee80211_sub_if_data *sdata;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (sdata->type == IEEE80211_SUB_IF_TYPE_STA)
+               return ieee80211_sta_set_extra_ie(dev, ie, len);
+
+       kfree(local->conf.generic_elem);
+       local->conf.generic_elem = kmalloc(len, GFP_KERNEL);
+       if (local->conf.generic_elem == NULL)
+               return -ENOMEM;
+       memcpy(local->conf.generic_elem, ie, len);
+       local->conf.generic_elem_len = len;
+
+       return ieee80211_hw_config(dev);
+}
+
+
 static int
 ieee80211_ioctl_set_generic_info_elem(struct net_device *dev,
                                      struct prism2_hostapd_param *param,
                                      int param_len)
 {
-       struct ieee80211_local *local = dev->priv;
        u8 *pos = param->u.set_generic_info_elem.data;
         int left = param_len - ((u8 *) pos - (u8 *) param);
        int len = param->u.set_generic_info_elem.len;
@@ -1107,20 +1141,7 @@ ieee80211_ioctl_set_generic_info_elem(st
        if (left < len)
                return -EINVAL;
 
-       {
-               struct ieee80211_sub_if_data *sdata;
-               sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-               if (sdata->type == IEEE80211_SUB_IF_TYPE_STA)
-                       return ieee80211_sta_set_extra_ie(dev, pos, len);
-       }
-       kfree(local->conf.generic_elem);
-       local->conf.generic_elem = kmalloc(len, GFP_KERNEL);
-       if (local->conf.generic_elem == NULL)
-               return -ENOMEM;
-       memcpy(local->conf.generic_elem, pos, len);
-       local->conf.generic_elem_len = len;
-
-       return ieee80211_hw_config(dev);
+       return ieee80211_set_gen_ie(dev, pos, len);
 }
 
 
@@ -2659,159 +2680,266 @@ static int ieee80211_ioctl_test_param(st
 }
 
 
-static const struct iw_priv_args ieee80211_ioctl_priv[] = {
-       { PRISM2_IOCTL_PRISM2_PARAM,
-         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" },
-       { PRISM2_IOCTL_GET_PRISM2_PARAM,
-         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" },
-       { PRISM2_IOCTL_TEST_PARAM,
-         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "test_param" },
-};
+static int ieee80211_ioctl_siwmlme(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  struct iw_point *data, char *extra)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct iw_mlme *mlme = (struct iw_mlme *) extra;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (sdata->type != IEEE80211_SUB_IF_TYPE_STA)
+               return -EINVAL;
+
+       switch (mlme->cmd) {
+       case IW_MLME_DEAUTH:
+               /* TODO: mlme->addr.sa_data */
+               return ieee80211_sta_deauthenticate(dev, mlme->reason_code);
+       case IW_MLME_DISASSOC:
+               /* TODO: mlme->addr.sa_data */
+               return ieee80211_sta_disassociate(dev, mlme->reason_code);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
 
 
-static int ieee80211_ioctl_giwpriv(struct net_device *dev,
-                                  struct iw_point *data)
+static int ieee80211_ioctl_siwencode(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    struct iw_point *erq, char *keybuf)
 {
+       struct ieee80211_sub_if_data *sdata;
+       int idx, i, alg = ALG_WEP;
+       u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-       if (!data->pointer ||
-           !access_ok(VERIFY_WRITE, data->pointer,
-                       sizeof(ieee80211_ioctl_priv)))
-               return -EINVAL;
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       idx = erq->flags & IW_ENCODE_INDEX;
+       if (idx < 1 || idx > 4) {
+               idx = -1;
+               if (sdata->default_key == NULL)
+                       idx = 0;
+               else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+                       if (sdata->default_key == sdata->keys[i])
+                               idx = i;
+                       break;
+               }
+               if (idx < 0)
+                       return -EINVAL;
+       } else
+               idx--;
+
+       if (erq->flags & IW_ENCODE_DISABLED)
+               alg = ALG_NONE;
+       else if (erq->length == 0) {
+               /* No key data - just set the default TX key index */
+               sdata->default_key = sdata->keys[idx];
+       }
+
+       return ieee80211_set_encryption(
+               dev, bcaddr,
+               idx, erq->length == 0 ? ALG_NONE : ALG_WEP,
+               sdata->default_key == NULL,
+               NULL, keybuf, erq->length);
 
-       data->length = sizeof(ieee80211_ioctl_priv) /
-               sizeof(ieee80211_ioctl_priv[0]);
-       if (copy_to_user(data->pointer, ieee80211_ioctl_priv,
-                        sizeof(ieee80211_ioctl_priv)))
-               return -EINVAL;
        return 0;
 }
 
 
-int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int ieee80211_ioctl_giwencode(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    struct iw_point *erq, char *key)
 {
-       struct iwreq *wrq = (struct iwreq *) rq;
+       struct ieee80211_sub_if_data *sdata;
+       int idx, i;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       idx = erq->flags & IW_ENCODE_INDEX;
+       if (idx < 1 || idx > 4) {
+               idx = -1;
+               if (sdata->default_key == NULL)
+                       idx = 0;
+               else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+                       if (sdata->default_key == sdata->keys[i])
+                               idx = i;
+                       break;
+               }
+               if (idx < 0)
+                       return -EINVAL;
+       } else
+               idx--;
+
+       erq->flags = idx + 1;
+
+       if (sdata->keys[idx] == NULL) {
+               erq->length = 0;
+               erq->flags |= IW_ENCODE_DISABLED;
+               return 0;
+       }
+
+       erq->length = 0;
+       erq->flags |= IW_ENCODE_ENABLED;
+
+       return 0;
+}
+
+
+static int ieee80211_ioctl_siwgenie(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   struct iw_point *data, char *extra)
+{
+       return ieee80211_set_gen_ie(dev, extra, data->length);
+}
+
+
+static int ieee80211_ioctl_siwauth(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  struct iw_param *data, char *extra)
+{
+       struct ieee80211_local *local = dev->priv;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        int ret = 0;
-       char ssid[IW_ESSID_MAX_SIZE + 1];
 
-       switch (cmd) {
-       case SIOCGIWNAME:
-               ret = ieee80211_ioctl_giwname(dev, NULL, (char *) &wrq->u,
-                                             NULL);
+       switch (data->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+       case IW_AUTH_CIPHER_PAIRWISE:
+       case IW_AUTH_CIPHER_GROUP:
+       case IW_AUTH_WPA_ENABLED:
+       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
                break;
-       case SIOCSIWESSID:
-               if (!wrq->u.essid.pointer)
+       case IW_AUTH_KEY_MGMT:
+               if (sdata->type != IEEE80211_SUB_IF_TYPE_STA)
                        ret = -EINVAL;
-               else if (wrq->u.essid.length > IW_ESSID_MAX_SIZE)
-                       ret = -E2BIG;
                else {
-                       if (copy_from_user(ssid, wrq->u.essid.pointer,
-                                          wrq->u.essid.length)) {
-                               ret = -EFAULT;
-                               break;
+                       /*
+                        * TODO: sdata->u.sta.key_mgmt does not match with WE18
+                        * value completely; could consider modifying this to
+                        * be closer to WE18. For now, this value is not really
+                        * used for anything else than Privacy matching, so the
+                        * current code here should be more or less OK.
+                        */
+                       if (data->value & IW_AUTH_KEY_MGMT_802_1X) {
+                               sdata->u.sta.key_mgmt =
+                                       IEEE80211_KEY_MGMT_WPA_EAP;
+                       } else if (data->value & IW_AUTH_KEY_MGMT_PSK) {
+                               sdata->u.sta.key_mgmt =
+                                       IEEE80211_KEY_MGMT_WPA_PSK;
+                       } else {
+                               sdata->u.sta.key_mgmt =
+                                       IEEE80211_KEY_MGMT_NONE;
                        }
-                       ret = ieee80211_ioctl_siwessid(dev, NULL,
-                                                      &wrq->u.essid, ssid);
                }
                break;
-       case SIOCGIWESSID:
-               if (!wrq->u.essid.pointer) {
-                       ret = -EINVAL;
-               } else {
-                       memset(ssid, 0, IW_ESSID_MAX_SIZE + 1);
-                       ret = ieee80211_ioctl_giwessid(dev, NULL,
-                                                      &wrq->u.essid, ssid);
-                       if (copy_to_user(wrq->u.essid.pointer, ssid,
-                                        wrq->u.essid.length)) {
-                               ret = -EFAULT;
-                               break;
-                       }
-               }
+       case IW_AUTH_80211_AUTH_ALG:
+               if (sdata->type == IEEE80211_SUB_IF_TYPE_STA)
+                       sdata->u.sta.auth_algs = data->value;
+               else
+                       ret = -EOPNOTSUPP;
                break;
-
-       case SIOCGIWRANGE:
-       {
-               struct iw_range range;
-               if (!access_ok(VERIFY_WRITE, wrq->u.data.pointer,
-                                 sizeof(range))) {
-                       ret = -EFAULT;
-                       break;
-               }
-               ret = ieee80211_ioctl_giwrange(dev, NULL, &wrq->u.data,
-                                              (char *) &range);
-               if (ret)
-                       break;
-               if (copy_to_user(wrq->u.data.pointer, &range, sizeof(range)))
-                       ret = -EFAULT;
+       case IW_AUTH_PRIVACY_INVOKED:
+               if (local->hw->set_privacy_invoked)
+                       ret = local->hw->set_privacy_invoked(dev, data->value);
+               break;
+       default:
+               ret = -EOPNOTSUPP;
                break;
        }
+       return ret;
+}
 
-       case SIOCSIWAP:
-               ret = ieee80211_ioctl_siwap(dev, NULL, &wrq->u.ap_addr, NULL);
-               break;
-       case SIOCGIWAP:
-               ret = ieee80211_ioctl_giwap(dev, NULL, &wrq->u.ap_addr, NULL);
-               break;
-       case SIOCSIWSCAN:
-               ret = ieee80211_ioctl_siwscan(dev, NULL, &wrq->u.data, NULL);
+
+static int ieee80211_ioctl_giwauth(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  struct iw_param *data, char *extra)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       int ret = 0;
+
+       switch (data->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_80211_AUTH_ALG:
+               if (sdata->type == IEEE80211_SUB_IF_TYPE_STA)
+                       data->value = sdata->u.sta.auth_algs;
+               else
+                       ret = -EOPNOTSUPP;
                break;
-       case SIOCGIWSCAN:
-       {
-               char *buf = kmalloc(IW_SCAN_MAX_DATA, GFP_KERNEL);
-               if (buf == NULL) {
-                       ret = -ENOMEM;
-                       break;
-               }
-               ret = ieee80211_ioctl_giwscan(dev, NULL, &wrq->u.data, buf);
-               if (ret == 0 &&
-                   copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length))
-                       ret = -EFAULT;
-               kfree(buf);
+       default:
+               ret = -EOPNOTSUPP;
                break;
        }
+       return ret;
+}
+
+
+static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
+                                       struct iw_request_info *info,
+                                       struct iw_point *erq, char *extra)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+       int alg, idx, i;
 
-       case SIOCSIWFREQ:
-               ret = ieee80211_ioctl_siwfreq(dev, NULL, &wrq->u.freq, NULL);
+       switch (ext->alg) {
+       case IW_ENCODE_ALG_NONE:
+               alg = ALG_NONE;
                break;
-       case SIOCGIWFREQ:
-               ret = ieee80211_ioctl_giwfreq(dev, NULL, &wrq->u.freq, NULL);
+       case IW_ENCODE_ALG_WEP:
+               alg = ALG_WEP;
                break;
-       case SIOCSIWMODE:
-               ret = ieee80211_ioctl_siwmode(dev, NULL, &wrq->u.mode, NULL);
+       case IW_ENCODE_ALG_TKIP:
+               alg = ALG_TKIP;
                break;
-       case SIOCGIWMODE:
-               ret = ieee80211_ioctl_giwmode(dev, NULL, &wrq->u.mode, NULL);
+       case IW_ENCODE_ALG_CCMP:
+               alg = ALG_CCMP;
                break;
+       default:
+               return -EOPNOTSUPP;
+       }
 
-       case SIOCSIWRTS:
-               ret = ieee80211_ioctl_siwrts(dev, NULL, &wrq->u.rts, NULL);
-               break;
-       case SIOCGIWRTS:
-               ret = ieee80211_ioctl_giwrts(dev, NULL, &wrq->u.rts, NULL);
-               break;
+       if (erq->flags & IW_ENCODE_DISABLED)
+               alg = ALG_NONE;
 
-       case SIOCSIWFRAG:
-               ret = ieee80211_ioctl_siwfrag(dev, NULL, &wrq->u.frag, NULL);
-               break;
-       case SIOCGIWFRAG:
-               ret = ieee80211_ioctl_giwfrag(dev, NULL, &wrq->u.frag, NULL);
-               break;
+       idx = erq->flags & IW_ENCODE_INDEX;
+       if (idx < 1 || idx > 4) {
+               idx = -1;
+               if (sdata->default_key == NULL)
+                       idx = 0;
+               else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+                       if (sdata->default_key == sdata->keys[i])
+                               idx = i;
+                       break;
+               }
+               if (idx < 0)
+                       return -EINVAL;
+       } else
+               idx--;
 
-       case SIOCSIWRETRY:
-               ret = ieee80211_ioctl_siwretry(dev, NULL, &wrq->u.retry, NULL);
-               break;
-       case SIOCGIWRETRY:
-               ret = ieee80211_ioctl_giwretry(dev, NULL, &wrq->u.retry, NULL);
-               break;
+       return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg,
+                                       ext->ext_flags &
+                                       IW_ENCODE_EXT_SET_TX_KEY,
+                                       NULL, ext->key, ext->key_len);
+}
 
-       case PRISM2_IOCTL_PRISM2_PARAM:
-               ret = ieee80211_ioctl_prism2_param(dev, NULL, &wrq->u,
-                                                  (char *) &wrq->u);
-               break;
-       case PRISM2_IOCTL_GET_PRISM2_PARAM:
-               ret = ieee80211_ioctl_get_prism2_param(dev, NULL, &wrq->u,
-                                                      (char *) &wrq->u);
-               break;
+
+static const struct iw_priv_args ieee80211_ioctl_priv[] = {
+       { PRISM2_IOCTL_PRISM2_PARAM,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" },
+       { PRISM2_IOCTL_GET_PRISM2_PARAM,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" },
+       { PRISM2_IOCTL_TEST_PARAM,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "test_param" },
+};
+
+
+int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct iwreq *wrq = (struct iwreq *) rq;
+       int ret = 0;
+
+       switch (cmd) {
+               /* Private ioctls (iwpriv) that have not yet been converted
+                * into new wireless extensions API */
        case PRISM2_IOCTL_TEST_PARAM:
                ret = ieee80211_ioctl_test_param(dev, NULL, &wrq->u,
                                                 (char *) &wrq->u);
@@ -2820,9 +2948,6 @@ int ieee80211_ioctl(struct net_device *d
                if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
                else ret = ieee80211_ioctl_priv_hostapd(dev, &wrq->u.data);
                break;
-       case SIOCGIWPRIV:
-               ret = ieee80211_ioctl_giwpriv(dev, &wrq->u.data);
-               break;
        default:
                ret = -EOPNOTSUPP;
                break;
@@ -2830,3 +2955,84 @@ int ieee80211_ioctl(struct net_device *d
 
        return ret;
 }
+
+
+/* Structures to export the Wireless Handlers */
+
+static const iw_handler ieee80211_handler[] =
+{
+       (iw_handler) NULL,                              /* SIOCSIWCOMMIT */
+       (iw_handler) ieee80211_ioctl_giwname,           /* SIOCGIWNAME */
+       (iw_handler) NULL,                              /* SIOCSIWNWID */
+       (iw_handler) NULL,                              /* SIOCGIWNWID */
+       (iw_handler) ieee80211_ioctl_siwfreq,           /* SIOCSIWFREQ */
+       (iw_handler) ieee80211_ioctl_giwfreq,           /* SIOCGIWFREQ */
+       (iw_handler) ieee80211_ioctl_siwmode,           /* SIOCSIWMODE */
+       (iw_handler) ieee80211_ioctl_giwmode,           /* SIOCGIWMODE */
+       (iw_handler) NULL,                              /* SIOCSIWSENS */
+       (iw_handler) NULL,                              /* SIOCGIWSENS */
+       (iw_handler) NULL /* not used */,               /* SIOCSIWRANGE */
+       (iw_handler) ieee80211_ioctl_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_set_spy,                             /* SIOCSIWSPY */
+       iw_handler_get_spy,                             /* SIOCGIWSPY */
+       iw_handler_set_thrspy,                          /* SIOCSIWTHRSPY */
+       iw_handler_get_thrspy,                          /* SIOCGIWTHRSPY */
+       (iw_handler) ieee80211_ioctl_siwap,             /* SIOCSIWAP */
+       (iw_handler) ieee80211_ioctl_giwap,             /* SIOCGIWAP */
+       (iw_handler) ieee80211_ioctl_siwmlme,           /* SIOCSIWMLME */
+       (iw_handler) NULL,                              /* SIOCGIWAPLIST */
+       (iw_handler) ieee80211_ioctl_siwscan,           /* SIOCSIWSCAN */
+       (iw_handler) ieee80211_ioctl_giwscan,           /* SIOCGIWSCAN */
+       (iw_handler) ieee80211_ioctl_siwessid,          /* SIOCSIWESSID */
+       (iw_handler) ieee80211_ioctl_giwessid,          /* SIOCGIWESSID */
+       (iw_handler) NULL,                              /* SIOCSIWNICKN */
+       (iw_handler) NULL,                              /* SIOCGIWNICKN */
+       (iw_handler) NULL,                              /* -- hole -- */
+       (iw_handler) NULL,                              /* -- hole -- */
+       (iw_handler) NULL,                              /* SIOCSIWRATE */
+       (iw_handler) NULL,                              /* SIOCGIWRATE */
+       (iw_handler) ieee80211_ioctl_siwrts,            /* SIOCSIWRTS */
+       (iw_handler) ieee80211_ioctl_giwrts,            /* SIOCGIWRTS */
+       (iw_handler) ieee80211_ioctl_siwfrag,           /* SIOCSIWFRAG */
+       (iw_handler) ieee80211_ioctl_giwfrag,           /* SIOCGIWFRAG */
+       (iw_handler) NULL,                              /* SIOCSIWTXPOW */
+       (iw_handler) NULL,                              /* SIOCGIWTXPOW */
+       (iw_handler) ieee80211_ioctl_siwretry,          /* SIOCSIWRETRY */
+       (iw_handler) ieee80211_ioctl_giwretry,          /* SIOCGIWRETRY */
+       (iw_handler) ieee80211_ioctl_siwencode,         /* SIOCSIWENCODE */
+       (iw_handler) ieee80211_ioctl_giwencode,         /* SIOCGIWENCODE */
+       (iw_handler) NULL,                              /* SIOCSIWPOWER */
+       (iw_handler) NULL,                              /* SIOCGIWPOWER */
+       (iw_handler) NULL,                              /* -- hole -- */
+       (iw_handler) NULL,                              /* -- hole -- */
+       (iw_handler) ieee80211_ioctl_siwgenie,          /* SIOCSIWGENIE */
+       (iw_handler) NULL,                              /* SIOCGIWGENIE */
+       (iw_handler) ieee80211_ioctl_siwauth,           /* SIOCSIWAUTH */
+       (iw_handler) ieee80211_ioctl_giwauth,           /* SIOCGIWAUTH */
+       (iw_handler) ieee80211_ioctl_siwencodeext,      /* SIOCSIWENCODEEXT */
+       (iw_handler) NULL,                              /* SIOCGIWENCODEEXT */
+       (iw_handler) NULL,                              /* SIOCSIWPMKSA */
+       (iw_handler) NULL,                              /* -- hole -- */
+};
+
+static const iw_handler ieee80211_private_handler[] =
+{                                                      /* SIOCIWFIRSTPRIV + */
+       (iw_handler) ieee80211_ioctl_prism2_param,      /* 0 */
+       (iw_handler) ieee80211_ioctl_get_prism2_param,  /* 1 */
+};
+
+const struct iw_handler_def ieee80211_iw_handler_def =
+{
+       .num_standard   = sizeof(ieee80211_handler) / sizeof(iw_handler),
+       .num_private    = sizeof(ieee80211_private_handler) /
+                         sizeof(iw_handler),
+       .num_private_args = sizeof(ieee80211_ioctl_priv) /
+                           sizeof(struct iw_priv_args),
+       .standard       = (iw_handler *) ieee80211_handler,
+       .private        = (iw_handler *) ieee80211_private_handler,
+       .private_args   = (struct iw_priv_args *) ieee80211_ioctl_priv,
+};



-- 
Jouni Malinen                                            PGP id EFC895FA
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to