Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 118eb304 authored by Hante Meuleman's avatar Hante Meuleman Committed by Kalle Valo
Browse files

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: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent f714e58e
Loading
Loading
Loading
Loading
+70 −25
Original line number Original line Diff line number Diff line
@@ -452,16 +452,16 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key,
}
}


static int
static int
send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
{
{
	int err;
	int err;
	struct brcmf_wsec_key_le key_le;
	struct brcmf_wsec_key_le key_le;


	convert_key_from_CPU(key, &key_le);
	convert_key_from_CPU(key, &key_le);


	brcmf_netdev_wait_pend8021x(ndev);
	brcmf_netdev_wait_pend8021x(ifp);


	err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
	err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
					sizeof(key_le));
					sizeof(key_le));


	if (err)
	if (err)
@@ -1670,7 +1670,7 @@ brcmf_set_sharedkey(struct net_device *ndev,
	brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
	brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
		  key.len, key.index, key.algo);
		  key.len, key.index, key.algo);
	brcmf_dbg(CONN, "key \"%s\"\n", key.data);
	brcmf_dbg(CONN, "key \"%s\"\n", key.data);
	err = send_key_to_dongle(ndev, &key);
	err = send_key_to_dongle(netdev_priv(ndev), &key);
	if (err)
	if (err)
		return err;
		return err;


@@ -2052,7 +2052,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
	/* check for key index change */
	/* check for key index change */
	if (key.len == 0) {
	if (key.len == 0) {
		/* key delete */
		/* key delete */
		err = send_key_to_dongle(ndev, &key);
		err = send_key_to_dongle(ifp, &key);
		if (err)
		if (err)
			brcmf_err("key delete error (%d)\n", err);
			brcmf_err("key delete error (%d)\n", err);
	} else {
	} else {
@@ -2108,7 +2108,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
			brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
			brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
			return -EINVAL;
			return -EINVAL;
		}
		}
		err = send_key_to_dongle(ndev, &key);
		err = send_key_to_dongle(ifp, &key);
		if (err)
		if (err)
			brcmf_err("wsec_key error (%d)\n", err);
			brcmf_err("wsec_key error (%d)\n", err);
	}
	}
@@ -2121,7 +2121,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
		    struct key_params *params)
		    struct key_params *params)
{
{
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_wsec_key key;
	struct brcmf_wsec_key *key;
	s32 val;
	s32 val;
	s32 wsec;
	s32 wsec;
	s32 err = 0;
	s32 err = 0;
@@ -2132,54 +2132,62 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
	if (!check_vif_up(ifp->vif))
	if (!check_vif_up(ifp->vif))
		return -EIO;
		return -EIO;


	if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
		/* we ignore this key index in this case */
		brcmf_err("invalid key index (%d)\n", key_idx);
		return -EINVAL;
	}

	if (mac_addr &&
	if (mac_addr &&
		(params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
		(params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
		(params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
		(params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
		brcmf_dbg(TRACE, "Exit");
		brcmf_dbg(TRACE, "Exit");
		return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
		return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
	}
	}
	memset(&key, 0, sizeof(key));


	key.len = (u32) params->key_len;
	key = &ifp->vif->profile.key[key_idx];
	key.index = (u32) key_idx;
	memset(key, 0, sizeof(*key));


	if (key.len > sizeof(key.data)) {
	if (params->key_len > sizeof(key->data)) {
		brcmf_err("Too long key length (%u)\n", key.len);
		brcmf_err("Too long key length (%u)\n", params->key_len);
		err = -EINVAL;
		err = -EINVAL;
		goto done;
		goto done;
	}
	}
	memcpy(key.data, params->key, key.len);
	key->len = params->key_len;
	key->index = key_idx;


	key.flags = BRCMF_PRIMARY_KEY;
	memcpy(key->data, params->key, key->len);

	key->flags = BRCMF_PRIMARY_KEY;
	switch (params->cipher) {
	switch (params->cipher) {
	case WLAN_CIPHER_SUITE_WEP40:
	case WLAN_CIPHER_SUITE_WEP40:
		key.algo = CRYPTO_ALGO_WEP1;
		key->algo = CRYPTO_ALGO_WEP1;
		val = WEP_ENABLED;
		val = WEP_ENABLED;
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
		break;
		break;
	case WLAN_CIPHER_SUITE_WEP104:
	case WLAN_CIPHER_SUITE_WEP104:
		key.algo = CRYPTO_ALGO_WEP128;
		key->algo = CRYPTO_ALGO_WEP128;
		val = WEP_ENABLED;
		val = WEP_ENABLED;
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
		break;
		break;
	case WLAN_CIPHER_SUITE_TKIP:
	case WLAN_CIPHER_SUITE_TKIP:
		if (!brcmf_is_apmode(ifp->vif)) {
		if (!brcmf_is_apmode(ifp->vif)) {
			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
			memcpy(keybuf, &key.data[24], sizeof(keybuf));
			memcpy(keybuf, &key->data[24], sizeof(keybuf));
			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
			memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
			memcpy(&key.data[16], keybuf, sizeof(keybuf));
			memcpy(&key->data[16], keybuf, sizeof(keybuf));
		}
		}
		key.algo = CRYPTO_ALGO_TKIP;
		key->algo = CRYPTO_ALGO_TKIP;
		val = TKIP_ENABLED;
		val = TKIP_ENABLED;
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
		break;
		break;
	case WLAN_CIPHER_SUITE_AES_CMAC:
	case WLAN_CIPHER_SUITE_AES_CMAC:
		key.algo = CRYPTO_ALGO_AES_CCM;
		key->algo = CRYPTO_ALGO_AES_CCM;
		val = AES_ENABLED;
		val = AES_ENABLED;
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
		break;
		break;
	case WLAN_CIPHER_SUITE_CCMP:
	case WLAN_CIPHER_SUITE_CCMP:
		key.algo = CRYPTO_ALGO_AES_CCM;
		key->algo = CRYPTO_ALGO_AES_CCM;
		val = AES_ENABLED;
		val = AES_ENABLED;
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
		break;
		break;
@@ -2189,7 +2197,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
		goto done;
		goto done;
	}
	}


	err = send_key_to_dongle(ndev, &key);
	err = send_key_to_dongle(ifp, key);
	if (err)
	if (err)
		goto done;
		goto done;


@@ -2222,7 +2230,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
	if (!check_vif_up(ifp->vif))
	if (!check_vif_up(ifp->vif))
		return -EIO;
		return -EIO;


	if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
	if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
		/* we ignore this key index in this case */
		/* we ignore this key index in this case */
		brcmf_err("invalid key index (%d)\n", key_idx);
		brcmf_err("invalid key index (%d)\n", key_idx);
		return -EINVAL;
		return -EINVAL;
@@ -2237,7 +2245,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);


	/* Set the new key/index */
	/* Set the new key/index */
	err = send_key_to_dongle(ndev, &key);
	err = send_key_to_dongle(ifp, &key);


	brcmf_dbg(TRACE, "Exit\n");
	brcmf_dbg(TRACE, "Exit\n");
	return err;
	return err;
@@ -2305,6 +2313,39 @@ brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
	return -EOPNOTSUPP;
	return -EOPNOTSUPP;
}
}


static void
brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
{
	s32 err;
	u8 key_idx;
	struct brcmf_wsec_key *key;
	s32 wsec;

	for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
		key = &ifp->vif->profile.key[key_idx];
		if ((key->algo == CRYPTO_ALGO_WEP1) ||
		    (key->algo == CRYPTO_ALGO_WEP128))
			break;
	}
	if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
		return;

	err = send_key_to_dongle(ifp, key);
	if (err) {
		brcmf_err("Setting WEP key failed (%d)\n", err);
		return;
	}
	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
	if (err) {
		brcmf_err("get wsec error (%d)\n", err);
		return;
	}
	wsec |= WEP_ENABLED;
	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
	if (err)
		brcmf_err("set wsec error (%d)\n", err);
}

static s32
static s32
brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
			   const u8 *mac, struct station_info *sinfo)
			   const u8 *mac, struct station_info *sinfo)
@@ -4057,6 +4098,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
			brcmf_err("BRCMF_C_UP error (%d)\n", err);
			brcmf_err("BRCMF_C_UP error (%d)\n", err);
			goto exit;
			goto exit;
		}
		}
		/* On DOWN the firmware removes the WEP keys, reconfigure
		 * them if they were set.
		 */
		brcmf_cfg80211_reconfigure_wep(ifp);


		memset(&join_params, 0, sizeof(join_params));
		memset(&join_params, 0, sizeof(join_params));
		/* join parameters starts with ssid */
		/* join parameters starts with ssid */
+4 −0
Original line number Original line Diff line number Diff line
@@ -75,6 +75,8 @@


#define BRCMF_VNDR_IE_P2PAF_SHIFT	12
#define BRCMF_VNDR_IE_P2PAF_SHIFT	12


#define BRCMF_MAX_DEFAULT_KEYS		4



/**
/**
 * enum brcmf_scan_status - scan engine status
 * enum brcmf_scan_status - scan engine status
@@ -125,11 +127,13 @@ struct brcmf_cfg80211_security {
 * @ssid: ssid of associated/associating ap.
 * @ssid: ssid of associated/associating ap.
 * @bssid: bssid of joined/joining ibss.
 * @bssid: bssid of joined/joining ibss.
 * @sec: security information.
 * @sec: security information.
 * @key: key information
 */
 */
struct brcmf_cfg80211_profile {
struct brcmf_cfg80211_profile {
	struct brcmf_ssid ssid;
	struct brcmf_ssid ssid;
	u8 bssid[ETH_ALEN];
	u8 bssid[ETH_ALEN];
	struct brcmf_cfg80211_security sec;
	struct brcmf_cfg80211_security sec;
	struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS];
};
};


/**
/**
+1 −2
Original line number Original line Diff line number Diff line
@@ -1093,9 +1093,8 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
	return atomic_read(&ifp->pend_8021x_cnt);
	return atomic_read(&ifp->pend_8021x_cnt);
}
}


int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp)
{
{
	struct brcmf_if *ifp = netdev_priv(ndev);
	int err;
	int err;


	err = wait_event_timeout(ifp->pend_8021x_wait,
	err = wait_event_timeout(ifp->pend_8021x_wait,
+1 −3
Original line number Original line Diff line number Diff line
@@ -29,8 +29,6 @@
/* For supporting multiple interfaces */
/* For supporting multiple interfaces */
#define BRCMF_MAX_IFS	16
#define BRCMF_MAX_IFS	16


#define DOT11_MAX_DEFAULT_KEYS	4

/* Small, medium and maximum buffer size for dcmd
/* Small, medium and maximum buffer size for dcmd
 */
 */
#define BRCMF_DCMD_SMLEN	256
#define BRCMF_DCMD_SMLEN	256
@@ -167,7 +165,7 @@ struct brcmf_skb_reorder_data {
	u8 *reorder;
	u8 *reorder;
};
};


int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);


/* Return pointer to interface name */
/* Return pointer to interface name */
char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
char *brcmf_ifname(struct brcmf_pub *drvr, int idx);