Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

orinoco: Add WE-18 ioctls for WPA

Includes basic plumbing to get the data into firmware, and retrieve it.

SIOCxIWGENIE simply record (and return) the IE, and do not act on it.

SIOCxIWENCODEEXT, SIOCxIWAUTH and SIOCSIWMLME should be as functional as
the driver will support.

Signed-off-by: David Kilroy <kilroyd@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

David Kilroy and committed by
John W. Linville
d03032af 409644a9

+554 -8
+16
drivers/net/wireless/hermes_rid.h
··· 30 30 #define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 31 31 #define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 32 32 #define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 33 + #define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22 33 34 #define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 34 35 #define HERMES_RID_CNFDEFAULTKEY0 0xFC24 35 36 #define HERMES_RID_CNFDEFAULTKEY1 0xFC25 ··· 86 85 #define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 87 86 #define HERMES_RID_CNFBASICRATES 0xFCB3 88 87 #define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 88 + #define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4 89 + #define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5 90 + #define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6 91 + #define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7 92 + #define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8 93 + #define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9 94 + #define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA 95 + #define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB 89 96 #define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2 97 + #define HERMES_RID_CNFDISASSOCIATE 0xFCC8 90 98 #define HERMES_RID_CNFTICKTIME 0xFCE0 91 99 #define HERMES_RID_CNFSCANREQUEST 0xFCE1 92 100 #define HERMES_RID_CNFJOINREQUEST 0xFCE2 ··· 148 138 #define HERMES_RID_CURRENTTXRATE6 0xFD85 149 139 #define HERMES_RID_OWNMACADDR 0xFD86 150 140 #define HERMES_RID_SCANRESULTSTABLE 0xFD88 141 + #define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89 142 + #define HERMES_RID_CURRENT_WPA_IE 0xFD8A 143 + #define HERMES_RID_CURRENT_TKIP_IV 0xFD8B 144 + #define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C 145 + #define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D 146 + #define HERMES_RID_TXQUEUEEMPTY 0xFD91 151 147 #define HERMES_RID_PHYTYPE 0xFDC0 152 148 #define HERMES_RID_CURRENTCHANNEL 0xFDC1 153 149 #define HERMES_RID_CURRENTPOWERSTATE 0xFDC2
+518 -8
drivers/net/wireless/orinoco.c
··· 79 79 #include <linux/module.h> 80 80 #include <linux/kernel.h> 81 81 #include <linux/init.h> 82 + #include <linux/delay.h> 82 83 #include <linux/netdevice.h> 83 84 #include <linux/etherdevice.h> 84 85 #include <linux/ethtool.h> ··· 2039 2038 } 2040 2039 2041 2040 /* Change the WEP keys and/or the current keys. Can be called 2042 - * either from __orinoco_hw_setup_wep() or directly from 2041 + * either from __orinoco_hw_setup_enc() or directly from 2043 2042 * orinoco_ioctl_setiwencode(). In the later case the association 2044 2043 * with the AP is not broken (if the firmware can handle it), 2045 2044 * which is needed for 802.1x implementations. */ ··· 2099 2098 return 0; 2100 2099 } 2101 2100 2102 - static int __orinoco_hw_setup_wep(struct orinoco_private *priv) 2101 + static int __orinoco_hw_setup_enc(struct orinoco_private *priv) 2103 2102 { 2104 2103 hermes_t *hw = &priv->hw; 2105 2104 int err = 0; ··· 2107 2106 int auth_flag; 2108 2107 int enc_flag; 2109 2108 2110 - if (priv->encode_alg == IW_ENCODE_ALG_WEP) 2109 + /* Setup WEP keys for WEP and WPA */ 2110 + if (priv->encode_alg) 2111 2111 __orinoco_hw_setup_wepkeys(priv); 2112 2112 2113 2113 if (priv->wep_restrict) ··· 2116 2114 else 2117 2115 auth_flag = HERMES_AUTH_OPEN; 2118 2116 2119 - if (priv->encode_alg == IW_ENCODE_ALG_WEP) 2117 + if (priv->wpa_enabled) 2118 + enc_flag = 2; 2119 + else if (priv->encode_alg == IW_ENCODE_ALG_WEP) 2120 2120 enc_flag = 1; 2121 2121 else 2122 2122 enc_flag = 0; ··· 2136 2132 enc_flag); 2137 2133 if (err) 2138 2134 return err; 2135 + 2136 + if (priv->has_wpa) { 2137 + /* Set WPA key management */ 2138 + err = hermes_write_wordrec(hw, USER_BAP, 2139 + HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, 2140 + priv->key_mgmt); 2141 + if (err) 2142 + return err; 2143 + } 2144 + 2139 2145 break; 2140 2146 2141 2147 case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ ··· 2180 2166 } 2181 2167 2182 2168 return 0; 2169 + } 2170 + 2171 + /* key must be 32 bytes, including the tx and rx MIC keys. 2172 + * rsc must be 8 bytes 2173 + * tsc must be 8 bytes or NULL 2174 + */ 2175 + static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, 2176 + u8 *key, u8 *rsc, u8 *tsc) 2177 + { 2178 + struct { 2179 + __le16 idx; 2180 + u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; 2181 + u8 key[TKIP_KEYLEN]; 2182 + u8 tx_mic[MIC_KEYLEN]; 2183 + u8 rx_mic[MIC_KEYLEN]; 2184 + u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; 2185 + } __attribute__ ((packed)) buf; 2186 + int ret; 2187 + int err; 2188 + int k; 2189 + u16 xmitting; 2190 + 2191 + key_idx &= 0x3; 2192 + 2193 + if (set_tx) 2194 + key_idx |= 0x8000; 2195 + 2196 + buf.idx = cpu_to_le16(key_idx); 2197 + memcpy(buf.key, key, 2198 + sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); 2199 + 2200 + if (rsc == NULL) 2201 + memset(buf.rsc, 0, sizeof(buf.rsc)); 2202 + else 2203 + memcpy(buf.rsc, rsc, sizeof(buf.rsc)); 2204 + 2205 + if (tsc == NULL) { 2206 + memset(buf.tsc, 0, sizeof(buf.tsc)); 2207 + buf.tsc[4] = 0x10; 2208 + } else { 2209 + memcpy(buf.tsc, tsc, sizeof(buf.tsc)); 2210 + } 2211 + 2212 + /* Wait upto 100ms for tx queue to empty */ 2213 + k = 100; 2214 + do { 2215 + k--; 2216 + udelay(1000); 2217 + ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, 2218 + &xmitting); 2219 + if (ret) 2220 + break; 2221 + } while ((k > 0) && xmitting); 2222 + 2223 + if (k == 0) 2224 + ret = -ETIMEDOUT; 2225 + 2226 + err = HERMES_WRITE_RECORD(hw, USER_BAP, 2227 + HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, 2228 + &buf); 2229 + 2230 + return ret ? ret : err; 2231 + } 2232 + 2233 + static int orinoco_clear_tkip_key(struct orinoco_private *priv, 2234 + int key_idx) 2235 + { 2236 + hermes_t *hw = &priv->hw; 2237 + int err; 2238 + 2239 + memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); 2240 + err = hermes_write_wordrec(hw, USER_BAP, 2241 + HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, 2242 + key_idx); 2243 + if (err) 2244 + printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", 2245 + priv->ndev->name, err, key_idx); 2246 + return err; 2183 2247 } 2184 2248 2185 2249 static int __orinoco_program_rids(struct net_device *dev) ··· 2456 2364 } 2457 2365 2458 2366 /* Set up encryption */ 2459 - if (priv->has_wep) { 2460 - err = __orinoco_hw_setup_wep(priv); 2367 + if (priv->has_wep || priv->has_wpa) { 2368 + err = __orinoco_hw_setup_enc(priv); 2461 2369 if (err) { 2462 - printk(KERN_ERR "%s: Error %d activating WEP\n", 2370 + printk(KERN_ERR "%s: Error %d activating encryption\n", 2463 2371 dev->name, err); 2464 2372 return err; 2465 2373 } ··· 2812 2720 priv->has_big_wep = 0; 2813 2721 priv->has_alt_txcntl = 0; 2814 2722 priv->has_ext_scan = 0; 2723 + priv->has_wpa = 0; 2815 2724 priv->do_fw_download = 0; 2816 2725 2817 2726 /* Determine capabilities from the firmware version */ ··· 2837 2744 priv->broken_monitor = (firmver >= 0x80000); 2838 2745 priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ 2839 2746 priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ 2747 + priv->has_wpa = (firmver >= 0x9002a); 2840 2748 /* Tested with Agere firmware : 2841 2749 * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II 2842 2750 * Tested CableTron firmware : 4.32 => Anton */ ··· 2991 2897 else 2992 2898 printk("40-bit key\n"); 2993 2899 } 2900 + if (priv->has_wpa) 2901 + printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name); 2994 2902 2995 2903 /* Now we have the firmware capabilities, allocate appropiate 2996 2904 * sized scan buffers */ ··· 3116 3020 priv->promiscuous = 0; 3117 3021 priv->encode_alg = IW_ENCODE_ALG_NONE; 3118 3022 priv->tx_key = 0; 3023 + priv->wpa_enabled = 0; 3024 + priv->tkip_cm_active = 0; 3025 + priv->key_mgmt = 0; 3026 + priv->wpa_ie_len = 0; 3027 + priv->wpa_ie = NULL; 3119 3028 3120 3029 /* Make the hardware available, as long as it hasn't been 3121 3030 * removed elsewhere (e.g. by PCMCIA hot unplug) */ ··· 3196 3095 { 3197 3096 struct orinoco_private *priv = netdev_priv(dev); 3198 3097 3098 + priv->wpa_ie_len = 0; 3099 + kfree(priv->wpa_ie); 3199 3100 orinoco_bss_data_free(priv); 3200 3101 free_netdev(dev); 3201 3102 } ··· 3509 3406 memset(range, 0, sizeof(struct iw_range)); 3510 3407 3511 3408 range->we_version_compiled = WIRELESS_EXT; 3512 - range->we_version_source = 14; 3409 + range->we_version_source = 22; 3513 3410 3514 3411 /* Set available channels/frequencies */ 3515 3412 range->num_channels = NUM_CHANNELS; ··· 3538 3435 range->num_encoding_sizes = 2; 3539 3436 } 3540 3437 } 3438 + 3439 + if (priv->has_wpa) 3440 + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; 3541 3441 3542 3442 if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){ 3543 3443 /* Quality stats meaningless in ad-hoc mode */ ··· 3633 3527 3634 3528 if (orinoco_lock(priv, &flags) != 0) 3635 3529 return -EBUSY; 3530 + 3531 + /* Clear any TKIP key we have */ 3532 + if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP)) 3533 + (void) orinoco_clear_tkip_key(priv, setindex); 3636 3534 3637 3535 if (erq->length > 0) { 3638 3536 if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) ··· 4300 4190 orinoco_unlock(priv, &flags); 4301 4191 4302 4192 return err; 4193 + } 4194 + 4195 + static int orinoco_ioctl_set_encodeext(struct net_device *dev, 4196 + struct iw_request_info *info, 4197 + union iwreq_data *wrqu, 4198 + char *extra) 4199 + { 4200 + struct orinoco_private *priv = netdev_priv(dev); 4201 + struct iw_point *encoding = &wrqu->encoding; 4202 + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 4203 + int idx, alg = ext->alg, set_key = 1; 4204 + unsigned long flags; 4205 + int err = -EINVAL; 4206 + u16 key_len; 4207 + 4208 + if (orinoco_lock(priv, &flags) != 0) 4209 + return -EBUSY; 4210 + 4211 + /* Determine and validate the key index */ 4212 + idx = encoding->flags & IW_ENCODE_INDEX; 4213 + if (idx) { 4214 + if ((idx < 1) || (idx > WEP_KEYS)) 4215 + goto out; 4216 + idx--; 4217 + } else 4218 + idx = priv->tx_key; 4219 + 4220 + if (encoding->flags & IW_ENCODE_DISABLED) 4221 + alg = IW_ENCODE_ALG_NONE; 4222 + 4223 + if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) { 4224 + /* Clear any TKIP TX key we had */ 4225 + (void) orinoco_clear_tkip_key(priv, priv->tx_key); 4226 + } 4227 + 4228 + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { 4229 + priv->tx_key = idx; 4230 + set_key = ((alg == IW_ENCODE_ALG_TKIP) || 4231 + (ext->key_len > 0)) ? 1 : 0; 4232 + } 4233 + 4234 + if (set_key) { 4235 + /* Set the requested key first */ 4236 + switch (alg) { 4237 + case IW_ENCODE_ALG_NONE: 4238 + priv->encode_alg = alg; 4239 + priv->keys[idx].len = 0; 4240 + break; 4241 + 4242 + case IW_ENCODE_ALG_WEP: 4243 + if (ext->key_len > SMALL_KEY_SIZE) 4244 + key_len = LARGE_KEY_SIZE; 4245 + else if (ext->key_len > 0) 4246 + key_len = SMALL_KEY_SIZE; 4247 + else 4248 + goto out; 4249 + 4250 + priv->encode_alg = alg; 4251 + priv->keys[idx].len = cpu_to_le16(key_len); 4252 + 4253 + key_len = min(ext->key_len, key_len); 4254 + 4255 + memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE); 4256 + memcpy(priv->keys[idx].data, ext->key, key_len); 4257 + break; 4258 + 4259 + case IW_ENCODE_ALG_TKIP: 4260 + { 4261 + hermes_t *hw = &priv->hw; 4262 + u8 *tkip_iv = NULL; 4263 + 4264 + if (!priv->has_wpa || 4265 + (ext->key_len > sizeof(priv->tkip_key[0]))) 4266 + goto out; 4267 + 4268 + priv->encode_alg = alg; 4269 + memset(&priv->tkip_key[idx], 0, 4270 + sizeof(priv->tkip_key[idx])); 4271 + memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); 4272 + 4273 + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) 4274 + tkip_iv = &ext->rx_seq[0]; 4275 + 4276 + err = __orinoco_hw_set_tkip_key(hw, idx, 4277 + ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, 4278 + (u8 *) &priv->tkip_key[idx], 4279 + tkip_iv, NULL); 4280 + if (err) 4281 + printk(KERN_ERR "%s: Error %d setting TKIP key" 4282 + "\n", dev->name, err); 4283 + 4284 + goto out; 4285 + } 4286 + default: 4287 + goto out; 4288 + } 4289 + } 4290 + err = -EINPROGRESS; 4291 + out: 4292 + orinoco_unlock(priv, &flags); 4293 + 4294 + return err; 4295 + } 4296 + 4297 + static int orinoco_ioctl_get_encodeext(struct net_device *dev, 4298 + struct iw_request_info *info, 4299 + union iwreq_data *wrqu, 4300 + char *extra) 4301 + { 4302 + struct orinoco_private *priv = netdev_priv(dev); 4303 + struct iw_point *encoding = &wrqu->encoding; 4304 + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 4305 + int idx, max_key_len; 4306 + unsigned long flags; 4307 + int err; 4308 + 4309 + if (orinoco_lock(priv, &flags) != 0) 4310 + return -EBUSY; 4311 + 4312 + err = -EINVAL; 4313 + max_key_len = encoding->length - sizeof(*ext); 4314 + if (max_key_len < 0) 4315 + goto out; 4316 + 4317 + idx = encoding->flags & IW_ENCODE_INDEX; 4318 + if (idx) { 4319 + if ((idx < 1) || (idx > WEP_KEYS)) 4320 + goto out; 4321 + idx--; 4322 + } else 4323 + idx = priv->tx_key; 4324 + 4325 + encoding->flags = idx + 1; 4326 + memset(ext, 0, sizeof(*ext)); 4327 + 4328 + ext->alg = priv->encode_alg; 4329 + switch (priv->encode_alg) { 4330 + case IW_ENCODE_ALG_NONE: 4331 + ext->key_len = 0; 4332 + encoding->flags |= IW_ENCODE_DISABLED; 4333 + break; 4334 + case IW_ENCODE_ALG_WEP: 4335 + ext->key_len = min(le16_to_cpu(priv->keys[idx].len), 4336 + (u16) max_key_len); 4337 + memcpy(ext->key, priv->keys[idx].data, ext->key_len); 4338 + encoding->flags |= IW_ENCODE_ENABLED; 4339 + break; 4340 + case IW_ENCODE_ALG_TKIP: 4341 + ext->key_len = min((u16) sizeof(struct orinoco_tkip_key), 4342 + (u16) max_key_len); 4343 + memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); 4344 + encoding->flags |= IW_ENCODE_ENABLED; 4345 + break; 4346 + } 4347 + 4348 + err = 0; 4349 + out: 4350 + orinoco_unlock(priv, &flags); 4351 + 4352 + return err; 4353 + } 4354 + 4355 + static int orinoco_ioctl_set_auth(struct net_device *dev, 4356 + struct iw_request_info *info, 4357 + union iwreq_data *wrqu, char *extra) 4358 + { 4359 + struct orinoco_private *priv = netdev_priv(dev); 4360 + hermes_t *hw = &priv->hw; 4361 + struct iw_param *param = &wrqu->param; 4362 + unsigned long flags; 4363 + int ret = -EINPROGRESS; 4364 + 4365 + if (orinoco_lock(priv, &flags) != 0) 4366 + return -EBUSY; 4367 + 4368 + switch (param->flags & IW_AUTH_INDEX) { 4369 + case IW_AUTH_WPA_VERSION: 4370 + case IW_AUTH_CIPHER_PAIRWISE: 4371 + case IW_AUTH_CIPHER_GROUP: 4372 + case IW_AUTH_RX_UNENCRYPTED_EAPOL: 4373 + case IW_AUTH_PRIVACY_INVOKED: 4374 + case IW_AUTH_DROP_UNENCRYPTED: 4375 + /* 4376 + * orinoco does not use these parameters 4377 + */ 4378 + break; 4379 + 4380 + case IW_AUTH_KEY_MGMT: 4381 + /* wl_lkm implies value 2 == PSK for Hermes I 4382 + * which ties in with WEXT 4383 + * no other hints tho :( 4384 + */ 4385 + priv->key_mgmt = param->value; 4386 + break; 4387 + 4388 + case IW_AUTH_TKIP_COUNTERMEASURES: 4389 + /* When countermeasures are enabled, shut down the 4390 + * card; when disabled, re-enable the card. This must 4391 + * take effect immediately. 4392 + * 4393 + * TODO: Make sure that the EAPOL message is getting 4394 + * out before card disabled 4395 + */ 4396 + if (param->value) { 4397 + priv->tkip_cm_active = 1; 4398 + ret = hermes_enable_port(hw, 0); 4399 + } else { 4400 + priv->tkip_cm_active = 0; 4401 + ret = hermes_disable_port(hw, 0); 4402 + } 4403 + break; 4404 + 4405 + case IW_AUTH_80211_AUTH_ALG: 4406 + if (param->value & IW_AUTH_ALG_SHARED_KEY) 4407 + priv->wep_restrict = 1; 4408 + else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) 4409 + priv->wep_restrict = 0; 4410 + else 4411 + ret = -EINVAL; 4412 + break; 4413 + 4414 + case IW_AUTH_WPA_ENABLED: 4415 + if (priv->has_wpa) { 4416 + priv->wpa_enabled = param->value ? 1 : 0; 4417 + } else { 4418 + if (param->value) 4419 + ret = -EOPNOTSUPP; 4420 + /* else silently accept disable of WPA */ 4421 + priv->wpa_enabled = 0; 4422 + } 4423 + break; 4424 + 4425 + default: 4426 + ret = -EOPNOTSUPP; 4427 + } 4428 + 4429 + orinoco_unlock(priv, &flags); 4430 + return ret; 4431 + } 4432 + 4433 + static int orinoco_ioctl_get_auth(struct net_device *dev, 4434 + struct iw_request_info *info, 4435 + union iwreq_data *wrqu, char *extra) 4436 + { 4437 + struct orinoco_private *priv = netdev_priv(dev); 4438 + struct iw_param *param = &wrqu->param; 4439 + unsigned long flags; 4440 + int ret = 0; 4441 + 4442 + if (orinoco_lock(priv, &flags) != 0) 4443 + return -EBUSY; 4444 + 4445 + switch (param->flags & IW_AUTH_INDEX) { 4446 + case IW_AUTH_KEY_MGMT: 4447 + param->value = priv->key_mgmt; 4448 + break; 4449 + 4450 + case IW_AUTH_TKIP_COUNTERMEASURES: 4451 + param->value = priv->tkip_cm_active; 4452 + break; 4453 + 4454 + case IW_AUTH_80211_AUTH_ALG: 4455 + if (priv->wep_restrict) 4456 + param->value = IW_AUTH_ALG_SHARED_KEY; 4457 + else 4458 + param->value = IW_AUTH_ALG_OPEN_SYSTEM; 4459 + break; 4460 + 4461 + case IW_AUTH_WPA_ENABLED: 4462 + param->value = priv->wpa_enabled; 4463 + break; 4464 + 4465 + default: 4466 + ret = -EOPNOTSUPP; 4467 + } 4468 + 4469 + orinoco_unlock(priv, &flags); 4470 + return ret; 4471 + } 4472 + 4473 + static int orinoco_ioctl_set_genie(struct net_device *dev, 4474 + struct iw_request_info *info, 4475 + union iwreq_data *wrqu, char *extra) 4476 + { 4477 + struct orinoco_private *priv = netdev_priv(dev); 4478 + u8 *buf; 4479 + unsigned long flags; 4480 + int err = 0; 4481 + 4482 + if ((wrqu->data.length > MAX_WPA_IE_LEN) || 4483 + (wrqu->data.length && (extra == NULL))) 4484 + return -EINVAL; 4485 + 4486 + if (orinoco_lock(priv, &flags) != 0) 4487 + return -EBUSY; 4488 + 4489 + if (wrqu->data.length) { 4490 + buf = kmalloc(wrqu->data.length, GFP_KERNEL); 4491 + if (buf == NULL) { 4492 + err = -ENOMEM; 4493 + goto out; 4494 + } 4495 + 4496 + memcpy(buf, extra, wrqu->data.length); 4497 + kfree(priv->wpa_ie); 4498 + priv->wpa_ie = buf; 4499 + priv->wpa_ie_len = wrqu->data.length; 4500 + } else { 4501 + kfree(priv->wpa_ie); 4502 + priv->wpa_ie = NULL; 4503 + priv->wpa_ie_len = 0; 4504 + } 4505 + 4506 + if (priv->wpa_ie) { 4507 + /* Looks like wl_lkm wants to check the auth alg, and 4508 + * somehow pass it to the firmware. 4509 + * Instead it just calls the key mgmt rid 4510 + * - we do this in set auth. 4511 + */ 4512 + } 4513 + 4514 + out: 4515 + orinoco_unlock(priv, &flags); 4516 + return err; 4517 + } 4518 + 4519 + static int orinoco_ioctl_get_genie(struct net_device *dev, 4520 + struct iw_request_info *info, 4521 + union iwreq_data *wrqu, char *extra) 4522 + { 4523 + struct orinoco_private *priv = netdev_priv(dev); 4524 + unsigned long flags; 4525 + int err = 0; 4526 + 4527 + if (orinoco_lock(priv, &flags) != 0) 4528 + return -EBUSY; 4529 + 4530 + if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) { 4531 + wrqu->data.length = 0; 4532 + goto out; 4533 + } 4534 + 4535 + if (wrqu->data.length < priv->wpa_ie_len) { 4536 + err = -E2BIG; 4537 + goto out; 4538 + } 4539 + 4540 + wrqu->data.length = priv->wpa_ie_len; 4541 + memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); 4542 + 4543 + out: 4544 + orinoco_unlock(priv, &flags); 4545 + return err; 4546 + } 4547 + 4548 + static int orinoco_ioctl_set_mlme(struct net_device *dev, 4549 + struct iw_request_info *info, 4550 + union iwreq_data *wrqu, char *extra) 4551 + { 4552 + struct orinoco_private *priv = netdev_priv(dev); 4553 + hermes_t *hw = &priv->hw; 4554 + struct iw_mlme *mlme = (struct iw_mlme *)extra; 4555 + unsigned long flags; 4556 + int ret = 0; 4557 + 4558 + if (orinoco_lock(priv, &flags) != 0) 4559 + return -EBUSY; 4560 + 4561 + switch (mlme->cmd) { 4562 + case IW_MLME_DEAUTH: 4563 + /* silently ignore */ 4564 + break; 4565 + 4566 + case IW_MLME_DISASSOC: 4567 + { 4568 + struct { 4569 + u8 addr[ETH_ALEN]; 4570 + __le16 reason_code; 4571 + } __attribute__ ((packed)) buf; 4572 + 4573 + memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN); 4574 + buf.reason_code = cpu_to_le16(mlme->reason_code); 4575 + ret = HERMES_WRITE_RECORD(hw, USER_BAP, 4576 + HERMES_RID_CNFDISASSOCIATE, 4577 + &buf); 4578 + break; 4579 + } 4580 + default: 4581 + ret = -EOPNOTSUPP; 4582 + } 4583 + 4584 + orinoco_unlock(priv, &flags); 4585 + return ret; 4303 4586 } 4304 4587 4305 4588 static int orinoco_ioctl_getretry(struct net_device *dev, ··· 5581 5078 STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), 5582 5079 STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), 5583 5080 STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), 5081 + STD_IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), 5082 + STD_IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), 5083 + STD_IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), 5084 + STD_IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), 5085 + STD_IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), 5086 + STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), 5087 + STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), 5584 5088 }; 5585 5089 5586 5090
+20
drivers/net/wireless/orinoco.h
··· 30 30 char data[ORINOCO_MAX_KEY_SIZE]; 31 31 } __attribute__ ((packed)); 32 32 33 + #define TKIP_KEYLEN 16 34 + #define MIC_KEYLEN 8 35 + 36 + struct orinoco_tkip_key { 37 + u8 tkip[TKIP_KEYLEN]; 38 + u8 tx_mic[MIC_KEYLEN]; 39 + u8 rx_mic[MIC_KEYLEN]; 40 + }; 41 + 33 42 typedef enum { 34 43 FIRMWARE_TYPE_AGERE, 35 44 FIRMWARE_TYPE_INTERSIL, ··· 102 93 unsigned int has_hostscan:1; 103 94 unsigned int has_alt_txcntl:1; 104 95 unsigned int has_ext_scan:1; 96 + unsigned int has_wpa:1; 105 97 unsigned int do_fw_download:1; 106 98 unsigned int broken_disableport:1; 107 99 unsigned int broken_monitor:1; ··· 138 128 139 129 int scan_inprogress; /* Scan pending... */ 140 130 u32 scan_mode; /* Type of scan done */ 131 + 132 + /* WPA support */ 133 + u8 *wpa_ie; 134 + int wpa_ie_len; 135 + 136 + struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS]; 137 + 138 + unsigned int wpa_enabled:1; 139 + unsigned int tkip_cm_active:1; 140 + unsigned int key_mgmt:3; 141 141 }; 142 142 143 143 #ifdef ORINOCO_DEBUG