diff options
author | Hante Meuleman <meuleman@broadcom.com> | 2014-12-21 06:43:49 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-01-06 13:28:53 -0500 |
commit | 118eb304d0554fbeab8567410bbece5bae533c23 (patch) | |
tree | 979d40093395d34913c537f803002e8a902e4021 /drivers/net/wireless/brcm80211 | |
parent | f714e58e19a567cc2659ea4645748ba06e3849a7 (diff) |
brcmfmac: Fix WEP configuration for AP mode.
When a device is configured for AP mode and it is configured for
WEP then the keys are plumbed first, followed by AP configuration.
During configuration a down command is given to the firmware which
will clear the configured keys. This patch reprograms the WEP keys
after AP has been brought up.
Reviewed-by: Arend Van Spriel <arend@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/brcm80211')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 95 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/core.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/core.h | 4 |
4 files changed, 76 insertions, 30 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 3aecc5f48719..11725518d19a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | |||
@@ -452,16 +452,16 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key, | |||
452 | } | 452 | } |
453 | 453 | ||
454 | static int | 454 | static int |
455 | send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key) | 455 | send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key) |
456 | { | 456 | { |
457 | int err; | 457 | int err; |
458 | struct brcmf_wsec_key_le key_le; | 458 | struct brcmf_wsec_key_le key_le; |
459 | 459 | ||
460 | convert_key_from_CPU(key, &key_le); | 460 | convert_key_from_CPU(key, &key_le); |
461 | 461 | ||
462 | brcmf_netdev_wait_pend8021x(ndev); | 462 | brcmf_netdev_wait_pend8021x(ifp); |
463 | 463 | ||
464 | err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le, | 464 | err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le, |
465 | sizeof(key_le)); | 465 | sizeof(key_le)); |
466 | 466 | ||
467 | if (err) | 467 | if (err) |
@@ -1670,7 +1670,7 @@ brcmf_set_sharedkey(struct net_device *ndev, | |||
1670 | brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n", | 1670 | brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n", |
1671 | key.len, key.index, key.algo); | 1671 | key.len, key.index, key.algo); |
1672 | brcmf_dbg(CONN, "key \"%s\"\n", key.data); | 1672 | brcmf_dbg(CONN, "key \"%s\"\n", key.data); |
1673 | err = send_key_to_dongle(ndev, &key); | 1673 | err = send_key_to_dongle(netdev_priv(ndev), &key); |
1674 | if (err) | 1674 | if (err) |
1675 | return err; | 1675 | return err; |
1676 | 1676 | ||
@@ -2052,7 +2052,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, | |||
2052 | /* check for key index change */ | 2052 | /* check for key index change */ |
2053 | if (key.len == 0) { | 2053 | if (key.len == 0) { |
2054 | /* key delete */ | 2054 | /* key delete */ |
2055 | err = send_key_to_dongle(ndev, &key); | 2055 | err = send_key_to_dongle(ifp, &key); |
2056 | if (err) | 2056 | if (err) |
2057 | brcmf_err("key delete error (%d)\n", err); | 2057 | brcmf_err("key delete error (%d)\n", err); |
2058 | } else { | 2058 | } else { |
@@ -2108,7 +2108,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, | |||
2108 | brcmf_err("Invalid cipher (0x%x)\n", params->cipher); | 2108 | brcmf_err("Invalid cipher (0x%x)\n", params->cipher); |
2109 | return -EINVAL; | 2109 | return -EINVAL; |
2110 | } | 2110 | } |
2111 | err = send_key_to_dongle(ndev, &key); | 2111 | err = send_key_to_dongle(ifp, &key); |
2112 | if (err) | 2112 | if (err) |
2113 | brcmf_err("wsec_key error (%d)\n", err); | 2113 | brcmf_err("wsec_key error (%d)\n", err); |
2114 | } | 2114 | } |
@@ -2121,7 +2121,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
2121 | struct key_params *params) | 2121 | struct key_params *params) |
2122 | { | 2122 | { |
2123 | struct brcmf_if *ifp = netdev_priv(ndev); | 2123 | struct brcmf_if *ifp = netdev_priv(ndev); |
2124 | struct brcmf_wsec_key key; | 2124 | struct brcmf_wsec_key *key; |
2125 | s32 val; | 2125 | s32 val; |
2126 | s32 wsec; | 2126 | s32 wsec; |
2127 | s32 err = 0; | 2127 | s32 err = 0; |
@@ -2132,54 +2132,62 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
2132 | if (!check_vif_up(ifp->vif)) | 2132 | if (!check_vif_up(ifp->vif)) |
2133 | return -EIO; | 2133 | return -EIO; |
2134 | 2134 | ||
2135 | if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { | ||
2136 | /* we ignore this key index in this case */ | ||
2137 | brcmf_err("invalid key index (%d)\n", key_idx); | ||
2138 | return -EINVAL; | ||
2139 | } | ||
2140 | |||
2135 | if (mac_addr && | 2141 | if (mac_addr && |
2136 | (params->cipher != WLAN_CIPHER_SUITE_WEP40) && | 2142 | (params->cipher != WLAN_CIPHER_SUITE_WEP40) && |
2137 | (params->cipher != WLAN_CIPHER_SUITE_WEP104)) { | 2143 | (params->cipher != WLAN_CIPHER_SUITE_WEP104)) { |
2138 | brcmf_dbg(TRACE, "Exit"); | 2144 | brcmf_dbg(TRACE, "Exit"); |
2139 | return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); | 2145 | return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); |
2140 | } | 2146 | } |
2141 | memset(&key, 0, sizeof(key)); | ||
2142 | 2147 | ||
2143 | key.len = (u32) params->key_len; | 2148 | key = &ifp->vif->profile.key[key_idx]; |
2144 | key.index = (u32) key_idx; | 2149 | memset(key, 0, sizeof(*key)); |
2145 | 2150 | ||
2146 | if (key.len > sizeof(key.data)) { | 2151 | if (params->key_len > sizeof(key->data)) { |
2147 | brcmf_err("Too long key length (%u)\n", key.len); | 2152 | brcmf_err("Too long key length (%u)\n", params->key_len); |
2148 | err = -EINVAL; | 2153 | err = -EINVAL; |
2149 | goto done; | 2154 | goto done; |
2150 | } | 2155 | } |
2151 | memcpy(key.data, params->key, key.len); | 2156 | key->len = params->key_len; |
2157 | key->index = key_idx; | ||
2152 | 2158 | ||
2153 | key.flags = BRCMF_PRIMARY_KEY; | 2159 | memcpy(key->data, params->key, key->len); |
2160 | |||
2161 | key->flags = BRCMF_PRIMARY_KEY; | ||
2154 | switch (params->cipher) { | 2162 | switch (params->cipher) { |
2155 | case WLAN_CIPHER_SUITE_WEP40: | 2163 | case WLAN_CIPHER_SUITE_WEP40: |
2156 | key.algo = CRYPTO_ALGO_WEP1; | 2164 | key->algo = CRYPTO_ALGO_WEP1; |
2157 | val = WEP_ENABLED; | 2165 | val = WEP_ENABLED; |
2158 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n"); | 2166 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n"); |
2159 | break; | 2167 | break; |
2160 | case WLAN_CIPHER_SUITE_WEP104: | 2168 | case WLAN_CIPHER_SUITE_WEP104: |
2161 | key.algo = CRYPTO_ALGO_WEP128; | 2169 | key->algo = CRYPTO_ALGO_WEP128; |
2162 | val = WEP_ENABLED; | 2170 | val = WEP_ENABLED; |
2163 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); | 2171 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); |
2164 | break; | 2172 | break; |
2165 | case WLAN_CIPHER_SUITE_TKIP: | 2173 | case WLAN_CIPHER_SUITE_TKIP: |
2166 | if (!brcmf_is_apmode(ifp->vif)) { | 2174 | if (!brcmf_is_apmode(ifp->vif)) { |
2167 | brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); | 2175 | brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); |
2168 | memcpy(keybuf, &key.data[24], sizeof(keybuf)); | 2176 | memcpy(keybuf, &key->data[24], sizeof(keybuf)); |
2169 | memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); | 2177 | memcpy(&key->data[24], &key->data[16], sizeof(keybuf)); |
2170 | memcpy(&key.data[16], keybuf, sizeof(keybuf)); | 2178 | memcpy(&key->data[16], keybuf, sizeof(keybuf)); |
2171 | } | 2179 | } |
2172 | key.algo = CRYPTO_ALGO_TKIP; | 2180 | key->algo = CRYPTO_ALGO_TKIP; |
2173 | val = TKIP_ENABLED; | 2181 | val = TKIP_ENABLED; |
2174 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); | 2182 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); |
2175 | break; | 2183 | break; |
2176 | case WLAN_CIPHER_SUITE_AES_CMAC: | 2184 | case WLAN_CIPHER_SUITE_AES_CMAC: |
2177 | key.algo = CRYPTO_ALGO_AES_CCM; | 2185 | key->algo = CRYPTO_ALGO_AES_CCM; |
2178 | val = AES_ENABLED; | 2186 | val = AES_ENABLED; |
2179 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); | 2187 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); |
2180 | break; | 2188 | break; |
2181 | case WLAN_CIPHER_SUITE_CCMP: | 2189 | case WLAN_CIPHER_SUITE_CCMP: |
2182 | key.algo = CRYPTO_ALGO_AES_CCM; | 2190 | key->algo = CRYPTO_ALGO_AES_CCM; |
2183 | val = AES_ENABLED; | 2191 | val = AES_ENABLED; |
2184 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n"); | 2192 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n"); |
2185 | break; | 2193 | break; |
@@ -2189,7 +2197,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
2189 | goto done; | 2197 | goto done; |
2190 | } | 2198 | } |
2191 | 2199 | ||
2192 | err = send_key_to_dongle(ndev, &key); | 2200 | err = send_key_to_dongle(ifp, key); |
2193 | if (err) | 2201 | if (err) |
2194 | goto done; | 2202 | goto done; |
2195 | 2203 | ||
@@ -2222,7 +2230,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, | |||
2222 | if (!check_vif_up(ifp->vif)) | 2230 | if (!check_vif_up(ifp->vif)) |
2223 | return -EIO; | 2231 | return -EIO; |
2224 | 2232 | ||
2225 | if (key_idx >= DOT11_MAX_DEFAULT_KEYS) { | 2233 | if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { |
2226 | /* we ignore this key index in this case */ | 2234 | /* we ignore this key index in this case */ |
2227 | brcmf_err("invalid key index (%d)\n", key_idx); | 2235 | brcmf_err("invalid key index (%d)\n", key_idx); |
2228 | return -EINVAL; | 2236 | return -EINVAL; |
@@ -2237,7 +2245,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, | |||
2237 | brcmf_dbg(CONN, "key index (%d)\n", key_idx); | 2245 | brcmf_dbg(CONN, "key index (%d)\n", key_idx); |
2238 | 2246 | ||
2239 | /* Set the new key/index */ | 2247 | /* Set the new key/index */ |
2240 | err = send_key_to_dongle(ndev, &key); | 2248 | err = send_key_to_dongle(ifp, &key); |
2241 | 2249 | ||
2242 | brcmf_dbg(TRACE, "Exit\n"); | 2250 | brcmf_dbg(TRACE, "Exit\n"); |
2243 | return err; | 2251 | return err; |
@@ -2305,6 +2313,39 @@ brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, | |||
2305 | return -EOPNOTSUPP; | 2313 | return -EOPNOTSUPP; |
2306 | } | 2314 | } |
2307 | 2315 | ||
2316 | static void | ||
2317 | brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp) | ||
2318 | { | ||
2319 | s32 err; | ||
2320 | u8 key_idx; | ||
2321 | struct brcmf_wsec_key *key; | ||
2322 | s32 wsec; | ||
2323 | |||
2324 | for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) { | ||
2325 | key = &ifp->vif->profile.key[key_idx]; | ||
2326 | if ((key->algo == CRYPTO_ALGO_WEP1) || | ||
2327 | (key->algo == CRYPTO_ALGO_WEP128)) | ||
2328 | break; | ||
2329 | } | ||
2330 | if (key_idx == BRCMF_MAX_DEFAULT_KEYS) | ||
2331 | return; | ||
2332 | |||
2333 | err = send_key_to_dongle(ifp, key); | ||
2334 | if (err) { | ||
2335 | brcmf_err("Setting WEP key failed (%d)\n", err); | ||
2336 | return; | ||
2337 | } | ||
2338 | err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); | ||
2339 | if (err) { | ||
2340 | brcmf_err("get wsec error (%d)\n", err); | ||
2341 | return; | ||
2342 | } | ||
2343 | wsec |= WEP_ENABLED; | ||
2344 | err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec); | ||
2345 | if (err) | ||
2346 | brcmf_err("set wsec error (%d)\n", err); | ||
2347 | } | ||
2348 | |||
2308 | static s32 | 2349 | static s32 |
2309 | brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, | 2350 | brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, |
2310 | const u8 *mac, struct station_info *sinfo) | 2351 | const u8 *mac, struct station_info *sinfo) |
@@ -4057,6 +4098,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
4057 | brcmf_err("BRCMF_C_UP error (%d)\n", err); | 4098 | brcmf_err("BRCMF_C_UP error (%d)\n", err); |
4058 | goto exit; | 4099 | goto exit; |
4059 | } | 4100 | } |
4101 | /* On DOWN the firmware removes the WEP keys, reconfigure | ||
4102 | * them if they were set. | ||
4103 | */ | ||
4104 | brcmf_cfg80211_reconfigure_wep(ifp); | ||
4060 | 4105 | ||
4061 | memset(&join_params, 0, sizeof(join_params)); | 4106 | memset(&join_params, 0, sizeof(join_params)); |
4062 | /* join parameters starts with ssid */ | 4107 | /* join parameters starts with ssid */ |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h index 9e98b8d52757..a5242af9da4c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h | |||
@@ -75,6 +75,8 @@ | |||
75 | 75 | ||
76 | #define BRCMF_VNDR_IE_P2PAF_SHIFT 12 | 76 | #define BRCMF_VNDR_IE_P2PAF_SHIFT 12 |
77 | 77 | ||
78 | #define BRCMF_MAX_DEFAULT_KEYS 4 | ||
79 | |||
78 | 80 | ||
79 | /** | 81 | /** |
80 | * enum brcmf_scan_status - scan engine status | 82 | * enum brcmf_scan_status - scan engine status |
@@ -125,11 +127,13 @@ struct brcmf_cfg80211_security { | |||
125 | * @ssid: ssid of associated/associating ap. | 127 | * @ssid: ssid of associated/associating ap. |
126 | * @bssid: bssid of joined/joining ibss. | 128 | * @bssid: bssid of joined/joining ibss. |
127 | * @sec: security information. | 129 | * @sec: security information. |
130 | * @key: key information | ||
128 | */ | 131 | */ |
129 | struct brcmf_cfg80211_profile { | 132 | struct brcmf_cfg80211_profile { |
130 | struct brcmf_ssid ssid; | 133 | struct brcmf_ssid ssid; |
131 | u8 bssid[ETH_ALEN]; | 134 | u8 bssid[ETH_ALEN]; |
132 | struct brcmf_cfg80211_security sec; | 135 | struct brcmf_cfg80211_security sec; |
136 | struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS]; | ||
133 | }; | 137 | }; |
134 | 138 | ||
135 | /** | 139 | /** |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index effe6d7831d9..e2a9e33f71ab 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c | |||
@@ -1093,9 +1093,8 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp) | |||
1093 | return atomic_read(&ifp->pend_8021x_cnt); | 1093 | return atomic_read(&ifp->pend_8021x_cnt); |
1094 | } | 1094 | } |
1095 | 1095 | ||
1096 | int brcmf_netdev_wait_pend8021x(struct net_device *ndev) | 1096 | int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp) |
1097 | { | 1097 | { |
1098 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
1099 | int err; | 1098 | int err; |
1100 | 1099 | ||
1101 | err = wait_event_timeout(ifp->pend_8021x_wait, | 1100 | err = wait_event_timeout(ifp->pend_8021x_wait, |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index 23f74b139cc8..f2f7d3d1a8ef 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h | |||
@@ -29,8 +29,6 @@ | |||
29 | /* For supporting multiple interfaces */ | 29 | /* For supporting multiple interfaces */ |
30 | #define BRCMF_MAX_IFS 16 | 30 | #define BRCMF_MAX_IFS 16 |
31 | 31 | ||
32 | #define DOT11_MAX_DEFAULT_KEYS 4 | ||
33 | |||
34 | /* Small, medium and maximum buffer size for dcmd | 32 | /* Small, medium and maximum buffer size for dcmd |
35 | */ | 33 | */ |
36 | #define BRCMF_DCMD_SMLEN 256 | 34 | #define BRCMF_DCMD_SMLEN 256 |
@@ -167,7 +165,7 @@ struct brcmf_skb_reorder_data { | |||
167 | u8 *reorder; | 165 | u8 *reorder; |
168 | }; | 166 | }; |
169 | 167 | ||
170 | int brcmf_netdev_wait_pend8021x(struct net_device *ndev); | 168 | int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp); |
171 | 169 | ||
172 | /* Return pointer to interface name */ | 170 | /* Return pointer to interface name */ |
173 | char *brcmf_ifname(struct brcmf_pub *drvr, int idx); | 171 | char *brcmf_ifname(struct brcmf_pub *drvr, int idx); |