| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 1 | /****************************************************************************** | 
 | 2 |  | 
| James Ketrenos | ebeaddc | 2005-09-21 11:58:43 -0500 | [diff] [blame] | 3 |   Copyright(c) 2004-2005 Intel Corporation. All rights reserved. | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 4 |  | 
 | 5 |   Portions of this file are based on the WEP enablement code provided by the | 
 | 6 |   Host AP project hostap-drivers v0.1.3 | 
 | 7 |   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | 
 | 8 |   <jkmaline@cc.hut.fi> | 
 | 9 |   Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> | 
 | 10 |  | 
 | 11 |   This program is free software; you can redistribute it and/or modify it | 
 | 12 |   under the terms of version 2 of the GNU General Public License as | 
 | 13 |   published by the Free Software Foundation. | 
 | 14 |  | 
 | 15 |   This program is distributed in the hope that it will be useful, but WITHOUT | 
 | 16 |   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
 | 17 |   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | 
 | 18 |   more details. | 
 | 19 |  | 
 | 20 |   You should have received a copy of the GNU General Public License along with | 
 | 21 |   this program; if not, write to the Free Software Foundation, Inc., 59 | 
 | 22 |   Temple Place - Suite 330, Boston, MA  02111-1307, USA. | 
 | 23 |  | 
 | 24 |   The full GNU General Public License is included in this distribution in the | 
 | 25 |   file called LICENSE. | 
 | 26 |  | 
 | 27 |   Contact Information: | 
 | 28 |   James P. Ketrenos <ipw2100-admin@linux.intel.com> | 
 | 29 |   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 
 | 30 |  | 
 | 31 | ******************************************************************************/ | 
| Jeff Garzik | bbeec90 | 2005-09-07 00:27:54 -0400 | [diff] [blame] | 32 |  | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 33 | #include <linux/kmod.h> | 
 | 34 | #include <linux/module.h> | 
| James Ketrenos | 42e349f | 2005-09-21 11:54:07 -0500 | [diff] [blame] | 35 | #include <linux/jiffies.h> | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 36 |  | 
 | 37 | #include <net/ieee80211.h> | 
| Jeff Garzik | bbeec90 | 2005-09-07 00:27:54 -0400 | [diff] [blame] | 38 | #include <linux/wireless.h> | 
 | 39 |  | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 40 | static const char *ieee80211_modes[] = { | 
 | 41 | 	"?", "a", "b", "ab", "g", "ag", "bg", "abg" | 
 | 42 | }; | 
 | 43 |  | 
 | 44 | #define MAX_CUSTOM_LEN 64 | 
 | 45 | static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee, | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 46 | 					   char *start, char *stop, | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 47 | 					   struct ieee80211_network *network) | 
 | 48 | { | 
 | 49 | 	char custom[MAX_CUSTOM_LEN]; | 
 | 50 | 	char *p; | 
 | 51 | 	struct iw_event iwe; | 
 | 52 | 	int i, j; | 
 | 53 | 	u8 max_rate, rate; | 
 | 54 |  | 
 | 55 | 	/* First entry *MUST* be the AP MAC address */ | 
 | 56 | 	iwe.cmd = SIOCGIWAP; | 
 | 57 | 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | 
 | 58 | 	memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); | 
 | 59 | 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); | 
 | 60 |  | 
 | 61 | 	/* Remaining entries will be displayed in the order we provide them */ | 
 | 62 |  | 
 | 63 | 	/* Add the ESSID */ | 
 | 64 | 	iwe.cmd = SIOCGIWESSID; | 
 | 65 | 	iwe.u.data.flags = 1; | 
 | 66 | 	if (network->flags & NETWORK_EMPTY_ESSID) { | 
 | 67 | 		iwe.u.data.length = sizeof("<hidden>"); | 
 | 68 | 		start = iwe_stream_add_point(start, stop, &iwe, "<hidden>"); | 
 | 69 | 	} else { | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 70 | 		iwe.u.data.length = min(network->ssid_len, (u8) 32); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 71 | 		start = iwe_stream_add_point(start, stop, &iwe, network->ssid); | 
 | 72 | 	} | 
 | 73 |  | 
 | 74 | 	/* Add the protocol name */ | 
 | 75 | 	iwe.cmd = SIOCGIWNAME; | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 76 | 	snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", | 
 | 77 | 		 ieee80211_modes[network->mode]); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 78 | 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN); | 
 | 79 |  | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 80 | 	/* Add mode */ | 
 | 81 | 	iwe.cmd = SIOCGIWMODE; | 
 | 82 | 	if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { | 
| Jeff Garzik | 1b5cca3 | 2005-08-15 00:32:15 -0400 | [diff] [blame] | 83 | 		if (network->capability & WLAN_CAPABILITY_ESS) | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 84 | 			iwe.u.mode = IW_MODE_MASTER; | 
 | 85 | 		else | 
 | 86 | 			iwe.u.mode = IW_MODE_ADHOC; | 
 | 87 |  | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 88 | 		start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 89 | 	} | 
 | 90 |  | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 91 | 	/* Add frequency/channel */ | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 92 | 	iwe.cmd = SIOCGIWFREQ; | 
 | 93 | /*	iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode); | 
 | 94 | 	iwe.u.freq.e = 3; */ | 
 | 95 | 	iwe.u.freq.m = network->channel; | 
 | 96 | 	iwe.u.freq.e = 0; | 
 | 97 | 	iwe.u.freq.i = 0; | 
 | 98 | 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); | 
 | 99 |  | 
 | 100 | 	/* Add encryption capability */ | 
 | 101 | 	iwe.cmd = SIOCGIWENCODE; | 
 | 102 | 	if (network->capability & WLAN_CAPABILITY_PRIVACY) | 
 | 103 | 		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | 
 | 104 | 	else | 
 | 105 | 		iwe.u.data.flags = IW_ENCODE_DISABLED; | 
 | 106 | 	iwe.u.data.length = 0; | 
 | 107 | 	start = iwe_stream_add_point(start, stop, &iwe, network->ssid); | 
 | 108 |  | 
 | 109 | 	/* Add basic and extended rates */ | 
 | 110 | 	max_rate = 0; | 
 | 111 | 	p = custom; | 
 | 112 | 	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 113 | 	for (i = 0, j = 0; i < network->rates_len;) { | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 114 | 		if (j < network->rates_ex_len && | 
 | 115 | 		    ((network->rates_ex[j] & 0x7F) < | 
 | 116 | 		     (network->rates[i] & 0x7F))) | 
 | 117 | 			rate = network->rates_ex[j++] & 0x7F; | 
 | 118 | 		else | 
 | 119 | 			rate = network->rates[i++] & 0x7F; | 
 | 120 | 		if (rate > max_rate) | 
 | 121 | 			max_rate = rate; | 
 | 122 | 		p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), | 
 | 123 | 			      "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); | 
 | 124 | 	} | 
 | 125 | 	for (; j < network->rates_ex_len; j++) { | 
 | 126 | 		rate = network->rates_ex[j] & 0x7F; | 
 | 127 | 		p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), | 
 | 128 | 			      "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); | 
 | 129 | 		if (rate > max_rate) | 
 | 130 | 			max_rate = rate; | 
 | 131 | 	} | 
 | 132 |  | 
 | 133 | 	iwe.cmd = SIOCGIWRATE; | 
 | 134 | 	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | 
 | 135 | 	iwe.u.bitrate.value = max_rate * 500000; | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 136 | 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 137 |  | 
 | 138 | 	iwe.cmd = IWEVCUSTOM; | 
 | 139 | 	iwe.u.data.length = p - custom; | 
 | 140 | 	if (iwe.u.data.length) | 
 | 141 | 		start = iwe_stream_add_point(start, stop, &iwe, custom); | 
 | 142 |  | 
 | 143 | 	/* Add quality statistics */ | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 144 | 	iwe.cmd = IWEVQUAL; | 
| James Ketrenos | b1b508e | 2005-09-13 17:27:19 -0500 | [diff] [blame] | 145 | 	iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | | 
 | 146 | 	    IW_QUAL_NOISE_UPDATED; | 
 | 147 |  | 
 | 148 | 	if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) { | 
 | 149 | 		iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID | | 
 | 150 | 		    IW_QUAL_LEVEL_INVALID; | 
 | 151 | 		iwe.u.qual.qual = 0; | 
 | 152 | 		iwe.u.qual.level = 0; | 
 | 153 | 	} else { | 
 | 154 | 		iwe.u.qual.level = network->stats.rssi; | 
| Jiri Benc | 757d18f | 2005-10-10 19:16:53 +0200 | [diff] [blame] | 155 | 		if (ieee->perfect_rssi == ieee->worst_rssi) | 
 | 156 | 			iwe.u.qual.qual = 100; | 
 | 157 | 		else | 
 | 158 | 			iwe.u.qual.qual = | 
 | 159 | 			    (100 * | 
 | 160 | 			     (ieee->perfect_rssi - ieee->worst_rssi) * | 
 | 161 | 			     (ieee->perfect_rssi - ieee->worst_rssi) - | 
 | 162 | 			     (ieee->perfect_rssi - network->stats.rssi) * | 
 | 163 | 			     (15 * (ieee->perfect_rssi - ieee->worst_rssi) + | 
 | 164 | 			      62 * (ieee->perfect_rssi - network->stats.rssi))) / | 
 | 165 | 			    ((ieee->perfect_rssi - ieee->worst_rssi) * | 
 | 166 | 			     (ieee->perfect_rssi - ieee->worst_rssi)); | 
| James Ketrenos | b1b508e | 2005-09-13 17:27:19 -0500 | [diff] [blame] | 167 | 		if (iwe.u.qual.qual > 100) | 
 | 168 | 			iwe.u.qual.qual = 100; | 
 | 169 | 		else if (iwe.u.qual.qual < 1) | 
 | 170 | 			iwe.u.qual.qual = 0; | 
 | 171 | 	} | 
 | 172 |  | 
 | 173 | 	if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) { | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 174 | 		iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; | 
| James Ketrenos | b1b508e | 2005-09-13 17:27:19 -0500 | [diff] [blame] | 175 | 		iwe.u.qual.noise = 0; | 
 | 176 | 	} else { | 
 | 177 | 		iwe.u.qual.noise = network->stats.noise; | 
 | 178 | 	} | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 179 |  | 
 | 180 | 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); | 
 | 181 |  | 
 | 182 | 	iwe.cmd = IWEVCUSTOM; | 
 | 183 | 	p = custom; | 
 | 184 |  | 
 | 185 | 	iwe.u.data.length = p - custom; | 
 | 186 | 	if (iwe.u.data.length) | 
 | 187 | 		start = iwe_stream_add_point(start, stop, &iwe, custom); | 
 | 188 |  | 
| James Ketrenos | 20d6471 | 2005-09-21 11:53:43 -0500 | [diff] [blame] | 189 | 	if (network->wpa_ie_len) { | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 190 | 		char buf[MAX_WPA_IE_LEN * 2 + 30]; | 
 | 191 |  | 
 | 192 | 		u8 *p = buf; | 
 | 193 | 		p += sprintf(p, "wpa_ie="); | 
 | 194 | 		for (i = 0; i < network->wpa_ie_len; i++) { | 
 | 195 | 			p += sprintf(p, "%02x", network->wpa_ie[i]); | 
 | 196 | 		} | 
 | 197 |  | 
 | 198 | 		memset(&iwe, 0, sizeof(iwe)); | 
 | 199 | 		iwe.cmd = IWEVCUSTOM; | 
 | 200 | 		iwe.u.data.length = strlen(buf); | 
 | 201 | 		start = iwe_stream_add_point(start, stop, &iwe, buf); | 
 | 202 | 	} | 
 | 203 |  | 
| James Ketrenos | 20d6471 | 2005-09-21 11:53:43 -0500 | [diff] [blame] | 204 | 	if (network->rsn_ie_len) { | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 205 | 		char buf[MAX_WPA_IE_LEN * 2 + 30]; | 
 | 206 |  | 
 | 207 | 		u8 *p = buf; | 
 | 208 | 		p += sprintf(p, "rsn_ie="); | 
 | 209 | 		for (i = 0; i < network->rsn_ie_len; i++) { | 
 | 210 | 			p += sprintf(p, "%02x", network->rsn_ie[i]); | 
 | 211 | 		} | 
 | 212 |  | 
 | 213 | 		memset(&iwe, 0, sizeof(iwe)); | 
 | 214 | 		iwe.cmd = IWEVCUSTOM; | 
 | 215 | 		iwe.u.data.length = strlen(buf); | 
 | 216 | 		start = iwe_stream_add_point(start, stop, &iwe, buf); | 
 | 217 | 	} | 
 | 218 |  | 
 | 219 | 	/* Add EXTRA: Age to display seconds since last beacon/probe response | 
 | 220 | 	 * for given network. */ | 
 | 221 | 	iwe.cmd = IWEVCUSTOM; | 
 | 222 | 	p = custom; | 
 | 223 | 	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), | 
| James Ketrenos | 42e349f | 2005-09-21 11:54:07 -0500 | [diff] [blame] | 224 | 		      " Last beacon: %dms ago", | 
 | 225 | 		      jiffies_to_msecs(jiffies - network->last_scanned)); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 226 | 	iwe.u.data.length = p - custom; | 
 | 227 | 	if (iwe.u.data.length) | 
 | 228 | 		start = iwe_stream_add_point(start, stop, &iwe, custom); | 
 | 229 |  | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 230 | 	return start; | 
 | 231 | } | 
 | 232 |  | 
 | 233 | int ieee80211_wx_get_scan(struct ieee80211_device *ieee, | 
 | 234 | 			  struct iw_request_info *info, | 
 | 235 | 			  union iwreq_data *wrqu, char *extra) | 
 | 236 | { | 
 | 237 | 	struct ieee80211_network *network; | 
 | 238 | 	unsigned long flags; | 
 | 239 |  | 
 | 240 | 	char *ev = extra; | 
 | 241 | 	char *stop = ev + IW_SCAN_MAX_DATA; | 
 | 242 | 	int i = 0; | 
 | 243 |  | 
 | 244 | 	IEEE80211_DEBUG_WX("Getting scan\n"); | 
 | 245 |  | 
 | 246 | 	spin_lock_irqsave(&ieee->lock, flags); | 
 | 247 |  | 
 | 248 | 	list_for_each_entry(network, &ieee->network_list, list) { | 
 | 249 | 		i++; | 
 | 250 | 		if (ieee->scan_age == 0 || | 
 | 251 | 		    time_after(network->last_scanned + ieee->scan_age, jiffies)) | 
 | 252 | 			ev = ipw2100_translate_scan(ieee, ev, stop, network); | 
 | 253 | 		else | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 254 | 			IEEE80211_DEBUG_SCAN("Not showing network '%s (" | 
| James Ketrenos | 42e349f | 2005-09-21 11:54:07 -0500 | [diff] [blame] | 255 | 					     MAC_FMT ")' due to age (%dms).\n", | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 256 | 					     escape_essid(network->ssid, | 
 | 257 | 							  network->ssid_len), | 
 | 258 | 					     MAC_ARG(network->bssid), | 
| James Ketrenos | 42e349f | 2005-09-21 11:54:07 -0500 | [diff] [blame] | 259 | 					     jiffies_to_msecs(jiffies - | 
 | 260 | 							      network-> | 
 | 261 | 							      last_scanned)); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 262 | 	} | 
 | 263 |  | 
 | 264 | 	spin_unlock_irqrestore(&ieee->lock, flags); | 
 | 265 |  | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 266 | 	wrqu->data.length = ev - extra; | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 267 | 	wrqu->data.flags = 0; | 
 | 268 |  | 
 | 269 | 	IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); | 
 | 270 |  | 
 | 271 | 	return 0; | 
 | 272 | } | 
 | 273 |  | 
 | 274 | int ieee80211_wx_set_encode(struct ieee80211_device *ieee, | 
 | 275 | 			    struct iw_request_info *info, | 
 | 276 | 			    union iwreq_data *wrqu, char *keybuf) | 
 | 277 | { | 
 | 278 | 	struct iw_point *erq = &(wrqu->encoding); | 
 | 279 | 	struct net_device *dev = ieee->dev; | 
 | 280 | 	struct ieee80211_security sec = { | 
 | 281 | 		.flags = 0 | 
 | 282 | 	}; | 
 | 283 | 	int i, key, key_provided, len; | 
 | 284 | 	struct ieee80211_crypt_data **crypt; | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 285 | 	int host_crypto = ieee->host_encrypt || ieee->host_decrypt; | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 286 |  | 
 | 287 | 	IEEE80211_DEBUG_WX("SET_ENCODE\n"); | 
 | 288 |  | 
 | 289 | 	key = erq->flags & IW_ENCODE_INDEX; | 
 | 290 | 	if (key) { | 
 | 291 | 		if (key > WEP_KEYS) | 
 | 292 | 			return -EINVAL; | 
 | 293 | 		key--; | 
 | 294 | 		key_provided = 1; | 
 | 295 | 	} else { | 
 | 296 | 		key_provided = 0; | 
 | 297 | 		key = ieee->tx_keyidx; | 
 | 298 | 	} | 
 | 299 |  | 
 | 300 | 	IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? | 
 | 301 | 			   "provided" : "default"); | 
 | 302 |  | 
 | 303 | 	crypt = &ieee->crypt[key]; | 
 | 304 |  | 
 | 305 | 	if (erq->flags & IW_ENCODE_DISABLED) { | 
 | 306 | 		if (key_provided && *crypt) { | 
 | 307 | 			IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", | 
 | 308 | 					   key); | 
 | 309 | 			ieee80211_crypt_delayed_deinit(ieee, crypt); | 
 | 310 | 		} else | 
 | 311 | 			IEEE80211_DEBUG_WX("Disabling encryption.\n"); | 
 | 312 |  | 
 | 313 | 		/* Check all the keys to see if any are still configured, | 
 | 314 | 		 * and if no key index was provided, de-init them all */ | 
 | 315 | 		for (i = 0; i < WEP_KEYS; i++) { | 
 | 316 | 			if (ieee->crypt[i] != NULL) { | 
 | 317 | 				if (key_provided) | 
 | 318 | 					break; | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 319 | 				ieee80211_crypt_delayed_deinit(ieee, | 
 | 320 | 							       &ieee->crypt[i]); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 321 | 			} | 
 | 322 | 		} | 
 | 323 |  | 
 | 324 | 		if (i == WEP_KEYS) { | 
 | 325 | 			sec.enabled = 0; | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 326 | 			sec.encrypt = 0; | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 327 | 			sec.level = SEC_LEVEL_0; | 
| James Ketrenos | 259bf1f | 2005-09-21 11:54:22 -0500 | [diff] [blame] | 328 | 			sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT; | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 329 | 		} | 
 | 330 |  | 
 | 331 | 		goto done; | 
 | 332 | 	} | 
 | 333 |  | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 334 | 	sec.enabled = 1; | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 335 | 	sec.encrypt = 1; | 
| James Ketrenos | 259bf1f | 2005-09-21 11:54:22 -0500 | [diff] [blame] | 336 | 	sec.flags |= SEC_ENABLED | SEC_ENCRYPT; | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 337 |  | 
 | 338 | 	if (*crypt != NULL && (*crypt)->ops != NULL && | 
 | 339 | 	    strcmp((*crypt)->ops->name, "WEP") != 0) { | 
 | 340 | 		/* changing to use WEP; deinit previously used algorithm | 
 | 341 | 		 * on this key */ | 
 | 342 | 		ieee80211_crypt_delayed_deinit(ieee, crypt); | 
 | 343 | 	} | 
 | 344 |  | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 345 | 	if (*crypt == NULL && host_crypto) { | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 346 | 		struct ieee80211_crypt_data *new_crypt; | 
 | 347 |  | 
 | 348 | 		/* take WEP into use */ | 
 | 349 | 		new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data), | 
 | 350 | 				    GFP_KERNEL); | 
 | 351 | 		if (new_crypt == NULL) | 
 | 352 | 			return -ENOMEM; | 
 | 353 | 		memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | 
 | 354 | 		new_crypt->ops = ieee80211_get_crypto_ops("WEP"); | 
 | 355 | 		if (!new_crypt->ops) { | 
 | 356 | 			request_module("ieee80211_crypt_wep"); | 
 | 357 | 			new_crypt->ops = ieee80211_get_crypto_ops("WEP"); | 
 | 358 | 		} | 
 | 359 |  | 
 | 360 | 		if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) | 
| James Ketrenos | 6eb6edf | 2005-09-22 10:34:15 +0000 | [diff] [blame] | 361 | 			new_crypt->priv = new_crypt->ops->init(key); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 362 |  | 
 | 363 | 		if (!new_crypt->ops || !new_crypt->priv) { | 
 | 364 | 			kfree(new_crypt); | 
 | 365 | 			new_crypt = NULL; | 
 | 366 |  | 
 | 367 | 			printk(KERN_WARNING "%s: could not initialize WEP: " | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 368 | 			       "load module ieee80211_crypt_wep\n", dev->name); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 369 | 			return -EOPNOTSUPP; | 
 | 370 | 		} | 
 | 371 | 		*crypt = new_crypt; | 
 | 372 | 	} | 
 | 373 |  | 
 | 374 | 	/* If a new key was provided, set it up */ | 
 | 375 | 	if (erq->length > 0) { | 
 | 376 | 		len = erq->length <= 5 ? 5 : 13; | 
 | 377 | 		memcpy(sec.keys[key], keybuf, erq->length); | 
 | 378 | 		if (len > erq->length) | 
 | 379 | 			memset(sec.keys[key] + erq->length, 0, | 
 | 380 | 			       len - erq->length); | 
 | 381 | 		IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", | 
 | 382 | 				   key, escape_essid(sec.keys[key], len), | 
 | 383 | 				   erq->length, len); | 
 | 384 | 		sec.key_sizes[key] = len; | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 385 | 		if (*crypt) | 
 | 386 | 			(*crypt)->ops->set_key(sec.keys[key], len, NULL, | 
 | 387 | 					       (*crypt)->priv); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 388 | 		sec.flags |= (1 << key); | 
 | 389 | 		/* This ensures a key will be activated if no key is | 
 | 390 | 		 * explicitely set */ | 
 | 391 | 		if (key == sec.active_key) | 
 | 392 | 			sec.flags |= SEC_ACTIVE_KEY; | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 393 |  | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 394 | 	} else { | 
 | 395 | 		if (host_crypto) { | 
 | 396 | 			len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, | 
 | 397 | 						     NULL, (*crypt)->priv); | 
 | 398 | 			if (len == 0) { | 
 | 399 | 				/* Set a default key of all 0 */ | 
 | 400 | 				IEEE80211_DEBUG_WX("Setting key %d to all " | 
 | 401 | 						   "zero.\n", key); | 
 | 402 | 				memset(sec.keys[key], 0, 13); | 
 | 403 | 				(*crypt)->ops->set_key(sec.keys[key], 13, NULL, | 
 | 404 | 						       (*crypt)->priv); | 
 | 405 | 				sec.key_sizes[key] = 13; | 
 | 406 | 				sec.flags |= (1 << key); | 
 | 407 | 			} | 
 | 408 | 		} | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 409 | 		/* No key data - just set the default TX key index */ | 
 | 410 | 		if (key_provided) { | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 411 | 			IEEE80211_DEBUG_WX("Setting key %d to default Tx " | 
 | 412 | 					   "key.\n", key); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 413 | 			ieee->tx_keyidx = key; | 
 | 414 | 			sec.active_key = key; | 
 | 415 | 			sec.flags |= SEC_ACTIVE_KEY; | 
 | 416 | 		} | 
 | 417 | 	} | 
| James Ketrenos | 7dc888f | 2005-09-21 11:58:38 -0500 | [diff] [blame] | 418 | 	if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) { | 
 | 419 | 		ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); | 
 | 420 | 		sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : | 
 | 421 | 		    WLAN_AUTH_SHARED_KEY; | 
 | 422 | 		sec.flags |= SEC_AUTH_MODE; | 
 | 423 | 		IEEE80211_DEBUG_WX("Auth: %s\n", | 
 | 424 | 				   sec.auth_mode == WLAN_AUTH_OPEN ? | 
 | 425 | 				   "OPEN" : "SHARED KEY"); | 
 | 426 | 	} | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 427 |  | 
 | 428 | 	/* For now we just support WEP, so only set that security level... | 
 | 429 | 	 * TODO: When WPA is added this is one place that needs to change */ | 
 | 430 | 	sec.flags |= SEC_LEVEL; | 
| Jeff Garzik | 0edd5b4 | 2005-09-07 00:48:31 -0400 | [diff] [blame] | 431 | 	sec.level = SEC_LEVEL_1;	/* 40 and 104 bit WEP */ | 
| James Ketrenos | e0d369d | 2005-09-21 11:54:30 -0500 | [diff] [blame] | 432 | 	sec.encode_alg[key] = SEC_ALG_WEP; | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 433 |  | 
| James Ketrenos | 259bf1f | 2005-09-21 11:54:22 -0500 | [diff] [blame] | 434 |       done: | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 435 | 	if (ieee->set_security) | 
 | 436 | 		ieee->set_security(dev, &sec); | 
 | 437 |  | 
 | 438 | 	/* Do not reset port if card is in Managed mode since resetting will | 
 | 439 | 	 * generate new IEEE 802.11 authentication which may end up in looping | 
 | 440 | 	 * with IEEE 802.1X.  If your hardware requires a reset after WEP | 
 | 441 | 	 * configuration (for example... Prism2), implement the reset_port in | 
 | 442 | 	 * the callbacks structures used to initialize the 802.11 stack. */ | 
 | 443 | 	if (ieee->reset_on_keychange && | 
 | 444 | 	    ieee->iw_mode != IW_MODE_INFRA && | 
 | 445 | 	    ieee->reset_port && ieee->reset_port(dev)) { | 
 | 446 | 		printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); | 
 | 447 | 		return -EINVAL; | 
 | 448 | 	} | 
 | 449 | 	return 0; | 
 | 450 | } | 
 | 451 |  | 
 | 452 | int ieee80211_wx_get_encode(struct ieee80211_device *ieee, | 
 | 453 | 			    struct iw_request_info *info, | 
 | 454 | 			    union iwreq_data *wrqu, char *keybuf) | 
 | 455 | { | 
 | 456 | 	struct iw_point *erq = &(wrqu->encoding); | 
 | 457 | 	int len, key; | 
 | 458 | 	struct ieee80211_crypt_data *crypt; | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 459 | 	struct ieee80211_security *sec = &ieee->sec; | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 460 |  | 
 | 461 | 	IEEE80211_DEBUG_WX("GET_ENCODE\n"); | 
 | 462 |  | 
 | 463 | 	key = erq->flags & IW_ENCODE_INDEX; | 
 | 464 | 	if (key) { | 
 | 465 | 		if (key > WEP_KEYS) | 
 | 466 | 			return -EINVAL; | 
 | 467 | 		key--; | 
 | 468 | 	} else | 
 | 469 | 		key = ieee->tx_keyidx; | 
 | 470 |  | 
 | 471 | 	crypt = ieee->crypt[key]; | 
 | 472 | 	erq->flags = key + 1; | 
 | 473 |  | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 474 | 	if (!sec->enabled) { | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 475 | 		erq->length = 0; | 
 | 476 | 		erq->flags |= IW_ENCODE_DISABLED; | 
 | 477 | 		return 0; | 
 | 478 | 	} | 
 | 479 |  | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 480 | 	len = sec->key_sizes[key]; | 
 | 481 | 	memcpy(keybuf, sec->keys[key], len); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 482 |  | 
| James Ketrenos | f1bf663 | 2005-09-21 11:53:54 -0500 | [diff] [blame] | 483 | 	erq->length = (len >= 0 ? len : 0); | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 484 | 	erq->flags |= IW_ENCODE_ENABLED; | 
 | 485 |  | 
 | 486 | 	if (ieee->open_wep) | 
 | 487 | 		erq->flags |= IW_ENCODE_OPEN; | 
 | 488 | 	else | 
 | 489 | 		erq->flags |= IW_ENCODE_RESTRICTED; | 
 | 490 |  | 
 | 491 | 	return 0; | 
 | 492 | } | 
 | 493 |  | 
| James Ketrenos | e0d369d | 2005-09-21 11:54:30 -0500 | [diff] [blame] | 494 | int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, | 
 | 495 | 			       struct iw_request_info *info, | 
 | 496 | 			       union iwreq_data *wrqu, char *extra) | 
 | 497 | { | 
 | 498 | 	struct net_device *dev = ieee->dev; | 
 | 499 | 	struct iw_point *encoding = &wrqu->encoding; | 
 | 500 | 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | 
 | 501 | 	int i, idx, ret = 0; | 
| James Ketrenos | ccd0fda | 2005-09-21 11:58:32 -0500 | [diff] [blame] | 502 | 	int group_key = 0; | 
| James Ketrenos | e0d369d | 2005-09-21 11:54:30 -0500 | [diff] [blame] | 503 | 	const char *alg, *module; | 
 | 504 | 	struct ieee80211_crypto_ops *ops; | 
 | 505 | 	struct ieee80211_crypt_data **crypt; | 
 | 506 |  | 
 | 507 | 	struct ieee80211_security sec = { | 
 | 508 | 		.flags = 0, | 
 | 509 | 	}; | 
 | 510 |  | 
 | 511 | 	idx = encoding->flags & IW_ENCODE_INDEX; | 
 | 512 | 	if (idx) { | 
 | 513 | 		if (idx < 1 || idx > WEP_KEYS) | 
 | 514 | 			return -EINVAL; | 
 | 515 | 		idx--; | 
 | 516 | 	} else | 
 | 517 | 		idx = ieee->tx_keyidx; | 
 | 518 |  | 
| James Ketrenos | ccd0fda | 2005-09-21 11:58:32 -0500 | [diff] [blame] | 519 | 	if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { | 
| James Ketrenos | e0d369d | 2005-09-21 11:54:30 -0500 | [diff] [blame] | 520 | 		crypt = &ieee->crypt[idx]; | 
| James Ketrenos | ccd0fda | 2005-09-21 11:58:32 -0500 | [diff] [blame] | 521 | 		group_key = 1; | 
 | 522 | 	} else { | 
| James Ketrenos | e0d369d | 2005-09-21 11:54:30 -0500 | [diff] [blame] | 523 | 		if (idx != 0) | 
 | 524 | 			return -EINVAL; | 
 | 525 | 		if (ieee->iw_mode == IW_MODE_INFRA) | 
 | 526 | 			crypt = &ieee->crypt[idx]; | 
 | 527 | 		else | 
 | 528 | 			return -EINVAL; | 
 | 529 | 	} | 
 | 530 |  | 
 | 531 | 	sec.flags |= SEC_ENABLED | SEC_ENCRYPT; | 
 | 532 | 	if ((encoding->flags & IW_ENCODE_DISABLED) || | 
 | 533 | 	    ext->alg == IW_ENCODE_ALG_NONE) { | 
 | 534 | 		if (*crypt) | 
 | 535 | 			ieee80211_crypt_delayed_deinit(ieee, crypt); | 
 | 536 |  | 
 | 537 | 		for (i = 0; i < WEP_KEYS; i++) | 
 | 538 | 			if (ieee->crypt[i] != NULL) | 
 | 539 | 				break; | 
 | 540 |  | 
 | 541 | 		if (i == WEP_KEYS) { | 
 | 542 | 			sec.enabled = 0; | 
 | 543 | 			sec.encrypt = 0; | 
 | 544 | 			sec.level = SEC_LEVEL_0; | 
 | 545 | 			sec.flags |= SEC_LEVEL; | 
 | 546 | 		} | 
 | 547 | 		goto done; | 
 | 548 | 	} | 
 | 549 |  | 
 | 550 | 	sec.enabled = 1; | 
 | 551 | 	sec.encrypt = 1; | 
 | 552 |  | 
| James Ketrenos | ccd0fda | 2005-09-21 11:58:32 -0500 | [diff] [blame] | 553 | 	if (group_key ? !ieee->host_mc_decrypt : | 
 | 554 | 	    !(ieee->host_encrypt || ieee->host_decrypt || | 
 | 555 | 	      ieee->host_encrypt_msdu)) | 
| James Ketrenos | e0d369d | 2005-09-21 11:54:30 -0500 | [diff] [blame] | 556 | 		goto skip_host_crypt; | 
 | 557 |  | 
 | 558 | 	switch (ext->alg) { | 
 | 559 | 	case IW_ENCODE_ALG_WEP: | 
 | 560 | 		alg = "WEP"; | 
 | 561 | 		module = "ieee80211_crypt_wep"; | 
 | 562 | 		break; | 
 | 563 | 	case IW_ENCODE_ALG_TKIP: | 
 | 564 | 		alg = "TKIP"; | 
 | 565 | 		module = "ieee80211_crypt_tkip"; | 
 | 566 | 		break; | 
 | 567 | 	case IW_ENCODE_ALG_CCMP: | 
 | 568 | 		alg = "CCMP"; | 
 | 569 | 		module = "ieee80211_crypt_ccmp"; | 
 | 570 | 		break; | 
 | 571 | 	default: | 
 | 572 | 		IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", | 
 | 573 | 				   dev->name, ext->alg); | 
 | 574 | 		ret = -EINVAL; | 
 | 575 | 		goto done; | 
 | 576 | 	} | 
 | 577 |  | 
 | 578 | 	ops = ieee80211_get_crypto_ops(alg); | 
 | 579 | 	if (ops == NULL) { | 
 | 580 | 		request_module(module); | 
 | 581 | 		ops = ieee80211_get_crypto_ops(alg); | 
 | 582 | 	} | 
 | 583 | 	if (ops == NULL) { | 
 | 584 | 		IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", | 
 | 585 | 				   dev->name, ext->alg); | 
 | 586 | 		ret = -EINVAL; | 
 | 587 | 		goto done; | 
 | 588 | 	} | 
 | 589 |  | 
 | 590 | 	if (*crypt == NULL || (*crypt)->ops != ops) { | 
 | 591 | 		struct ieee80211_crypt_data *new_crypt; | 
 | 592 |  | 
 | 593 | 		ieee80211_crypt_delayed_deinit(ieee, crypt); | 
 | 594 |  | 
 | 595 | 		new_crypt = (struct ieee80211_crypt_data *) | 
 | 596 | 		    kmalloc(sizeof(*new_crypt), GFP_KERNEL); | 
 | 597 | 		if (new_crypt == NULL) { | 
 | 598 | 			ret = -ENOMEM; | 
 | 599 | 			goto done; | 
 | 600 | 		} | 
 | 601 | 		memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | 
 | 602 | 		new_crypt->ops = ops; | 
 | 603 | 		if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) | 
| James Ketrenos | 6eb6edf | 2005-09-22 10:34:15 +0000 | [diff] [blame] | 604 | 			new_crypt->priv = new_crypt->ops->init(idx); | 
| James Ketrenos | e0d369d | 2005-09-21 11:54:30 -0500 | [diff] [blame] | 605 | 		if (new_crypt->priv == NULL) { | 
 | 606 | 			kfree(new_crypt); | 
 | 607 | 			ret = -EINVAL; | 
 | 608 | 			goto done; | 
 | 609 | 		} | 
 | 610 | 		*crypt = new_crypt; | 
 | 611 | 	} | 
 | 612 |  | 
 | 613 | 	if (ext->key_len > 0 && (*crypt)->ops->set_key && | 
 | 614 | 	    (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, | 
 | 615 | 				   (*crypt)->priv) < 0) { | 
 | 616 | 		IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); | 
 | 617 | 		ret = -EINVAL; | 
 | 618 | 		goto done; | 
 | 619 | 	} | 
 | 620 |  | 
 | 621 |       skip_host_crypt: | 
 | 622 | 	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | 
 | 623 | 		ieee->tx_keyidx = idx; | 
 | 624 | 		sec.active_key = idx; | 
 | 625 | 		sec.flags |= SEC_ACTIVE_KEY; | 
 | 626 | 	} | 
 | 627 |  | 
 | 628 | 	if (ext->alg != IW_ENCODE_ALG_NONE) { | 
 | 629 | 		memcpy(sec.keys[idx], ext->key, ext->key_len); | 
 | 630 | 		sec.key_sizes[idx] = ext->key_len; | 
 | 631 | 		sec.flags |= (1 << idx); | 
 | 632 | 		if (ext->alg == IW_ENCODE_ALG_WEP) { | 
 | 633 | 			sec.encode_alg[idx] = SEC_ALG_WEP; | 
 | 634 | 			sec.flags |= SEC_LEVEL; | 
 | 635 | 			sec.level = SEC_LEVEL_1; | 
 | 636 | 		} else if (ext->alg == IW_ENCODE_ALG_TKIP) { | 
 | 637 | 			sec.encode_alg[idx] = SEC_ALG_TKIP; | 
 | 638 | 			sec.flags |= SEC_LEVEL; | 
 | 639 | 			sec.level = SEC_LEVEL_2; | 
 | 640 | 		} else if (ext->alg == IW_ENCODE_ALG_CCMP) { | 
 | 641 | 			sec.encode_alg[idx] = SEC_ALG_CCMP; | 
 | 642 | 			sec.flags |= SEC_LEVEL; | 
 | 643 | 			sec.level = SEC_LEVEL_3; | 
 | 644 | 		} | 
| James Ketrenos | ccd0fda | 2005-09-21 11:58:32 -0500 | [diff] [blame] | 645 | 		/* Don't set sec level for group keys. */ | 
 | 646 | 		if (group_key) | 
 | 647 | 			sec.flags &= ~SEC_LEVEL; | 
| James Ketrenos | e0d369d | 2005-09-21 11:54:30 -0500 | [diff] [blame] | 648 | 	} | 
 | 649 |       done: | 
 | 650 | 	if (ieee->set_security) | 
 | 651 | 		ieee->set_security(ieee->dev, &sec); | 
 | 652 |  | 
 | 653 | 	/* | 
 | 654 | 	 * Do not reset port if card is in Managed mode since resetting will | 
 | 655 | 	 * generate new IEEE 802.11 authentication which may end up in looping | 
 | 656 | 	 * with IEEE 802.1X. If your hardware requires a reset after WEP | 
 | 657 | 	 * configuration (for example... Prism2), implement the reset_port in | 
 | 658 | 	 * the callbacks structures used to initialize the 802.11 stack. | 
 | 659 | 	 */ | 
 | 660 | 	if (ieee->reset_on_keychange && | 
 | 661 | 	    ieee->iw_mode != IW_MODE_INFRA && | 
 | 662 | 	    ieee->reset_port && ieee->reset_port(dev)) { | 
 | 663 | 		IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); | 
 | 664 | 		return -EINVAL; | 
 | 665 | 	} | 
 | 666 |  | 
 | 667 | 	return ret; | 
 | 668 | } | 
 | 669 |  | 
 | 670 | int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, | 
 | 671 | 			       struct iw_request_info *info, | 
 | 672 | 			       union iwreq_data *wrqu, char *extra) | 
 | 673 | { | 
 | 674 | 	struct iw_point *encoding = &wrqu->encoding; | 
 | 675 | 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | 
 | 676 | 	struct ieee80211_security *sec = &ieee->sec; | 
 | 677 | 	int idx, max_key_len; | 
 | 678 |  | 
 | 679 | 	max_key_len = encoding->length - sizeof(*ext); | 
 | 680 | 	if (max_key_len < 0) | 
 | 681 | 		return -EINVAL; | 
 | 682 |  | 
 | 683 | 	idx = encoding->flags & IW_ENCODE_INDEX; | 
 | 684 | 	if (idx) { | 
 | 685 | 		if (idx < 1 || idx > WEP_KEYS) | 
 | 686 | 			return -EINVAL; | 
 | 687 | 		idx--; | 
 | 688 | 	} else | 
 | 689 | 		idx = ieee->tx_keyidx; | 
 | 690 |  | 
 | 691 | 	if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) | 
 | 692 | 		if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA) | 
 | 693 | 			return -EINVAL; | 
 | 694 |  | 
 | 695 | 	encoding->flags = idx + 1; | 
 | 696 | 	memset(ext, 0, sizeof(*ext)); | 
 | 697 |  | 
 | 698 | 	if (!sec->enabled) { | 
 | 699 | 		ext->alg = IW_ENCODE_ALG_NONE; | 
 | 700 | 		ext->key_len = 0; | 
 | 701 | 		encoding->flags |= IW_ENCODE_DISABLED; | 
 | 702 | 	} else { | 
 | 703 | 		if (sec->encode_alg[idx] == SEC_ALG_WEP) | 
 | 704 | 			ext->alg = IW_ENCODE_ALG_WEP; | 
 | 705 | 		else if (sec->encode_alg[idx] == SEC_ALG_TKIP) | 
 | 706 | 			ext->alg = IW_ENCODE_ALG_TKIP; | 
 | 707 | 		else if (sec->encode_alg[idx] == SEC_ALG_CCMP) | 
 | 708 | 			ext->alg = IW_ENCODE_ALG_CCMP; | 
 | 709 | 		else | 
 | 710 | 			return -EINVAL; | 
 | 711 |  | 
 | 712 | 		ext->key_len = sec->key_sizes[idx]; | 
 | 713 | 		memcpy(ext->key, sec->keys[idx], ext->key_len); | 
 | 714 | 		encoding->flags |= IW_ENCODE_ENABLED; | 
 | 715 | 		if (ext->key_len && | 
 | 716 | 		    (ext->alg == IW_ENCODE_ALG_TKIP || | 
 | 717 | 		     ext->alg == IW_ENCODE_ALG_CCMP)) | 
 | 718 | 			ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; | 
 | 719 |  | 
 | 720 | 	} | 
 | 721 |  | 
 | 722 | 	return 0; | 
 | 723 | } | 
 | 724 |  | 
 | 725 | EXPORT_SYMBOL(ieee80211_wx_set_encodeext); | 
 | 726 | EXPORT_SYMBOL(ieee80211_wx_get_encodeext); | 
| James Ketrenos | e0d369d | 2005-09-21 11:54:30 -0500 | [diff] [blame] | 727 |  | 
| Jeff Garzik | b453872 | 2005-05-12 22:48:20 -0400 | [diff] [blame] | 728 | EXPORT_SYMBOL(ieee80211_wx_get_scan); | 
 | 729 | EXPORT_SYMBOL(ieee80211_wx_set_encode); | 
 | 730 | EXPORT_SYMBOL(ieee80211_wx_get_encode); |