| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2002-2005, Instant802 Networks, Inc. | 
|  | 3 | * Copyright 2005-2006, Devicescape Software, Inc. | 
|  | 4 | * | 
|  | 5 | * This program is free software; you can redistribute it and/or modify | 
|  | 6 | * it under the terms of the GNU General Public License version 2 as | 
|  | 7 | * published by the Free Software Foundation. | 
|  | 8 | */ | 
|  | 9 |  | 
|  | 10 | #include <linux/module.h> | 
|  | 11 | #include <linux/init.h> | 
|  | 12 | #include <linux/netdevice.h> | 
|  | 13 | #include <linux/types.h> | 
|  | 14 | #include <linux/slab.h> | 
|  | 15 | #include <linux/skbuff.h> | 
|  | 16 | #include <linux/etherdevice.h> | 
|  | 17 | #include <linux/if_arp.h> | 
|  | 18 | #include <linux/wireless.h> | 
|  | 19 | #include <net/iw_handler.h> | 
|  | 20 | #include <asm/uaccess.h> | 
|  | 21 |  | 
|  | 22 | #include <net/mac80211.h> | 
|  | 23 | #include "ieee80211_i.h" | 
| Johannes Berg | 2c8dccc | 2008-04-08 15:14:40 -0400 | [diff] [blame] | 24 | #include "led.h" | 
|  | 25 | #include "rate.h" | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 26 | #include "wpa.h" | 
|  | 27 | #include "aes_ccm.h" | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 28 |  | 
| Johannes Berg | b708e61 | 2007-09-14 11:10:25 -0400 | [diff] [blame] | 29 |  | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 30 | static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta_addr, | 
| Johannes Berg | 628a140 | 2007-09-26 17:53:17 +0200 | [diff] [blame] | 31 | int idx, int alg, int remove, | 
|  | 32 | int set_tx_key, const u8 *_key, | 
|  | 33 | size_t key_len) | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 34 | { | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 35 | struct ieee80211_local *local = sdata->local; | 
| Johannes Berg | d0709a6 | 2008-02-25 16:27:46 +0100 | [diff] [blame] | 36 | struct sta_info *sta; | 
| Johannes Berg | 11a843b | 2007-08-28 17:01:55 -0400 | [diff] [blame] | 37 | struct ieee80211_key *key; | 
| Johannes Berg | 3b96766 | 2008-04-08 17:56:52 +0200 | [diff] [blame] | 38 | int err; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 39 |  | 
| Volker Braun | 139c3a0 | 2007-09-14 11:10:25 -0400 | [diff] [blame] | 40 | if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { | 
|  | 41 | printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 42 | sdata->dev->name, idx); | 
| Volker Braun | 139c3a0 | 2007-09-14 11:10:25 -0400 | [diff] [blame] | 43 | return -EINVAL; | 
|  | 44 | } | 
|  | 45 |  | 
| Johannes Berg | 628a140 | 2007-09-26 17:53:17 +0200 | [diff] [blame] | 46 | if (remove) { | 
| Johannes Berg | 3b96766 | 2008-04-08 17:56:52 +0200 | [diff] [blame] | 47 | rcu_read_lock(); | 
|  | 48 |  | 
|  | 49 | err = 0; | 
|  | 50 |  | 
| Johannes Berg | db4d116 | 2008-02-25 16:27:45 +0100 | [diff] [blame] | 51 | if (is_broadcast_ether_addr(sta_addr)) { | 
|  | 52 | key = sdata->keys[idx]; | 
|  | 53 | } else { | 
|  | 54 | sta = sta_info_get(local, sta_addr); | 
| Johannes Berg | 3b96766 | 2008-04-08 17:56:52 +0200 | [diff] [blame] | 55 | if (!sta) { | 
|  | 56 | err = -ENOENT; | 
|  | 57 | goto out_unlock; | 
|  | 58 | } | 
| Johannes Berg | db4d116 | 2008-02-25 16:27:45 +0100 | [diff] [blame] | 59 | key = sta->key; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 60 | } | 
| Johannes Berg | db4d116 | 2008-02-25 16:27:45 +0100 | [diff] [blame] | 61 |  | 
| Johannes Berg | d0709a6 | 2008-02-25 16:27:46 +0100 | [diff] [blame] | 62 | ieee80211_key_free(key); | 
| Johannes Berg | db4d116 | 2008-02-25 16:27:45 +0100 | [diff] [blame] | 63 | } else { | 
|  | 64 | key = ieee80211_key_alloc(alg, idx, key_len, _key); | 
|  | 65 | if (!key) | 
|  | 66 | return -ENOMEM; | 
|  | 67 |  | 
| Johannes Berg | d0709a6 | 2008-02-25 16:27:46 +0100 | [diff] [blame] | 68 | sta = NULL; | 
| Johannes Berg | 3b96766 | 2008-04-08 17:56:52 +0200 | [diff] [blame] | 69 | err = 0; | 
|  | 70 |  | 
|  | 71 | rcu_read_lock(); | 
| Johannes Berg | d0709a6 | 2008-02-25 16:27:46 +0100 | [diff] [blame] | 72 |  | 
| Johannes Berg | db4d116 | 2008-02-25 16:27:45 +0100 | [diff] [blame] | 73 | if (!is_broadcast_ether_addr(sta_addr)) { | 
|  | 74 | set_tx_key = 0; | 
|  | 75 | /* | 
|  | 76 | * According to the standard, the key index of a | 
|  | 77 | * pairwise key must be zero. However, some AP are | 
|  | 78 | * broken when it comes to WEP key indices, so we | 
|  | 79 | * work around this. | 
|  | 80 | */ | 
|  | 81 | if (idx != 0 && alg != ALG_WEP) { | 
| Johannes Berg | d0709a6 | 2008-02-25 16:27:46 +0100 | [diff] [blame] | 82 | ieee80211_key_free(key); | 
| Johannes Berg | 3b96766 | 2008-04-08 17:56:52 +0200 | [diff] [blame] | 83 | err = -EINVAL; | 
|  | 84 | goto out_unlock; | 
| Johannes Berg | db4d116 | 2008-02-25 16:27:45 +0100 | [diff] [blame] | 85 | } | 
|  | 86 |  | 
|  | 87 | sta = sta_info_get(local, sta_addr); | 
|  | 88 | if (!sta) { | 
| Johannes Berg | d0709a6 | 2008-02-25 16:27:46 +0100 | [diff] [blame] | 89 | ieee80211_key_free(key); | 
| Johannes Berg | 3b96766 | 2008-04-08 17:56:52 +0200 | [diff] [blame] | 90 | err = -ENOENT; | 
|  | 91 | goto out_unlock; | 
| Johannes Berg | db4d116 | 2008-02-25 16:27:45 +0100 | [diff] [blame] | 92 | } | 
|  | 93 | } | 
|  | 94 |  | 
| Emmanuel Grumbach | 23976ef | 2008-06-28 02:50:13 +0300 | [diff] [blame] | 95 | if (alg == ALG_WEP && | 
|  | 96 | key_len != LEN_WEP40 && key_len != LEN_WEP104) { | 
|  | 97 | ieee80211_key_free(key); | 
|  | 98 | err = -EINVAL; | 
|  | 99 | goto out_unlock; | 
|  | 100 | } | 
|  | 101 |  | 
| Johannes Berg | db4d116 | 2008-02-25 16:27:45 +0100 | [diff] [blame] | 102 | ieee80211_key_link(key, sdata, sta); | 
|  | 103 |  | 
|  | 104 | if (set_tx_key || (!sta && !sdata->default_key && key)) | 
|  | 105 | ieee80211_set_default_key(sdata, idx); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 106 | } | 
|  | 107 |  | 
| Johannes Berg | 3b96766 | 2008-04-08 17:56:52 +0200 | [diff] [blame] | 108 | out_unlock: | 
|  | 109 | rcu_read_unlock(); | 
|  | 110 |  | 
|  | 111 | return err; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 112 | } | 
|  | 113 |  | 
|  | 114 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, | 
|  | 115 | struct iw_request_info *info, | 
|  | 116 | struct iw_point *data, char *extra) | 
|  | 117 | { | 
|  | 118 | struct ieee80211_sub_if_data *sdata; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 119 |  | 
|  | 120 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Johannes Berg | ddd3d2b | 2007-09-26 17:53:20 +0200 | [diff] [blame] | 121 |  | 
|  | 122 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) | 
|  | 123 | return -EOPNOTSUPP; | 
|  | 124 |  | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 125 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 
|  | 126 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 127 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 128 | if (ret) | 
|  | 129 | return ret; | 
| Jiri Slaby | d6f2da5 | 2007-08-28 17:01:54 -0400 | [diff] [blame] | 130 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 131 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 132 | return 0; | 
|  | 133 | } | 
|  | 134 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 135 | return -EOPNOTSUPP; | 
|  | 136 | } | 
|  | 137 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 138 | static int ieee80211_ioctl_giwname(struct net_device *dev, | 
|  | 139 | struct iw_request_info *info, | 
|  | 140 | char *name, char *extra) | 
|  | 141 | { | 
| Tomas Winkler | f37d08b | 2008-06-24 15:50:17 +0300 | [diff] [blame] | 142 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 143 | struct ieee80211_supported_band *sband; | 
|  | 144 | u8 is_ht = 0, is_a = 0, is_b = 0, is_g = 0; | 
|  | 145 |  | 
|  | 146 |  | 
|  | 147 | sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ]; | 
|  | 148 | if (sband) { | 
|  | 149 | is_a = 1; | 
|  | 150 | is_ht |= sband->ht_info.ht_supported; | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ]; | 
|  | 154 | if (sband) { | 
|  | 155 | int i; | 
|  | 156 | /* Check for mandatory rates */ | 
|  | 157 | for (i = 0; i < sband->n_bitrates; i++) { | 
|  | 158 | if (sband->bitrates[i].bitrate == 10) | 
|  | 159 | is_b = 1; | 
|  | 160 | if (sband->bitrates[i].bitrate == 60) | 
|  | 161 | is_g = 1; | 
|  | 162 | } | 
|  | 163 | is_ht |= sband->ht_info.ht_supported; | 
|  | 164 | } | 
|  | 165 |  | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 166 | strcpy(name, "IEEE 802.11"); | 
| Tomas Winkler | f37d08b | 2008-06-24 15:50:17 +0300 | [diff] [blame] | 167 | if (is_a) | 
|  | 168 | strcat(name, "a"); | 
|  | 169 | if (is_b) | 
|  | 170 | strcat(name, "b"); | 
|  | 171 | if (is_g) | 
|  | 172 | strcat(name, "g"); | 
|  | 173 | if (is_ht) | 
|  | 174 | strcat(name, "n"); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 175 |  | 
|  | 176 | return 0; | 
|  | 177 | } | 
|  | 178 |  | 
|  | 179 |  | 
|  | 180 | static int ieee80211_ioctl_giwrange(struct net_device *dev, | 
|  | 181 | struct iw_request_info *info, | 
|  | 182 | struct iw_point *data, char *extra) | 
|  | 183 | { | 
|  | 184 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 185 | struct iw_range *range = (struct iw_range *) extra; | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 186 | enum ieee80211_band band; | 
| Hong Liu | 333af2f | 2007-07-10 19:32:08 +0200 | [diff] [blame] | 187 | int c = 0; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 188 |  | 
|  | 189 | data->length = sizeof(struct iw_range); | 
|  | 190 | memset(range, 0, sizeof(struct iw_range)); | 
|  | 191 |  | 
|  | 192 | range->we_version_compiled = WIRELESS_EXT; | 
|  | 193 | range->we_version_source = 21; | 
|  | 194 | range->retry_capa = IW_RETRY_LIMIT; | 
|  | 195 | range->retry_flags = IW_RETRY_LIMIT; | 
|  | 196 | range->min_retry = 0; | 
|  | 197 | range->max_retry = 255; | 
|  | 198 | range->min_rts = 0; | 
|  | 199 | range->max_rts = 2347; | 
|  | 200 | range->min_frag = 256; | 
|  | 201 | range->max_frag = 2346; | 
|  | 202 |  | 
|  | 203 | range->encoding_size[0] = 5; | 
|  | 204 | range->encoding_size[1] = 13; | 
|  | 205 | range->num_encoding_sizes = 2; | 
|  | 206 | range->max_encoding_tokens = NUM_DEFAULT_KEYS; | 
|  | 207 |  | 
| Bruno Randolf | 566bfe5 | 2008-05-08 19:15:40 +0200 | [diff] [blame] | 208 | if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC || | 
|  | 209 | local->hw.flags & IEEE80211_HW_SIGNAL_DB) | 
|  | 210 | range->max_qual.level = local->hw.max_signal; | 
|  | 211 | else if  (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 
|  | 212 | range->max_qual.level = -110; | 
|  | 213 | else | 
|  | 214 | range->max_qual.level = 0; | 
|  | 215 |  | 
|  | 216 | if (local->hw.flags & IEEE80211_HW_NOISE_DBM) | 
|  | 217 | range->max_qual.noise = -110; | 
|  | 218 | else | 
|  | 219 | range->max_qual.noise = 0; | 
|  | 220 |  | 
|  | 221 | range->max_qual.qual = 100; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 222 | range->max_qual.updated = local->wstats_flags; | 
|  | 223 |  | 
| Bruno Randolf | 566bfe5 | 2008-05-08 19:15:40 +0200 | [diff] [blame] | 224 | range->avg_qual.qual = 50; | 
|  | 225 | /* not always true but better than nothing */ | 
|  | 226 | range->avg_qual.level = range->max_qual.level / 2; | 
|  | 227 | range->avg_qual.noise = range->max_qual.noise / 2; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 228 | range->avg_qual.updated = local->wstats_flags; | 
|  | 229 |  | 
|  | 230 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | 
|  | 231 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | 
|  | 232 |  | 
| Hong Liu | 333af2f | 2007-07-10 19:32:08 +0200 | [diff] [blame] | 233 |  | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 234 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { | 
|  | 235 | int i; | 
|  | 236 | struct ieee80211_supported_band *sband; | 
|  | 237 |  | 
|  | 238 | sband = local->hw.wiphy->bands[band]; | 
|  | 239 |  | 
|  | 240 | if (!sband) | 
| Hong Liu | 333af2f | 2007-07-10 19:32:08 +0200 | [diff] [blame] | 241 | continue; | 
|  | 242 |  | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 243 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { | 
|  | 244 | struct ieee80211_channel *chan = &sband->channels[i]; | 
| Hong Liu | 333af2f | 2007-07-10 19:32:08 +0200 | [diff] [blame] | 245 |  | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 246 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { | 
|  | 247 | range->freq[c].i = | 
|  | 248 | ieee80211_frequency_to_channel( | 
|  | 249 | chan->center_freq); | 
|  | 250 | range->freq[c].m = chan->center_freq; | 
|  | 251 | range->freq[c].e = 6; | 
| Hong Liu | 333af2f | 2007-07-10 19:32:08 +0200 | [diff] [blame] | 252 | c++; | 
|  | 253 | } | 
| Hong Liu | 333af2f | 2007-07-10 19:32:08 +0200 | [diff] [blame] | 254 | } | 
|  | 255 | } | 
|  | 256 | range->num_channels = c; | 
|  | 257 | range->num_frequency = c; | 
|  | 258 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 259 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 260 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); | 
|  | 261 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); | 
|  | 262 |  | 
| Dan Williams | 374fdfb | 2007-12-12 10:25:07 -0500 | [diff] [blame] | 263 | range->scan_capa |= IW_SCAN_CAPA_ESSID; | 
|  | 264 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 265 | return 0; | 
|  | 266 | } | 
|  | 267 |  | 
|  | 268 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 269 | static int ieee80211_ioctl_siwmode(struct net_device *dev, | 
|  | 270 | struct iw_request_info *info, | 
|  | 271 | __u32 *mode, char *extra) | 
|  | 272 | { | 
|  | 273 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
|  | 274 | int type; | 
|  | 275 |  | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 276 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 277 | return -EOPNOTSUPP; | 
|  | 278 |  | 
|  | 279 | switch (*mode) { | 
|  | 280 | case IW_MODE_INFRA: | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 281 | type = NL80211_IFTYPE_STATION; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 282 | break; | 
|  | 283 | case IW_MODE_ADHOC: | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 284 | type = NL80211_IFTYPE_ADHOC; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 285 | break; | 
| Johannes Berg | b454048 | 2008-04-14 15:37:03 +0200 | [diff] [blame] | 286 | case IW_MODE_REPEAT: | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 287 | type = NL80211_IFTYPE_WDS; | 
| Johannes Berg | b454048 | 2008-04-14 15:37:03 +0200 | [diff] [blame] | 288 | break; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 289 | case IW_MODE_MONITOR: | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 290 | type = NL80211_IFTYPE_MONITOR; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 291 | break; | 
|  | 292 | default: | 
|  | 293 | return -EINVAL; | 
|  | 294 | } | 
|  | 295 |  | 
| Johannes Berg | f3947e2 | 2008-07-09 14:40:36 +0200 | [diff] [blame] | 296 | return ieee80211_if_change_type(sdata, type); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 297 | } | 
|  | 298 |  | 
|  | 299 |  | 
|  | 300 | static int ieee80211_ioctl_giwmode(struct net_device *dev, | 
|  | 301 | struct iw_request_info *info, | 
|  | 302 | __u32 *mode, char *extra) | 
|  | 303 | { | 
|  | 304 | struct ieee80211_sub_if_data *sdata; | 
|  | 305 |  | 
|  | 306 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Johannes Berg | 51fb61e | 2007-12-19 01:31:27 +0100 | [diff] [blame] | 307 | switch (sdata->vif.type) { | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 308 | case NL80211_IFTYPE_AP: | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 309 | *mode = IW_MODE_MASTER; | 
|  | 310 | break; | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 311 | case NL80211_IFTYPE_STATION: | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 312 | *mode = IW_MODE_INFRA; | 
|  | 313 | break; | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 314 | case NL80211_IFTYPE_ADHOC: | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 315 | *mode = IW_MODE_ADHOC; | 
|  | 316 | break; | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 317 | case NL80211_IFTYPE_MONITOR: | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 318 | *mode = IW_MODE_MONITOR; | 
|  | 319 | break; | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 320 | case NL80211_IFTYPE_WDS: | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 321 | *mode = IW_MODE_REPEAT; | 
|  | 322 | break; | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 323 | case NL80211_IFTYPE_AP_VLAN: | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 324 | *mode = IW_MODE_SECOND;		/* FIXME */ | 
|  | 325 | break; | 
|  | 326 | default: | 
|  | 327 | *mode = IW_MODE_AUTO; | 
|  | 328 | break; | 
|  | 329 | } | 
|  | 330 | return 0; | 
|  | 331 | } | 
|  | 332 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 333 | static int ieee80211_ioctl_siwfreq(struct net_device *dev, | 
|  | 334 | struct iw_request_info *info, | 
|  | 335 | struct iw_freq *freq, char *extra) | 
|  | 336 | { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 337 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
|  | 338 |  | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 339 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 
| Jiri Slaby | d6f2da5 | 2007-08-28 17:01:54 -0400 | [diff] [blame] | 340 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 341 |  | 
|  | 342 | /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ | 
|  | 343 | if (freq->e == 0) { | 
|  | 344 | if (freq->m < 0) { | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 345 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 
| Jiri Slaby | d6f2da5 | 2007-08-28 17:01:54 -0400 | [diff] [blame] | 346 | sdata->u.sta.flags |= | 
|  | 347 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 348 | return 0; | 
|  | 349 | } else | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 350 | return ieee80211_set_freq(sdata, | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 351 | ieee80211_channel_to_frequency(freq->m)); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 352 | } else { | 
|  | 353 | int i, div = 1000000; | 
|  | 354 | for (i = 0; i < freq->e; i++) | 
|  | 355 | div /= 10; | 
|  | 356 | if (div > 0) | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 357 | return ieee80211_set_freq(sdata, freq->m / div); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 358 | else | 
|  | 359 | return -EINVAL; | 
|  | 360 | } | 
|  | 361 | } | 
|  | 362 |  | 
|  | 363 |  | 
|  | 364 | static int ieee80211_ioctl_giwfreq(struct net_device *dev, | 
|  | 365 | struct iw_request_info *info, | 
|  | 366 | struct iw_freq *freq, char *extra) | 
|  | 367 | { | 
|  | 368 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 369 |  | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 370 | freq->m = local->hw.conf.channel->center_freq; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 371 | freq->e = 6; | 
|  | 372 |  | 
|  | 373 | return 0; | 
|  | 374 | } | 
|  | 375 |  | 
|  | 376 |  | 
|  | 377 | static int ieee80211_ioctl_siwessid(struct net_device *dev, | 
|  | 378 | struct iw_request_info *info, | 
|  | 379 | struct iw_point *data, char *ssid) | 
|  | 380 | { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 381 | struct ieee80211_sub_if_data *sdata; | 
|  | 382 | size_t len = data->length; | 
|  | 383 |  | 
|  | 384 | /* iwconfig uses nul termination in SSID.. */ | 
|  | 385 | if (len > 0 && ssid[len - 1] == '\0') | 
|  | 386 | len--; | 
|  | 387 |  | 
|  | 388 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 389 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 
|  | 390 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 391 | int ret; | 
| Johannes Berg | ddd3d2b | 2007-09-26 17:53:20 +0200 | [diff] [blame] | 392 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 393 | if (len > IEEE80211_MAX_SSID_LEN) | 
|  | 394 | return -EINVAL; | 
|  | 395 | memcpy(sdata->u.sta.ssid, ssid, len); | 
|  | 396 | sdata->u.sta.ssid_len = len; | 
|  | 397 | return 0; | 
|  | 398 | } | 
| Jiri Slaby | d6f2da5 | 2007-08-28 17:01:54 -0400 | [diff] [blame] | 399 | if (data->flags) | 
|  | 400 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; | 
|  | 401 | else | 
|  | 402 | sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL; | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 403 | ret = ieee80211_sta_set_ssid(sdata, ssid, len); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 404 | if (ret) | 
|  | 405 | return ret; | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 406 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 407 | return 0; | 
|  | 408 | } | 
|  | 409 |  | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 410 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 411 | memcpy(sdata->u.ap.ssid, ssid, len); | 
|  | 412 | memset(sdata->u.ap.ssid + len, 0, | 
|  | 413 | IEEE80211_MAX_SSID_LEN - len); | 
|  | 414 | sdata->u.ap.ssid_len = len; | 
| Johannes Berg | 9d139c8 | 2008-07-09 14:40:37 +0200 | [diff] [blame] | 415 | return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 416 | } | 
|  | 417 | return -EOPNOTSUPP; | 
|  | 418 | } | 
|  | 419 |  | 
|  | 420 |  | 
|  | 421 | static int ieee80211_ioctl_giwessid(struct net_device *dev, | 
|  | 422 | struct iw_request_info *info, | 
|  | 423 | struct iw_point *data, char *ssid) | 
|  | 424 | { | 
|  | 425 | size_t len; | 
|  | 426 |  | 
|  | 427 | struct ieee80211_sub_if_data *sdata; | 
|  | 428 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 429 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 
|  | 430 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 431 | int res = ieee80211_sta_get_ssid(sdata, ssid, &len); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 432 | if (res == 0) { | 
|  | 433 | data->length = len; | 
|  | 434 | data->flags = 1; | 
|  | 435 | } else | 
|  | 436 | data->flags = 0; | 
|  | 437 | return res; | 
|  | 438 | } | 
|  | 439 |  | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 440 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 441 | len = sdata->u.ap.ssid_len; | 
|  | 442 | if (len > IW_ESSID_MAX_SIZE) | 
|  | 443 | len = IW_ESSID_MAX_SIZE; | 
|  | 444 | memcpy(ssid, sdata->u.ap.ssid, len); | 
|  | 445 | data->length = len; | 
|  | 446 | data->flags = 1; | 
|  | 447 | return 0; | 
|  | 448 | } | 
|  | 449 | return -EOPNOTSUPP; | 
|  | 450 | } | 
|  | 451 |  | 
|  | 452 |  | 
|  | 453 | static int ieee80211_ioctl_siwap(struct net_device *dev, | 
|  | 454 | struct iw_request_info *info, | 
|  | 455 | struct sockaddr *ap_addr, char *extra) | 
|  | 456 | { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 457 | struct ieee80211_sub_if_data *sdata; | 
|  | 458 |  | 
|  | 459 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 460 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 
|  | 461 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 462 | int ret; | 
| Johannes Berg | ddd3d2b | 2007-09-26 17:53:20 +0200 | [diff] [blame] | 463 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 464 | memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data, | 
|  | 465 | ETH_ALEN); | 
|  | 466 | return 0; | 
|  | 467 | } | 
| Jiri Slaby | d6f2da5 | 2007-08-28 17:01:54 -0400 | [diff] [blame] | 468 | if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) | 
|  | 469 | sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL | | 
|  | 470 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 
|  | 471 | else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) | 
|  | 472 | sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 473 | else | 
| Jiri Slaby | d6f2da5 | 2007-08-28 17:01:54 -0400 | [diff] [blame] | 474 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 475 | ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 476 | if (ret) | 
|  | 477 | return ret; | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 478 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 479 | return 0; | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 480 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 
| Johannes Berg | 44213b5 | 2008-02-25 16:27:49 +0100 | [diff] [blame] | 481 | /* | 
|  | 482 | * If it is necessary to update the WDS peer address | 
|  | 483 | * while the interface is running, then we need to do | 
|  | 484 | * more work here, namely if it is running we need to | 
|  | 485 | * add a new and remove the old STA entry, this is | 
|  | 486 | * normally handled by _open() and _stop(). | 
|  | 487 | */ | 
|  | 488 | if (netif_running(dev)) | 
|  | 489 | return -EBUSY; | 
|  | 490 |  | 
|  | 491 | memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, | 
|  | 492 | ETH_ALEN); | 
|  | 493 |  | 
|  | 494 | return 0; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 495 | } | 
|  | 496 |  | 
|  | 497 | return -EOPNOTSUPP; | 
|  | 498 | } | 
|  | 499 |  | 
|  | 500 |  | 
|  | 501 | static int ieee80211_ioctl_giwap(struct net_device *dev, | 
|  | 502 | struct iw_request_info *info, | 
|  | 503 | struct sockaddr *ap_addr, char *extra) | 
|  | 504 | { | 
|  | 505 | struct ieee80211_sub_if_data *sdata; | 
|  | 506 |  | 
|  | 507 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 508 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 
|  | 509 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 
| Tomas Winkler | 48c2fc5 | 2008-08-06 14:22:01 +0300 | [diff] [blame] | 510 | if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATED || | 
|  | 511 | sdata->u.sta.state == IEEE80211_STA_MLME_IBSS_JOINED) { | 
| Abhijeet Kolekar | d4231ca | 2008-05-23 10:15:26 -0700 | [diff] [blame] | 512 | ap_addr->sa_family = ARPHRD_ETHER; | 
|  | 513 | memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN); | 
|  | 514 | return 0; | 
|  | 515 | } else { | 
|  | 516 | memset(&ap_addr->sa_data, 0, ETH_ALEN); | 
|  | 517 | return 0; | 
|  | 518 | } | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 519 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 520 | ap_addr->sa_family = ARPHRD_ETHER; | 
|  | 521 | memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); | 
|  | 522 | return 0; | 
|  | 523 | } | 
|  | 524 |  | 
|  | 525 | return -EOPNOTSUPP; | 
|  | 526 | } | 
|  | 527 |  | 
|  | 528 |  | 
|  | 529 | static int ieee80211_ioctl_siwscan(struct net_device *dev, | 
|  | 530 | struct iw_request_info *info, | 
| Bill Moss | 107acb2 | 2007-10-10 16:23:55 -0400 | [diff] [blame] | 531 | union iwreq_data *wrqu, char *extra) | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 532 | { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 533 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Bill Moss | 107acb2 | 2007-10-10 16:23:55 -0400 | [diff] [blame] | 534 | struct iw_scan_req *req = NULL; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 535 | u8 *ssid = NULL; | 
|  | 536 | size_t ssid_len = 0; | 
|  | 537 |  | 
|  | 538 | if (!netif_running(dev)) | 
|  | 539 | return -ENETDOWN; | 
|  | 540 |  | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 541 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 
|  | 542 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 
|  | 543 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && | 
|  | 544 | sdata->vif.type != NL80211_IFTYPE_AP) | 
| John W. Linville | d114f39 | 2007-10-17 21:16:16 -0700 | [diff] [blame] | 545 | return -EOPNOTSUPP; | 
| John W. Linville | d114f39 | 2007-10-17 21:16:16 -0700 | [diff] [blame] | 546 |  | 
|  | 547 | /* if SSID was specified explicitly then use that */ | 
| Bill Moss | 107acb2 | 2007-10-10 16:23:55 -0400 | [diff] [blame] | 548 | if (wrqu->data.length == sizeof(struct iw_scan_req) && | 
|  | 549 | wrqu->data.flags & IW_SCAN_THIS_ESSID) { | 
|  | 550 | req = (struct iw_scan_req *)extra; | 
|  | 551 | ssid = req->essid; | 
|  | 552 | ssid_len = req->essid_len; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 553 | } | 
| Daniel Drake | f27b62d | 2007-07-27 15:43:24 +0200 | [diff] [blame] | 554 |  | 
| Johannes Berg | c2b1345 | 2008-09-11 00:01:55 +0200 | [diff] [blame] | 555 | return ieee80211_request_scan(sdata, ssid, ssid_len); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 556 | } | 
|  | 557 |  | 
|  | 558 |  | 
|  | 559 | static int ieee80211_ioctl_giwscan(struct net_device *dev, | 
|  | 560 | struct iw_request_info *info, | 
|  | 561 | struct iw_point *data, char *extra) | 
|  | 562 | { | 
|  | 563 | int res; | 
|  | 564 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 565 | struct ieee80211_sub_if_data *sdata; | 
|  | 566 |  | 
|  | 567 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Zhu Yi | ece8edd | 2007-11-22 10:53:21 +0800 | [diff] [blame] | 568 |  | 
| Johannes Berg | c2b1345 | 2008-09-11 00:01:55 +0200 | [diff] [blame] | 569 | if (local->sw_scanning || local->hw_scanning) | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 570 | return -EAGAIN; | 
| Zhu Yi | ece8edd | 2007-11-22 10:53:21 +0800 | [diff] [blame] | 571 |  | 
| Johannes Berg | c2b1345 | 2008-09-11 00:01:55 +0200 | [diff] [blame] | 572 | res = ieee80211_scan_results(local, info, extra, data->length); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 573 | if (res >= 0) { | 
|  | 574 | data->length = res; | 
|  | 575 | return 0; | 
|  | 576 | } | 
|  | 577 | data->length = 0; | 
|  | 578 | return res; | 
|  | 579 | } | 
|  | 580 |  | 
|  | 581 |  | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 582 | static int ieee80211_ioctl_siwrate(struct net_device *dev, | 
|  | 583 | struct iw_request_info *info, | 
|  | 584 | struct iw_param *rate, char *extra) | 
|  | 585 | { | 
|  | 586 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 587 | int i, err = -EINVAL; | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 588 | u32 target_rate = rate->value / 100000; | 
|  | 589 | struct ieee80211_sub_if_data *sdata; | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 590 | struct ieee80211_supported_band *sband; | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 591 |  | 
|  | 592 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 593 |  | 
|  | 594 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 
|  | 595 |  | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 596 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | 
|  | 597 | * target_rate = X, rate->fixed = 1 means only rate X | 
|  | 598 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | 
| Johannes Berg | 3e122be | 2008-07-09 14:40:34 +0200 | [diff] [blame] | 599 | sdata->max_ratectrl_rateidx = -1; | 
|  | 600 | sdata->force_unicast_rateidx = -1; | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 601 | if (rate->value < 0) | 
|  | 602 | return 0; | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 603 |  | 
|  | 604 | for (i=0; i< sband->n_bitrates; i++) { | 
|  | 605 | struct ieee80211_rate *brate = &sband->bitrates[i]; | 
|  | 606 | int this_rate = brate->bitrate; | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 607 |  | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 608 | if (target_rate == this_rate) { | 
| Johannes Berg | 3e122be | 2008-07-09 14:40:34 +0200 | [diff] [blame] | 609 | sdata->max_ratectrl_rateidx = i; | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 610 | if (rate->fixed) | 
| Johannes Berg | 3e122be | 2008-07-09 14:40:34 +0200 | [diff] [blame] | 611 | sdata->force_unicast_rateidx = i; | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 612 | err = 0; | 
|  | 613 | break; | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 614 | } | 
|  | 615 | } | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 616 | return err; | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 617 | } | 
|  | 618 |  | 
| Larry Finger | b3d88ad | 2007-06-10 17:57:33 -0700 | [diff] [blame] | 619 | static int ieee80211_ioctl_giwrate(struct net_device *dev, | 
|  | 620 | struct iw_request_info *info, | 
|  | 621 | struct iw_param *rate, char *extra) | 
|  | 622 | { | 
|  | 623 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 624 | struct sta_info *sta; | 
|  | 625 | struct ieee80211_sub_if_data *sdata; | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 626 | struct ieee80211_supported_band *sband; | 
| Larry Finger | b3d88ad | 2007-06-10 17:57:33 -0700 | [diff] [blame] | 627 |  | 
|  | 628 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 629 |  | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 630 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 
| Larry Finger | b3d88ad | 2007-06-10 17:57:33 -0700 | [diff] [blame] | 631 | return -EOPNOTSUPP; | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 632 |  | 
|  | 633 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 
|  | 634 |  | 
| Johannes Berg | 380a942 | 2008-04-04 23:40:35 +0200 | [diff] [blame] | 635 | rcu_read_lock(); | 
|  | 636 |  | 
|  | 637 | sta = sta_info_get(local, sdata->u.sta.bssid); | 
|  | 638 |  | 
| Johannes Berg | ae17e98 | 2008-09-11 03:04:36 +0200 | [diff] [blame] | 639 | if (sta && sta->last_txrate_idx < sband->n_bitrates) | 
|  | 640 | rate->value = sband->bitrates[sta->last_txrate_idx].bitrate; | 
| Larry Finger | b3d88ad | 2007-06-10 17:57:33 -0700 | [diff] [blame] | 641 | else | 
|  | 642 | rate->value = 0; | 
| Johannes Berg | 380a942 | 2008-04-04 23:40:35 +0200 | [diff] [blame] | 643 |  | 
|  | 644 | rcu_read_unlock(); | 
|  | 645 |  | 
|  | 646 | if (!sta) | 
|  | 647 | return -ENODEV; | 
|  | 648 |  | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 649 | rate->value *= 100000; | 
| Johannes Berg | d0709a6 | 2008-02-25 16:27:46 +0100 | [diff] [blame] | 650 |  | 
| Larry Finger | b3d88ad | 2007-06-10 17:57:33 -0700 | [diff] [blame] | 651 | return 0; | 
|  | 652 | } | 
|  | 653 |  | 
| Michael Buesch | 61609bc | 2007-09-20 22:06:39 +0200 | [diff] [blame] | 654 | static int ieee80211_ioctl_siwtxpower(struct net_device *dev, | 
|  | 655 | struct iw_request_info *info, | 
|  | 656 | union iwreq_data *data, char *extra) | 
|  | 657 | { | 
|  | 658 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 659 | bool need_reconfig = 0; | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 660 | int new_power_level; | 
| Michael Buesch | 61609bc | 2007-09-20 22:06:39 +0200 | [diff] [blame] | 661 |  | 
|  | 662 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | 
|  | 663 | return -EINVAL; | 
|  | 664 | if (data->txpower.flags & IW_TXPOW_RANGE) | 
|  | 665 | return -EINVAL; | 
| Michael Buesch | 61609bc | 2007-09-20 22:06:39 +0200 | [diff] [blame] | 666 |  | 
| Mattias Nissler | 6a43295 | 2007-10-24 23:30:36 +0200 | [diff] [blame] | 667 | if (data->txpower.fixed) { | 
|  | 668 | new_power_level = data->txpower.value; | 
|  | 669 | } else { | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 670 | /* | 
|  | 671 | * Automatic power level. Use maximum power for the current | 
|  | 672 | * channel. Should be part of rate control. | 
|  | 673 | */ | 
|  | 674 | struct ieee80211_channel* chan = local->hw.conf.channel; | 
| Mattias Nissler | 6a43295 | 2007-10-24 23:30:36 +0200 | [diff] [blame] | 675 | if (!chan) | 
|  | 676 | return -EINVAL; | 
|  | 677 |  | 
| Johannes Berg | 8318d78 | 2008-01-24 19:38:38 +0100 | [diff] [blame] | 678 | new_power_level = chan->max_power; | 
| Mattias Nissler | 6a43295 | 2007-10-24 23:30:36 +0200 | [diff] [blame] | 679 | } | 
|  | 680 |  | 
|  | 681 | if (local->hw.conf.power_level != new_power_level) { | 
|  | 682 | local->hw.conf.power_level = new_power_level; | 
| Michael Buesch | 61609bc | 2007-09-20 22:06:39 +0200 | [diff] [blame] | 683 | need_reconfig = 1; | 
|  | 684 | } | 
| Mattias Nissler | 6a43295 | 2007-10-24 23:30:36 +0200 | [diff] [blame] | 685 |  | 
| Michael Buesch | 61609bc | 2007-09-20 22:06:39 +0200 | [diff] [blame] | 686 | if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { | 
|  | 687 | local->hw.conf.radio_enabled = !(data->txpower.disabled); | 
|  | 688 | need_reconfig = 1; | 
| Ivo van Doorn | cdcb006 | 2008-01-07 19:45:24 +0100 | [diff] [blame] | 689 | ieee80211_led_radio(local, local->hw.conf.radio_enabled); | 
| Michael Buesch | 61609bc | 2007-09-20 22:06:39 +0200 | [diff] [blame] | 690 | } | 
| Mattias Nissler | 6a43295 | 2007-10-24 23:30:36 +0200 | [diff] [blame] | 691 |  | 
| Michael Buesch | 61609bc | 2007-09-20 22:06:39 +0200 | [diff] [blame] | 692 | if (need_reconfig) { | 
|  | 693 | ieee80211_hw_config(local); | 
|  | 694 | /* The return value of hw_config is not of big interest here, | 
|  | 695 | * as it doesn't say that it failed because of _this_ config | 
|  | 696 | * change or something else. Ignore it. */ | 
|  | 697 | } | 
|  | 698 |  | 
|  | 699 | return 0; | 
|  | 700 | } | 
|  | 701 |  | 
| Larry Finger | fe6aa30 | 2007-08-10 11:23:20 -0500 | [diff] [blame] | 702 | static int ieee80211_ioctl_giwtxpower(struct net_device *dev, | 
|  | 703 | struct iw_request_info *info, | 
|  | 704 | union iwreq_data *data, char *extra) | 
|  | 705 | { | 
|  | 706 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 707 |  | 
|  | 708 | data->txpower.fixed = 1; | 
|  | 709 | data->txpower.disabled = !(local->hw.conf.radio_enabled); | 
|  | 710 | data->txpower.value = local->hw.conf.power_level; | 
|  | 711 | data->txpower.flags = IW_TXPOW_DBM; | 
|  | 712 |  | 
|  | 713 | return 0; | 
|  | 714 | } | 
|  | 715 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 716 | static int ieee80211_ioctl_siwrts(struct net_device *dev, | 
|  | 717 | struct iw_request_info *info, | 
|  | 718 | struct iw_param *rts, char *extra) | 
|  | 719 | { | 
|  | 720 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 721 |  | 
|  | 722 | if (rts->disabled) | 
|  | 723 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | 
| Emmanuel Grumbach | fa6adfe | 2008-06-24 13:37:58 +0300 | [diff] [blame] | 724 | else if (!rts->fixed) | 
|  | 725 | /* if the rts value is not fixed, then take default */ | 
|  | 726 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 727 | else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD) | 
|  | 728 | return -EINVAL; | 
|  | 729 | else | 
|  | 730 | local->rts_threshold = rts->value; | 
|  | 731 |  | 
|  | 732 | /* If the wlan card performs RTS/CTS in hardware/firmware, | 
|  | 733 | * configure it here */ | 
|  | 734 |  | 
|  | 735 | if (local->ops->set_rts_threshold) | 
|  | 736 | local->ops->set_rts_threshold(local_to_hw(local), | 
|  | 737 | local->rts_threshold); | 
|  | 738 |  | 
|  | 739 | return 0; | 
|  | 740 | } | 
|  | 741 |  | 
|  | 742 | static int ieee80211_ioctl_giwrts(struct net_device *dev, | 
|  | 743 | struct iw_request_info *info, | 
|  | 744 | struct iw_param *rts, char *extra) | 
|  | 745 | { | 
|  | 746 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 747 |  | 
|  | 748 | rts->value = local->rts_threshold; | 
|  | 749 | rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD); | 
|  | 750 | rts->fixed = 1; | 
|  | 751 |  | 
|  | 752 | return 0; | 
|  | 753 | } | 
|  | 754 |  | 
|  | 755 |  | 
|  | 756 | static int ieee80211_ioctl_siwfrag(struct net_device *dev, | 
|  | 757 | struct iw_request_info *info, | 
|  | 758 | struct iw_param *frag, char *extra) | 
|  | 759 | { | 
|  | 760 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 761 |  | 
|  | 762 | if (frag->disabled) | 
|  | 763 | local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | 
| Emmanuel Grumbach | e4abd4d | 2008-07-03 18:02:27 +0300 | [diff] [blame] | 764 | else if (!frag->fixed) | 
|  | 765 | local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 766 | else if (frag->value < 256 || | 
|  | 767 | frag->value > IEEE80211_MAX_FRAG_THRESHOLD) | 
|  | 768 | return -EINVAL; | 
|  | 769 | else { | 
|  | 770 | /* Fragment length must be even, so strip LSB. */ | 
|  | 771 | local->fragmentation_threshold = frag->value & ~0x1; | 
|  | 772 | } | 
|  | 773 |  | 
|  | 774 | /* If the wlan card performs fragmentation in hardware/firmware, | 
|  | 775 | * configure it here */ | 
|  | 776 |  | 
|  | 777 | if (local->ops->set_frag_threshold) | 
| Johannes Berg | 4233df6 | 2008-10-13 13:35:05 +0200 | [diff] [blame] | 778 | return local->ops->set_frag_threshold( | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 779 | local_to_hw(local), | 
|  | 780 | local->fragmentation_threshold); | 
|  | 781 |  | 
|  | 782 | return 0; | 
|  | 783 | } | 
|  | 784 |  | 
|  | 785 | static int ieee80211_ioctl_giwfrag(struct net_device *dev, | 
|  | 786 | struct iw_request_info *info, | 
|  | 787 | struct iw_param *frag, char *extra) | 
|  | 788 | { | 
|  | 789 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 790 |  | 
|  | 791 | frag->value = local->fragmentation_threshold; | 
|  | 792 | frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD); | 
|  | 793 | frag->fixed = 1; | 
|  | 794 |  | 
|  | 795 | return 0; | 
|  | 796 | } | 
|  | 797 |  | 
|  | 798 |  | 
|  | 799 | static int ieee80211_ioctl_siwretry(struct net_device *dev, | 
|  | 800 | struct iw_request_info *info, | 
|  | 801 | struct iw_param *retry, char *extra) | 
|  | 802 | { | 
|  | 803 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 804 |  | 
|  | 805 | if (retry->disabled || | 
|  | 806 | (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) | 
|  | 807 | return -EINVAL; | 
|  | 808 |  | 
|  | 809 | if (retry->flags & IW_RETRY_MAX) | 
|  | 810 | local->long_retry_limit = retry->value; | 
|  | 811 | else if (retry->flags & IW_RETRY_MIN) | 
|  | 812 | local->short_retry_limit = retry->value; | 
|  | 813 | else { | 
|  | 814 | local->long_retry_limit = retry->value; | 
|  | 815 | local->short_retry_limit = retry->value; | 
|  | 816 | } | 
|  | 817 |  | 
|  | 818 | if (local->ops->set_retry_limit) { | 
|  | 819 | return local->ops->set_retry_limit( | 
|  | 820 | local_to_hw(local), | 
|  | 821 | local->short_retry_limit, | 
|  | 822 | local->long_retry_limit); | 
|  | 823 | } | 
|  | 824 |  | 
|  | 825 | return 0; | 
|  | 826 | } | 
|  | 827 |  | 
|  | 828 |  | 
|  | 829 | static int ieee80211_ioctl_giwretry(struct net_device *dev, | 
|  | 830 | struct iw_request_info *info, | 
|  | 831 | struct iw_param *retry, char *extra) | 
|  | 832 | { | 
|  | 833 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 834 |  | 
|  | 835 | retry->disabled = 0; | 
|  | 836 | if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) { | 
|  | 837 | /* first return min value, iwconfig will ask max value | 
|  | 838 | * later if needed */ | 
|  | 839 | retry->flags |= IW_RETRY_LIMIT; | 
|  | 840 | retry->value = local->short_retry_limit; | 
|  | 841 | if (local->long_retry_limit != local->short_retry_limit) | 
|  | 842 | retry->flags |= IW_RETRY_MIN; | 
|  | 843 | return 0; | 
|  | 844 | } | 
|  | 845 | if (retry->flags & IW_RETRY_MAX) { | 
|  | 846 | retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | 
|  | 847 | retry->value = local->long_retry_limit; | 
|  | 848 | } | 
|  | 849 |  | 
|  | 850 | return 0; | 
|  | 851 | } | 
|  | 852 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 853 | static int ieee80211_ioctl_siwmlme(struct net_device *dev, | 
|  | 854 | struct iw_request_info *info, | 
|  | 855 | struct iw_point *data, char *extra) | 
|  | 856 | { | 
|  | 857 | struct ieee80211_sub_if_data *sdata; | 
|  | 858 | struct iw_mlme *mlme = (struct iw_mlme *) extra; | 
|  | 859 |  | 
|  | 860 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 861 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 
|  | 862 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 863 | return -EINVAL; | 
|  | 864 |  | 
|  | 865 | switch (mlme->cmd) { | 
|  | 866 | case IW_MLME_DEAUTH: | 
|  | 867 | /* TODO: mlme->addr.sa_data */ | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 868 | return ieee80211_sta_deauthenticate(sdata, mlme->reason_code); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 869 | case IW_MLME_DISASSOC: | 
|  | 870 | /* TODO: mlme->addr.sa_data */ | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 871 | return ieee80211_sta_disassociate(sdata, mlme->reason_code); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 872 | default: | 
|  | 873 | return -EOPNOTSUPP; | 
|  | 874 | } | 
|  | 875 | } | 
|  | 876 |  | 
|  | 877 |  | 
|  | 878 | static int ieee80211_ioctl_siwencode(struct net_device *dev, | 
|  | 879 | struct iw_request_info *info, | 
|  | 880 | struct iw_point *erq, char *keybuf) | 
|  | 881 | { | 
|  | 882 | struct ieee80211_sub_if_data *sdata; | 
|  | 883 | int idx, i, alg = ALG_WEP; | 
|  | 884 | u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | 
| Johannes Berg | 628a140 | 2007-09-26 17:53:17 +0200 | [diff] [blame] | 885 | int remove = 0; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 886 |  | 
|  | 887 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
|  | 888 |  | 
|  | 889 | idx = erq->flags & IW_ENCODE_INDEX; | 
|  | 890 | if (idx == 0) { | 
|  | 891 | if (sdata->default_key) | 
|  | 892 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | 
|  | 893 | if (sdata->default_key == sdata->keys[i]) { | 
|  | 894 | idx = i; | 
|  | 895 | break; | 
|  | 896 | } | 
|  | 897 | } | 
|  | 898 | } else if (idx < 1 || idx > 4) | 
|  | 899 | return -EINVAL; | 
|  | 900 | else | 
|  | 901 | idx--; | 
|  | 902 |  | 
|  | 903 | if (erq->flags & IW_ENCODE_DISABLED) | 
| Johannes Berg | 628a140 | 2007-09-26 17:53:17 +0200 | [diff] [blame] | 904 | remove = 1; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 905 | else if (erq->length == 0) { | 
|  | 906 | /* No key data - just set the default TX key index */ | 
| Johannes Berg | 11a843b | 2007-08-28 17:01:55 -0400 | [diff] [blame] | 907 | ieee80211_set_default_key(sdata, idx); | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 908 | return 0; | 
|  | 909 | } | 
|  | 910 |  | 
|  | 911 | return ieee80211_set_encryption( | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 912 | sdata, bcaddr, | 
| Johannes Berg | 628a140 | 2007-09-26 17:53:17 +0200 | [diff] [blame] | 913 | idx, alg, remove, | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 914 | !sdata->default_key, | 
|  | 915 | keybuf, erq->length); | 
|  | 916 | } | 
|  | 917 |  | 
|  | 918 |  | 
|  | 919 | static int ieee80211_ioctl_giwencode(struct net_device *dev, | 
|  | 920 | struct iw_request_info *info, | 
|  | 921 | struct iw_point *erq, char *key) | 
|  | 922 | { | 
|  | 923 | struct ieee80211_sub_if_data *sdata; | 
|  | 924 | int idx, i; | 
|  | 925 |  | 
|  | 926 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
|  | 927 |  | 
|  | 928 | idx = erq->flags & IW_ENCODE_INDEX; | 
|  | 929 | if (idx < 1 || idx > 4) { | 
|  | 930 | idx = -1; | 
|  | 931 | if (!sdata->default_key) | 
|  | 932 | idx = 0; | 
|  | 933 | else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | 
|  | 934 | if (sdata->default_key == sdata->keys[i]) { | 
|  | 935 | idx = i; | 
|  | 936 | break; | 
|  | 937 | } | 
|  | 938 | } | 
|  | 939 | if (idx < 0) | 
|  | 940 | return -EINVAL; | 
|  | 941 | } else | 
|  | 942 | idx--; | 
|  | 943 |  | 
|  | 944 | erq->flags = idx + 1; | 
|  | 945 |  | 
|  | 946 | if (!sdata->keys[idx]) { | 
|  | 947 | erq->length = 0; | 
|  | 948 | erq->flags |= IW_ENCODE_DISABLED; | 
|  | 949 | return 0; | 
|  | 950 | } | 
|  | 951 |  | 
| Johannes Berg | 8f20fc2 | 2007-08-28 17:01:54 -0400 | [diff] [blame] | 952 | memcpy(key, sdata->keys[idx]->conf.key, | 
| Johannes Berg | 11a843b | 2007-08-28 17:01:55 -0400 | [diff] [blame] | 953 | min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); | 
| Johannes Berg | 8f20fc2 | 2007-08-28 17:01:54 -0400 | [diff] [blame] | 954 | erq->length = sdata->keys[idx]->conf.keylen; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 955 | erq->flags |= IW_ENCODE_ENABLED; | 
|  | 956 |  | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 957 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 
| Emmanuel Grumbach | b9fcc4f | 2008-06-24 13:37:59 +0300 | [diff] [blame] | 958 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 
|  | 959 | switch (ifsta->auth_alg) { | 
|  | 960 | case WLAN_AUTH_OPEN: | 
|  | 961 | case WLAN_AUTH_LEAP: | 
|  | 962 | erq->flags |= IW_ENCODE_OPEN; | 
|  | 963 | break; | 
|  | 964 | case WLAN_AUTH_SHARED_KEY: | 
|  | 965 | erq->flags |= IW_ENCODE_RESTRICTED; | 
|  | 966 | break; | 
|  | 967 | } | 
|  | 968 | } | 
|  | 969 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 970 | return 0; | 
|  | 971 | } | 
|  | 972 |  | 
| Samuel Ortiz | 49292d5 | 2008-07-04 10:49:31 +0200 | [diff] [blame] | 973 | static int ieee80211_ioctl_siwpower(struct net_device *dev, | 
|  | 974 | struct iw_request_info *info, | 
|  | 975 | struct iw_param *wrq, | 
|  | 976 | char *extra) | 
|  | 977 | { | 
|  | 978 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 979 | struct ieee80211_conf *conf = &local->hw.conf; | 
|  | 980 |  | 
|  | 981 | if (wrq->disabled) { | 
|  | 982 | conf->flags &= ~IEEE80211_CONF_PS; | 
|  | 983 | return ieee80211_hw_config(local); | 
|  | 984 | } | 
|  | 985 |  | 
|  | 986 | switch (wrq->flags & IW_POWER_MODE) { | 
|  | 987 | case IW_POWER_ON:       /* If not specified */ | 
|  | 988 | case IW_POWER_MODE:     /* If set all mask */ | 
|  | 989 | case IW_POWER_ALL_R:    /* If explicitely state all */ | 
|  | 990 | conf->flags |= IEEE80211_CONF_PS; | 
|  | 991 | break; | 
|  | 992 | default:                /* Otherwise we don't support it */ | 
|  | 993 | return -EINVAL; | 
|  | 994 | } | 
|  | 995 |  | 
|  | 996 | return ieee80211_hw_config(local); | 
|  | 997 | } | 
|  | 998 |  | 
|  | 999 | static int ieee80211_ioctl_giwpower(struct net_device *dev, | 
|  | 1000 | struct iw_request_info *info, | 
|  | 1001 | union iwreq_data *wrqu, | 
|  | 1002 | char *extra) | 
|  | 1003 | { | 
|  | 1004 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 1005 | struct ieee80211_conf *conf = &local->hw.conf; | 
|  | 1006 |  | 
|  | 1007 | wrqu->power.disabled = !(conf->flags & IEEE80211_CONF_PS); | 
|  | 1008 |  | 
|  | 1009 | return 0; | 
|  | 1010 | } | 
|  | 1011 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1012 | static int ieee80211_ioctl_siwauth(struct net_device *dev, | 
|  | 1013 | struct iw_request_info *info, | 
|  | 1014 | struct iw_param *data, char *extra) | 
|  | 1015 | { | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1016 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
|  | 1017 | int ret = 0; | 
|  | 1018 |  | 
|  | 1019 | switch (data->flags & IW_AUTH_INDEX) { | 
|  | 1020 | case IW_AUTH_WPA_VERSION: | 
|  | 1021 | case IW_AUTH_CIPHER_PAIRWISE: | 
|  | 1022 | case IW_AUTH_CIPHER_GROUP: | 
|  | 1023 | case IW_AUTH_WPA_ENABLED: | 
|  | 1024 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1025 | case IW_AUTH_KEY_MGMT: | 
| Johannes Berg | 5b98b1f | 2007-11-03 13:11:10 +0000 | [diff] [blame] | 1026 | break; | 
| Johannes Berg | b1357a8 | 2007-11-28 11:04:21 +0100 | [diff] [blame] | 1027 | case IW_AUTH_DROP_UNENCRYPTED: | 
|  | 1028 | sdata->drop_unencrypted = !!data->value; | 
|  | 1029 | break; | 
| Johannes Berg | 5b98b1f | 2007-11-03 13:11:10 +0000 | [diff] [blame] | 1030 | case IW_AUTH_PRIVACY_INVOKED: | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 1031 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1032 | ret = -EINVAL; | 
|  | 1033 | else { | 
| Johannes Berg | 5b98b1f | 2007-11-03 13:11:10 +0000 | [diff] [blame] | 1034 | sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1035 | /* | 
| Johannes Berg | 5b98b1f | 2007-11-03 13:11:10 +0000 | [diff] [blame] | 1036 | * Privacy invoked by wpa_supplicant, store the | 
|  | 1037 | * value and allow associating to a protected | 
|  | 1038 | * network without having a key up front. | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1039 | */ | 
| Johannes Berg | 5b98b1f | 2007-11-03 13:11:10 +0000 | [diff] [blame] | 1040 | if (data->value) | 
|  | 1041 | sdata->u.sta.flags |= | 
|  | 1042 | IEEE80211_STA_PRIVACY_INVOKED; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1043 | } | 
|  | 1044 | break; | 
|  | 1045 | case IW_AUTH_80211_AUTH_ALG: | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 1046 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 
|  | 1047 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1048 | sdata->u.sta.auth_algs = data->value; | 
|  | 1049 | else | 
|  | 1050 | ret = -EOPNOTSUPP; | 
|  | 1051 | break; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1052 | default: | 
|  | 1053 | ret = -EOPNOTSUPP; | 
|  | 1054 | break; | 
|  | 1055 | } | 
|  | 1056 | return ret; | 
|  | 1057 | } | 
|  | 1058 |  | 
|  | 1059 | /* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */ | 
|  | 1060 | static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) | 
|  | 1061 | { | 
|  | 1062 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
|  | 1063 | struct iw_statistics *wstats = &local->wstats; | 
|  | 1064 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
|  | 1065 | struct sta_info *sta = NULL; | 
|  | 1066 |  | 
| Johannes Berg | 98dd6a5 | 2008-04-10 15:36:09 +0200 | [diff] [blame] | 1067 | rcu_read_lock(); | 
|  | 1068 |  | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 1069 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 
|  | 1070 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1071 | sta = sta_info_get(local, sdata->u.sta.bssid); | 
|  | 1072 | if (!sta) { | 
|  | 1073 | wstats->discard.fragment = 0; | 
|  | 1074 | wstats->discard.misc = 0; | 
|  | 1075 | wstats->qual.qual = 0; | 
|  | 1076 | wstats->qual.level = 0; | 
|  | 1077 | wstats->qual.noise = 0; | 
|  | 1078 | wstats->qual.updated = IW_QUAL_ALL_INVALID; | 
|  | 1079 | } else { | 
| Bruno Randolf | 566bfe5 | 2008-05-08 19:15:40 +0200 | [diff] [blame] | 1080 | wstats->qual.level = sta->last_signal; | 
|  | 1081 | wstats->qual.qual = sta->last_qual; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1082 | wstats->qual.noise = sta->last_noise; | 
|  | 1083 | wstats->qual.updated = local->wstats_flags; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1084 | } | 
| Johannes Berg | 98dd6a5 | 2008-04-10 15:36:09 +0200 | [diff] [blame] | 1085 |  | 
|  | 1086 | rcu_read_unlock(); | 
|  | 1087 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1088 | return wstats; | 
|  | 1089 | } | 
|  | 1090 |  | 
|  | 1091 | static int ieee80211_ioctl_giwauth(struct net_device *dev, | 
|  | 1092 | struct iw_request_info *info, | 
|  | 1093 | struct iw_param *data, char *extra) | 
|  | 1094 | { | 
|  | 1095 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
|  | 1096 | int ret = 0; | 
|  | 1097 |  | 
|  | 1098 | switch (data->flags & IW_AUTH_INDEX) { | 
|  | 1099 | case IW_AUTH_80211_AUTH_ALG: | 
| Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 1100 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 
|  | 1101 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1102 | data->value = sdata->u.sta.auth_algs; | 
|  | 1103 | else | 
|  | 1104 | ret = -EOPNOTSUPP; | 
|  | 1105 | break; | 
|  | 1106 | default: | 
|  | 1107 | ret = -EOPNOTSUPP; | 
|  | 1108 | break; | 
|  | 1109 | } | 
|  | 1110 | return ret; | 
|  | 1111 | } | 
|  | 1112 |  | 
|  | 1113 |  | 
|  | 1114 | static int ieee80211_ioctl_siwencodeext(struct net_device *dev, | 
|  | 1115 | struct iw_request_info *info, | 
|  | 1116 | struct iw_point *erq, char *extra) | 
|  | 1117 | { | 
|  | 1118 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
|  | 1119 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | 
| Johannes Berg | 628a140 | 2007-09-26 17:53:17 +0200 | [diff] [blame] | 1120 | int uninitialized_var(alg), idx, i, remove = 0; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1121 |  | 
|  | 1122 | switch (ext->alg) { | 
|  | 1123 | case IW_ENCODE_ALG_NONE: | 
| Johannes Berg | 628a140 | 2007-09-26 17:53:17 +0200 | [diff] [blame] | 1124 | remove = 1; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1125 | break; | 
|  | 1126 | case IW_ENCODE_ALG_WEP: | 
|  | 1127 | alg = ALG_WEP; | 
|  | 1128 | break; | 
|  | 1129 | case IW_ENCODE_ALG_TKIP: | 
|  | 1130 | alg = ALG_TKIP; | 
|  | 1131 | break; | 
|  | 1132 | case IW_ENCODE_ALG_CCMP: | 
|  | 1133 | alg = ALG_CCMP; | 
|  | 1134 | break; | 
|  | 1135 | default: | 
|  | 1136 | return -EOPNOTSUPP; | 
|  | 1137 | } | 
|  | 1138 |  | 
|  | 1139 | if (erq->flags & IW_ENCODE_DISABLED) | 
| Johannes Berg | 628a140 | 2007-09-26 17:53:17 +0200 | [diff] [blame] | 1140 | remove = 1; | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1141 |  | 
|  | 1142 | idx = erq->flags & IW_ENCODE_INDEX; | 
|  | 1143 | if (idx < 1 || idx > 4) { | 
|  | 1144 | idx = -1; | 
|  | 1145 | if (!sdata->default_key) | 
|  | 1146 | idx = 0; | 
|  | 1147 | else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | 
|  | 1148 | if (sdata->default_key == sdata->keys[i]) { | 
|  | 1149 | idx = i; | 
|  | 1150 | break; | 
|  | 1151 | } | 
|  | 1152 | } | 
|  | 1153 | if (idx < 0) | 
|  | 1154 | return -EINVAL; | 
|  | 1155 | } else | 
|  | 1156 | idx--; | 
|  | 1157 |  | 
| Jasper Bryant-Greene | f698d85 | 2008-08-03 12:04:37 +1200 | [diff] [blame] | 1158 | return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg, | 
| Johannes Berg | 628a140 | 2007-09-26 17:53:17 +0200 | [diff] [blame] | 1159 | remove, | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1160 | ext->ext_flags & | 
|  | 1161 | IW_ENCODE_EXT_SET_TX_KEY, | 
|  | 1162 | ext->key, ext->key_len); | 
|  | 1163 | } | 
|  | 1164 |  | 
|  | 1165 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1166 | /* Structures to export the Wireless Handlers */ | 
|  | 1167 |  | 
|  | 1168 | static const iw_handler ieee80211_handler[] = | 
|  | 1169 | { | 
|  | 1170 | (iw_handler) NULL,				/* SIOCSIWCOMMIT */ | 
|  | 1171 | (iw_handler) ieee80211_ioctl_giwname,		/* SIOCGIWNAME */ | 
|  | 1172 | (iw_handler) NULL,				/* SIOCSIWNWID */ | 
|  | 1173 | (iw_handler) NULL,				/* SIOCGIWNWID */ | 
|  | 1174 | (iw_handler) ieee80211_ioctl_siwfreq,		/* SIOCSIWFREQ */ | 
|  | 1175 | (iw_handler) ieee80211_ioctl_giwfreq,		/* SIOCGIWFREQ */ | 
|  | 1176 | (iw_handler) ieee80211_ioctl_siwmode,		/* SIOCSIWMODE */ | 
|  | 1177 | (iw_handler) ieee80211_ioctl_giwmode,		/* SIOCGIWMODE */ | 
|  | 1178 | (iw_handler) NULL,				/* SIOCSIWSENS */ | 
|  | 1179 | (iw_handler) NULL,				/* SIOCGIWSENS */ | 
|  | 1180 | (iw_handler) NULL /* not used */,		/* SIOCSIWRANGE */ | 
|  | 1181 | (iw_handler) ieee80211_ioctl_giwrange,		/* SIOCGIWRANGE */ | 
|  | 1182 | (iw_handler) NULL /* not used */,		/* SIOCSIWPRIV */ | 
|  | 1183 | (iw_handler) NULL /* kernel code */,		/* SIOCGIWPRIV */ | 
|  | 1184 | (iw_handler) NULL /* not used */,		/* SIOCSIWSTATS */ | 
|  | 1185 | (iw_handler) NULL /* kernel code */,		/* SIOCGIWSTATS */ | 
| Johannes Berg | 5d4ecd9 | 2007-09-14 11:10:24 -0400 | [diff] [blame] | 1186 | (iw_handler) NULL,				/* SIOCSIWSPY */ | 
|  | 1187 | (iw_handler) NULL,				/* SIOCGIWSPY */ | 
|  | 1188 | (iw_handler) NULL,				/* SIOCSIWTHRSPY */ | 
|  | 1189 | (iw_handler) NULL,				/* SIOCGIWTHRSPY */ | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1190 | (iw_handler) ieee80211_ioctl_siwap,		/* SIOCSIWAP */ | 
|  | 1191 | (iw_handler) ieee80211_ioctl_giwap,		/* SIOCGIWAP */ | 
|  | 1192 | (iw_handler) ieee80211_ioctl_siwmlme,		/* SIOCSIWMLME */ | 
|  | 1193 | (iw_handler) NULL,				/* SIOCGIWAPLIST */ | 
|  | 1194 | (iw_handler) ieee80211_ioctl_siwscan,		/* SIOCSIWSCAN */ | 
|  | 1195 | (iw_handler) ieee80211_ioctl_giwscan,		/* SIOCGIWSCAN */ | 
|  | 1196 | (iw_handler) ieee80211_ioctl_siwessid,		/* SIOCSIWESSID */ | 
|  | 1197 | (iw_handler) ieee80211_ioctl_giwessid,		/* SIOCGIWESSID */ | 
|  | 1198 | (iw_handler) NULL,				/* SIOCSIWNICKN */ | 
|  | 1199 | (iw_handler) NULL,				/* SIOCGIWNICKN */ | 
|  | 1200 | (iw_handler) NULL,				/* -- hole -- */ | 
|  | 1201 | (iw_handler) NULL,				/* -- hole -- */ | 
| Larry Finger | 1fd5e58 | 2007-07-10 19:32:10 +0200 | [diff] [blame] | 1202 | (iw_handler) ieee80211_ioctl_siwrate,		/* SIOCSIWRATE */ | 
| Larry Finger | b3d88ad | 2007-06-10 17:57:33 -0700 | [diff] [blame] | 1203 | (iw_handler) ieee80211_ioctl_giwrate,		/* SIOCGIWRATE */ | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1204 | (iw_handler) ieee80211_ioctl_siwrts,		/* SIOCSIWRTS */ | 
|  | 1205 | (iw_handler) ieee80211_ioctl_giwrts,		/* SIOCGIWRTS */ | 
|  | 1206 | (iw_handler) ieee80211_ioctl_siwfrag,		/* SIOCSIWFRAG */ | 
|  | 1207 | (iw_handler) ieee80211_ioctl_giwfrag,		/* SIOCGIWFRAG */ | 
| Michael Buesch | 61609bc | 2007-09-20 22:06:39 +0200 | [diff] [blame] | 1208 | (iw_handler) ieee80211_ioctl_siwtxpower,	/* SIOCSIWTXPOW */ | 
| Larry Finger | fe6aa30 | 2007-08-10 11:23:20 -0500 | [diff] [blame] | 1209 | (iw_handler) ieee80211_ioctl_giwtxpower,	/* SIOCGIWTXPOW */ | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1210 | (iw_handler) ieee80211_ioctl_siwretry,		/* SIOCSIWRETRY */ | 
|  | 1211 | (iw_handler) ieee80211_ioctl_giwretry,		/* SIOCGIWRETRY */ | 
|  | 1212 | (iw_handler) ieee80211_ioctl_siwencode,		/* SIOCSIWENCODE */ | 
|  | 1213 | (iw_handler) ieee80211_ioctl_giwencode,		/* SIOCGIWENCODE */ | 
| Samuel Ortiz | 49292d5 | 2008-07-04 10:49:31 +0200 | [diff] [blame] | 1214 | (iw_handler) ieee80211_ioctl_siwpower,		/* SIOCSIWPOWER */ | 
|  | 1215 | (iw_handler) ieee80211_ioctl_giwpower,		/* SIOCGIWPOWER */ | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1216 | (iw_handler) NULL,				/* -- hole -- */ | 
|  | 1217 | (iw_handler) NULL,				/* -- hole -- */ | 
|  | 1218 | (iw_handler) ieee80211_ioctl_siwgenie,		/* SIOCSIWGENIE */ | 
|  | 1219 | (iw_handler) NULL,				/* SIOCGIWGENIE */ | 
|  | 1220 | (iw_handler) ieee80211_ioctl_siwauth,		/* SIOCSIWAUTH */ | 
|  | 1221 | (iw_handler) ieee80211_ioctl_giwauth,		/* SIOCGIWAUTH */ | 
|  | 1222 | (iw_handler) ieee80211_ioctl_siwencodeext,	/* SIOCSIWENCODEEXT */ | 
|  | 1223 | (iw_handler) NULL,				/* SIOCGIWENCODEEXT */ | 
|  | 1224 | (iw_handler) NULL,				/* SIOCSIWPMKSA */ | 
|  | 1225 | (iw_handler) NULL,				/* -- hole -- */ | 
|  | 1226 | }; | 
|  | 1227 |  | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1228 | const struct iw_handler_def ieee80211_iw_handler_def = | 
|  | 1229 | { | 
|  | 1230 | .num_standard	= ARRAY_SIZE(ieee80211_handler), | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1231 | .standard	= (iw_handler *) ieee80211_handler, | 
| Jiri Benc | f0706e8 | 2007-05-05 11:45:53 -0700 | [diff] [blame] | 1232 | .get_wireless_stats = ieee80211_get_wireless_stats, | 
|  | 1233 | }; |