aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ieee80211.h14
-rw-r--r--net/ieee80211/ieee80211_wx.c238
2 files changed, 244 insertions, 8 deletions
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index c7ab7cd9de13..dfc5d65cc6c1 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -447,6 +447,11 @@ struct ieee80211_device;
447#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ 447#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
448#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ 448#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
449 449
450#define SEC_ALG_NONE 0
451#define SEC_ALG_WEP 1
452#define SEC_ALG_TKIP 2
453#define SEC_ALG_CCMP 3
454
450#define WEP_KEYS 4 455#define WEP_KEYS 4
451#define WEP_KEY_LEN 13 456#define WEP_KEY_LEN 13
452#define SCM_KEY_LEN 32 457#define SCM_KEY_LEN 32
@@ -456,6 +461,7 @@ struct ieee80211_security {
456 u16 active_key:2, 461 u16 active_key:2,
457 enabled:1, 462 enabled:1,
458 auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1; 463 auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1;
464 u8 encode_alg[WEP_KEYS];
459 u8 key_sizes[WEP_KEYS]; 465 u8 key_sizes[WEP_KEYS];
460 u8 keys[WEP_KEYS][SCM_KEY_LEN]; 466 u8 keys[WEP_KEYS][SCM_KEY_LEN];
461 u8 level; 467 u8 level;
@@ -824,6 +830,14 @@ extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
824extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, 830extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
825 struct iw_request_info *info, 831 struct iw_request_info *info,
826 union iwreq_data *wrqu, char *key); 832 union iwreq_data *wrqu, char *key);
833#if WIRELESS_EXT > 17
834extern int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
835 struct iw_request_info *info,
836 union iwreq_data *wrqu, char *extra);
837extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
838 struct iw_request_info *info,
839 union iwreq_data *wrqu, char *extra);
840#endif
827 841
828extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) 842extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
829{ 843{
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 49afea7989d0..db66217699d5 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -422,6 +422,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
422 * TODO: When WPA is added this is one place that needs to change */ 422 * TODO: When WPA is added this is one place that needs to change */
423 sec.flags |= SEC_LEVEL; 423 sec.flags |= SEC_LEVEL;
424 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ 424 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
425 sec.encode_alg[key] = SEC_ALG_WEP;
425 426
426 done: 427 done:
427 if (ieee->set_security) 428 if (ieee->set_security)
@@ -469,14 +470,6 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
469 return 0; 470 return 0;
470 } 471 }
471 472
472 if (sec->level != SEC_LEVEL_1) {
473 /* only WEP is supported with wireless extensions, so just
474 * report that encryption is used */
475 erq->length = 0;
476 erq->flags |= IW_ENCODE_ENABLED;
477 return 0;
478 }
479
480 len = sec->key_sizes[key]; 473 len = sec->key_sizes[key];
481 memcpy(keybuf, sec->keys[key], len); 474 memcpy(keybuf, sec->keys[key], len);
482 475
@@ -491,6 +484,235 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
491 return 0; 484 return 0;
492} 485}
493 486
487#if WIRELESS_EXT > 17
488int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
489 struct iw_request_info *info,
490 union iwreq_data *wrqu, char *extra)
491{
492 struct net_device *dev = ieee->dev;
493 struct iw_point *encoding = &wrqu->encoding;
494 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
495 int i, idx, ret = 0;
496 const char *alg, *module;
497 struct ieee80211_crypto_ops *ops;
498 struct ieee80211_crypt_data **crypt;
499
500 struct ieee80211_security sec = {
501 .flags = 0,
502 };
503
504 idx = encoding->flags & IW_ENCODE_INDEX;
505 if (idx) {
506 if (idx < 1 || idx > WEP_KEYS)
507 return -EINVAL;
508 idx--;
509 } else
510 idx = ieee->tx_keyidx;
511
512 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
513 crypt = &ieee->crypt[idx];
514 else {
515 if (idx != 0)
516 return -EINVAL;
517 if (ieee->iw_mode == IW_MODE_INFRA)
518 crypt = &ieee->crypt[idx];
519 else
520 return -EINVAL;
521 }
522
523 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
524 if ((encoding->flags & IW_ENCODE_DISABLED) ||
525 ext->alg == IW_ENCODE_ALG_NONE) {
526 if (*crypt)
527 ieee80211_crypt_delayed_deinit(ieee, crypt);
528
529 for (i = 0; i < WEP_KEYS; i++)
530 if (ieee->crypt[i] != NULL)
531 break;
532
533 if (i == WEP_KEYS) {
534 sec.enabled = 0;
535 sec.encrypt = 0;
536 sec.level = SEC_LEVEL_0;
537 sec.flags |= SEC_LEVEL;
538 }
539 goto done;
540 }
541
542 sec.enabled = 1;
543 sec.encrypt = 1;
544
545 if (!(ieee->host_encrypt || ieee->host_decrypt))
546 goto skip_host_crypt;
547
548 switch (ext->alg) {
549 case IW_ENCODE_ALG_WEP:
550 alg = "WEP";
551 module = "ieee80211_crypt_wep";
552 break;
553 case IW_ENCODE_ALG_TKIP:
554 alg = "TKIP";
555 module = "ieee80211_crypt_tkip";
556 break;
557 case IW_ENCODE_ALG_CCMP:
558 alg = "CCMP";
559 module = "ieee80211_crypt_ccmp";
560 break;
561 default:
562 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
563 dev->name, ext->alg);
564 ret = -EINVAL;
565 goto done;
566 }
567
568 ops = ieee80211_get_crypto_ops(alg);
569 if (ops == NULL) {
570 request_module(module);
571 ops = ieee80211_get_crypto_ops(alg);
572 }
573 if (ops == NULL) {
574 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
575 dev->name, ext->alg);
576 ret = -EINVAL;
577 goto done;
578 }
579
580 if (*crypt == NULL || (*crypt)->ops != ops) {
581 struct ieee80211_crypt_data *new_crypt;
582
583 ieee80211_crypt_delayed_deinit(ieee, crypt);
584
585 new_crypt = (struct ieee80211_crypt_data *)
586 kmalloc(sizeof(*new_crypt), GFP_KERNEL);
587 if (new_crypt == NULL) {
588 ret = -ENOMEM;
589 goto done;
590 }
591 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
592 new_crypt->ops = ops;
593 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
594 new_crypt->priv = new_crypt->ops->init(ieee, idx);
595 if (new_crypt->priv == NULL) {
596 kfree(new_crypt);
597 ret = -EINVAL;
598 goto done;
599 }
600 *crypt = new_crypt;
601 }
602
603 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
604 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
605 (*crypt)->priv) < 0) {
606 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
607 ret = -EINVAL;
608 goto done;
609 }
610
611 skip_host_crypt:
612 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
613 ieee->tx_keyidx = idx;
614 sec.active_key = idx;
615 sec.flags |= SEC_ACTIVE_KEY;
616 }
617
618 if (ext->alg != IW_ENCODE_ALG_NONE) {
619 memcpy(sec.keys[idx], ext->key, ext->key_len);
620 sec.key_sizes[idx] = ext->key_len;
621 sec.flags |= (1 << idx);
622 if (ext->alg == IW_ENCODE_ALG_WEP) {
623 sec.encode_alg[idx] = SEC_ALG_WEP;
624 sec.flags |= SEC_LEVEL;
625 sec.level = SEC_LEVEL_1;
626 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
627 sec.encode_alg[idx] = SEC_ALG_TKIP;
628 sec.flags |= SEC_LEVEL;
629 sec.level = SEC_LEVEL_2;
630 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
631 sec.encode_alg[idx] = SEC_ALG_CCMP;
632 sec.flags |= SEC_LEVEL;
633 sec.level = SEC_LEVEL_3;
634 }
635 }
636 done:
637 if (ieee->set_security)
638 ieee->set_security(ieee->dev, &sec);
639
640 /*
641 * Do not reset port if card is in Managed mode since resetting will
642 * generate new IEEE 802.11 authentication which may end up in looping
643 * with IEEE 802.1X. If your hardware requires a reset after WEP
644 * configuration (for example... Prism2), implement the reset_port in
645 * the callbacks structures used to initialize the 802.11 stack.
646 */
647 if (ieee->reset_on_keychange &&
648 ieee->iw_mode != IW_MODE_INFRA &&
649 ieee->reset_port && ieee->reset_port(dev)) {
650 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
651 return -EINVAL;
652 }
653
654 return ret;
655}
656
657int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
658 struct iw_request_info *info,
659 union iwreq_data *wrqu, char *extra)
660{
661 struct iw_point *encoding = &wrqu->encoding;
662 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
663 struct ieee80211_security *sec = &ieee->sec;
664 int idx, max_key_len;
665
666 max_key_len = encoding->length - sizeof(*ext);
667 if (max_key_len < 0)
668 return -EINVAL;
669
670 idx = encoding->flags & IW_ENCODE_INDEX;
671 if (idx) {
672 if (idx < 1 || idx > WEP_KEYS)
673 return -EINVAL;
674 idx--;
675 } else
676 idx = ieee->tx_keyidx;
677
678 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
679 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
680 return -EINVAL;
681
682 encoding->flags = idx + 1;
683 memset(ext, 0, sizeof(*ext));
684
685 if (!sec->enabled) {
686 ext->alg = IW_ENCODE_ALG_NONE;
687 ext->key_len = 0;
688 encoding->flags |= IW_ENCODE_DISABLED;
689 } else {
690 if (sec->encode_alg[idx] == SEC_ALG_WEP)
691 ext->alg = IW_ENCODE_ALG_WEP;
692 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
693 ext->alg = IW_ENCODE_ALG_TKIP;
694 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
695 ext->alg = IW_ENCODE_ALG_CCMP;
696 else
697 return -EINVAL;
698
699 ext->key_len = sec->key_sizes[idx];
700 memcpy(ext->key, sec->keys[idx], ext->key_len);
701 encoding->flags |= IW_ENCODE_ENABLED;
702 if (ext->key_len &&
703 (ext->alg == IW_ENCODE_ALG_TKIP ||
704 ext->alg == IW_ENCODE_ALG_CCMP))
705 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
706
707 }
708
709 return 0;
710}
711
712EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
713EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
714#endif
715
494EXPORT_SYMBOL(ieee80211_wx_get_scan); 716EXPORT_SYMBOL(ieee80211_wx_get_scan);
495EXPORT_SYMBOL(ieee80211_wx_set_encode); 717EXPORT_SYMBOL(ieee80211_wx_set_encode);
496EXPORT_SYMBOL(ieee80211_wx_get_encode); 718EXPORT_SYMBOL(ieee80211_wx_get_encode);