[PATCH stable] Separate multicast configuration for mesh and wlan interfaces.

javier at cozybit.com javier at cozybit.com
Sat May 10 00:00:54 EDT 2008


Each device maintains its own list of bound multicast addresses.  Those lists
are merged and purged from duplicate addresses before being sent to firmware.
The maximum number of multicast addresses per virtual device has been cut in
half to ensure that the merged list can be accommodated by the hardware.

Also, configuration flags are ORed before being sent to firmware, which
appears to be the least conflicting way of combining two virtual operating
modes into one for a single physical device.

Based on patches from Ashish Shukla and David Woodhouse.

Signed-off-by: Javier Cardona <javier at cozybit.com>
Tested by: Ricardo Carrano <carrano at ricardocarrano.com>

---
 drivers/net/wireless/libertas/cmd.c  |   58 ++++++++++++++++++--
 drivers/net/wireless/libertas/defs.h |    2 +
 drivers/net/wireless/libertas/dev.h  |    9 +++-
 drivers/net/wireless/libertas/main.c |  100 +++++++++++++++++++---------------
 4 files changed, 117 insertions(+), 52 deletions(-)

diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 0ae9851..a3cb4bd 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -814,21 +814,67 @@ static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
 				      u16 cmd_action)
 {
 	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
+	u8 *mc_list_ptr = pMCastAdr->maclist;
+	u32 mc_count = 0, i, j, m, w;
+	DECLARE_MAC_BUF(mac);
+	int mesh_nr_mcastaddr, wlan_nr_mcastaddr;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
 			     S_DS_GEN);
 	cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
-
-	lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
 	pMCastAdr->action = cpu_to_le16(cmd_action);
-	pMCastAdr->nr_of_adrs =
-	    cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
-	memcpy(pMCastAdr->maclist, priv->multicastlist,
-	       priv->nr_of_multicastmacaddr * ETH_ALEN);
 
+	/* There are two multicast address lists in priv.  Combine them into
+	 * one before sending to firmware.
+	 */
+	m = MESH_MCAST_FILTER;
+	w = WLAN_MCAST_FILTER;
+
+	/* Only include addresses for interfaces that are up */
+	wlan_nr_mcastaddr = (priv->dev->flags & IFF_UP) ?
+		priv->nr_of_multicastmacaddr[w] : 0;
+
+	mesh_nr_mcastaddr =
+		(priv->mesh_dev && priv->mesh_dev->flags & IFF_UP) ?
+		priv->nr_of_multicastmacaddr[m] : 0;
+
+	for (i = 0; i < wlan_nr_mcastaddr; i++) {
+		/* Skip duplicate address */
+		int found = 0;
+		char *maddr = (char *)&priv->multicastlist[w][i];
+
+		for (j = 0; j < mesh_nr_mcastaddr; j++) {
+			if (!memcmp(maddr, priv->multicastlist[m][j],
+						ETH_ALEN)) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			memcpy(mc_list_ptr, maddr, ETH_ALEN);
+			lbs_deb_cmd("MULTICAST_ADR: %s added to mcast filter\n",
+				print_mac(mac, maddr));
+			mc_list_ptr += ETH_ALEN;
+			mc_count++;
+		}
+	}
+
+	/* Copy rest of the list */
+	for (j = 0; j < mesh_nr_mcastaddr; j++) {
+		memcpy(mc_list_ptr, priv->multicastlist[m][j], ETH_ALEN);
+		lbs_deb_cmd("MULTICAST_ADR: %s added to mcast filter\n",
+			print_mac(mac, priv->multicastlist[m][j]));
+		mc_list_ptr += ETH_ALEN;
+		mc_count++;
+	}
+
+	pMCastAdr->nr_of_adrs = cpu_to_le16((u16)mc_count);
+	lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n",
+			pMCastAdr->nr_of_adrs);
 	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
+
 }
 
 /**
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 3053cc2..71ecb4c 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -126,6 +126,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 *	station firmware to store Rx packet information.
 *
 *	Current version of MAC has a 32x6 multicast address buffer.
+*	The driver maintains separate multicast address lists for mesh and
+*	wlan interfaces, each one of size MRVDRV_MAX_MULTICAST_LIST_SIZE/2.
 *
 *	802.11b can have up to  14 channels, the driver keeps the
 *	BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 1c6ec4d..03e018e 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -230,8 +230,13 @@ struct lbs_private {
 
 	/** MAC address information */
 	u8 current_addr[ETH_ALEN];
-	u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
-	u32 nr_of_multicastmacaddr;
+
+	/* Per virtual interface multicast settings */
+#define WLAN_MCAST_FILTER 0
+#define MESH_MCAST_FILTER 1
+	u8 multicastlist[2][MRVDRV_MAX_MULTICAST_LIST_SIZE/2][ETH_ALEN];
+	u32 nr_of_multicastmacaddr[2];
+	u16 packetfilter[2];
 
 	/** 802.11 statistics */
 //	struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index e012d08..f666cf2 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -556,90 +556,100 @@ done:
 	return ret;
 }
 
-static int lbs_copy_multicast_address(struct lbs_private *priv,
-				     struct net_device *dev)
+static int lbs_copy_multicast_address(u8 (*mcast_list)[ETH_ALEN],
+		struct net_device *dev)
 {
-	int i = 0;
+	int i;
 	struct dev_mc_list *mcptr = dev->mc_list;
+	DECLARE_MAC_BUF(mac);
 
 	for (i = 0; i < dev->mc_count; i++) {
-		memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
+		memcpy(*mcast_list, mcptr->dmi_addr, ETH_ALEN);
+		lbs_deb_net("mcast address %s added to per-if filter\n",
+			print_mac(mac, mcptr->dmi_addr));
 		mcptr = mcptr->next;
+		mcast_list++;
 	}
-
 	return i;
-
 }
 
-static void lbs_set_multicast_list(struct net_device *dev)
+static void lbs_set_if_multicast_list(struct net_device *dev)
 {
 	struct lbs_private *priv = dev->priv;
-	int oldpacketfilter;
-	DECLARE_MAC_BUF(mac);
+	char *iftyp;
+	int i;
 
 	lbs_deb_enter(LBS_DEB_NET);
 
-	oldpacketfilter = priv->currentpacketfilter;
+	i = (priv->mesh_dev == dev) ? MESH_MCAST_FILTER : WLAN_MCAST_FILTER;
+	iftyp = (i == MESH_MCAST_FILTER) ? "mesh" : "wlan";
 
 	if (dev->flags & IFF_PROMISC) {
-		lbs_deb_net("enable promiscuous mode\n");
-		priv->currentpacketfilter |=
+		lbs_deb_net("enable promiscuous mode on %s if\n", iftyp);
+		priv->packetfilter[i] |=
 		    CMD_ACT_MAC_PROMISCUOUS_ENABLE;
-		priv->currentpacketfilter &=
+		priv->packetfilter[i] &=
 		    ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
 		      CMD_ACT_MAC_MULTICAST_ENABLE);
 	} else {
 		/* Multicast */
-		priv->currentpacketfilter &=
+		priv->packetfilter[i] &=
 		    ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
 
 		if (dev->flags & IFF_ALLMULTI || dev->mc_count >
-		    MRVDRV_MAX_MULTICAST_LIST_SIZE) {
-			lbs_deb_net( "enabling all multicast\n");
-			priv->currentpacketfilter |=
+		    MRVDRV_MAX_MULTICAST_LIST_SIZE/2) {
+			lbs_deb_net("enable allmulti mode on %s if\n", iftyp);
+			priv->packetfilter[i] |=
 			    CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
-			priv->currentpacketfilter &=
+			priv->packetfilter[i] &=
 			    ~CMD_ACT_MAC_MULTICAST_ENABLE;
 		} else {
-			priv->currentpacketfilter &=
+			priv->packetfilter[i] &=
 			    ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
 
 			if (!dev->mc_count) {
-				lbs_deb_net("no multicast addresses, "
-				       "disabling multicast\n");
-				priv->currentpacketfilter &=
-				    ~CMD_ACT_MAC_MULTICAST_ENABLE;
+				priv->nr_of_multicastmacaddr[i] = 0;
+				lbs_deb_net("no mcast on %s if\n", iftyp);
+				priv->packetfilter[i] &=
+					~CMD_ACT_MAC_MULTICAST_ENABLE;
 			} else {
-				int i;
-
-				priv->currentpacketfilter |=
+				priv->packetfilter[i] |=
 				    CMD_ACT_MAC_MULTICAST_ENABLE;
 
-				priv->nr_of_multicastmacaddr =
-				    lbs_copy_multicast_address(priv, dev);
-
-				lbs_deb_net("multicast addresses: %d\n",
-				       dev->mc_count);
-
-				for (i = 0; i < dev->mc_count; i++) {
-					lbs_deb_net("Multicast address %d:%s\n",
-					       i, print_mac(mac,
-					       priv->multicastlist[i]));
-				}
-				/* send multicast addresses to firmware */
-				lbs_prepare_and_send_command(priv,
-						      CMD_MAC_MULTICAST_ADR,
-						      CMD_ACT_SET, 0, 0,
-						      NULL);
+				lbs_deb_net("mcast enable on %s if\n", iftyp);
+				priv->nr_of_multicastmacaddr[i] =
+					lbs_copy_multicast_address(
+						priv->multicastlist[i], dev);
 			}
 		}
 	}
 
+	lbs_deb_leave(LBS_DEB_NET);
+}
+
+static void lbs_set_multicast_list(struct net_device *dev)
+{
+	struct lbs_private *priv = dev->priv;
+	int oldpacketfilter;
+
+	lbs_deb_enter(LBS_DEB_NET);
+
+	oldpacketfilter = priv->currentpacketfilter;
+
+	/* Update the multicast filter for this device. */
+	lbs_set_if_multicast_list(dev);
+
+	/* Combine mcast flags from both devs before sending to firmware. */
+	priv->currentpacketfilter = priv->packetfilter[MESH_MCAST_FILTER] |
+		priv->packetfilter[WLAN_MCAST_FILTER];
+
+	if (priv->currentpacketfilter & CMD_ACT_MAC_MULTICAST_ENABLE)
+		lbs_prepare_and_send_command(priv, CMD_MAC_MULTICAST_ADR,
+				CMD_ACT_SET, 0, 0, NULL);
+
 	if (priv->currentpacketfilter != oldpacketfilter) {
 		lbs_set_mac_packet_filter(priv);
 	}
-
-	lbs_deb_leave(LBS_DEB_NET);
 }
 
 /**
@@ -1316,6 +1326,8 @@ static int lbs_add_mesh(struct lbs_private *priv)
 #ifdef	WIRELESS_EXT
 	mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def;
 #endif
+	mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+	mesh_dev->set_multicast_list = lbs_set_multicast_list;
 	/* Register virtual mesh interface */
 	ret = register_netdev(mesh_dev);
 	if (ret) {
-- 
1.5.2.4






More information about the Devel mailing list