mac80211: provide interface iterator for drivers
[powerpc.git] / net / mac80211 / ieee80211_ioctl.c
index 48e6843..da3350d 100644 (file)
@@ -27,8 +27,9 @@
 
 
 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;
@@ -75,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 {
@@ -104,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);
@@ -305,9 +306,12 @@ int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
                            ((chan->chan == channel) || (chan->freq == freq))) {
                                local->oper_channel = chan;
                                local->oper_hw_mode = mode;
-                               set++;
+                               set = 1;
+                               break;
                        }
                }
+               if (set)
+                       break;
        }
 
        if (set) {
@@ -373,7 +377,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;
 
@@ -385,7 +388,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);
@@ -450,14 +453,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;
@@ -509,10 +511,11 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
 
 static int ieee80211_ioctl_siwscan(struct net_device *dev,
                                   struct iw_request_info *info,
-                                  struct iw_point *data, char *extra)
+                                  union iwreq_data *wrqu, char *extra)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct iw_scan_req *req = NULL;
        u8 *ssid = NULL;
        size_t ssid_len = 0;
 
@@ -537,6 +540,14 @@ static int ieee80211_ioctl_siwscan(struct net_device *dev,
                return -EOPNOTSUPP;
        }
 
+       /* if SSID was specified explicitly then use that */
+       if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+           wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+               req = (struct iw_scan_req *)extra;
+               ssid = req->essid;
+               ssid_len = req->essid_len;
+       }
+
        return ieee80211_sta_req_scan(dev, ssid, ssid_len);
 }
 
@@ -580,7 +591,7 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
        sdata->bss->force_unicast_rateidx = -1;
        if (rate->value < 0)
                return 0;
-       for (i=0; i< mode->num_rates; i++) {
+       for (i=0; i < mode->num_rates; i++) {
                struct ieee80211_rate *rates = &mode->rates[i];
                int this_rate = rates->rate;
 
@@ -588,10 +599,10 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
                        sdata->bss->max_ratectrl_rateidx = i;
                        if (rate->fixed)
                                sdata->bss->force_unicast_rateidx = i;
-                       break;
+                       return 0;
                }
        }
-       return 0;
+       return -EINVAL;
 }
 
 static int ieee80211_ioctl_giwrate(struct net_device *dev,
@@ -623,22 +634,35 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        bool need_reconfig = 0;
+       u8 new_power_level;
 
        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;
+       if (data->txpower.fixed) {
+               new_power_level = data->txpower.value;
+       } else {
+               /* Automatic power level. Get the px power from the current
+                * channel. */
+               struct ieee80211_channel* chan = local->oper_channel;
+               if (!chan)
+                       return -EINVAL;
+
+               new_power_level = chan->power_level;
+       }
+
+       if (local->hw.conf.power_level != new_power_level) {
+               local->hw.conf.power_level = new_power_level;
                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,
@@ -827,6 +851,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);
 
@@ -845,7 +870,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);
@@ -854,7 +879,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);
 }
@@ -905,7 +930,6 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
                                   struct iw_request_info *info,
                                   struct iw_param *data, char *extra)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        int ret = 0;
 
@@ -915,18 +939,21 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
        case IW_AUTH_CIPHER_GROUP:
        case IW_AUTH_WPA_ENABLED:
        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-               break;
        case IW_AUTH_KEY_MGMT:
+               break;
+       case IW_AUTH_PRIVACY_INVOKED:
                if (sdata->type != IEEE80211_IF_TYPE_STA)
                        ret = -EINVAL;
                else {
+                       sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
                        /*
-                        * Key management was set by wpa_supplicant,
-                        * we only need this to associate to a network
-                        * that has privacy enabled regardless of not
-                        * having a key.
+                        * Privacy invoked by wpa_supplicant, store the
+                        * value and allow associating to a protected
+                        * network without having a key up front.
                         */
-                       sdata->u.sta.key_management_enabled = !!data->value;
+                       if (data->value)
+                               sdata->u.sta.flags |=
+                                       IEEE80211_STA_PRIVACY_INVOKED;
                }
                break;
        case IW_AUTH_80211_AUTH_ALG:
@@ -936,11 +963,6 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
                else
                        ret = -EOPNOTSUPP;
                break;
-       case IW_AUTH_PRIVACY_INVOKED:
-               if (local->ops->set_privacy_invoked)
-                       ret = local->ops->set_privacy_invoked(
-                                       local_to_hw(local), data->value);
-               break;
        default:
                ret = -EOPNOTSUPP;
                break;
@@ -1005,11 +1027,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;
@@ -1025,7 +1047,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) {
@@ -1044,6 +1066,7 @@ 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);