--- a/src/config.c
+++ b/src/config.c
@@ -65,6 +65,10 @@ static struct Config commonConfig;
 struct vifconfig *parsePhyintToken(void);
 struct SubnetList *parseSubnetAddress(char *addrstr);
 
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+void qca_mcs_add_brdev(char *brdevstr);
+#endif
+
 /**
 *   Initializes common config..
 */
@@ -136,17 +140,25 @@ int loadConfig(char *configFile) {
                 my_log(LOG_WARNING, 0, "Unknown token '%s' in configfile", token);
                 return 0;
             } else {
-
-                my_log(LOG_DEBUG, 0, "IF name : %s", tmpPtr->name);
-                my_log(LOG_DEBUG, 0, "Next ptr : %x", tmpPtr->next);
-                my_log(LOG_DEBUG, 0, "Ratelimit : %d", tmpPtr->ratelimit);
-                my_log(LOG_DEBUG, 0, "Threshold : %d", tmpPtr->threshold);
-                my_log(LOG_DEBUG, 0, "State : %d", tmpPtr->state);
-                my_log(LOG_DEBUG, 0, "Allowednet ptr : %x", tmpPtr->allowednets);
-
-                // Insert config, and move temppointer to next location...
-                *currPtr = tmpPtr;
-                currPtr = &tmpPtr->next;
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+                if (tmpPtr->state == IF_STATE_QCA_MCS_BR) {
+                    free(tmpPtr->name);
+                    free(tmpPtr);
+                }
+                else
+#endif
+                {
+                    my_log(LOG_DEBUG, 0, "IF name : %s", tmpPtr->name);
+                    my_log(LOG_DEBUG, 0, "Next ptr : %x", tmpPtr->next);
+                    my_log(LOG_DEBUG, 0, "Ratelimit : %d", tmpPtr->ratelimit);
+                    my_log(LOG_DEBUG, 0, "Threshold : %d", tmpPtr->threshold);
+                    my_log(LOG_DEBUG, 0, "State : %d", tmpPtr->state);
+                    my_log(LOG_DEBUG, 0, "Allowednet ptr : %x", tmpPtr->allowednets);
+
+                    // Insert config, and move temppointer to next location...
+                    *currPtr = tmpPtr;
+                    currPtr = &tmpPtr->next;
+                }
             }
         }
         else if(strcmp("quickleave", token)==0) {
@@ -294,6 +306,9 @@ struct vifconfig *parsePhyintToken(void)
     struct SubnetList **anetPtr, **agrpPtr;
     char *token;
     short parseError = 0;
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+    char qcaMcsIntfs[300] = { 0 };
+#endif
 
     // First token should be the interface name....
     token = nextConfigToken();
@@ -323,6 +338,10 @@ struct vifconfig *parsePhyintToken(void)
         my_log(LOG_ERR, 0, "Out of memory.");
     }
 
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+    strcpy(qcaMcsIntfs, tmpPtr->name);
+#endif
+
     // Set the altnet pointer to the allowednets pointer.
     anetPtr = &tmpPtr->allowednets;
     agrpPtr = &tmpPtr->allowedgroups;
@@ -411,6 +430,20 @@ struct vifconfig *parsePhyintToken(void)
                 break;
             }
         }
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+        else if(strcmp("qca-mcs-bridge", token)==0) {
+            // QCA MCS bridge
+            my_log(LOG_DEBUG, 0, "Config: IF: Got qca-mcs module bridge token.");
+            tmpPtr->state = IF_STATE_QCA_MCS_BR;
+	}
+        else if(strcmp("brport", token)==0) {
+            // QCA MCS bridge port
+            token = nextConfigToken();
+            my_log(LOG_DEBUG, 0, "Config: IF: Got brport token %s.",token);
+            strcat(&qcaMcsIntfs, "|");
+            strcat(&qcaMcsIntfs, token);
+        }
+#endif
         else {
             // Unknown token. Break...
             break;
@@ -425,6 +458,13 @@ struct vifconfig *parsePhyintToken(void)
         tmpPtr = NULL;
     }
 
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+    if (tmpPtr->state == IF_STATE_QCA_MCS_BR) {
+        // Configure QCA MCS configurations
+        qca_mcs_add_brdev(&qcaMcsIntfs);
+    }
+#endif
+
     return tmpPtr;
 }
 
--- a/src/igmpproxy.h
+++ b/src/igmpproxy.h
@@ -124,6 +124,10 @@ void my_log( int Serverity, int Errno, c
 #define IF_STATE_LOST          3   // aimwang: Temp from downstream to hidden
 #define IF_STATE_HIDDEN        4   // aimwang: Interface is hidden
 
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+#define IF_STATE_QCA_MCS_BR    5   // QCA MCA support
+#endif
+
 // Multicast default values...
 #define DEFAULT_ROBUSTNESS     2
 #define DEFAULT_THRESHOLD      1
--- a/src/igmpproxy.c
+++ b/src/igmpproxy.c
@@ -61,6 +61,12 @@ int     igmpProxyInit(void);
 void    igmpProxyCleanUp(void);
 void    igmpProxyRun(void);
 
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+bool qca_mcs_is_configured(void);
+void qca_mcs_start(void);
+void qca_mcs_stop(void);
+#endif
+
 // Global vars...
 static int sighandled = 0;
 #define GOT_SIGINT  0x01
@@ -185,9 +191,21 @@ int main( int ArgCn, char *ArgVc[] ) {
                 close(devnull);
         }
 
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+        if (qca_mcs_is_configured()) {
+            qca_mcs_start();
+        }
+#endif
+
         // Go to the main loop.
         igmpProxyRun();
 
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+        if (qca_mcs_is_configured()) {
+            qca_mcs_stop();
+        }
+#endif
+
         // Clean up
         igmpProxyCleanUp();
 
--- a/src/rttable.c
+++ b/src/rttable.c
@@ -75,6 +75,11 @@ void logRouteTable(const char *header);
 int internAgeRoute(struct RouteTable *croute);
 int internUpdateKernelRoute(struct RouteTable *route, int activate);
 
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+bool qca_mcs_is_configured(void);
+void qca_mcs_flood_brport(u_int32_t mc_addr, bool is_join);
+#endif
+
 
 /**
 *   Functions for downstream hosts hash table
@@ -192,6 +197,12 @@ static void sendJoinLeaveUpstream(struct
                     k_join(upstrIf, route->group);
 
                     route->upstrState = ROUTESTATE_JOINED;
+
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+                    if (qca_mcs_is_configured()) {
+                        qca_mcs_flood_brport( route->group, true );
+                    }
+#endif
                 } else {
                     my_log(LOG_DEBUG, 0, "No downstream listeners for group %s. No join sent.",
                         inetFmt(route->group, s1));
@@ -206,6 +217,12 @@ static void sendJoinLeaveUpstream(struct
                     k_leave(upstrIf, route->group);
 
                     route->upstrState = ROUTESTATE_NOTJOINED;
+
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
+                    if (qca_mcs_is_configured()) {
+                        qca_mcs_flood_brport( route->group, false );
+                    }
+#endif
                 }
             }
         }
--- /dev/null
+++ b/src/qca-mcs.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012, 2015 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Header files copied from QCA NHSS.QSDK.12.0.r8 qca-mcs sources
+ */
+
+#define NETLINK_QCA_MC  	23
+
+#define MC_DEF_IF_MAX		16
+#define MC_DEF_IP6_SIZE		16
+
+#define MC_ACL_RULE_MAX_COUNT	8	/* 8 for IGMP, 8 for MLD */
+
+/* netlink message type */
+enum {
+	MC_MSG_SET_ENABLE,
+	MC_MSG_SET_DEBUG,
+	MC_MSG_SET_POLICY,
+	MC_MSG_SET_MEMBERSHIP_INTERVAL,
+	MC_MSG_SET_RETAG,
+	MC_MSG_SET_ROUTER_PORT,
+	MC_MSG_SET_ADD_ACL_RULE,
+	MC_MSG_SET_FLUSH_ACL_RULE,
+	MC_MSG_SET_CONVERT_ALL,
+	MC_MSG_SET_TIMEOUT,
+	MC_MSG_SET_M2I3_FILTER,
+	MC_MSG_SET_TBIT,
+	MC_MSG_SET_LOCAL_QUERY_INTERVAL,
+	MC_MSG_SET_PSW_ENCAP,
+	MC_MSG_SET_PSW_FLOOD,
+	MC_MSG_SET_EVENT_PID,
+	MC_MSG_GET_ACL,
+	MC_MSG_GET_MDB,
+	MC_MSG_SET_ROUTER,
+	MC_MSG_GET_ROUTER_PORT,
+	MC_MSG_MAX
+};
+
+struct __mcctl_msg_header {
+	char if_name[IFNAMSIZ];	/* bridge name: br-lan */
+	u_int32_t buf_len;	/* not include this header */
+	u_int32_t tbl_offsite;	/* how many entries to skip */
+	u_int32_t status;
+	u_int32_t bytes_written;
+	u_int32_t bytes_needed;
+} __attribute__ ((packed));;
+
+struct __mc_param_value {
+	u_int32_t val;
+};
+
+enum {
+	MC_RTPORT_FLOOD = 0,
+	MC_RTPORT_DROP,
+	MC_RTPORT_SPECIFY,
+	MC_RTPORT_DEFAULT,
+	MC_RTPORT_MAX
+};
+
+struct __mc_param_router_port {
+	u_int32_t type;
+	u_int32_t ifindex;
+};
+
+struct __mc_group {
+	u_int32_t pro;
+	union {
+		u_int32_t ip4;
+		u_int8_t ip6[MC_DEF_IP6_SIZE];
+	} u;
+};
+
+struct __mc_floodtbl_entry {
+	struct __mc_group group;
+	u_int32_t ifcnt;
+	u_int32_t ifindex[MC_DEF_IF_MAX];
+} __attribute__ ((packed));
+
--- /dev/null
+++ b/src/qca-mcs.c
@@ -0,0 +1,319 @@
+/*
+** QCA Multicast Snooping (MCS) Module Support
+**
+** Enables the ipq806x NSS ECM multicast acceleration support.
+**/
+
+#include <linux/netlink.h>
+#include "igmpproxy.h"
+#include "qca-mcs.h"
+
+#define QCA_MCS_MAX_MCAST_GRP	32
+
+struct qca_mcs_brdev {
+	char if_name[IFNAMSIZ];	/* bridge interface name */
+	u_int32_t br_ifidx;	/* bridge interface index */
+	u_int32_t port_num;	/* number of bridge port to flood */
+	u_int32_t port_ifidx[MC_DEF_IF_MAX];	/* bridge port interface index */
+};
+
+struct qca_mcs_all_brdev {
+	u_int32_t num_brdev;	/* number of bridge interface to manage */
+	struct qca_mcs_brdev brdev[MC_DEF_IF_MAX]; /* bridge details */
+};
+
+static unsigned int mcsNlFd = -1;
+
+static struct qca_mcs_all_brdev all_brdev = { 0 };
+
+static u_int32_t flooded_mc_addr[QCA_MCS_MAX_MCAST_GRP] = { 0 };
+static int flooded_mc_addr_cnt = 0;
+
+static bool qca_mcs_configured = false;
+
+/*
+ * data - netlink messages payload - includes the __mcctl_msg_header
+ */
+static int qca_mcs_sendmsg(void *data, int data_len, int msg_type)
+{
+	struct sockaddr_nl sa, da;
+	struct nlmsghdr *nlh;
+	struct iovec iov;
+	struct msghdr msg;
+	int sentcnt;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.nl_family = AF_NETLINK;
+	sa.nl_pid = getpid();
+	sa.nl_groups = 0;
+	if (bind(mcsNlFd, (struct sockaddr *) &sa, sizeof(sa))) {
+		my_log( LOG_WARNING, errno, "%s: Unable to bind socket", __func__);
+		return -1;
+	}
+
+	memset(&da, 0, sizeof(da));
+	da.nl_family = AF_NETLINK;
+	da.nl_pid = 0;
+	da.nl_groups = 0;
+
+	nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(data_len));
+	if (!nlh) {
+		my_log( LOG_WARNING, errno, "%s: malloc() failed", __func__);
+		return -1;
+	}
+
+	memset(nlh, 0, NLMSG_SPACE(data_len));
+	nlh->nlmsg_len = NLMSG_SPACE(data_len);
+	nlh->nlmsg_pid = getpid();
+	nlh->nlmsg_flags = 0;
+	nlh->nlmsg_type = msg_type;
+
+	memcpy(NLMSG_DATA(nlh), data, data_len);
+
+	iov.iov_base = (void *)nlh;
+	iov.iov_len = nlh->nlmsg_len;
+	msg.msg_name = (void *)&da;
+	msg.msg_namelen = sizeof(da);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	sentcnt = sendmsg(mcsNlFd, &msg, 0);
+	if (sentcnt < 0) {
+		my_log( LOG_WARNING, 0, "%s: Failed - data_len[%d], mcsNlFd[%d], msg_type[%d]", __func__,
+			data_len, mcsNlFd, msg_type);
+	}
+	free(nlh);
+
+	return sentcnt;
+}
+
+/*
+ * Enable/disable the QCA MCS bridge device and bridge ports
+ */
+static int qca_mcs_brdev_state(bool enable)
+{
+	void *mcctl_br_state;
+	struct __mcctl_msg_header *mcctl_msghdr;
+	struct __mc_param_value *mc_param_val;
+	int br_state_msglen;
+	int err = 0;
+
+	/* Prepare bridge state message structures */
+	br_state_msglen = sizeof(struct __mcctl_msg_header) + sizeof(struct __mc_param_value) + 32;
+	mcctl_br_state = malloc(br_state_msglen);
+	if (!mcctl_br_state) {
+		my_log( LOG_ERR, errno, "Out of memory trying to allocate [%] byte(s)!", br_state_msglen );
+		return -1;
+	}
+	memset(mcctl_br_state, 0, br_state_msglen);
+	mcctl_msghdr = (struct __mcctl_msg_header *)mcctl_br_state;
+	mcctl_msghdr->buf_len = sizeof(struct __mc_param_value);
+	mc_param_val = (struct __mc_param_value *)(mcctl_br_state +
+			sizeof(struct __mcctl_msg_header));
+	if (enable)
+		mc_param_val->val = 1;
+	else
+		mc_param_val->val = 0;
+
+	for (int i=0; i < all_brdev.num_brdev; i++) {
+		/* enable or disable bridge */
+		strcpy(mcctl_br_state, all_brdev.brdev[i].if_name);
+		qca_mcs_sendmsg(mcctl_br_state, br_state_msglen, MC_MSG_SET_ENABLE);
+	}
+
+	free(mcctl_br_state);
+
+	return err;
+}
+
+static bool qca_mcs_mcastgrp_flooded(u_int32_t mc_addr)
+{
+	for (int i=0; i < QCA_MCS_MAX_MCAST_GRP; i++) {
+		if (flooded_mc_addr[i] == 0)
+			break;
+
+		if (flooded_mc_addr[i] == mc_addr)
+			return true;
+	}
+
+	return false;
+}
+
+static void qca_mcs_add_flood_entry(u_int32_t mc_addr)
+{
+	for (int i=0; i < QCA_MCS_MAX_MCAST_GRP; i++) {
+		if (flooded_mc_addr[i])
+			continue;
+
+		flooded_mc_addr[i] = mc_addr;
+		flooded_mc_addr_cnt++;
+
+		if (flooded_mc_addr_cnt > QCA_MCS_MAX_MCAST_GRP) {
+			flooded_mc_addr_cnt = QCA_MCS_MAX_MCAST_GRP;
+			my_log( LOG_WARNING, 0, "MCastAddr count is greater than buffer size! Set to max size.");
+		}
+
+		return;
+	}
+
+	my_log( LOG_WARNING, 0, "Maximum[%d] multicast group flood entry reach!  Unable to add more.",
+		QCA_MCS_MAX_MCAST_GRP );
+}
+
+static void qca_mcs_remove_flood_entry(u_int32_t mc_addr)
+{
+	bool mc_addr_found = false;
+	int i;
+
+	for (i=0; i < flooded_mc_addr_cnt; i++) {
+		if (flooded_mc_addr[i]  == mc_addr) {
+			mc_addr_found = true;
+			break;
+		}
+	}
+
+	if (!mc_addr_found) {
+		my_log( LOG_WARNING, 0, "MCastAddr[%d.%d.%d.%d] not found in multcast address list",
+			((char *)&mc_addr)[0], ((char *)&mc_addr)[1],
+			((char *)&mc_addr)[2], ((char *)&mc_addr)[3]);
+		return;
+	}
+
+	for (; i < flooded_mc_addr_cnt - 1; i++) {
+		flooded_mc_addr[i] = flooded_mc_addr[i + 1];
+	}
+	flooded_mc_addr[i] = 0;
+
+	flooded_mc_addr_cnt--;
+	if (flooded_mc_addr_cnt < 0) {
+		flooded_mc_addr_cnt = 0;
+		my_log( LOG_WARNING, 0, "MCastAddr count is negative!  Reset to zero.");
+	}
+}
+
+/*
+ * Enable/disabled a multicast group to be flooded to the bridge pors
+ * when the multicast router joins an upstream multicast group.
+ */
+void qca_mcs_flood_brport(u_int32_t mc_addr, bool is_join)
+{
+	void *mcctl_br_fldentry;
+	struct __mcctl_msg_header *mcctl_msghdr;
+	struct __mc_floodtbl_entry *mc_fld_entry;
+	int br_fldentry_msglen;
+	bool flooded = false;
+	int err = -1;
+
+	flooded = qca_mcs_mcastgrp_flooded(mc_addr);
+	if (is_join && !flooded)
+		qca_mcs_add_flood_entry(mc_addr);
+
+	/* Prepare bridge state message structures */
+	br_fldentry_msglen = sizeof(struct __mcctl_msg_header) +
+			    (sizeof(struct __mc_floodtbl_entry) * flooded_mc_addr_cnt);
+	mcctl_br_fldentry = malloc(br_fldentry_msglen);
+	if (!mcctl_br_fldentry) {
+		my_log( LOG_WARNING, errno, "%s: out of memory trying to allocate [%d] byte(s)",
+			__func__, br_fldentry_msglen );
+		return;
+	}
+
+	memset(mcctl_br_fldentry, 0, br_fldentry_msglen);
+	mcctl_msghdr = (struct __mcctl_msg_header *)mcctl_br_fldentry;
+	mcctl_msghdr->buf_len = br_fldentry_msglen - sizeof(struct __mcctl_msg_header);
+	mc_fld_entry = (struct __mc_floodtbl_entry *)(mcctl_br_fldentry +
+			sizeof(struct __mcctl_msg_header));
+
+	for (int i=0; i < flooded_mc_addr_cnt; i++) {
+		mc_fld_entry[i].group.pro = htons(0x0800); /* ETH_P_IP */
+		mc_fld_entry[i].group.u.ip4 = flooded_mc_addr[i];
+	}
+
+	for (int i=0; i < all_brdev.num_brdev; i++) {
+		strcpy(mcctl_br_fldentry, all_brdev.brdev[i].if_name);
+
+		for (int fei=0; fei < flooded_mc_addr_cnt; fei++) {
+			if (is_join || mc_fld_entry[fei].group.u.ip4 != mc_addr) {
+				mc_fld_entry[fei].ifcnt = all_brdev.brdev[i].port_num;
+
+				for (int bpi=0; bpi < all_brdev.brdev[i].port_num; bpi++) {
+					mc_fld_entry[fei].ifindex[bpi] = all_brdev.brdev[i].port_ifidx[bpi];
+				}
+			}
+		}
+		qca_mcs_sendmsg(mcctl_br_fldentry, br_fldentry_msglen, MC_MSG_SET_PSW_FLOOD);
+	}
+	free(mcctl_br_fldentry);
+
+	if (!is_join && flooded)
+		qca_mcs_remove_flood_entry(mc_addr);
+}
+
+bool qca_mcs_is_configured(void)
+{
+	return qca_mcs_configured;
+}
+
+/*
+ * Setup the data structure for bridge and bridge port(s)
+ *
+ * brdevstr - bridge and bridge port delimited string
+ *            "<bridge dev>|<bridge port 1>|<bridge port 2>|..."
+ */
+void qca_mcs_add_brdev(char *brdevstr)
+{
+	char *token;
+	char *delimiter = "|";
+	int curIdx, i = 0;
+
+	if (curIdx >= MC_DEF_IF_MAX) {
+		my_log( LOG_ERR, 0, "Max QCA MCS bridge limit[%d] reached.", MC_DEF_IF_MAX );
+	}
+
+	token = strtok(brdevstr, delimiter);
+	strcpy(all_brdev.brdev[curIdx].if_name, token);
+	all_brdev.brdev[curIdx].br_ifidx = if_nametoindex(token);
+
+	while(token = strtok(NULL, delimiter)) {
+		all_brdev.brdev[curIdx].port_ifidx[i++] = if_nametoindex(token);
+		if (i >= MC_DEF_IF_MAX) {
+			my_log( LOG_ERR, 0, "Max QCA MCS bridge port limit[%d] reached.", MC_DEF_IF_MAX );
+		}
+	}
+	all_brdev.brdev[curIdx].port_num = i;
+	all_brdev.num_brdev++;
+	qca_mcs_configured = true;
+}
+
+/*
+ * Start QCA MCS support.
+ */
+void qca_mcs_start(void)
+{
+	if (!qca_mcs_configured) {
+		my_log( LOG_WARNING, 0, "QCA MCS bridges not configured.  Unable to enable QCA MCS support." );
+		return;
+	}
+
+	mcsNlFd = socket(AF_NETLINK, SOCK_RAW, NETLINK_QCA_MC);
+	if ( mcsNlFd < 0 ) {
+		my_log( LOG_ERR, errno, "NETLINK_QCA_MC socket open" );
+	}
+
+	qca_mcs_brdev_state(true);
+	my_log( LOG_NOTICE, 0, "QCA MCS support enabled." );
+}
+
+/*
+ * Stop QCA MCS support.
+ */
+void qca_mcs_stop(void)
+{
+	qca_mcs_configured = false;
+
+	qca_mcs_brdev_state(false);
+	my_log( LOG_NOTICE, 0, "QCA MCS support disabled." );
+
+	if ( mcsNlFd > 0 )
+		close(mcsNlFd);
+}
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -19,4 +19,5 @@ igmpproxy_SOURCES = \
 	os-qnxnto.h \
 	request.c \
 	rttable.c \
+	qca-mcs.c \
 	syslog.c
