diff options
Diffstat (limited to 'drivers/net/wireless/orinoco/hw.c')
-rw-r--r-- | drivers/net/wireless/orinoco/hw.c | 120 |
1 files changed, 94 insertions, 26 deletions
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index fa508af1a351..40d8dfa7eace 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c | |||
@@ -642,7 +642,7 @@ int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) | |||
642 | { | 642 | { |
643 | hermes_t *hw = &priv->hw; | 643 | hermes_t *hw = &priv->hw; |
644 | int err = 0; | 644 | int err = 0; |
645 | u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE]; | 645 | u8 tsc_arr[4][ORINOCO_SEQ_LEN]; |
646 | 646 | ||
647 | if ((key < 0) || (key > 4)) | 647 | if ((key < 0) || (key > 4)) |
648 | return -EINVAL; | 648 | return -EINVAL; |
@@ -768,12 +768,29 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) | |||
768 | { | 768 | { |
769 | hermes_t *hw = &priv->hw; | 769 | hermes_t *hw = &priv->hw; |
770 | int err = 0; | 770 | int err = 0; |
771 | int i; | ||
771 | 772 | ||
772 | switch (priv->firmware_type) { | 773 | switch (priv->firmware_type) { |
773 | case FIRMWARE_TYPE_AGERE: | 774 | case FIRMWARE_TYPE_AGERE: |
775 | { | ||
776 | struct orinoco_key keys[ORINOCO_MAX_KEYS]; | ||
777 | |||
778 | memset(&keys, 0, sizeof(keys)); | ||
779 | for (i = 0; i < ORINOCO_MAX_KEYS; i++) { | ||
780 | int len = min(priv->keys[i].key_len, | ||
781 | ORINOCO_MAX_KEY_SIZE); | ||
782 | memcpy(&keys[i].data, priv->keys[i].key, len); | ||
783 | if (len > SMALL_KEY_SIZE) | ||
784 | keys[i].len = cpu_to_le16(LARGE_KEY_SIZE); | ||
785 | else if (len > 0) | ||
786 | keys[i].len = cpu_to_le16(SMALL_KEY_SIZE); | ||
787 | else | ||
788 | keys[i].len = cpu_to_le16(0); | ||
789 | } | ||
790 | |||
774 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | 791 | err = HERMES_WRITE_RECORD(hw, USER_BAP, |
775 | HERMES_RID_CNFWEPKEYS_AGERE, | 792 | HERMES_RID_CNFWEPKEYS_AGERE, |
776 | &priv->keys); | 793 | &keys); |
777 | if (err) | 794 | if (err) |
778 | return err; | 795 | return err; |
779 | err = hermes_write_wordrec(hw, USER_BAP, | 796 | err = hermes_write_wordrec(hw, USER_BAP, |
@@ -782,28 +799,38 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) | |||
782 | if (err) | 799 | if (err) |
783 | return err; | 800 | return err; |
784 | break; | 801 | break; |
802 | } | ||
785 | case FIRMWARE_TYPE_INTERSIL: | 803 | case FIRMWARE_TYPE_INTERSIL: |
786 | case FIRMWARE_TYPE_SYMBOL: | 804 | case FIRMWARE_TYPE_SYMBOL: |
787 | { | 805 | { |
788 | int keylen; | 806 | int keylen; |
789 | int i; | ||
790 | 807 | ||
791 | /* Force uniform key length to work around | 808 | /* Force uniform key length to work around |
792 | * firmware bugs */ | 809 | * firmware bugs */ |
793 | keylen = le16_to_cpu(priv->keys[priv->tx_key].len); | 810 | keylen = priv->keys[priv->tx_key].key_len; |
794 | 811 | ||
795 | if (keylen > LARGE_KEY_SIZE) { | 812 | if (keylen > LARGE_KEY_SIZE) { |
796 | printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", | 813 | printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", |
797 | priv->ndev->name, priv->tx_key, keylen); | 814 | priv->ndev->name, priv->tx_key, keylen); |
798 | return -E2BIG; | 815 | return -E2BIG; |
799 | } | 816 | } else if (keylen > SMALL_KEY_SIZE) |
817 | keylen = LARGE_KEY_SIZE; | ||
818 | else if (keylen > 0) | ||
819 | keylen = SMALL_KEY_SIZE; | ||
820 | else | ||
821 | keylen = 0; | ||
800 | 822 | ||
801 | /* Write all 4 keys */ | 823 | /* Write all 4 keys */ |
802 | for (i = 0; i < ORINOCO_MAX_KEYS; i++) { | 824 | for (i = 0; i < ORINOCO_MAX_KEYS; i++) { |
825 | u8 key[LARGE_KEY_SIZE] = { 0 }; | ||
826 | |||
827 | memcpy(key, priv->keys[i].key, | ||
828 | priv->keys[i].key_len); | ||
829 | |||
803 | err = hermes_write_ltv(hw, USER_BAP, | 830 | err = hermes_write_ltv(hw, USER_BAP, |
804 | HERMES_RID_CNFDEFAULTKEY0 + i, | 831 | HERMES_RID_CNFDEFAULTKEY0 + i, |
805 | HERMES_BYTES_TO_RECLEN(keylen), | 832 | HERMES_BYTES_TO_RECLEN(keylen), |
806 | priv->keys[i].data); | 833 | key); |
807 | if (err) | 834 | if (err) |
808 | return err; | 835 | return err; |
809 | } | 836 | } |
@@ -829,8 +856,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) | |||
829 | int auth_flag; | 856 | int auth_flag; |
830 | int enc_flag; | 857 | int enc_flag; |
831 | 858 | ||
832 | /* Setup WEP keys for WEP and WPA */ | 859 | /* Setup WEP keys */ |
833 | if (priv->encode_alg) | 860 | if (priv->encode_alg == ORINOCO_ALG_WEP) |
834 | __orinoco_hw_setup_wepkeys(priv); | 861 | __orinoco_hw_setup_wepkeys(priv); |
835 | 862 | ||
836 | if (priv->wep_restrict) | 863 | if (priv->wep_restrict) |
@@ -840,14 +867,14 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) | |||
840 | 867 | ||
841 | if (priv->wpa_enabled) | 868 | if (priv->wpa_enabled) |
842 | enc_flag = 2; | 869 | enc_flag = 2; |
843 | else if (priv->encode_alg == IW_ENCODE_ALG_WEP) | 870 | else if (priv->encode_alg == ORINOCO_ALG_WEP) |
844 | enc_flag = 1; | 871 | enc_flag = 1; |
845 | else | 872 | else |
846 | enc_flag = 0; | 873 | enc_flag = 0; |
847 | 874 | ||
848 | switch (priv->firmware_type) { | 875 | switch (priv->firmware_type) { |
849 | case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ | 876 | case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ |
850 | if (priv->encode_alg == IW_ENCODE_ALG_WEP) { | 877 | if (priv->encode_alg == ORINOCO_ALG_WEP) { |
851 | /* Enable the shared-key authentication. */ | 878 | /* Enable the shared-key authentication. */ |
852 | err = hermes_write_wordrec(hw, USER_BAP, | 879 | err = hermes_write_wordrec(hw, USER_BAP, |
853 | HERMES_RID_CNFAUTHENTICATION_AGERE, | 880 | HERMES_RID_CNFAUTHENTICATION_AGERE, |
@@ -872,7 +899,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) | |||
872 | 899 | ||
873 | case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ | 900 | case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ |
874 | case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ | 901 | case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ |
875 | if (priv->encode_alg == IW_ENCODE_ALG_WEP) { | 902 | if (priv->encode_alg == ORINOCO_ALG_WEP) { |
876 | if (priv->wep_restrict || | 903 | if (priv->wep_restrict || |
877 | (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) | 904 | (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) |
878 | master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | | 905 | master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | |
@@ -905,19 +932,20 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) | |||
905 | } | 932 | } |
906 | 933 | ||
907 | /* key must be 32 bytes, including the tx and rx MIC keys. | 934 | /* key must be 32 bytes, including the tx and rx MIC keys. |
908 | * rsc must be 8 bytes | 935 | * rsc must be NULL or up to 8 bytes |
909 | * tsc must be 8 bytes or NULL | 936 | * tsc must be NULL or up to 8 bytes |
910 | */ | 937 | */ |
911 | int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, | 938 | int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, |
912 | int set_tx, u8 *key, u8 *rsc, u8 *tsc) | 939 | int set_tx, u8 *key, u8 *rsc, size_t rsc_len, |
940 | u8 *tsc, size_t tsc_len) | ||
913 | { | 941 | { |
914 | struct { | 942 | struct { |
915 | __le16 idx; | 943 | __le16 idx; |
916 | u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; | 944 | u8 rsc[ORINOCO_SEQ_LEN]; |
917 | u8 key[TKIP_KEYLEN]; | 945 | u8 key[TKIP_KEYLEN]; |
918 | u8 tx_mic[MIC_KEYLEN]; | 946 | u8 tx_mic[MIC_KEYLEN]; |
919 | u8 rx_mic[MIC_KEYLEN]; | 947 | u8 rx_mic[MIC_KEYLEN]; |
920 | u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; | 948 | u8 tsc[ORINOCO_SEQ_LEN]; |
921 | } __attribute__ ((packed)) buf; | 949 | } __attribute__ ((packed)) buf; |
922 | hermes_t *hw = &priv->hw; | 950 | hermes_t *hw = &priv->hw; |
923 | int ret; | 951 | int ret; |
@@ -934,17 +962,22 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, | |||
934 | memcpy(buf.key, key, | 962 | memcpy(buf.key, key, |
935 | sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); | 963 | sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); |
936 | 964 | ||
937 | if (rsc == NULL) | 965 | if (rsc_len > sizeof(buf.rsc)) |
938 | memset(buf.rsc, 0, sizeof(buf.rsc)); | 966 | rsc_len = sizeof(buf.rsc); |
939 | else | ||
940 | memcpy(buf.rsc, rsc, sizeof(buf.rsc)); | ||
941 | 967 | ||
942 | if (tsc == NULL) { | 968 | if (tsc_len > sizeof(buf.tsc)) |
943 | memset(buf.tsc, 0, sizeof(buf.tsc)); | 969 | tsc_len = sizeof(buf.tsc); |
970 | |||
971 | memset(buf.rsc, 0, sizeof(buf.rsc)); | ||
972 | memset(buf.tsc, 0, sizeof(buf.tsc)); | ||
973 | |||
974 | if (rsc != NULL) | ||
975 | memcpy(buf.rsc, rsc, rsc_len); | ||
976 | |||
977 | if (tsc != NULL) | ||
978 | memcpy(buf.tsc, tsc, tsc_len); | ||
979 | else | ||
944 | buf.tsc[4] = 0x10; | 980 | buf.tsc[4] = 0x10; |
945 | } else { | ||
946 | memcpy(buf.tsc, tsc, sizeof(buf.tsc)); | ||
947 | } | ||
948 | 981 | ||
949 | /* Wait upto 100ms for tx queue to empty */ | 982 | /* Wait upto 100ms for tx queue to empty */ |
950 | for (k = 100; k > 0; k--) { | 983 | for (k = 100; k > 0; k--) { |
@@ -970,7 +1003,6 @@ int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx) | |||
970 | hermes_t *hw = &priv->hw; | 1003 | hermes_t *hw = &priv->hw; |
971 | int err; | 1004 | int err; |
972 | 1005 | ||
973 | memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); | ||
974 | err = hermes_write_wordrec(hw, USER_BAP, | 1006 | err = hermes_write_wordrec(hw, USER_BAP, |
975 | HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, | 1007 | HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, |
976 | key_idx); | 1008 | key_idx); |
@@ -1242,3 +1274,39 @@ int orinoco_hw_trigger_scan(struct orinoco_private *priv, | |||
1242 | 1274 | ||
1243 | return err; | 1275 | return err; |
1244 | } | 1276 | } |
1277 | |||
1278 | /* Disassociate from node with BSSID addr */ | ||
1279 | int orinoco_hw_disassociate(struct orinoco_private *priv, | ||
1280 | u8 *addr, u16 reason_code) | ||
1281 | { | ||
1282 | hermes_t *hw = &priv->hw; | ||
1283 | int err; | ||
1284 | |||
1285 | struct { | ||
1286 | u8 addr[ETH_ALEN]; | ||
1287 | __le16 reason_code; | ||
1288 | } __attribute__ ((packed)) buf; | ||
1289 | |||
1290 | /* Currently only supported by WPA enabled Agere fw */ | ||
1291 | if (!priv->has_wpa) | ||
1292 | return -EOPNOTSUPP; | ||
1293 | |||
1294 | memcpy(buf.addr, addr, ETH_ALEN); | ||
1295 | buf.reason_code = cpu_to_le16(reason_code); | ||
1296 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
1297 | HERMES_RID_CNFDISASSOCIATE, | ||
1298 | &buf); | ||
1299 | return err; | ||
1300 | } | ||
1301 | |||
1302 | int orinoco_hw_get_current_bssid(struct orinoco_private *priv, | ||
1303 | u8 *addr) | ||
1304 | { | ||
1305 | hermes_t *hw = &priv->hw; | ||
1306 | int err; | ||
1307 | |||
1308 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, | ||
1309 | ETH_ALEN, NULL, addr); | ||
1310 | |||
1311 | return err; | ||
1312 | } | ||