x86: unify include/asm/cache_32/64.h
[powerpc.git] / net / mac80211 / ieee80211_ioctl.c
index e1c4502..f0224c2 100644 (file)
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
-#include "hostapd_ioctl.h"
 #include "ieee80211_rate.h"
 #include "wpa.h"
 #include "aes_ccm.h"
 
 
-/*
- * Wow. This ioctl interface is such crap, it's tied
- * to internal definitions. I hope it dies soon.
- */
-static int mode_to_hostapd_mode(enum ieee80211_phymode mode)
-{
-       switch (mode) {
-       case MODE_IEEE80211A:
-               return 0;
-       case MODE_IEEE80211B:
-               return 1;
-       case MODE_IEEE80211G:
-               return 3;
-       case NUM_IEEE80211_MODES:
-               WARN_ON(1);
-               break;
-       }
-       WARN_ON(1);
-       return -1;
-}
-
-static enum ieee80211_phymode hostapd_mode_to_mode(int hostapd_mode)
-{
-       switch (hostapd_mode) {
-       case 0:
-               return MODE_IEEE80211A;
-       case 1:
-               return MODE_IEEE80211B;
-       case 3:
-               return MODE_IEEE80211G;
-       }
-       return NUM_IEEE80211_MODES;
-}
-
 static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
-                                   int idx, int alg, int set_tx_key,
-                                   const u8 *_key, size_t key_len)
+                                   int idx, int alg, int remove,
+                                   int set_tx_key, const u8 *_key,
+                                   size_t key_len)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        int ret = 0;
@@ -73,17 +39,23 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
+       if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
+               printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
+                      dev->name, idx);
+               return -EINVAL;
+       }
+
        if (is_broadcast_ether_addr(sta_addr)) {
                sta = NULL;
-               if (idx >= NUM_DEFAULT_KEYS) {
-                       printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
-                              dev->name, idx);
-                       return -EINVAL;
-               }
                key = sdata->keys[idx];
        } else {
                set_tx_key = 0;
-               if (idx != 0) {
+               /*
+                * According to the standard, the key index of a pairwise
+                * key must be zero. However, some AP are broken when it
+                * comes to WEP key indices, so we work around this.
+                */
+               if (idx != 0 && alg != ALG_WEP) {
                        printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
                               "individual key\n", dev->name);
                        return -EINVAL;
@@ -92,9 +64,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
                sta = sta_info_get(local, sta_addr);
                if (!sta) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+                       DECLARE_MAC_BUF(mac);
                        printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
-                              MAC_FMT "\n",
-                              dev->name, MAC_ARG(sta_addr));
+                              "%s\n",
+                              dev->name, print_mac(mac, sta_addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
                        return -ENOENT;
@@ -103,7 +76,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
                key = sta->key;
        }
 
-       if (alg == ALG_NONE) {
+       if (remove) {
                ieee80211_key_free(key);
                key = NULL;
        } else {
@@ -132,12 +105,12 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
                                    struct iw_point *data, char *extra)
 {
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       if (local->user_space_mlme)
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
                return -EOPNOTSUPP;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->type == IEEE80211_IF_TYPE_STA ||
            sdata->type == IEEE80211_IF_TYPE_IBSS) {
                int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
@@ -148,15 +121,6 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
                return 0;
        }
 
-       if (sdata->type == IEEE80211_IF_TYPE_AP) {
-               kfree(sdata->u.ap.generic_elem);
-               sdata->u.ap.generic_elem = kmalloc(data->length, GFP_KERNEL);
-               if (!sdata->u.ap.generic_elem)
-                       return -ENOMEM;
-               memcpy(sdata->u.ap.generic_elem, extra, data->length);
-               sdata->u.ap.generic_elem_len = data->length;
-               return ieee80211_if_config(dev);
-       }
        return -EOPNOTSUPP;
 }
 
@@ -340,11 +304,6 @@ int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
                        struct ieee80211_channel *chan = &mode->channels[c];
                        if (chan->flag & IEEE80211_CHAN_W_SCAN &&
                            ((chan->chan == channel) || (chan->freq == freq))) {
-                               /* Use next_mode as the mode preference to
-                                * resolve non-unique channel numbers. */
-                               if (set && mode->mode != local->next_mode)
-                                       continue;
-
                                local->oper_channel = chan;
                                local->oper_hw_mode = mode;
                                set++;
@@ -415,7 +374,6 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
                                    struct iw_request_info *info,
                                    struct iw_point *data, char *ssid)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata;
        size_t len = data->length;
 
@@ -427,7 +385,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
        if (sdata->type == IEEE80211_IF_TYPE_STA ||
            sdata->type == IEEE80211_IF_TYPE_IBSS) {
                int ret;
-               if (local->user_space_mlme) {
+               if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
                        if (len > IEEE80211_MAX_SSID_LEN)
                                return -EINVAL;
                        memcpy(sdata->u.sta.ssid, ssid, len);
@@ -492,14 +450,13 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
                                 struct iw_request_info *info,
                                 struct sockaddr *ap_addr, char *extra)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->type == IEEE80211_IF_TYPE_STA ||
            sdata->type == IEEE80211_IF_TYPE_IBSS) {
                int ret;
-               if (local->user_space_mlme) {
+               if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
                        memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
                               ETH_ALEN);
                        return 0;
@@ -659,6 +616,38 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
        return 0;
 }
 
+static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
+                                     struct iw_request_info *info,
+                                     union iwreq_data *data, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       bool need_reconfig = 0;
+
+       if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
+               return -EINVAL;
+       if (data->txpower.flags & IW_TXPOW_RANGE)
+               return -EINVAL;
+       if (!data->txpower.fixed)
+               return -EINVAL;
+
+       if (local->hw.conf.power_level != data->txpower.value) {
+               local->hw.conf.power_level = data->txpower.value;
+               need_reconfig = 1;
+       }
+       if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
+               local->hw.conf.radio_enabled = !(data->txpower.disabled);
+               need_reconfig = 1;
+       }
+       if (need_reconfig) {
+               ieee80211_hw_config(local);
+               /* The return value of hw_config is not of big interest here,
+                * as it doesn't say that it failed because of _this_ config
+                * change or something else. Ignore it. */
+       }
+
+       return 0;
+}
+
 static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
                                   struct iw_request_info *info,
                                   union iwreq_data *data, char *extra)
@@ -805,228 +794,6 @@ static int ieee80211_ioctl_giwretry(struct net_device *dev,
        return 0;
 }
 
-static int ieee80211_ioctl_prism2_param(struct net_device *dev,
-                                       struct iw_request_info *info,
-                                       void *wrqu, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
-       int *i = (int *) extra;
-       int param = *i;
-       int value = *(i + 1);
-       int ret = 0;
-       int mode;
-
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       switch (param) {
-       case PRISM2_PARAM_IEEE_802_1X:
-               if (local->ops->set_ieee8021x)
-                       ret = local->ops->set_ieee8021x(local_to_hw(local),
-                                                       value);
-               if (ret)
-                       printk(KERN_DEBUG "%s: failed to set IEEE 802.1X (%d) "
-                              "for low-level driver\n", dev->name, value);
-               else
-                       sdata->ieee802_1x = value;
-               break;
-
-       case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
-               if (sdata->type == IEEE80211_IF_TYPE_AP) {
-                       if (value)
-                               sdata->flags |= IEEE80211_SDATA_USE_PROTECTION;
-                       else
-                               sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION;
-                       ieee80211_erp_info_change_notify(dev,
-                                       IEEE80211_ERP_CHANGE_PROTECTION);
-               } else {
-                       ret = -ENOENT;
-               }
-               break;
-
-       case PRISM2_PARAM_PREAMBLE:
-               if (sdata->type == IEEE80211_IF_TYPE_AP) {
-                       if (value)
-                               sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE;
-                       else
-                               sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE;
-                       ieee80211_erp_info_change_notify(dev,
-                                       IEEE80211_ERP_CHANGE_PREAMBLE);
-               } else {
-                       ret = -ENOENT;
-               }
-               break;
-
-       case PRISM2_PARAM_SHORT_SLOT_TIME:
-               if (value)
-                       local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME;
-               else
-                       local->hw.conf.flags &= ~IEEE80211_CONF_SHORT_SLOT_TIME;
-               if (ieee80211_hw_config(local))
-                       ret = -EINVAL;
-               break;
-
-       case PRISM2_PARAM_NEXT_MODE:
-               local->next_mode = hostapd_mode_to_mode(value);
-               break;
-
-       case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
-               local->key_tx_rx_threshold = value;
-               break;
-
-       case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
-               local->wifi_wme_noack_test = value;
-               break;
-
-       case PRISM2_PARAM_SCAN_FLAGS:
-               local->scan_flags = value;
-               break;
-
-       case PRISM2_PARAM_MIXED_CELL:
-               if (sdata->type != IEEE80211_IF_TYPE_STA &&
-                   sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else {
-                       if (value)
-                               sdata->u.sta.flags |= IEEE80211_STA_MIXED_CELL;
-                       else
-                               sdata->u.sta.flags &= ~IEEE80211_STA_MIXED_CELL;
-               }
-               break;
-
-       case PRISM2_PARAM_HW_MODES:
-               mode = 1;
-               local->enabled_modes = 0;
-               while (value) {
-                       if (value & 1)
-                               local->enabled_modes |=
-                                       hostapd_mode_to_mode(mode);
-                       mode <<= 1;
-                       value >>= 1;
-               }
-               break;
-
-       case PRISM2_PARAM_CREATE_IBSS:
-               if (sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else {
-                       if (value)
-                               sdata->u.sta.flags |= IEEE80211_STA_CREATE_IBSS;
-                       else
-                               sdata->u.sta.flags &= ~IEEE80211_STA_CREATE_IBSS;
-               }
-               break;
-       case PRISM2_PARAM_WMM_ENABLED:
-               if (sdata->type != IEEE80211_IF_TYPE_STA &&
-                   sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else {
-                       if (value)
-                               sdata->u.sta.flags |= IEEE80211_STA_WMM_ENABLED;
-                       else
-                               sdata->u.sta.flags &= ~IEEE80211_STA_WMM_ENABLED;
-               }
-               break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-       }
-
-       return ret;
-}
-
-
-static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
-                                           struct iw_request_info *info,
-                                           void *wrqu, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
-       int *param = (int *) extra;
-       int ret = 0;
-       int mode;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       switch (*param) {
-       case PRISM2_PARAM_IEEE_802_1X:
-               *param = sdata->ieee802_1x;
-               break;
-
-       case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
-               *param = !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION);
-               break;
-
-       case PRISM2_PARAM_PREAMBLE:
-               *param = !!(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);
-               break;
-
-       case PRISM2_PARAM_SHORT_SLOT_TIME:
-               *param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME);
-               break;
-
-       case PRISM2_PARAM_NEXT_MODE:
-               *param = local->next_mode;
-               break;
-
-       case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
-               *param = local->key_tx_rx_threshold;
-               break;
-
-       case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
-               *param = local->wifi_wme_noack_test;
-               break;
-
-       case PRISM2_PARAM_SCAN_FLAGS:
-               *param = local->scan_flags;
-               break;
-
-       case PRISM2_PARAM_HW_MODES:
-               mode = 0;
-               *param = 0;
-               while (mode < NUM_IEEE80211_MODES) {
-                       if (local->enabled_modes & (1<<mode))
-                               *param |= mode_to_hostapd_mode(1<<mode);
-                       mode++;
-               }
-               break;
-
-       case PRISM2_PARAM_CREATE_IBSS:
-               if (sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else
-                       *param = !!(sdata->u.sta.flags &
-                                       IEEE80211_STA_CREATE_IBSS);
-               break;
-
-       case PRISM2_PARAM_MIXED_CELL:
-               if (sdata->type != IEEE80211_IF_TYPE_STA &&
-                   sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else
-                       *param = !!(sdata->u.sta.flags &
-                                       IEEE80211_STA_MIXED_CELL);
-               break;
-
-       case PRISM2_PARAM_WMM_ENABLED:
-               if (sdata->type != IEEE80211_IF_TYPE_STA &&
-                   sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else
-                       *param = !!(sdata->u.sta.flags &
-                                       IEEE80211_STA_WMM_ENABLED);
-               break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-       }
-
-       return ret;
-}
-
 static int ieee80211_ioctl_siwmlme(struct net_device *dev,
                                   struct iw_request_info *info,
                                   struct iw_point *data, char *extra)
@@ -1059,6 +826,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev,
        struct ieee80211_sub_if_data *sdata;
        int idx, i, alg = ALG_WEP;
        u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+       int remove = 0;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -1077,7 +845,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev,
                idx--;
 
        if (erq->flags & IW_ENCODE_DISABLED)
-               alg = ALG_NONE;
+               remove = 1;
        else if (erq->length == 0) {
                /* No key data - just set the default TX key index */
                ieee80211_set_default_key(sdata, idx);
@@ -1086,7 +854,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev,
 
        return ieee80211_set_encryption(
                dev, bcaddr,
-               idx, alg,
+               idx, alg, remove,
                !sdata->default_key,
                keybuf, erq->length);
 }
@@ -1237,11 +1005,11 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
 {
        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;
+       int uninitialized_var(alg), idx, i, remove = 0;
 
        switch (ext->alg) {
        case IW_ENCODE_ALG_NONE:
-               alg = ALG_NONE;
+               remove = 1;
                break;
        case IW_ENCODE_ALG_WEP:
                alg = ALG_WEP;
@@ -1257,7 +1025,7 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
        }
 
        if (erq->flags & IW_ENCODE_DISABLED)
-               alg = ALG_NONE;
+               remove = 1;
 
        idx = erq->flags & IW_ENCODE_INDEX;
        if (idx < 1 || idx > 4) {
@@ -1276,20 +1044,13 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
                idx--;
 
        return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg,
+                                       remove,
                                        ext->ext_flags &
                                        IW_ENCODE_EXT_SET_TX_KEY,
                                        ext->key, ext->key_len);
 }
 
 
-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" },
-};
-
 /* Structures to export the Wireless Handlers */
 
 static const iw_handler ieee80211_handler[] =
@@ -1332,7 +1093,7 @@ static const iw_handler ieee80211_handler[] =
        (iw_handler) ieee80211_ioctl_giwrts,            /* SIOCGIWRTS */
        (iw_handler) ieee80211_ioctl_siwfrag,           /* SIOCSIWFRAG */
        (iw_handler) ieee80211_ioctl_giwfrag,           /* SIOCGIWFRAG */
-       (iw_handler) NULL,                              /* SIOCSIWTXPOW */
+       (iw_handler) ieee80211_ioctl_siwtxpower,        /* SIOCSIWTXPOW */
        (iw_handler) ieee80211_ioctl_giwtxpower,        /* SIOCGIWTXPOW */
        (iw_handler) ieee80211_ioctl_siwretry,          /* SIOCSIWRETRY */
        (iw_handler) ieee80211_ioctl_giwretry,          /* SIOCGIWRETRY */
@@ -1352,19 +1113,9 @@ static const iw_handler ieee80211_handler[] =
        (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   = ARRAY_SIZE(ieee80211_handler),
-       .num_private    = ARRAY_SIZE(ieee80211_private_handler),
-       .num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv),
        .standard       = (iw_handler *) ieee80211_handler,
-       .private        = (iw_handler *) ieee80211_private_handler,
-       .private_args   = (struct iw_priv_args *) ieee80211_ioctl_priv,
        .get_wireless_stats = ieee80211_get_wireless_stats,
 };