mirror of
https://github.com/coolsnowwolf/packages.git
synced 2025-05-01 03:12:38 +08:00
621 lines
17 KiB
Diff
621 lines
17 KiB
Diff
--- 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
|