diff options
author | David S. Miller <davem@davemloft.net> | 2009-05-25 03:38:24 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-05-25 03:38:24 -0400 |
commit | 45ea4ea2af358fe316c918381c7868f9418cad09 (patch) | |
tree | 4deb3d87b26e884b06929fe33740d45e78fbdcab /drivers/net/wireless/rndis_wlan.c | |
parent | dddc045e2fdd4eb8d7dfac29bff191d639fff8c3 (diff) | |
parent | a2e2322d83df82a57ba456cfa604c8b8f7b04670 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net/wireless/rndis_wlan.c')
-rw-r--r-- | drivers/net/wireless/rndis_wlan.c | 216 |
1 files changed, 118 insertions, 98 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 52fc647e6cb6..c254fdf446fd 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Driver for RNDIS based wireless USB devices. | 2 | * Driver for RNDIS based wireless USB devices. |
3 | * | 3 | * |
4 | * Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net> | 4 | * Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net> |
5 | * Copyright (C) 2008 by Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 5 | * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@mbnet.fi> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -196,6 +196,18 @@ enum ndis_80211_priv_filter { | |||
196 | ndis_80211_priv_8021x_wep | 196 | ndis_80211_priv_8021x_wep |
197 | }; | 197 | }; |
198 | 198 | ||
199 | enum ndis_80211_addkey_bits { | ||
200 | ndis_80211_addkey_8021x_auth = cpu_to_le32(1 << 28), | ||
201 | ndis_80211_addkey_set_init_recv_seq = cpu_to_le32(1 << 29), | ||
202 | ndis_80211_addkey_pairwise_key = cpu_to_le32(1 << 30), | ||
203 | ndis_80211_addkey_transmit_key = cpu_to_le32(1 << 31), | ||
204 | }; | ||
205 | |||
206 | enum ndis_80211_addwep_bits { | ||
207 | ndis_80211_addwep_perclient_key = cpu_to_le32(1 << 30), | ||
208 | ndis_80211_addwep_transmit_key = cpu_to_le32(1 << 31), | ||
209 | }; | ||
210 | |||
199 | struct ndis_80211_ssid { | 211 | struct ndis_80211_ssid { |
200 | __le32 length; | 212 | __le32 length; |
201 | u8 essid[NDIS_802_11_LENGTH_SSID]; | 213 | u8 essid[NDIS_802_11_LENGTH_SSID]; |
@@ -309,7 +321,6 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, | |||
309 | #define CAP_MODE_80211B 2 | 321 | #define CAP_MODE_80211B 2 |
310 | #define CAP_MODE_80211G 4 | 322 | #define CAP_MODE_80211G 4 |
311 | #define CAP_MODE_MASK 7 | 323 | #define CAP_MODE_MASK 7 |
312 | #define CAP_SUPPORT_TXPOWER 8 | ||
313 | 324 | ||
314 | #define WORK_LINK_UP (1<<0) | 325 | #define WORK_LINK_UP (1<<0) |
315 | #define WORK_LINK_DOWN (1<<1) | 326 | #define WORK_LINK_DOWN (1<<1) |
@@ -394,6 +405,7 @@ struct rndis_wext_private { | |||
394 | int encr_tx_key_index; | 405 | int encr_tx_key_index; |
395 | char encr_keys[4][32]; | 406 | char encr_keys[4][32]; |
396 | int encr_key_len[4]; | 407 | int encr_key_len[4]; |
408 | char encr_key_wpa[4]; | ||
397 | int wpa_version; | 409 | int wpa_version; |
398 | int wpa_keymgmt; | 410 | int wpa_keymgmt; |
399 | int wpa_authalg; | 411 | int wpa_authalg; |
@@ -945,7 +957,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) | |||
945 | if (priv->wpa_keymgmt == 0 || | 957 | if (priv->wpa_keymgmt == 0 || |
946 | priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) { | 958 | priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) { |
947 | for (i = 0; i < 4; i++) { | 959 | for (i = 0; i < 4; i++) { |
948 | if (priv->encr_key_len[i] > 0) | 960 | if (priv->encr_key_len[i] > 0 && !priv->encr_key_wpa[i]) |
949 | add_wep_key(usbdev, priv->encr_keys[i], | 961 | add_wep_key(usbdev, priv->encr_keys[i], |
950 | priv->encr_key_len[i], i); | 962 | priv->encr_key_len[i], i); |
951 | } | 963 | } |
@@ -999,7 +1011,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) | |||
999 | memcpy(&ndis_key.material, key, key_len); | 1011 | memcpy(&ndis_key.material, key, key_len); |
1000 | 1012 | ||
1001 | if (index == priv->encr_tx_key_index) { | 1013 | if (index == priv->encr_tx_key_index) { |
1002 | ndis_key.index |= cpu_to_le32(1 << 31); | 1014 | ndis_key.index |= ndis_80211_addwep_transmit_key; |
1003 | ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, | 1015 | ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, |
1004 | IW_AUTH_CIPHER_NONE); | 1016 | IW_AUTH_CIPHER_NONE); |
1005 | if (ret) | 1017 | if (ret) |
@@ -1016,12 +1028,81 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) | |||
1016 | } | 1028 | } |
1017 | 1029 | ||
1018 | priv->encr_key_len[index] = key_len; | 1030 | priv->encr_key_len[index] = key_len; |
1031 | priv->encr_key_wpa[index] = 0; | ||
1019 | memcpy(&priv->encr_keys[index], key, key_len); | 1032 | memcpy(&priv->encr_keys[index], key, key_len); |
1020 | 1033 | ||
1021 | return 0; | 1034 | return 0; |
1022 | } | 1035 | } |
1023 | 1036 | ||
1024 | 1037 | ||
1038 | static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, | ||
1039 | int index, const struct sockaddr *addr, | ||
1040 | const u8 *rx_seq, int alg, int flags) | ||
1041 | { | ||
1042 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | ||
1043 | struct ndis_80211_key ndis_key; | ||
1044 | int ret; | ||
1045 | |||
1046 | if (index < 0 || index >= 4) | ||
1047 | return -EINVAL; | ||
1048 | if (key_len > sizeof(ndis_key.material) || key_len < 0) | ||
1049 | return -EINVAL; | ||
1050 | if ((flags & ndis_80211_addkey_set_init_recv_seq) && !rx_seq) | ||
1051 | return -EINVAL; | ||
1052 | if ((flags & ndis_80211_addkey_pairwise_key) && !addr) | ||
1053 | return -EINVAL; | ||
1054 | |||
1055 | devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index, | ||
1056 | !!(flags & ndis_80211_addkey_transmit_key), | ||
1057 | !!(flags & ndis_80211_addkey_pairwise_key), | ||
1058 | !!(flags & ndis_80211_addkey_set_init_recv_seq)); | ||
1059 | |||
1060 | memset(&ndis_key, 0, sizeof(ndis_key)); | ||
1061 | |||
1062 | ndis_key.size = cpu_to_le32(sizeof(ndis_key) - | ||
1063 | sizeof(ndis_key.material) + key_len); | ||
1064 | ndis_key.length = cpu_to_le32(key_len); | ||
1065 | ndis_key.index = cpu_to_le32(index) | flags; | ||
1066 | |||
1067 | if (alg == IW_ENCODE_ALG_TKIP && key_len == 32) { | ||
1068 | /* wpa_supplicant gives us the Michael MIC RX/TX keys in | ||
1069 | * different order than NDIS spec, so swap the order here. */ | ||
1070 | memcpy(ndis_key.material, key, 16); | ||
1071 | memcpy(ndis_key.material + 16, key + 24, 8); | ||
1072 | memcpy(ndis_key.material + 24, key + 16, 8); | ||
1073 | } else | ||
1074 | memcpy(ndis_key.material, key, key_len); | ||
1075 | |||
1076 | if (flags & ndis_80211_addkey_set_init_recv_seq) | ||
1077 | memcpy(ndis_key.rsc, rx_seq, 6); | ||
1078 | |||
1079 | if (flags & ndis_80211_addkey_pairwise_key) { | ||
1080 | /* pairwise key */ | ||
1081 | memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN); | ||
1082 | } else { | ||
1083 | /* group key */ | ||
1084 | if (priv->infra_mode == ndis_80211_infra_adhoc) | ||
1085 | memset(ndis_key.bssid, 0xff, ETH_ALEN); | ||
1086 | else | ||
1087 | get_bssid(usbdev, ndis_key.bssid); | ||
1088 | } | ||
1089 | |||
1090 | ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, | ||
1091 | le32_to_cpu(ndis_key.size)); | ||
1092 | devdbg(usbdev, "add_wpa_key: OID_802_11_ADD_KEY -> %08X", ret); | ||
1093 | if (ret != 0) | ||
1094 | return ret; | ||
1095 | |||
1096 | priv->encr_key_len[index] = key_len; | ||
1097 | priv->encr_key_wpa[index] = 1; | ||
1098 | |||
1099 | if (flags & ndis_80211_addkey_transmit_key) | ||
1100 | priv->encr_tx_key_index = index; | ||
1101 | |||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1105 | |||
1025 | /* remove_key is for both wep and wpa */ | 1106 | /* remove_key is for both wep and wpa */ |
1026 | static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) | 1107 | static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) |
1027 | { | 1108 | { |
@@ -1034,6 +1115,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) | |||
1034 | return 0; | 1115 | return 0; |
1035 | 1116 | ||
1036 | priv->encr_key_len[index] = 0; | 1117 | priv->encr_key_len[index] = 0; |
1118 | priv->encr_key_wpa[index] = 0; | ||
1037 | memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); | 1119 | memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); |
1038 | 1120 | ||
1039 | if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP || | 1121 | if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP || |
@@ -1045,7 +1127,8 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) | |||
1045 | if (bssid) { | 1127 | if (bssid) { |
1046 | /* pairwise key */ | 1128 | /* pairwise key */ |
1047 | if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) | 1129 | if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) |
1048 | remove_key.index |= cpu_to_le32(1 << 30); | 1130 | remove_key.index |= |
1131 | ndis_80211_addkey_pairwise_key; | ||
1049 | memcpy(remove_key.bssid, bssid, | 1132 | memcpy(remove_key.bssid, bssid, |
1050 | sizeof(remove_key.bssid)); | 1133 | sizeof(remove_key.bssid)); |
1051 | } else | 1134 | } else |
@@ -1590,9 +1673,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, | |||
1590 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | 1673 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; |
1591 | struct usbnet *usbdev = netdev_priv(dev); | 1674 | struct usbnet *usbdev = netdev_priv(dev); |
1592 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | 1675 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); |
1593 | struct ndis_80211_key ndis_key; | 1676 | int keyidx, flags; |
1594 | int keyidx, ret; | ||
1595 | u8 *addr; | ||
1596 | 1677 | ||
1597 | keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; | 1678 | keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; |
1598 | 1679 | ||
@@ -1615,58 +1696,16 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, | |||
1615 | ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) | 1696 | ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) |
1616 | return remove_key(usbdev, keyidx, NULL); | 1697 | return remove_key(usbdev, keyidx, NULL); |
1617 | 1698 | ||
1618 | if (ext->key_len > sizeof(ndis_key.material)) | 1699 | flags = 0; |
1619 | return -1; | 1700 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) |
1620 | 1701 | flags |= ndis_80211_addkey_set_init_recv_seq; | |
1621 | memset(&ndis_key, 0, sizeof(ndis_key)); | 1702 | if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) |
1622 | 1703 | flags |= ndis_80211_addkey_pairwise_key; | |
1623 | ndis_key.size = cpu_to_le32(sizeof(ndis_key) - | ||
1624 | sizeof(ndis_key.material) + ext->key_len); | ||
1625 | ndis_key.length = cpu_to_le32(ext->key_len); | ||
1626 | ndis_key.index = cpu_to_le32(keyidx); | ||
1627 | |||
1628 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { | ||
1629 | memcpy(ndis_key.rsc, ext->rx_seq, 6); | ||
1630 | ndis_key.index |= cpu_to_le32(1 << 29); | ||
1631 | } | ||
1632 | |||
1633 | addr = ext->addr.sa_data; | ||
1634 | if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { | ||
1635 | /* group key */ | ||
1636 | if (priv->infra_mode == ndis_80211_infra_adhoc) | ||
1637 | memset(ndis_key.bssid, 0xff, ETH_ALEN); | ||
1638 | else | ||
1639 | get_bssid(usbdev, ndis_key.bssid); | ||
1640 | } else { | ||
1641 | /* pairwise key */ | ||
1642 | ndis_key.index |= cpu_to_le32(1 << 30); | ||
1643 | memcpy(ndis_key.bssid, addr, ETH_ALEN); | ||
1644 | } | ||
1645 | |||
1646 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) | ||
1647 | ndis_key.index |= cpu_to_le32(1 << 31); | ||
1648 | |||
1649 | if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { | ||
1650 | /* wpa_supplicant gives us the Michael MIC RX/TX keys in | ||
1651 | * different order than NDIS spec, so swap the order here. */ | ||
1652 | memcpy(ndis_key.material, ext->key, 16); | ||
1653 | memcpy(ndis_key.material + 16, ext->key + 24, 8); | ||
1654 | memcpy(ndis_key.material + 24, ext->key + 16, 8); | ||
1655 | } else | ||
1656 | memcpy(ndis_key.material, ext->key, ext->key_len); | ||
1657 | |||
1658 | ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, | ||
1659 | le32_to_cpu(ndis_key.size)); | ||
1660 | devdbg(usbdev, "SIOCSIWENCODEEXT: OID_802_11_ADD_KEY -> %08X", ret); | ||
1661 | if (ret != 0) | ||
1662 | return ret; | ||
1663 | |||
1664 | priv->encr_key_len[keyidx] = ext->key_len; | ||
1665 | memcpy(&priv->encr_keys[keyidx], ndis_key.material, ext->key_len); | ||
1666 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) | 1704 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) |
1667 | priv->encr_tx_key_index = keyidx; | 1705 | flags |= ndis_80211_addkey_transmit_key; |
1668 | 1706 | ||
1669 | return 0; | 1707 | return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr, |
1708 | ext->rx_seq, ext->alg, flags); | ||
1670 | } | 1709 | } |
1671 | 1710 | ||
1672 | 1711 | ||
@@ -1849,18 +1888,10 @@ static int rndis_iw_get_txpower(struct net_device *dev, | |||
1849 | struct usbnet *usbdev = netdev_priv(dev); | 1888 | struct usbnet *usbdev = netdev_priv(dev); |
1850 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | 1889 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); |
1851 | __le32 tx_power; | 1890 | __le32 tx_power; |
1852 | int ret = 0, len; | ||
1853 | 1891 | ||
1854 | if (priv->radio_on) { | 1892 | if (priv->radio_on) { |
1855 | if (priv->caps & CAP_SUPPORT_TXPOWER) { | 1893 | /* fake since changing tx_power (by userlevel) not supported */ |
1856 | len = sizeof(tx_power); | 1894 | tx_power = cpu_to_le32(get_bcm4320_power(priv)); |
1857 | ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, | ||
1858 | &tx_power, &len); | ||
1859 | if (ret != 0) | ||
1860 | return ret; | ||
1861 | } else | ||
1862 | /* fake incase not supported */ | ||
1863 | tx_power = cpu_to_le32(get_bcm4320_power(priv)); | ||
1864 | 1895 | ||
1865 | wrqu->txpower.flags = IW_TXPOW_MWATT; | 1896 | wrqu->txpower.flags = IW_TXPOW_MWATT; |
1866 | wrqu->txpower.value = le32_to_cpu(tx_power); | 1897 | wrqu->txpower.value = le32_to_cpu(tx_power); |
@@ -1873,7 +1904,7 @@ static int rndis_iw_get_txpower(struct net_device *dev, | |||
1873 | 1904 | ||
1874 | devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value); | 1905 | devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value); |
1875 | 1906 | ||
1876 | return ret; | 1907 | return 0; |
1877 | } | 1908 | } |
1878 | 1909 | ||
1879 | 1910 | ||
@@ -1883,7 +1914,6 @@ static int rndis_iw_set_txpower(struct net_device *dev, | |||
1883 | struct usbnet *usbdev = netdev_priv(dev); | 1914 | struct usbnet *usbdev = netdev_priv(dev); |
1884 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | 1915 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); |
1885 | __le32 tx_power = 0; | 1916 | __le32 tx_power = 0; |
1886 | int ret = 0; | ||
1887 | 1917 | ||
1888 | if (!wrqu->txpower.disabled) { | 1918 | if (!wrqu->txpower.disabled) { |
1889 | if (wrqu->txpower.flags == IW_TXPOW_MWATT) | 1919 | if (wrqu->txpower.flags == IW_TXPOW_MWATT) |
@@ -1906,22 +1936,10 @@ static int rndis_iw_set_txpower(struct net_device *dev, | |||
1906 | devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power)); | 1936 | devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power)); |
1907 | 1937 | ||
1908 | if (le32_to_cpu(tx_power) != 0) { | 1938 | if (le32_to_cpu(tx_power) != 0) { |
1909 | if (priv->caps & CAP_SUPPORT_TXPOWER) { | 1939 | /* txpower unsupported, just turn radio on */ |
1910 | /* turn radio on first */ | 1940 | if (!priv->radio_on) |
1911 | if (!priv->radio_on) | 1941 | return disassociate(usbdev, 1); |
1912 | disassociate(usbdev, 1); | 1942 | return 0; /* all ready on */ |
1913 | |||
1914 | ret = rndis_set_oid(usbdev, OID_802_11_TX_POWER_LEVEL, | ||
1915 | &tx_power, sizeof(tx_power)); | ||
1916 | if (ret != 0) | ||
1917 | ret = -EOPNOTSUPP; | ||
1918 | return ret; | ||
1919 | } else { | ||
1920 | /* txpower unsupported, just turn radio on */ | ||
1921 | if (!priv->radio_on) | ||
1922 | return disassociate(usbdev, 1); | ||
1923 | return 0; /* all ready on */ | ||
1924 | } | ||
1925 | } | 1943 | } |
1926 | 1944 | ||
1927 | /* tx_power == 0, turn off radio */ | 1945 | /* tx_power == 0, turn off radio */ |
@@ -2130,16 +2148,8 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) | |||
2130 | __le32 items[8]; | 2148 | __le32 items[8]; |
2131 | } networks_supported; | 2149 | } networks_supported; |
2132 | int len, retval, i, n; | 2150 | int len, retval, i, n; |
2133 | __le32 tx_power; | ||
2134 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | 2151 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); |
2135 | 2152 | ||
2136 | /* determine if supports setting txpower */ | ||
2137 | len = sizeof(tx_power); | ||
2138 | retval = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, &tx_power, | ||
2139 | &len); | ||
2140 | if (retval == 0 && le32_to_cpu(tx_power) != 0xFF) | ||
2141 | priv->caps |= CAP_SUPPORT_TXPOWER; | ||
2142 | |||
2143 | /* determine supported modes */ | 2153 | /* determine supported modes */ |
2144 | len = sizeof(networks_supported); | 2154 | len = sizeof(networks_supported); |
2145 | retval = rndis_query_oid(usbdev, OID_802_11_NETWORK_TYPES_SUPPORTED, | 2155 | retval = rndis_query_oid(usbdev, OID_802_11_NETWORK_TYPES_SUPPORTED, |
@@ -2275,7 +2285,17 @@ end: | |||
2275 | } | 2285 | } |
2276 | 2286 | ||
2277 | 2287 | ||
2278 | static int bcm4320_early_init(struct usbnet *usbdev) | 2288 | static int bcm4320a_early_init(struct usbnet *usbdev) |
2289 | { | ||
2290 | /* bcm4320a doesn't handle configuration parameters well. Try | ||
2291 | * set any and you get partially zeroed mac and broken device. | ||
2292 | */ | ||
2293 | |||
2294 | return 0; | ||
2295 | } | ||
2296 | |||
2297 | |||
2298 | static int bcm4320b_early_init(struct usbnet *usbdev) | ||
2279 | { | 2299 | { |
2280 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | 2300 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); |
2281 | char buf[8]; | 2301 | char buf[8]; |
@@ -2515,7 +2535,7 @@ static const struct driver_info bcm4320b_info = { | |||
2515 | .rx_fixup = rndis_rx_fixup, | 2535 | .rx_fixup = rndis_rx_fixup, |
2516 | .tx_fixup = rndis_tx_fixup, | 2536 | .tx_fixup = rndis_tx_fixup, |
2517 | .reset = rndis_wext_reset, | 2537 | .reset = rndis_wext_reset, |
2518 | .early_init = bcm4320_early_init, | 2538 | .early_init = bcm4320b_early_init, |
2519 | .link_change = rndis_wext_link_change, | 2539 | .link_change = rndis_wext_link_change, |
2520 | }; | 2540 | }; |
2521 | 2541 | ||
@@ -2528,7 +2548,7 @@ static const struct driver_info bcm4320a_info = { | |||
2528 | .rx_fixup = rndis_rx_fixup, | 2548 | .rx_fixup = rndis_rx_fixup, |
2529 | .tx_fixup = rndis_tx_fixup, | 2549 | .tx_fixup = rndis_tx_fixup, |
2530 | .reset = rndis_wext_reset, | 2550 | .reset = rndis_wext_reset, |
2531 | .early_init = bcm4320_early_init, | 2551 | .early_init = bcm4320a_early_init, |
2532 | .link_change = rndis_wext_link_change, | 2552 | .link_change = rndis_wext_link_change, |
2533 | }; | 2553 | }; |
2534 | 2554 | ||
@@ -2541,7 +2561,7 @@ static const struct driver_info rndis_wext_info = { | |||
2541 | .rx_fixup = rndis_rx_fixup, | 2561 | .rx_fixup = rndis_rx_fixup, |
2542 | .tx_fixup = rndis_tx_fixup, | 2562 | .tx_fixup = rndis_tx_fixup, |
2543 | .reset = rndis_wext_reset, | 2563 | .reset = rndis_wext_reset, |
2544 | .early_init = bcm4320_early_init, | 2564 | .early_init = bcm4320a_early_init, |
2545 | .link_change = rndis_wext_link_change, | 2565 | .link_change = rndis_wext_link_change, |
2546 | }; | 2566 | }; |
2547 | 2567 | ||