diff options
Diffstat (limited to 'drivers/net/wireless/ipw2200.c')
-rw-r--r-- | drivers/net/wireless/ipw2200.c | 141 |
1 files changed, 125 insertions, 16 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index f8dac52df93a..c6da5f534250 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -5557,6 +5557,55 @@ static void ipw_send_wep_keys(struct ipw_priv *priv, int type) | |||
5557 | } | 5557 | } |
5558 | } | 5558 | } |
5559 | 5559 | ||
5560 | static void ipw_set_hw_decrypt_unicast(struct ipw_priv *priv, int level) | ||
5561 | { | ||
5562 | if (priv->ieee->host_encrypt) | ||
5563 | return; | ||
5564 | |||
5565 | switch (level) { | ||
5566 | case SEC_LEVEL_3: | ||
5567 | priv->sys_config.disable_unicast_decryption = 0; | ||
5568 | priv->ieee->host_decrypt = 0; | ||
5569 | break; | ||
5570 | case SEC_LEVEL_2: | ||
5571 | priv->sys_config.disable_unicast_decryption = 1; | ||
5572 | priv->ieee->host_decrypt = 1; | ||
5573 | break; | ||
5574 | case SEC_LEVEL_1: | ||
5575 | priv->sys_config.disable_unicast_decryption = 0; | ||
5576 | priv->ieee->host_decrypt = 0; | ||
5577 | break; | ||
5578 | case SEC_LEVEL_0: | ||
5579 | priv->sys_config.disable_unicast_decryption = 1; | ||
5580 | break; | ||
5581 | default: | ||
5582 | break; | ||
5583 | } | ||
5584 | } | ||
5585 | |||
5586 | static void ipw_set_hw_decrypt_multicast(struct ipw_priv *priv, int level) | ||
5587 | { | ||
5588 | if (priv->ieee->host_encrypt) | ||
5589 | return; | ||
5590 | |||
5591 | switch (level) { | ||
5592 | case SEC_LEVEL_3: | ||
5593 | priv->sys_config.disable_multicast_decryption = 0; | ||
5594 | break; | ||
5595 | case SEC_LEVEL_2: | ||
5596 | priv->sys_config.disable_multicast_decryption = 1; | ||
5597 | break; | ||
5598 | case SEC_LEVEL_1: | ||
5599 | priv->sys_config.disable_multicast_decryption = 0; | ||
5600 | break; | ||
5601 | case SEC_LEVEL_0: | ||
5602 | priv->sys_config.disable_multicast_decryption = 1; | ||
5603 | break; | ||
5604 | default: | ||
5605 | break; | ||
5606 | } | ||
5607 | } | ||
5608 | |||
5560 | static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) | 5609 | static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) |
5561 | { | 5610 | { |
5562 | switch (priv->ieee->sec.level) { | 5611 | switch (priv->ieee->sec.level) { |
@@ -5567,33 +5616,23 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) | |||
5567 | priv->ieee->sec.active_key); | 5616 | priv->ieee->sec.active_key); |
5568 | 5617 | ||
5569 | ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); | 5618 | ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); |
5570 | priv->sys_config.disable_unicast_decryption = 0; | ||
5571 | priv->sys_config.disable_multicast_decryption = 0; | ||
5572 | priv->ieee->host_decrypt = 0; | ||
5573 | break; | 5619 | break; |
5574 | case SEC_LEVEL_2: | 5620 | case SEC_LEVEL_2: |
5575 | if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) | 5621 | if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) |
5576 | ipw_send_tgi_tx_key(priv, | 5622 | ipw_send_tgi_tx_key(priv, |
5577 | DCT_FLAG_EXT_SECURITY_TKIP, | 5623 | DCT_FLAG_EXT_SECURITY_TKIP, |
5578 | priv->ieee->sec.active_key); | 5624 | priv->ieee->sec.active_key); |
5579 | |||
5580 | priv->sys_config.disable_unicast_decryption = 1; | ||
5581 | priv->sys_config.disable_multicast_decryption = 1; | ||
5582 | priv->ieee->host_decrypt = 1; | ||
5583 | break; | 5625 | break; |
5584 | case SEC_LEVEL_1: | 5626 | case SEC_LEVEL_1: |
5585 | ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); | 5627 | ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); |
5586 | priv->sys_config.disable_unicast_decryption = 0; | ||
5587 | priv->sys_config.disable_multicast_decryption = 0; | ||
5588 | priv->ieee->host_decrypt = 0; | ||
5589 | break; | 5628 | break; |
5590 | case SEC_LEVEL_0: | 5629 | case SEC_LEVEL_0: |
5591 | priv->sys_config.disable_unicast_decryption = 1; | ||
5592 | priv->sys_config.disable_multicast_decryption = 1; | ||
5593 | break; | ||
5594 | default: | 5630 | default: |
5595 | break; | 5631 | break; |
5596 | } | 5632 | } |
5633 | |||
5634 | ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level); | ||
5635 | ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level); | ||
5597 | } | 5636 | } |
5598 | 5637 | ||
5599 | static void ipw_adhoc_check(void *data) | 5638 | static void ipw_adhoc_check(void *data) |
@@ -6185,12 +6224,31 @@ static int ipw_wpa_mlme(struct net_device *dev, int command, int reason) | |||
6185 | return ret; | 6224 | return ret; |
6186 | } | 6225 | } |
6187 | 6226 | ||
6227 | static int ipw_wpa_ie_cipher2level(u8 cipher) | ||
6228 | { | ||
6229 | switch (cipher) { | ||
6230 | case 4: /* CCMP */ | ||
6231 | return SEC_LEVEL_3; | ||
6232 | case 2: /* TKIP */ | ||
6233 | return SEC_LEVEL_2; | ||
6234 | case 5: /* WEP104 */ | ||
6235 | case 1: /* WEP40 */ | ||
6236 | return SEC_LEVEL_1; | ||
6237 | case 0: /* NONE */ | ||
6238 | return SEC_LEVEL_0; | ||
6239 | default: | ||
6240 | return -1; | ||
6241 | } | ||
6242 | } | ||
6243 | |||
6188 | static int ipw_wpa_set_wpa_ie(struct net_device *dev, | 6244 | static int ipw_wpa_set_wpa_ie(struct net_device *dev, |
6189 | struct ipw_param *param, int plen) | 6245 | struct ipw_param *param, int plen) |
6190 | { | 6246 | { |
6191 | struct ipw_priv *priv = ieee80211_priv(dev); | 6247 | struct ipw_priv *priv = ieee80211_priv(dev); |
6192 | struct ieee80211_device *ieee = priv->ieee; | 6248 | struct ieee80211_device *ieee = priv->ieee; |
6193 | u8 *buf; | 6249 | u8 *buf; |
6250 | u8 *ptk, *gtk; | ||
6251 | int level; | ||
6194 | 6252 | ||
6195 | if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || | 6253 | if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || |
6196 | (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) | 6254 | (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) |
@@ -6209,8 +6267,35 @@ static int ipw_wpa_set_wpa_ie(struct net_device *dev, | |||
6209 | kfree(ieee->wpa_ie); | 6267 | kfree(ieee->wpa_ie); |
6210 | ieee->wpa_ie = NULL; | 6268 | ieee->wpa_ie = NULL; |
6211 | ieee->wpa_ie_len = 0; | 6269 | ieee->wpa_ie_len = 0; |
6270 | goto done; | ||
6271 | } | ||
6272 | |||
6273 | if (priv->ieee->host_encrypt) | ||
6274 | goto done; | ||
6275 | |||
6276 | /* HACK: Parse wpa_ie here to get pairwise suite, otherwise | ||
6277 | * we need to change driver_ipw.c from wpa_supplicant. This | ||
6278 | * is OK since -Dipw is deprecated. The -Dwext driver has a | ||
6279 | * clean way to handle this. */ | ||
6280 | gtk = ptk = (u8 *) ieee->wpa_ie; | ||
6281 | if (ieee->wpa_ie[0] == 0x30) { /* RSN IE */ | ||
6282 | gtk += 4 + 3; | ||
6283 | ptk += 4 + 4 + 2 + 3; | ||
6284 | } else { /* WPA IE */ | ||
6285 | gtk += 8 + 3; | ||
6286 | ptk += 8 + 4 + 2 + 3; | ||
6212 | } | 6287 | } |
6213 | 6288 | ||
6289 | if (ptk - (u8 *) ieee->wpa_ie > ieee->wpa_ie_len) | ||
6290 | return -EINVAL; | ||
6291 | |||
6292 | level = ipw_wpa_ie_cipher2level(*gtk); | ||
6293 | ipw_set_hw_decrypt_multicast(priv, level); | ||
6294 | |||
6295 | level = ipw_wpa_ie_cipher2level(*ptk); | ||
6296 | ipw_set_hw_decrypt_unicast(priv, level); | ||
6297 | |||
6298 | done: | ||
6214 | ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); | 6299 | ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); |
6215 | return 0; | 6300 | return 0; |
6216 | } | 6301 | } |
@@ -6510,6 +6595,23 @@ static int ipw_wx_get_genie(struct net_device *dev, | |||
6510 | return err; | 6595 | return err; |
6511 | } | 6596 | } |
6512 | 6597 | ||
6598 | static int wext_cipher2level(int cipher) | ||
6599 | { | ||
6600 | switch (cipher) { | ||
6601 | case IW_AUTH_CIPHER_NONE: | ||
6602 | return SEC_LEVEL_0; | ||
6603 | case IW_AUTH_CIPHER_WEP40: | ||
6604 | case IW_AUTH_CIPHER_WEP104: | ||
6605 | return SEC_LEVEL_1; | ||
6606 | case IW_AUTH_CIPHER_TKIP: | ||
6607 | return SEC_LEVEL_2; | ||
6608 | case IW_AUTH_CIPHER_CCMP: | ||
6609 | return SEC_LEVEL_3; | ||
6610 | default: | ||
6611 | return -1; | ||
6612 | } | ||
6613 | } | ||
6614 | |||
6513 | /* SIOCSIWAUTH */ | 6615 | /* SIOCSIWAUTH */ |
6514 | static int ipw_wx_set_auth(struct net_device *dev, | 6616 | static int ipw_wx_set_auth(struct net_device *dev, |
6515 | struct iw_request_info *info, | 6617 | struct iw_request_info *info, |
@@ -6524,8 +6626,15 @@ static int ipw_wx_set_auth(struct net_device *dev, | |||
6524 | 6626 | ||
6525 | switch (param->flags & IW_AUTH_INDEX) { | 6627 | switch (param->flags & IW_AUTH_INDEX) { |
6526 | case IW_AUTH_WPA_VERSION: | 6628 | case IW_AUTH_WPA_VERSION: |
6629 | break; | ||
6527 | case IW_AUTH_CIPHER_PAIRWISE: | 6630 | case IW_AUTH_CIPHER_PAIRWISE: |
6631 | ipw_set_hw_decrypt_unicast(priv, | ||
6632 | wext_cipher2level(param->value)); | ||
6633 | break; | ||
6528 | case IW_AUTH_CIPHER_GROUP: | 6634 | case IW_AUTH_CIPHER_GROUP: |
6635 | ipw_set_hw_decrypt_multicast(priv, | ||
6636 | wext_cipher2level(param->value)); | ||
6637 | break; | ||
6529 | case IW_AUTH_KEY_MGMT: | 6638 | case IW_AUTH_KEY_MGMT: |
6530 | /* | 6639 | /* |
6531 | * ipw2200 does not use these parameters | 6640 | * ipw2200 does not use these parameters |
@@ -10256,11 +10365,11 @@ static void shim__set_security(struct net_device *dev, | |||
10256 | priv->ieee->sec.level = sec->level; | 10365 | priv->ieee->sec.level = sec->level; |
10257 | priv->ieee->sec.flags |= SEC_LEVEL; | 10366 | priv->ieee->sec.flags |= SEC_LEVEL; |
10258 | priv->status |= STATUS_SECURITY_UPDATED; | 10367 | priv->status |= STATUS_SECURITY_UPDATED; |
10259 | |||
10260 | if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT)) | ||
10261 | ipw_set_hwcrypto_keys(priv); | ||
10262 | } | 10368 | } |
10263 | 10369 | ||
10370 | if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT)) | ||
10371 | ipw_set_hwcrypto_keys(priv); | ||
10372 | |||
10264 | /* To match current functionality of ipw2100 (which works well w/ | 10373 | /* To match current functionality of ipw2100 (which works well w/ |
10265 | * various supplicants, we don't force a disassociate if the | 10374 | * various supplicants, we don't force a disassociate if the |
10266 | * privacy capability changes ... */ | 10375 | * privacy capability changes ... */ |