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

Commit 9ed74ba0 authored by David Gnedt's avatar David Gnedt Committed by John W. Linville
Browse files

wl1251: implement multicast address filtering (fwd)



Port multicast address filtering from wl1271 driver.
It sets up the hardware multicast address filter in configure_filter() with
addresses supplied through prepare_multicast().

Signed-off-by: default avatarDavid Gnedt <david.gnedt@davizone.at>
Signed-off-by: default avatarPali Rohár <pali.rohar@gmail.com>
Signed-off-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 4d09b537
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -381,7 +381,8 @@ out:
	return ret;
}

int wl1251_acx_group_address_tbl(struct wl1251 *wl)
int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable,
				 void *mc_list, u32 mc_list_len)
{
	struct acx_dot11_grp_addr_tbl *acx;
	int ret;
@@ -393,9 +394,9 @@ int wl1251_acx_group_address_tbl(struct wl1251 *wl)
		return -ENOMEM;

	/* MAC filtering */
	acx->enabled = 0;
	acx->num_groups = 0;
	memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
	acx->enabled = enable;
	acx->num_groups = mc_list_len;
	memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);

	ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
				   acx, sizeof(*acx));
+5 −4
Original line number Diff line number Diff line
@@ -350,8 +350,8 @@ struct acx_slot {
} __packed;


#define ADDRESS_GROUP_MAX	(8)
#define ADDRESS_GROUP_MAX_LEN	(ETH_ALEN * ADDRESS_GROUP_MAX)
#define ACX_MC_ADDRESS_GROUP_MAX	(8)
#define ACX_MC_ADDRESS_GROUP_MAX_LEN	(ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX)

struct acx_dot11_grp_addr_tbl {
	struct acx_header header;
@@ -359,7 +359,7 @@ struct acx_dot11_grp_addr_tbl {
	u8 enabled;
	u8 num_groups;
	u8 pad[2];
	u8 mac_table[ADDRESS_GROUP_MAX_LEN];
	u8 mac_table[ACX_MC_ADDRESS_GROUP_MAX_LEN];
} __packed;


@@ -1463,7 +1463,8 @@ int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time);
int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter);
int wl1251_acx_pd_threshold(struct wl1251 *wl);
int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time);
int wl1251_acx_group_address_tbl(struct wl1251 *wl);
int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable,
				 void *mc_list, u32 mc_list_len);
int wl1251_acx_service_period_timeout(struct wl1251 *wl);
int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold);
int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter);
+1 −1
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ int wl1251_hw_init_phy_config(struct wl1251 *wl)
	if (ret < 0)
		return ret;

	ret = wl1251_acx_group_address_tbl(wl);
	ret = wl1251_acx_group_address_tbl(wl, true, NULL, 0);
	if (ret < 0)
		return ret;

+55 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/etherdevice.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/netdevice.h>

#include "wl1251.h"
#include "wl12xx_80211.h"
@@ -677,6 +678,44 @@ out:
	return ret;
}

struct wl1251_filter_params {
	bool enabled;
	int mc_list_length;
	u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
};

static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw,
				       struct netdev_hw_addr_list *mc_list)
{
	struct wl1251_filter_params *fp;
	struct netdev_hw_addr *ha;
	struct wl1251 *wl = hw->priv;

	if (unlikely(wl->state == WL1251_STATE_OFF))
		return 0;

	fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
	if (!fp) {
		wl1251_error("Out of memory setting filters.");
		return 0;
	}

	/* update multicast filtering parameters */
	fp->mc_list_length = 0;
	if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
		fp->enabled = false;
	} else {
		fp->enabled = true;
		netdev_hw_addr_list_for_each(ha, mc_list) {
			memcpy(fp->mc_list[fp->mc_list_length],
					ha->addr, ETH_ALEN);
			fp->mc_list_length++;
		}
	}

	return (u64)(unsigned long)fp;
}

#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
				  FIF_ALLMULTI | \
				  FIF_FCSFAIL | \
@@ -689,6 +728,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
				       unsigned int changed,
				       unsigned int *total, u64 multicast)
{
	struct wl1251_filter_params *fp = (void *)(unsigned long)multicast;
	struct wl1251 *wl = hw->priv;
	int ret;

@@ -697,9 +737,11 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
	*total &= WL1251_SUPPORTED_FILTERS;
	changed &= WL1251_SUPPORTED_FILTERS;

	if (changed == 0)
	if (changed == 0) {
		/* no filters which we support changed */
		kfree(fp);
		return;
	}

	mutex_lock(&wl->mutex);

@@ -736,6 +778,15 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
	if (ret < 0)
		goto out;

	if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS)
		ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0);
	else if (fp)
		ret = wl1251_acx_group_address_tbl(wl, fp->enabled,
						   fp->mc_list,
						   fp->mc_list_length);
	if (ret < 0)
		goto out;

	/* send filters to firmware */
	wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter);

@@ -743,6 +794,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,

out:
	mutex_unlock(&wl->mutex);
	kfree(fp);
}

/* HW encryption */
@@ -1282,6 +1334,7 @@ static const struct ieee80211_ops wl1251_ops = {
	.add_interface = wl1251_op_add_interface,
	.remove_interface = wl1251_op_remove_interface,
	.config = wl1251_op_config,
	.prepare_multicast = wl1251_op_prepare_multicast,
	.configure_filter = wl1251_op_configure_filter,
	.tx = wl1251_op_tx,
	.set_key = wl1251_op_set_key,
+1 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ enum {
	} while (0)

#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN |	\
				  CFG_MC_FILTER_EN |	\
				  CFG_BSSID_FILTER_EN)

#define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN |  \