summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping')
-rw-r--r--target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/Makefile37
-rw-r--r--target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/igmp_delete.c119
-rw-r--r--target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping.c5078
-rw-r--r--target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_glue.c108
-rw-r--r--target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_local.h575
-rw-r--r--target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_new.c6895
6 files changed, 12812 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/Makefile b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/Makefile
new file mode 100644
index 000000000..3b9f114a6
--- /dev/null
+++ b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/Makefile
@@ -0,0 +1,37 @@
+#
+# Makefile for igmp snooping
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+#Add mips16 Support
+ifdef CONFIG_RTL865X_KERNEL_MIPS16_LAYERDRIVER
+ CFLAGS_rtl865x_igmpsnooping_glue.o = -mips16
+ #CFLAGS_rtl865x_igmpsnooping.o = -mips16
+endif
+DIR_RTLASIC = $(DIR_LINUX)/drivers/net/rtl819x/
+CONFIG_NEW_IGMP_IMPLEMENTATION=y
+ifeq ($(CONFIG_NEW_IGMP_IMPLEMENTATION),y)
+obj-y := rtl865x_igmpsnooping_glue.o rtl865x_igmpsnooping_new.o igmp_delete.o
+EXTRA_CFLAGS += -DCONFIG_NEW_IGMP_IMPLEMENTATION
+else
+obj-y := rtl865x_igmpsnooping_glue.o rtl865x_igmpsnooping.o
+endif
+
+EXTRA_CFLAGS += -O1 -DRTL_TBLDRV -D__linux__ -D __KERNEL__ -DEXPORT_SYMTAB -mno-memcpy -DRTL865X_OVER_KERNEL -DRTL865X_OVER_LINUX -Werror
+EXTRA_CFLAGS += -I$(DIR_LINUX)/include
+#EXTRA_CFLAGS += -I$(DIR_RTLASIC)/AsicDriver
+#EXTRA_CFLAGS += -I$(DIR_RTLASIC)/common
+EXTRA_CFLAGS += -I$(DIR_RTLASIC)
+#EXTRA_CFLAGS += -I. -I..
+
+
+
+ifeq ($(CONFIG_RTL865X_MODULE_ROMEDRV),y)
+ EXTRA_CFLAGS += -G 0
+ EXTRA_CFLAGS += -DMODULE
+ EXTRA_CFLAGS += -mlong-calls
+endif
+
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/igmp_delete.c b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/igmp_delete.c
new file mode 100644
index 000000000..2b3ec0057
--- /dev/null
+++ b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/igmp_delete.c
@@ -0,0 +1,119 @@
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/string.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/route.h>
+#include <net/sock.h>
+#include <net/arp.h>
+#include <net/raw.h>
+#include <net/checksum.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netlink.h>
+#include <linux/inetdevice.h>
+#include <linux/icmp.h>
+#include <net/udp.h>
+#include <net/tcp.h>
+
+#include <net/rtl/rtl_types.h>
+#ifdef CONFIG_NETFILTER
+#include <net/netfilter/nf_conntrack.h>
+#include <net/rtl/fastpath/fastpath_core.h>
+#endif
+#include <net/rtl/rtl865x_netif.h>
+#include <net/rtl/rtl_nic.h>
+
+
+struct sock *igmp_delete_sk = NULL;
+struct test_struct
+{
+ char data[30];
+};
+static int try_mac(const char *data, char array[],
+ int array_size, char sep)
+{
+ uint32 i;
+
+ memset(array, 0, sizeof(array[0])*array_size);
+
+ /* Keep data pointing at next char. */
+ for (i = 0; i < array_size; data++) {
+ if (*data >= '0' && *data <= '9') {
+ array[i] = array[i]*16 + *data - '0';
+ }
+ else if(*data >='a' && *data <='f') {
+ array[i] = array[i]*16 + *data - 'a'+10;
+ }
+ else if(*data >='A' && *data <='F') {
+ array[i] = array[i]*16 + *data - 'A'+10;
+ }
+ else if (*data == sep)
+ i++;
+ else {
+ /* Unexpected character; true if it's the
+ terminator and we're finished. */
+ if (i == array_size - 1)
+ return 1;
+
+ printk("Char %u '%c' unexpected\n",\
+ i, *data);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+extern int32 rtl_delIgmpRecordByMacAddr(uint8 *macAddr);
+void igmp_delete (struct sk_buff *__skb)
+{
+ int pid;
+ struct test_struct send_data,recv_data;
+ uint8 mac[6];
+ char *ptr;
+ pid=rtk_nlrecvmsg(__skb,sizeof(struct test_struct),&recv_data);
+ //printk("igmp_delete data:%s\n", recv_data.data);
+ memset(mac, 0, 6);
+ ptr = recv_data.data;
+ if(try_mac(recv_data.data, mac, 6, ':'))
+ {
+ rtl_delIgmpRecordByMacAddr(mac);
+ //printk("filter mac: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
+ sprintf(send_data.data,"clear igmp cache ok\n");
+ }
+ else
+ {
+ printk("clear igmp cache of bad format mac:%s\n", recv_data.data);
+ sprintf(send_data.data,"please input like 00:23:e8:79:99:32\n");
+ }
+ rtk_nlsendmsg(pid, igmp_delete_sk, sizeof(struct test_struct), &send_data);
+ return;
+}
+
+int igmp_delete_init_netlink(void)
+{
+ igmp_delete_sk = netlink_kernel_create(&init_net, NETLINK_MULTICAST_DELETE, 0, igmp_delete, NULL, THIS_MODULE);
+
+ if (!igmp_delete_sk) {
+ printk(KERN_ERR "Netlink[Kernel] Cannot create netlink socket for igmp delete.\n");
+ return -EIO;
+ }
+ printk("Netlink[Kernel] create socket for igmp ok.\n");
+ return 0;
+}
+
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping.c b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping.c
new file mode 100644
index 000000000..bdc097f7e
--- /dev/null
+++ b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping.c
@@ -0,0 +1,5078 @@
+/*
+* Copyright c Realsil Semiconductor Corporation, 2006
+* All rights reserved.
+*
+* Program : igmp snooping function
+* Abstract :
+* Author :qinjunjie
+* Email:qinjunjie1980@hotmail.com
+*
+*/
+/* @doc Realtek_Igmp_Snooping_API
+
+ @module rtl865x_igmpsnooping.c - Realtek Igmp Snooping API documentation |
+ This document explains the API interface of the igmp snooping module.
+ @normal Jun-Jie Qin (qjj_qin@realsil.com.cn) <date>
+
+ Copyright <cp>2009 Realtek<tm> Semiconductor Cooperation, All Rights Reserved.
+
+ @head3 List of Symbols |
+ Here is a list of all functions and variables in this module.
+
+ @index | Realtek_Igmp_Snooping_API
+*/
+#ifdef __linux__
+#include <linux/config.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/seq_file.h>
+#endif
+#endif
+
+#include "rtl865x_igmpsnooping_glue.h"
+#include "rtl865x_igmpsnooping.h"
+#include "rtl865x_igmpsnooping_local.h"
+
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+#include "../common/rtl865x_eventMgr.h"
+#endif
+
+static struct rtl_multicastModule rtl_mCastModuleArray[MAX_MCAST_MODULE_NUM];
+#if defined(__linux__) && defined(__KERNEL__)
+static struct timer_list igmpSysTimer; /*igmp timer*/
+#endif
+/*global system resources declaration*/
+static uint32 rtl_totalMaxGroupCnt; /*maximum total group entry count, default is 100*/
+static uint32 rtl_totalMaxSourceCnt; /*maximum total group entry count, default is 3000*/
+
+void *rtl_groupMemory=NULL;
+void *rtl_sourceMemory=NULL;
+
+static struct rtl_groupEntry *rtl_groupEntryPool=NULL;
+static struct rtl_sourceEntry *rtl_sourceEntryPool=NULL;
+
+static struct rtl_mCastTimerParameters rtl_mCastTimerParas; /*IGMP snooping parameters */
+
+static uint32 rtl_hashTableSize=0;
+static uint32 rtl_hashMask=0;
+
+/*the system up time*/
+static uint32 rtl_startTime;
+static uint32 rtl_sysUpSeconds;
+
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+static rtl_multicastEventContext_t reportEventContext;
+static rtl_multicastEventContext_t timerEventContext;
+static rtl_multicastEventContext_t linkEventContext;
+#endif
+
+/*******************************internal function declaration*****************************/
+
+
+
+/**************************
+ resource managment
+**************************/
+static struct rtl_groupEntry* rtl_initGroupEntryPool(uint32 poolSize);
+static struct rtl_groupEntry* rtl_allocateGroupEntry(void);
+static void rtl_freeGroupEntry(struct rtl_groupEntry* groupEntryPtr) ;
+
+
+static struct rtl_sourceEntry* rtl_initSourceEntryPool(uint32 poolSize);
+static struct rtl_sourceEntry* rtl_allocateSourceEntry(void);
+static void rtl_freeSourceEntry(struct rtl_sourceEntry* sourceEntryPtr) ;
+
+
+/**********************************Structure Maintenance*************************/
+
+static struct rtl_groupEntry* rtl_searchGroupEntry(uint32 moduleIndex, uint32 ipVersion,uint32 *multicastAddr);
+static void rtl_linkGroupEntry(struct rtl_groupEntry* entryNode , struct rtl_groupEntry ** hashTable, uint32 hashIndex);
+static void rtl_unlinkGroupEntry(struct rtl_groupEntry* entryNode, struct rtl_groupEntry ** hashTable, uint32 hashIndex);
+static void rtl_clearGroupEntry(struct rtl_groupEntry* groupEntryPtr);
+
+static struct rtl_sourceEntry* rtl_searchSourceEntry(uint32 ipVersion, uint32 *sourceAddr, struct rtl_groupEntry *groupEntry);
+static void rtl_linkSourceEntry(struct rtl_groupEntry *groupEntry, struct rtl_sourceEntry* entryNode);
+static void rtl_unlinkSourceEntry(struct rtl_groupEntry *groupEntry, struct rtl_sourceEntry* entryNode);
+static void rtl_clearSourceEntry(struct rtl_sourceEntry* sourceEntryPtr);
+static void rtl_deleteSourceEntry(struct rtl_groupEntry *groupEntry, struct rtl_sourceEntry* sourceEntry);
+#if 0
+static int32 rtl_checkPortMask(uint8 pktPortMask);
+static uint32 rtl_mapPortMaskToPortNum(uint8 pormask);
+#endif
+
+
+//static int32 rtl_mapMCastIPToMAC(uint32 ipVersion, uint32 *ipAddr, uint8 *macAddr );
+static int32 rtl_checkMCastAddrMapping(uint32 ipVersion, uint32 *ipAddr, uint8* macAddr);
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+static int32 rtl_compareIpv6Addr(uint32* ipv6Addr1, uint32* ipv6Addr2);
+static uint16 rtl_ipv6L3Checksum(uint8 *pktBuf, uint32 pktLen, union pseudoHeader *ipv6PseudoHdr);
+#endif
+static int32 rtl_compareMacAddr(uint8* macAddr1, uint8* macAddr2);
+static uint16 rtl_checksum(uint8 *packetBuf, uint32 packetLen);
+
+static uint32 rtl_getGroupFwdPortMask(struct rtl_groupEntry * groupEntry, uint32 enableSourceList, uint32 sysTime);
+static void rtl_checkSourceTimer(struct rtl_groupEntry * groupEntry , struct rtl_sourceEntry * sourceEntry);
+static uint32 rtl_getSourceFwdPortMask(struct rtl_groupEntry * groupEntry,uint32 *sourceAddr, uint32 sysTime);
+//static void rtl_checkGroupFilterTimer(struct rtl_groupEntry *groupEntry);
+static void rtl_checkGroupEntryTimer(struct rtl_groupEntry * groupEntry,uint32 enableSourceList, struct rtl_groupEntry ** hashTable);
+
+static uint32 rtl_getMulticastRouterPortMask(uint32 moduleIndex, uint32 ipVersion, uint32 sysTime);
+
+
+/*hash table operation*/
+static int32 rtl_initHashTable(uint32 moduleIndex, uint32 hashTableSize);
+
+
+/************************************Pkt Process**********************************/
+/*MAC frame analyze function*/
+static void rtl_parseMacFrame(uint32 moduleIndex, uint8* MacFrame, uint32 verifyCheckSum, struct rtl_macFrameInfo* macInfo);
+
+/*Process Query Packet*/
+static void rtl_snoopQuerier(uint32 moduleIndex, uint32 ipVersion, uint32 portNum);
+static uint32 rtl_processQueries(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8* pktBuf, uint32 pktLen);
+/*Process Report Packet*/
+static uint32 rtl_processJoin(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf); // process join report packet
+static uint32 rtl_processLeave(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf); //process leave/done report packet
+static int32 rtl_processIsInclude(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf); //process MODE_IS_INCLUDE report packet
+static int32 rtl_processIsExclude(uint32 moduleIndex, uint32 ipVersion,uint32 portNum, uint8 *pktBuf); //process MODE_IS_EXCLUDE report packet
+static int32 rtl_processToInclude(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf); //process CHANGE_TO_INCLUDE_MODE report packet
+static int32 rtl_processToExclude(uint32 moduleIndex, uint32 ipVersion,uint32 portNum, uint8 *pktBuf); //process CHANGE_TO_EXCLUDE_MODE report packet
+static int32 rtl_processAllow(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf); //process ALLOW_NEW_SOURCES report packet
+static int32 rtl_processBlock(uint32 moduleIndex, uint32 ipVersion,uint32 portNum, uint8 *pktBuf); //process BLOCK_OLD_SOURCES report packet
+static uint32 rtl_processIgmpv3Mldv2Reports(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf);
+
+/*******************different protocol process function**********************************/
+static uint32 rtl_processIgmpMld(uint32 moduleIndex, uint32 ipVersion, uint8* pktBuf, uint32 pktLen, uint32 portNum);
+static uint32 rtl_processDvmrp(uint32 moduleIndex, uint32 ipVersion, uint8* pktBuf, uint32 pktLen, uint32 portNum);
+static uint32 rtl_processMospf(uint32 moduleIndex, uint32 ipVersion, uint8* pktBuf, uint32 pktLen, uint32 portNum);
+static uint32 rtl_processPim(uint32 moduleIndex, uint32 ipVersion, uint8* pktBuf, uint32 pktLen, uint32 portNum);
+
+#if defined(__linux__) && defined(__KERNEL__)
+static void rtl_multicastSysTimerExpired(uint32 expireDada);
+static void rtl_multicastSysTimerInit(void);
+static void rtl_multicastSysTimerDestroy(void);
+#endif
+
+
+/************************************************
+ Implementation
+ ************************************************/
+
+/**************************
+ Initialize
+**************************/
+/*
+@func int32 | rtl_initMulticastSnooping |Initialize igmp snooping system.
+@parm struct rtl_mCastSnoopingGlobalConfig | mCastSnoopingGlobalConfig | Global parameters to config igmp snooping system.
+@rvalue SUCCESS | Initialize successfully.
+@rvalue FAILED | Initialize failed.
+*/
+int32 rtl_initMulticastSnooping(struct rtl_mCastSnoopingGlobalConfig mCastSnoopingGlobalConfig)
+{
+ int i,j;
+ uint32 maxHashTableSize=MAX_HASH_TABLE_SIZE;
+ for(i=0; i<MAX_MCAST_MODULE_NUM; i++)
+ {
+ memset(&(rtl_mCastModuleArray[i]), 0,sizeof(struct rtl_multicastModule));
+
+ for(j=0; j<6; j++)
+ {
+ rtl_mCastModuleArray[i].rtl_gatewayMac[j]=0;
+ }
+
+ rtl_mCastModuleArray[i].rtl_gatewayIpv4Addr=0;
+ rtl_mCastModuleArray[i].rtl_ipv4HashTable=NULL;
+
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ for(j=0; j<4; j++)
+ {
+ rtl_mCastModuleArray[i].rtl_gatewayIpv6Addr[j]=0;
+ }
+ rtl_mCastModuleArray[i].rtl_ipv6HashTable=NULL;
+ #endif
+
+ rtl_mCastModuleArray[i].enableSourceList=TRUE;
+ rtl_mCastModuleArray[i].enableSnooping=FALSE;
+ rtl_mCastModuleArray[i].enableFastLeave=TRUE;
+ }
+
+
+ /*set multicast snooping parameters, use default value*/
+ if(mCastSnoopingGlobalConfig.groupMemberAgingTime==0)
+ {
+ rtl_mCastTimerParas.groupMemberAgingTime= DEFAULT_GROUP_MEMBER_INTERVAL;
+ }
+ else
+ {
+ rtl_mCastTimerParas.groupMemberAgingTime= mCastSnoopingGlobalConfig.groupMemberAgingTime;
+ }
+
+ if(mCastSnoopingGlobalConfig.lastMemberAgingTime==0)
+ {
+ rtl_mCastTimerParas.lastMemberAgingTime= 0;
+ }
+ else
+ {
+ rtl_mCastTimerParas.lastMemberAgingTime= mCastSnoopingGlobalConfig.lastMemberAgingTime;
+ }
+
+ if(mCastSnoopingGlobalConfig.querierPresentInterval==0)
+ {
+ rtl_mCastTimerParas.querierPresentInterval= DEFAULT_QUERIER_PRESENT_TIMEOUT;
+ }
+ else
+ {
+ rtl_mCastTimerParas.querierPresentInterval=mCastSnoopingGlobalConfig.querierPresentInterval;
+ }
+
+
+ if(mCastSnoopingGlobalConfig.dvmrpRouterAgingTime==0)
+ {
+ rtl_mCastTimerParas.dvmrpRouterAgingTime=DEFAULT_DVMRP_AGING_TIME;
+ }
+ else
+ {
+ rtl_mCastTimerParas.dvmrpRouterAgingTime=mCastSnoopingGlobalConfig.dvmrpRouterAgingTime;
+ }
+
+ if(mCastSnoopingGlobalConfig.mospfRouterAgingTime==0)
+ {
+ rtl_mCastTimerParas.mospfRouterAgingTime=DEFAULT_MOSPF_AGING_TIME;
+ }
+ else
+ {
+ rtl_mCastTimerParas.mospfRouterAgingTime=mCastSnoopingGlobalConfig.mospfRouterAgingTime;
+ }
+
+ if(mCastSnoopingGlobalConfig.pimRouterAgingTime==0)
+ {
+ rtl_mCastTimerParas.pimRouterAgingTime=DEFAULT_PIM_AGING_TIME;
+ }
+ else
+ {
+ rtl_mCastTimerParas.pimRouterAgingTime=mCastSnoopingGlobalConfig.pimRouterAgingTime;
+ }
+
+ /* set hash table size and hash mask*/
+ if(mCastSnoopingGlobalConfig.hashTableSize==0)
+ {
+ rtl_hashTableSize=DEFAULT_HASH_TABLE_SIZE; /*default hash table size*/
+ }
+ else
+ {
+ for(i=0;i<11;i++)
+ {
+ if(mCastSnoopingGlobalConfig.hashTableSize>=maxHashTableSize)
+ {
+ rtl_hashTableSize=maxHashTableSize;
+
+ break;
+ }
+ maxHashTableSize=maxHashTableSize>>1;
+
+ }
+ }
+
+ rtl_hashMask=rtl_hashTableSize-1;
+
+
+ if(mCastSnoopingGlobalConfig.maxGroupNum==0)
+ {
+ rtl_totalMaxGroupCnt=DEFAULT_MAX_GROUP_COUNT;
+ }
+ else
+ {
+ rtl_totalMaxGroupCnt=mCastSnoopingGlobalConfig.maxGroupNum;
+ }
+
+ /*initialize group entry pool*/
+ rtl_groupMemory=NULL;
+ rtl_sourceMemory=NULL;
+
+ rtl_groupEntryPool=rtl_initGroupEntryPool(rtl_totalMaxGroupCnt);
+ if(rtl_groupEntryPool==NULL)
+ {
+ return FAILED;
+ }
+
+
+ if(mCastSnoopingGlobalConfig.maxSourceNum==0)
+ {
+ rtl_totalMaxSourceCnt=DEFAULT_MAX_SOURCE_COUNT;
+ }
+ else
+ {
+ rtl_totalMaxSourceCnt=mCastSnoopingGlobalConfig.maxSourceNum;
+ }
+
+ rtl_sourceEntryPool=rtl_initSourceEntryPool(rtl_totalMaxSourceCnt);
+ if(rtl_sourceEntryPool==NULL)
+ {
+ rtl_totalMaxSourceCnt=0;
+ return FAILED;
+ }
+
+#if defined(__linux__) && defined(__KERNEL__)
+ rtl_multicastSysTimerInit();
+#endif
+
+ return SUCCESS;
+
+}
+
+/*
+@func int32 | rtl_exitMulticastSnooping | Exit igmp snooping system.
+@rvalue SUCCESS | Exit successfully.
+@rvalue FAILED | Exit failed.
+*/
+int32 rtl_exitMulticastSnooping(void)
+{
+
+ uint32 moduleIndex;
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM; moduleIndex++)
+ {
+ rtl_unregisterIgmpSnoopingModule(moduleIndex);
+ }
+
+ rtl_hashTableSize=0;
+ rtl_hashMask=0;
+ memset(&rtl_mCastTimerParas,0,sizeof(struct rtl_mCastTimerParameters));
+
+ if(rtl_groupMemory!=NULL)
+ {
+ rtl_glueFree(rtl_groupMemory);
+ }
+
+ rtl_totalMaxGroupCnt=0;
+ rtl_groupMemory=NULL;
+ rtl_groupEntryPool=NULL;
+
+
+ if(rtl_sourceMemory!=NULL)
+ {
+ rtl_glueFree(rtl_sourceMemory);
+ }
+
+ rtl_totalMaxSourceCnt=0;
+ rtl_sourceMemory=NULL;
+ rtl_sourceEntryPool=NULL;
+
+#if defined(__linux__) && defined(__KERNEL__)
+ rtl_multicastSysTimerDestroy();
+#endif
+
+ return SUCCESS;
+
+}
+
+static struct rtl_groupEntry* rtl_initGroupEntryPool(uint32 poolSize)
+{
+
+ uint32 idx=0;
+ struct rtl_groupEntry *poolHead=NULL;
+ struct rtl_groupEntry *entryPtr=NULL;
+ rtl_glueMutexLock(); /* Lock resource */
+ if (poolSize == 0)
+ {
+ goto out;
+ }
+
+ /* Allocate memory */
+ poolHead = (struct rtl_groupEntry *)rtl_glueMalloc(sizeof(struct rtl_groupEntry) * poolSize);
+ rtl_groupMemory=(void *)poolHead;
+
+ if (poolHead != NULL)
+ {
+ memset(poolHead, 0, (poolSize * sizeof(struct rtl_groupEntry)));
+ entryPtr = poolHead;
+
+ /* link the whole group entry pool */
+ for (idx = 0 ; idx < poolSize ; idx++, entryPtr++)
+ {
+ if(idx==0)
+ {
+ entryPtr->previous=NULL;
+ if(idx == (poolSize - 1))
+ {
+ entryPtr->next=NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+ else
+ {
+ entryPtr->previous=entryPtr-1;
+ if (idx == (poolSize - 1))
+ {
+ entryPtr->next = NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+ }
+ }
+
+out:
+
+ rtl_glueMutexUnlock(); /* UnLock resource */
+ return poolHead;
+
+}
+
+
+
+/**************************
+ Resource Managment
+**************************/
+
+// allocate a group entry pool from the group entry pool
+static struct rtl_groupEntry* rtl_allocateGroupEntry(void)
+{
+ struct rtl_groupEntry *ret = NULL;
+
+ rtl_glueMutexLock();
+ if (rtl_groupEntryPool!=NULL)
+ {
+ ret = rtl_groupEntryPool;
+ if(rtl_groupEntryPool->next!=NULL)
+ {
+ rtl_groupEntryPool->next->previous=NULL;
+ }
+ rtl_groupEntryPool = rtl_groupEntryPool->next;
+ memset(ret, 0, sizeof(struct rtl_groupEntry));
+ }
+
+ rtl_glueMutexUnlock();
+
+ return ret;
+}
+
+// free a group entry and link it back to the group entry pool, default is link to the pool head
+static void rtl_freeGroupEntry(struct rtl_groupEntry* groupEntryPtr)
+{
+ if (!groupEntryPtr)
+ {
+ return;
+ }
+
+ rtl_glueMutexLock();
+ groupEntryPtr->next = rtl_groupEntryPool;
+ if(rtl_groupEntryPool!=NULL)
+ {
+ rtl_groupEntryPool->previous=groupEntryPtr;
+ }
+ rtl_groupEntryPool=groupEntryPtr;
+ rtl_glueMutexUnlock();
+}
+
+
+
+static struct rtl_sourceEntry* rtl_initSourceEntryPool(uint32 poolSize)
+{
+
+ uint32 idx=0;
+ struct rtl_sourceEntry *poolHead=NULL;
+ struct rtl_sourceEntry *entryPtr=NULL;
+ rtl_glueMutexLock(); /* Lock resource */
+ if (poolSize == 0)
+ {
+ goto out;
+ }
+
+ /* Allocate memory */
+ poolHead = (struct rtl_sourceEntry *)rtl_glueMalloc(sizeof(struct rtl_sourceEntry) * rtl_totalMaxSourceCnt);
+ rtl_sourceMemory=(void *)poolHead;
+ if (poolHead != NULL)
+ {
+ memset(poolHead, 0, (poolSize * sizeof(struct rtl_sourceEntry)));
+ entryPtr = poolHead;
+
+ /* link the whole source entry pool */
+ for (idx = 0 ; idx < poolSize ; idx++, entryPtr++)
+ {
+ if(idx==0)
+ {
+ entryPtr->previous=NULL;
+ if(idx == (poolSize - 1))
+ {
+ entryPtr->next=NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+ else
+ {
+ entryPtr->previous=entryPtr-1;
+ if (idx == (poolSize - 1))
+ {
+ entryPtr->next = NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+
+ }
+ }
+
+out:
+ rtl_glueMutexUnlock(); /* UnLock resource */
+ return poolHead;
+
+}
+
+
+
+/**************************
+ Resource Managment
+**************************/
+
+// allocate a group entry pool from the group entry pool
+static struct rtl_sourceEntry* rtl_allocateSourceEntry(void)
+{
+ struct rtl_sourceEntry *ret = NULL;
+
+ rtl_glueMutexLock();
+ if (rtl_sourceEntryPool!=NULL)
+ {
+ ret = rtl_sourceEntryPool;
+ if(rtl_sourceEntryPool->next!=NULL)
+ {
+ rtl_sourceEntryPool->next->previous=NULL;
+ }
+ rtl_sourceEntryPool = rtl_sourceEntryPool->next;
+ memset(ret, 0, sizeof(struct rtl_sourceEntry));
+ }
+
+ rtl_glueMutexUnlock();
+
+ return ret;
+}
+
+// free a group entry and link it back to the group entry pool, default is link to the pool head
+static void rtl_freeSourceEntry(struct rtl_sourceEntry* sourceEntryPtr)
+{
+ if (!sourceEntryPtr)
+ {
+ return;
+ }
+
+ rtl_glueMutexLock();
+ sourceEntryPtr->next = rtl_sourceEntryPool;
+ if(rtl_sourceEntryPool!=NULL)
+ {
+ rtl_sourceEntryPool->previous=sourceEntryPtr;
+ }
+
+ rtl_sourceEntryPool=sourceEntryPtr;
+
+ rtl_glueMutexUnlock();
+}
+
+
+
+/*********************************************
+ Group list operation
+ *********************************************/
+
+/* find a group address in a group list */
+
+struct rtl_groupEntry* rtl_searchGroupEntry(uint32 moduleIndex, uint32 ipVersion,uint32 *multicastAddr)
+{
+ struct rtl_groupEntry* groupPtr = NULL;
+ int32 hashIndex;
+ if(ipVersion==IP_VERSION4)
+ {
+ hashIndex=rtl_hashMask&multicastAddr[0];
+ groupPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[hashIndex];
+
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ hashIndex=rtl_hashMask&multicastAddr[3];
+ groupPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[hashIndex];
+ }
+#endif
+
+ while (groupPtr!=NULL)
+ {
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION4)
+ {
+ if((multicastAddr[0]==groupPtr->groupAddr[0]) && (groupPtr->ipVersion==IP_VERSION4))
+ {
+ return groupPtr;
+ }
+ }
+
+ if(ipVersion==IP_VERSION6)
+ {
+ if( (multicastAddr[0]==groupPtr->groupAddr[0])&&
+ (multicastAddr[1]==groupPtr->groupAddr[1])&&
+ (multicastAddr[2]==groupPtr->groupAddr[2])&&
+ (multicastAddr[3]==groupPtr->groupAddr[3])
+ )
+ {
+ return groupPtr;
+
+ }
+ }
+#else
+ if(ipVersion==IP_VERSION4)
+ {
+ if(multicastAddr[0]==groupPtr->groupAddr[0])
+ {
+ return groupPtr;
+ }
+ }
+#endif
+ groupPtr = groupPtr->next;
+
+ }
+
+ return NULL;
+}
+
+
+/* link group Entry in the front of a group list */
+static void rtl_linkGroupEntry(struct rtl_groupEntry* groupEntry , struct rtl_groupEntry ** hashTable, uint32 hashIndex)
+{
+ rtl_glueMutexLock();//Lock resource
+ if(NULL==groupEntry)
+ {
+ return;
+ }
+ else
+ {
+ if(hashTable[hashIndex]!=NULL)
+ {
+ hashTable[hashIndex]->previous=groupEntry;
+ }
+ groupEntry->next = hashTable[hashIndex];
+ hashTable[hashIndex]=groupEntry;
+ hashTable[hashIndex]->previous=NULL;
+
+ }
+ rtl_glueMutexUnlock();//UnLock resource
+
+}
+
+
+/* unlink a group entry from group list */
+static void rtl_unlinkGroupEntry(struct rtl_groupEntry* groupEntry, struct rtl_groupEntry ** hashTable, uint32 hashIndex)
+{
+ if(NULL==groupEntry)
+ {
+ return;
+ }
+ else
+ {
+ rtl_glueMutexLock(); /* lock resource*/
+ /* unlink entry node*/
+ if(groupEntry==hashTable[hashIndex]) /*unlink group list head*/
+ {
+ hashTable[hashIndex]=groupEntry->next;
+ if(hashTable[hashIndex]!=NULL)
+ {
+ hashTable[hashIndex]->previous=NULL;
+ }
+
+ groupEntry->previous=NULL;
+ groupEntry->next=NULL;
+ }
+ else
+ {
+ if(groupEntry->previous!=NULL)
+ {
+ groupEntry->previous->next=groupEntry->next;
+ }
+
+ if(groupEntry->next!=NULL)
+ {
+ groupEntry->next->previous=groupEntry->previous;
+ }
+ groupEntry->previous=NULL;
+ groupEntry->next=NULL;
+ }
+
+ rtl_glueMutexUnlock();//UnLock resource
+ }
+}
+
+
+/* clear the content of group entry */
+static void rtl_clearGroupEntry(struct rtl_groupEntry* groupEntry)
+{
+ rtl_glueMutexLock();
+ if (NULL!=groupEntry)
+ {
+ memset(groupEntry, 0, sizeof(struct rtl_groupEntry));
+ }
+ rtl_glueMutexUnlock();
+}
+
+static void rtl_deleteSourceList(struct rtl_groupEntry* groupEntry)
+{
+ struct rtl_sourceEntry *sourceEntry=groupEntry->sourceList;
+ struct rtl_sourceEntry *nextSourceEntry=NULL;
+ while(sourceEntry!=NULL)
+ {
+ nextSourceEntry=sourceEntry->next;
+ rtl_deleteSourceEntry(groupEntry,sourceEntry);
+ sourceEntry=nextSourceEntry;
+ }
+}
+
+static void rtl_deleteGroupEntry( struct rtl_groupEntry* groupEntry,struct rtl_groupEntry ** hashTable)
+{
+ if(groupEntry!=NULL)
+ {
+
+ if(groupEntry->ipVersion==IP_VERSION4)
+ {
+ rtl_deleteSourceList(groupEntry);
+ rtl_unlinkGroupEntry(groupEntry, hashTable,(groupEntry->groupAddr[0]&rtl_hashMask));
+ rtl_clearGroupEntry(groupEntry);
+ rtl_freeGroupEntry(groupEntry);
+ }
+ else
+ {
+ rtl_deleteSourceList(groupEntry);
+ rtl_unlinkGroupEntry(groupEntry, hashTable,(groupEntry->groupAddr[3]&rtl_hashMask));
+ rtl_clearGroupEntry(groupEntry);
+ rtl_freeGroupEntry(groupEntry);
+ }
+ }
+
+}
+
+static struct rtl_sourceEntry* rtl_searchSourceEntry(uint32 ipVersion, uint32 *sourceAddr, struct rtl_groupEntry *groupEntry)
+{
+ struct rtl_sourceEntry *sourcePtr=groupEntry->sourceList;
+ while(sourcePtr!=NULL)
+ {
+ if(ipVersion==IP_VERSION4)
+ {
+ if(sourceAddr[0]==sourcePtr->sourceAddr[0])
+ {
+ return sourcePtr;
+ }
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ if( (sourceAddr[0]==sourcePtr->sourceAddr[0]) &&
+ (sourceAddr[1]==sourcePtr->sourceAddr[1])&&
+ (sourceAddr[2]==sourcePtr->sourceAddr[2])&&
+ (sourceAddr[3]==sourcePtr->sourceAddr[3])
+ )
+ {
+ return sourcePtr;
+
+ }
+ }
+#endif
+ sourcePtr=sourcePtr->next;
+ }
+
+ return NULL;
+}
+
+static int32 rtl_searchSourceAddr(uint32 ipVersion, uint32 *sourceAddr, uint32 *sourceArray, uint32 elementCount)
+{
+ uint32 i=0;
+ uint32 *srcPtr=sourceArray;
+
+ for(i=0; i<elementCount; i++)
+ {
+ if(ipVersion==IP_VERSION4)
+ {
+ if(sourceAddr[0]==srcPtr[0])
+ {
+ return TRUE;
+ }
+ srcPtr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ if( (sourceAddr[0]==srcPtr[0])&&\
+ (sourceAddr[1]==srcPtr[1])&&\
+ (sourceAddr[2]==srcPtr[2])&&\
+ (sourceAddr[3]==srcPtr[3]))
+ {
+
+ return TRUE;
+ }
+
+ srcPtr=srcPtr+4;
+ }
+#endif
+ }
+
+ return FALSE;
+}
+
+static void rtl_linkSourceEntry(struct rtl_groupEntry *groupEntry, struct rtl_sourceEntry* entryNode)
+{
+ if((NULL==entryNode) || (NULL==groupEntry))
+ {
+ return;
+ }
+ else
+ {
+ rtl_glueMutexLock(); /* lock resource*/
+
+ if(groupEntry->sourceList!=NULL)
+ {
+ groupEntry->sourceList->previous=entryNode;
+ }
+ entryNode->next=groupEntry->sourceList;
+ groupEntry->sourceList=entryNode;
+ groupEntry->sourceList->previous=NULL;
+
+ rtl_glueMutexUnlock(); /* lock resource*/
+ }
+}
+
+static void rtl_unlinkSourceEntry(struct rtl_groupEntry *groupEntry, struct rtl_sourceEntry* sourceEntry)
+{
+
+ if((NULL==sourceEntry) ||(NULL==groupEntry))
+ {
+ return;
+ }
+ else
+ {
+ rtl_glueMutexLock(); /* lock resource*/
+ /* unlink entry node*/
+ if(sourceEntry==groupEntry->sourceList) /*unlink group list head*/
+ {
+
+ groupEntry->sourceList=sourceEntry->next;
+ if(groupEntry->sourceList!=NULL)
+ {
+ groupEntry->sourceList ->previous=NULL;
+ }
+
+ sourceEntry->previous=NULL;
+ sourceEntry->next=NULL;
+ }
+ else
+ {
+ if(sourceEntry->previous!=NULL)
+ {
+ sourceEntry->previous->next=sourceEntry->next;
+ }
+
+ if(sourceEntry->next!=NULL)
+ {
+ sourceEntry->next->previous=sourceEntry->previous;
+ }
+ sourceEntry->previous=NULL;
+ sourceEntry->next=NULL;
+ }
+
+ rtl_glueMutexUnlock();//UnLock resource
+ }
+
+
+}
+
+static void rtl_clearSourceEntry(struct rtl_sourceEntry* sourceEntryPtr)
+{
+ rtl_glueMutexLock();
+ if (NULL!=sourceEntryPtr)
+ {
+ memset(sourceEntryPtr, 0, sizeof(struct rtl_sourceEntry));
+ }
+ rtl_glueMutexUnlock();
+}
+
+
+static void rtl_deleteSourceEntry(struct rtl_groupEntry *groupEntry, struct rtl_sourceEntry* sourceEntry)
+{
+ if(sourceEntry!=NULL)
+ {
+ rtl_unlinkSourceEntry(groupEntry,sourceEntry);
+ rtl_clearSourceEntry(sourceEntry);
+ rtl_freeSourceEntry(sourceEntry);
+ }
+}
+
+#if 0
+static int32 rtl_checkPortMask(uint8 pktPortMask)
+{
+ int32 i=0;
+ uint8 portMaskn=PORT0_MASK;
+ uint8 count=0;
+ for(i=0; i<MAX_SUPPORT_PORT_NUMBER; i++)
+ {
+ if(portMaskn&pktPortMask)
+ {
+ count++;
+ }
+ portMaskn=portMaskn<<1;
+ }
+
+ if(count==1)
+ {
+ return SUCCESS;
+ }
+ else
+ {
+ return FAILED;
+ }
+}
+
+static uint32 rtl_mapPortMaskToPortNum(uint8 portMask)
+{
+ int i;
+ for(i=0; i<MAX_SUPPORT_PORT_NUMBER; i++)
+ {
+ if((portMask&(1<<i))!=0)
+ {
+ return i;
+ }
+ }
+
+ return 0xFFFFFFFF;
+}
+
+
+static int32 rtl_mapMCastIPToMAC(uint32 ipVersion, uint32 *ipAddr, uint8 *macAddr )
+{
+ if(ipVersion==IP_VERSION6)
+ {
+ if(IS_IPV6_MULTICAST_ADDRESS(ipAddr))
+ {
+ macAddr[0]=0x33;
+ macAddr[1]=0x33;
+ macAddr[2]=(ipAddr[3]&0xff000000)>>24;
+ macAddr[3]=(ipAddr[3]&0x00ff0000)>>16;
+ macAddr[4]=(ipAddr[3]&0x0000ff00)>>8;
+ macAddr[5]= ipAddr[3]&0x000000ff;
+ return SUCCESS;
+ }
+ else
+ {
+ return FAILED;
+ }
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ if(IS_IPV4_MULTICAST_ADDRESS(ipAddr))
+ {
+ macAddr[0]=0x01;
+ macAddr[1]=0x00;
+ macAddr[2]=0x5e;
+ macAddr[3]=(ipAddr[0]&0x007f0000)>>16;
+ macAddr[4]=(ipAddr[0]&0x0000ff00)>>8;
+ macAddr[5]= ipAddr[0]&0x000000ff;
+ return SUCCESS;
+ }
+ else
+ {
+ return FAILED;
+ }
+ }
+
+ return FAILED;
+}
+#endif
+
+static int32 rtl_checkMCastAddrMapping(uint32 ipVersion, uint32 *ipAddr, uint8* macAddr)
+{
+ if(ipVersion==IP_VERSION4)
+ {
+ if(macAddr[0]!=0x01)
+ {
+ return FALSE;
+ }
+
+ if((macAddr[3]&0x7f)!=(uint8)((ipAddr[0]&0x007f0000)>>16))
+ {
+ return FALSE;
+ }
+
+ if(macAddr[4]!=(uint8)((ipAddr[0]&0x0000ff00)>>8))
+ {
+ return FALSE;
+ }
+
+ if(macAddr[5]!=(uint8)(ipAddr[0]&0x000000ff))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ if(macAddr[0]!=0x33)
+ {
+ return FALSE;
+ }
+
+ if(macAddr[1]!=0x33)
+ {
+ return FALSE;
+ }
+
+ if(macAddr[2]!=(uint8)((ipAddr[3]&0xff000000)>>24))
+ {
+ return FALSE;
+ }
+
+ if(macAddr[3]!=(uint8)((ipAddr[3]&0x00ff0000)>>16))
+ {
+ return FALSE;
+ }
+
+ if(macAddr[4]!=(uint8)((ipAddr[3]&0x0000ff00)>>8))
+ {
+ return FALSE;
+ }
+
+ if(macAddr[5]!=(uint8)(ipAddr[3]&0x000000ff))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+static int32 rtl_compareIpv6Addr(uint32* ipv6Addr1, uint32* ipv6Addr2)
+{
+ int i;
+ for(i=0; i<4; i++)
+ {
+ if(ipv6Addr1[i]!=ipv6Addr2[i])
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+#endif
+
+static int32 rtl_compareMacAddr(uint8* macAddr1, uint8* macAddr2)
+{
+ int i;
+ for(i=0; i<6; i++)
+ {
+ if(macAddr1[i]!=macAddr2[i])
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static uint16 rtl_checksum(uint8 *packetBuf, uint32 packetLen)
+{
+ /*note: the first bytes of packetBuf should be two bytes aligned*/
+ uint32 checksum=0;
+ uint32 count=packetLen;
+ uint16 *ptr= (uint16 *) (packetBuf);
+
+ while(count>1)
+ {
+ checksum+= ntohs(*ptr);
+ ptr++;
+ count -= 2;
+ }
+
+ if(count>0)
+ {
+ checksum+= *(packetBuf+packetLen-1)<<8; /*the last odd byte is treated as bit 15~8 of unsigned short*/
+ }
+
+ /* Roll over carry bits */
+ checksum = (checksum >> 16) + (checksum & 0xffff);
+ checksum += (checksum >> 16);
+
+ /* Return checksum */
+ return ((uint16) ~ checksum);
+
+}
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+static uint16 rtl_ipv6L3Checksum(uint8 *pktBuf, uint32 pktLen, union pseudoHeader *ipv6PseudoHdr)
+{
+ uint32 checksum=0;
+ uint32 count=pktLen;
+ uint16 *ptr;
+
+ /*compute ipv6 pseudo-header checksum*/
+ ptr= (uint16 *) (ipv6PseudoHdr);
+ for(count=0; count<20; count++) /*the pseudo header is 40 bytes long*/
+ {
+ checksum+= ntohs(*ptr);
+ ptr++;
+ }
+
+ /*compute the checksum of mld buffer*/
+ count=pktLen;
+ ptr=(uint16 *) (pktBuf);
+ while(count>1)
+ {
+ checksum+= ntohs(*ptr);
+ ptr++;
+ count -= 2;
+ }
+
+ if(count>0)
+ {
+ checksum+= *(pktBuf+pktLen-1)<<8; /*the last odd byte is treated as bit 15~8 of unsigned short*/
+ }
+
+ /* Roll over carry bits */
+ checksum = (checksum >> 16) + (checksum & 0xffff);
+ checksum += (checksum >> 16);
+
+ /* Return checksum */
+ return ((uint16) ~ checksum);
+
+}
+#endif
+
+static uint32 rtl_getGroupFwdPortMask(struct rtl_groupEntry * groupEntry, uint32 enableSourceList, uint32 sysTime)
+{
+ int i;
+ uint32 portMaskn=PORT0_MASK;
+ uint32 fwdPortMask=0;
+ struct rtl_sourceEntry * sourcePtr=NULL;;
+
+ for(i=0; i<MAX_SUPPORT_PORT_NUMBER; i++)
+ {
+ if(enableSourceList==TRUE)
+ {
+ if(groupEntry->groupFilterTimer[i]>sysTime) /*exclude mode never expired*/
+ {
+ fwdPortMask|=portMaskn;
+ }
+ else/*include mode*/
+ {
+ sourcePtr=groupEntry->sourceList;
+ while(sourcePtr!=NULL)
+ {
+ if(sourcePtr->portTimer[i]>sysTime)
+ {
+ fwdPortMask|=portMaskn;
+ break;
+ }
+ else
+ {
+ sourcePtr=sourcePtr->next;
+ }
+
+ }
+
+ }
+ }
+ else
+ {
+ if(groupEntry->groupFilterTimer[i]>sysTime) /*exclude mode never expired*/
+ {
+ fwdPortMask|=portMaskn;
+ }
+ }
+ portMaskn=portMaskn<<1;
+ }
+
+
+ return fwdPortMask;
+}
+
+
+
+static void rtl_checkSourceTimer(struct rtl_groupEntry * groupEntry , struct rtl_sourceEntry * sourceEntry)
+{
+ int i=0;
+
+ uint32 portMaskn=PORT0_MASK;
+ uint32 deletePortMask=0;
+ for(i=0; i<MAX_SUPPORT_PORT_NUMBER; i++)
+ {
+
+ if(sourceEntry->portTimer[i]==0)/*means not exist*/
+ {
+ deletePortMask|=portMaskn;
+ }
+ else
+ {
+ if(sourceEntry->portTimer[i]<=rtl_sysUpSeconds) /*means time out*/
+ {
+ if(groupEntry->groupFilterTimer[i]<=rtl_sysUpSeconds) /*means include mode*/
+ {
+ sourceEntry->portTimer[i]=0;
+ deletePortMask|=portMaskn;
+ }
+
+ }
+ }
+
+ portMaskn=portMaskn<<1;
+ }
+
+ if(deletePortMask==((1<<MAX_SUPPORT_PORT_NUMBER)-1)) /*means all port are INCLUDE mode and expired*/
+ {
+ rtl_deleteSourceEntry(groupEntry,sourceEntry);
+ }
+
+
+}
+
+static uint32 rtl_getSourceFwdPortMask(struct rtl_groupEntry * groupEntry,uint32 *sourceAddr, uint32 sysTime)
+{
+ int i;
+ uint32 portMaskn=PORT0_MASK;
+ uint32 fwdPortMask=0;
+ struct rtl_sourceEntry * sourceEntry=NULL;
+ if(groupEntry==NULL)
+ {
+ return 0xFFFFFFFF; /*broadcast*/
+ }
+ else
+ {
+ sourceEntry=rtl_searchSourceEntry((uint32)(groupEntry->ipVersion),sourceAddr, groupEntry);
+ for(i=0; i<MAX_SUPPORT_PORT_NUMBER; i++)
+ {
+
+ if(groupEntry->groupFilterTimer[i]<=sysTime) /*include mode*/
+ {
+ if(sourceEntry!=NULL)
+ {
+ if( sourceEntry->portTimer[i]>sysTime)
+ {
+ fwdPortMask|=portMaskn;
+ }
+ }
+ }
+ else/*exclude mode*/
+ {
+ if(sourceEntry==NULL)
+ {
+ fwdPortMask|=portMaskn;
+ }
+ else
+ {
+ if((sourceEntry->portTimer[i]>sysTime) || (sourceEntry->portTimer[i]==0))
+ {
+ fwdPortMask|=portMaskn;
+ }
+ }
+ }
+
+ portMaskn=portMaskn<<1;
+ }
+ return fwdPortMask;
+
+ }
+}
+
+
+
+
+static void rtl_checkGroupEntryTimer(struct rtl_groupEntry * groupEntry, uint32 enableSourceList, struct rtl_groupEntry ** hashTable)
+{
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ uint32 oldFwdPortMask=0;
+ uint32 tmpFwdPortMask=0;
+ #endif
+
+ uint32 newFwdPortMask=0;
+ struct rtl_sourceEntry *sourceEntry=groupEntry->sourceList;
+ struct rtl_sourceEntry *nextSourceEntry=NULL;
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ oldFwdPortMask=rtl_getGroupFwdPortMask(groupEntry, enableSourceList, rtl_sysUpSeconds?(rtl_sysUpSeconds-1):0);
+ #endif
+
+ while(sourceEntry!=NULL)
+ {
+ nextSourceEntry=sourceEntry->next;
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ timerEventContext.sourceAddr[0]=sourceEntry->sourceAddr[0];
+ #endif
+ rtl_checkSourceTimer(groupEntry, sourceEntry);
+ sourceEntry=nextSourceEntry;
+ }
+
+ newFwdPortMask=rtl_getGroupFwdPortMask(groupEntry, enableSourceList, rtl_sysUpSeconds);
+
+
+ if(newFwdPortMask==0) /*none active port*/
+ {
+ rtl_deleteGroupEntry(groupEntry,hashTable);
+ }
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if((oldFwdPortMask!=newFwdPortMask) ||(newFwdPortMask==0))
+ {
+ timerEventContext.sourceAddr[0]=0;
+
+ tmpFwdPortMask=oldFwdPortMask&(~newFwdPortMask);
+ if(tmpFwdPortMask==0)
+ {
+ tmpFwdPortMask=newFwdPortMask & (~oldFwdPortMask);
+ }
+
+#ifdef CONFIG_PROC_FS
+ rtl_mCastModuleArray[timerEventContext.moduleIndex].expireEventCnt++;
+#endif
+ timerEventContext.portMask=(uint32)tmpFwdPortMask;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &timerEventContext);
+
+ }
+ #endif
+
+}
+
+
+
+static int32 rtl_initHashTable(uint32 moduleIndex, uint32 hashTableSize)
+{
+ uint32 i=0;
+
+ /* Allocate memory */
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable=NULL;
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable = (struct rtl_groupEntry **)rtl_glueMalloc(4 * hashTableSize);
+ if (rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!= NULL)
+ {
+ for (i = 0 ; i < hashTableSize ; i++)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i]=NULL;
+ }
+
+#ifndef CONFIG_RTL_MLD_SNOOPING
+ return SUCCESS;
+#endif
+
+ }
+ else
+ {
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!=NULL)
+ {
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+
+#ifndef CONFIG_RTL_MLD_SNOOPING
+ return FAILED;
+#endif
+
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable=NULL;
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable= (struct rtl_groupEntry **)rtl_glueMalloc(4 * hashTableSize);
+ if (rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable!=NULL)
+ {
+ for (i = 0 ; i < hashTableSize ; i++)
+ {
+
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i]=NULL;
+ }
+ return SUCCESS;
+ }
+ else
+ {
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable!=NULL)
+ {
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!=NULL)
+ {
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+
+ return FAILED;
+
+ }
+#endif
+
+
+}
+
+
+
+/**************************
+ Utility
+**************************/
+static void rtl_parseMacFrame(uint32 moduleIndex, uint8* macFrame, uint32 verifyCheckSum, struct rtl_macFrameInfo* macInfo)
+{
+
+//MAC Frame :DA(6 bytes)+SA(6 bytes)+ CPU tag(4 bytes) + VlAN tag(Optional, 4 bytes)
+// +Type(IPv4:0x0800, IPV6:0x86DD, PPPOE:0x8864, 2 bytes )+Data(46~1500 bytes)+CRC(4 bytes)
+//CPU tag: Realtek Ethertype==0x8899(2 bytes)+protocol==0x9(4 MSB)+priority(2 bits)+reserved(4 bits)+portmask(6 LSB)
+ uint8 *ptr=macFrame;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ int i=0;
+ uint8 nextHeader=0;
+ uint16 extensionHdrLen=0;
+ uint8 routerhead=FALSE;
+ uint8 needchecksum=FALSE;
+
+ uint8 optionDataLen=0;
+ uint8 optionType=0;
+ uint32 ipv6RAO=0;
+#endif
+
+ uint32 ipAddr[4]={0,0,0,0};
+ union pseudoHeader pHeader;
+
+ memset(macInfo,0,sizeof(struct rtl_macFrameInfo));
+ memset(&pHeader, 0, sizeof(union pseudoHeader));
+
+ ptr=ptr+12;
+
+
+ /*check the presence of VLAN tag*/
+ if(*(int16 *)(ptr)==(int16)htons(VLAN_PROTOCOL_ID))
+ {
+ ptr=ptr+4;
+ }
+
+ /*ignore packet with PPPOE header*/
+ if(*(int16 *)(ptr)==(int16)htons(PPPOE_ETHER_TYPE))
+ {
+ return;
+ }
+
+
+ /*check the presence of ipv4 type*/
+ if(*(int16 *)(ptr)==(int16)htons(IPV4_ETHER_TYPE))
+ {
+ ptr=ptr+2;
+ macInfo->ipBuf=ptr;
+ macInfo->ipVersion=IP_VERSION4;
+ }
+ else
+ {
+ /*check the presence of ipv4 type*/
+ if(*(int16 *)(ptr)==(int16)htons(IPV6_ETHER_TYPE))
+ {
+ ptr=ptr+2;
+ macInfo->ipBuf=ptr;
+ macInfo->ipVersion=IP_VERSION6;
+ }
+ }
+
+ if((macInfo->ipVersion!=IP_VERSION4) && (macInfo->ipVersion!=IP_VERSION6))
+ {
+ return;
+ }
+ macInfo->checksumFlag=FAILED;
+
+ if(macInfo->ipVersion==IP_VERSION4)
+ {
+ macInfo->ipHdrLen=(uint16)((((struct ipv4Pkt *)(macInfo->ipBuf))->vhl&0x0f)<<2);
+ macInfo->l3PktLen=ntohs(((struct ipv4Pkt *)(macInfo->ipBuf))->length)-macInfo->ipHdrLen;
+ ptr=ptr+macInfo->ipHdrLen;
+ macInfo->l3PktBuf=ptr;
+ macInfo->macFrameLen=(uint16)((ptr-macFrame)+macInfo->l3PktLen);
+
+/*distinguish different IGMP packet:
+ ip_header_length destination_ip igmp_packet_length igmp_type group_address
+IGMPv1_general_query: 20 224.0.0.1 8 0x11 0
+IGMPv2_general_query: 24 224.0.0.1 8 0x11 0
+IGMPv2_group_specific_query: 24 224.0.0.1 8 0x11 !=0
+IGMPv3 _query: 24 224.0.0.1 >=12 0x11 according_to_different_situation
+
+IGMPv1_join: 20 actual_multicast_address 8 0x12 actual_multicast_address
+IGMPv2_join: 24 actual_multicast_address 8 0x16 actual_multicast_address
+IGMPv2_leave: 24 actual_multicast_address 8 0x17 actual_multicast_address
+IGMPv3_report: 24 actual_multicast_address >=12 0x22 actual_multicast_address*/
+
+ /* parse IGMP type and version*/
+ if(((struct ipv4Pkt *)(macInfo->ipBuf))->protocol==IGMP_PROTOCOL)
+ {
+ /*check DVMRP*/
+ if((macInfo->l3PktBuf[0]==DVMRP_TYPE) && (((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp==htonl(DVMRP_ADDR)) )
+ {
+ macInfo->l3Protocol=DVMRP_PROTOCOL;
+ }
+ else
+ {
+ /*means unicast*/
+ if((macFrame[0]&0x01)==0)
+ {
+ if(rtl_compareMacAddr(macFrame, rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac)==TRUE)
+ {
+ if(((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp==htonl(rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv4Addr))
+ {
+ macInfo->l3Protocol=IGMP_PROTOCOL;
+ goto otherpro;
+ }
+ }
+
+ }
+ else /*means multicast*/
+ {
+ ipAddr[0]=ntohl(((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp);
+ if(rtl_checkMCastAddrMapping(IP_VERSION4,ipAddr,macFrame)==TRUE)
+ {
+ macInfo->l3Protocol=IGMP_PROTOCOL;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+ }
+
+otherpro:
+ if(((struct ipv4Pkt *)(macInfo->ipBuf))->protocol==MOSPF_PROTOCOL &&\
+ ((((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp==htonl(IPV4_MOSPF_ADDR1)) ||\
+ (((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp==htonl(IPV4_MOSPF_ADDR2))))
+ {
+ macInfo->l3Protocol=MOSPF_PROTOCOL;
+ }
+
+ if(((struct ipv4Pkt *)(macInfo->ipBuf))->protocol==PIM_PROTOCOL && (((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp==htonl(IPV4_PIM_ADDR)))
+ {
+ macInfo->l3Protocol=PIM_PROTOCOL;
+ }
+
+ if(verifyCheckSum==TRUE)
+ {
+ if(rtl_checksum(macInfo->l3PktBuf, macInfo->l3PktLen)!=0)
+ {
+ macInfo->checksumFlag=FAILED;
+ }
+ else
+ {
+ macInfo->checksumFlag=SUCCESS;
+ }
+ }
+ else
+ {
+ macInfo->checksumFlag=SUCCESS;
+ }
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(macInfo->ipVersion==IP_VERSION6)
+ {
+ macInfo->macFrameLen=(uint16)(ptr-macFrame+IPV6_HEADER_LENGTH+ntohs(((struct ipv6Pkt *)(macInfo->ipBuf))->payloadLenth));
+ macInfo->ipHdrLen=IPV6_HEADER_LENGTH;
+
+ nextHeader=((struct ipv6Pkt *)(macInfo->ipBuf))->nextHeader;
+ ptr=ptr+IPV6_HEADER_LENGTH;
+ while((ptr-macInfo->ipBuf)<(ntohs(((struct ipv6Pkt *)(macInfo->ipBuf))->payloadLenth)+IPV6_HEADER_LENGTH))
+ {
+ switch(nextHeader)
+ {
+ case HOP_BY_HOP_OPTIONS_HEADER:
+ /*parse hop-by-hop option*/
+ nextHeader=ptr[0];
+ extensionHdrLen=((uint16)(ptr[1])+1)*8;
+ ptr=ptr+2;
+
+ while((ptr-macInfo->ipBuf-40)<extensionHdrLen)
+ {
+ optionType=ptr[0];
+ /*pad1 option*/
+ if(optionType==0)
+ {
+ ptr=ptr+1;
+ continue;
+ }
+
+ /*padN option*/
+ if(optionType==1)
+ {
+ optionDataLen=ptr[1];
+ ptr=ptr+optionDataLen+2;
+ continue;
+ }
+
+ /*router alter option*/
+ if(ntohl(*(uint32 *)(ptr))==IPV6_ROUTER_ALTER_OPTION)
+ {
+ ipv6RAO=IPV6_ROUTER_ALTER_OPTION;
+ ptr=ptr+4;
+ continue;
+ }
+
+ /*other TLV option*/
+ if((optionType!=0) && (optionType!=1))
+ {
+ optionDataLen=ptr[1];
+ ptr=ptr+optionDataLen+2;
+ continue;
+ }
+
+
+ }
+ /*
+ if((ptr-macInfo->ipBuf-40)!=extensionHdrLen)
+ {
+ rtl_gluePrintf("ipv6 packet parse error\n");
+ }*/
+
+ break;
+
+ case ROUTING_HEADER:
+ nextHeader=ptr[0];
+ extensionHdrLen=((uint16)(ptr[1])+1)*8;
+
+
+ if (ptr[3]>0)
+ {
+ ptr=ptr+extensionHdrLen;
+ for(i=0; i<4; i++)
+ {
+ pHeader.ipv6_pHdr.destinationAddr[i]=*((uint32 *)(ptr)-4+i);
+
+ }
+ routerhead=TRUE;
+
+
+ }
+ else
+ {
+ ptr=ptr+extensionHdrLen;
+ }
+
+
+
+ break;
+
+ case FRAGMENT_HEADER:
+ nextHeader=ptr[0];
+ ptr=ptr+8;
+ break;
+
+ case DESTINATION_OPTION_HEADER:
+ nextHeader=ptr[0];
+ extensionHdrLen=((uint16)(ptr[1])+1)*8;
+ ptr=ptr+extensionHdrLen;
+ break;
+
+ case ICMP_PROTOCOL:
+ nextHeader=NO_NEXT_HEADER;
+ macInfo->l3PktLen=ntohs(((struct ipv6Pkt *)(macInfo->ipBuf))->payloadLenth)-(uint16)(ptr-macInfo->ipBuf-IPV6_HEADER_LENGTH);
+ macInfo->l3PktBuf=ptr;
+ if((ptr[0]==MLD_QUERY) ||(ptr[0]==MLDV1_REPORT) ||(ptr[0]==MLDV1_DONE) ||(ptr[0]==MLDV2_REPORT))
+ {
+ /*means multicast*/
+ if( (macFrame[0]==0x33)&&\
+ (macFrame[1]==0x33))
+ {
+ ipAddr[0]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[0]);
+ ipAddr[1]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[1]);
+ ipAddr[2]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[2]);
+ ipAddr[3]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[3]);
+
+ if(rtl_checkMCastAddrMapping(IP_VERSION6, ipAddr, macFrame)==TRUE)
+ {
+ macInfo->l3Protocol=ICMP_PROTOCOL;
+ }
+
+ }
+ else /*means multicast*/
+ {
+
+ ipAddr[0]=htonl(rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[0]);
+ ipAddr[1]=htonl(rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[1]);
+ ipAddr[2]=htonl(rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[2]);
+ ipAddr[3]=htonl(rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[3]);
+ if( (rtl_compareMacAddr(macFrame, rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac)==TRUE) &&\
+ (rtl_compareIpv6Addr(((struct ipv6Pkt *)macInfo->ipBuf)->destinationAddr, ipAddr) == TRUE))
+ {
+ macInfo->l3Protocol=ICMP_PROTOCOL;
+ }
+
+
+ }
+
+ needchecksum=TRUE;
+ /*
+ if(ipv6RAO!=IPV6_ROUTER_ALTER_OPTION)
+ {
+ rtl_gluePrintf("router alter option error\n");
+ }*/
+ }
+
+
+ break;
+
+ case PIM_PROTOCOL:
+ nextHeader=NO_NEXT_HEADER;
+ macInfo->l3PktLen=ntohs(((struct ipv6Pkt *)(macInfo->ipBuf))->payloadLenth)-(uint16)(ptr-macInfo->ipBuf-IPV6_HEADER_LENGTH);
+ macInfo->l3PktBuf=ptr;
+
+ ipAddr[0]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[0]);
+ ipAddr[1]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[1]);
+ ipAddr[2]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[2]);
+ ipAddr[3]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[3]);
+ if(IS_IPV6_PIM_ADDR(ipAddr))
+ {
+ macInfo->l3Protocol=PIM_PROTOCOL;
+ }
+ needchecksum=TRUE;
+
+ break;
+
+ case MOSPF_PROTOCOL:
+ nextHeader=NO_NEXT_HEADER;
+ macInfo->l3PktLen=ntohs(((struct ipv6Pkt *)(macInfo->ipBuf))->payloadLenth)-(uint16)(ptr-macInfo->ipBuf-IPV6_HEADER_LENGTH);
+ macInfo->l3PktBuf=ptr;
+
+ ipAddr[0]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[0]);
+ ipAddr[1]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[1]);
+ ipAddr[2]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[2]);
+ ipAddr[3]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[3]);
+
+ if(IS_IPV6_MOSPF_ADDR1(ipAddr) || IS_IPV6_MOSPF_ADDR2(ipAddr))
+ {
+ macInfo->l3Protocol=MOSPF_PROTOCOL;
+ }
+ needchecksum=TRUE;
+ break;
+
+ default:
+ goto out;
+ break;
+ }
+
+ }
+
+out:
+ /*compute pseudo header*/
+ if(needchecksum==TRUE)
+ {
+ for(i=0; i<4; i++)
+ {
+ pHeader.ipv6_pHdr.sourceAddr[i]=((struct ipv6Pkt *)(macInfo->ipBuf))->sourceAddr[i];
+
+ }
+
+ if(routerhead==FALSE)
+ {
+ for(i=0;i<4;i++)
+ {
+ pHeader.ipv6_pHdr.destinationAddr[i]=((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[i];
+ }
+ }
+
+
+ pHeader.ipv6_pHdr.nextHeader=macInfo->l3Protocol;
+ pHeader.ipv6_pHdr.upperLayerPacketLength=htonl((uint32)(macInfo->l3PktLen));
+ pHeader.ipv6_pHdr.zeroData[0]=0;
+ pHeader.ipv6_pHdr.zeroData[1]=0;
+ pHeader.ipv6_pHdr.zeroData[2]=0;
+
+ if(macInfo->l3PktBuf!=NULL)
+ {
+ if(verifyCheckSum==TRUE)
+ {
+ if(rtl_ipv6L3Checksum(macInfo->l3PktBuf, macInfo->l3PktLen,&pHeader)!=0)
+ {
+ macInfo->checksumFlag=FAILED;
+ }
+ else
+ {
+ macInfo->checksumFlag=SUCCESS;
+ }
+ }
+ else
+ {
+ macInfo->checksumFlag=FAILED;
+ }
+ }
+ }
+ }
+#endif
+ return;
+}
+
+
+static uint32 rtl_getMulticastRouterPortMask(uint32 moduleIndex, uint32 ipVersion, uint32 sysTime)
+{
+ uint32 portIndex=0;
+ uint32 portMaskn=PORT0_MASK;
+ uint32 routerPortmask=0;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ for(portIndex=0; portIndex<MAX_SUPPORT_PORT_NUMBER; portIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.querier.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.dvmrpRouter.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.mospfRouter.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.pimRouter.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+ portMaskn=portMaskn<<1; /*shift to next port mask*/
+
+ }
+
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ for(portIndex=0; portIndex<MAX_SUPPORT_PORT_NUMBER; portIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.querier.portTimer[portIndex]>sysTime)
+ {
+
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.mospfRouter.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.pimRouter.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+ portMaskn=portMaskn<<1; /*shift to next port mask*/
+
+ }
+
+ }
+#endif
+
+ routerPortmask= routerPortmask |rtl_mCastModuleArray[moduleIndex].staticRouterPortMask;
+
+ return routerPortmask;
+}
+
+static uint32 rtl_processQueries(uint32 moduleIndex,uint32 ipVersion, uint32 portNum, uint8* pktBuf, uint32 pktLen)
+{
+ struct rtl_groupEntry *groupEntry=NULL;
+ struct rtl_sourceEntry*sourceEntry=NULL;
+ uint32 timerIndex=0;
+ uint32 hashIndex=0;
+ uint32 groupAddress[4]={0,0,0,0};
+ uint32 suppressFlag=0;
+ uint32 *sourceAddr=NULL;
+ uint32 numOfSrc=0;
+ uint32 i=0;
+
+ /*querier timer update and election process*/
+ rtl_snoopQuerier(moduleIndex, ipVersion, portNum);
+
+ if(ipVersion==IP_VERSION4)
+ {
+ if(pktLen>=12) /*means igmpv3 query*/
+ {
+ groupAddress[0]=ntohl(((struct igmpv3Query*)pktBuf)->groupAddr);
+ suppressFlag=((struct igmpv3Query*)pktBuf)->rsq & S_FLAG_MASK;
+ sourceAddr=&(((struct igmpv3Query*)pktBuf)->srcList);
+ numOfSrc=(uint32)ntohs(((struct igmpv3Query*)pktBuf)->numOfSrc);
+
+ }
+ else
+ {
+ groupAddress[0]=ntohl(((struct igmpv2Pkt *)pktBuf)->groupAddr);
+ }
+
+ if(groupAddress[0]==0) /*means general query*/
+ {
+ goto out;
+ }
+ else
+ {
+ hashIndex=groupAddress[0]&rtl_hashMask;
+ }
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ if(pktLen>=28) /*means mldv2 query*/
+ {
+ groupAddress[0]=ntohl(((struct mldv2Query*)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mldv2Query*)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mldv2Query*)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mldv2Query*)pktBuf)->mCastAddr[3]);
+
+ suppressFlag=((struct mldv2Query*)pktBuf)->rsq & S_FLAG_MASK;
+ sourceAddr=&(((struct mldv2Query*)pktBuf)->srcList);
+ numOfSrc=(uint32)ntohs(((struct mldv2Query*)pktBuf)->numOfSrc);
+
+ }
+ else /*means mldv1 query*/
+ {
+ groupAddress[0]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[3]);
+
+ }
+
+ if( (groupAddress[0]==0) &&
+ (groupAddress[1]==0) &&
+ (groupAddress[2]==0) &&
+ (groupAddress[3]==0) )/*means general query*/
+ {
+ goto out;
+ }
+ else
+ {
+ hashIndex=groupAddress[3]&rtl_hashMask;
+ }
+ }
+#endif
+ if(suppressFlag==0)
+ {
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ if((groupEntry!=NULL))
+ {
+ if(numOfSrc==0) /*means group specific query*/
+ {
+ for(timerIndex=0; timerIndex<MAX_SUPPORT_PORT_NUMBER; timerIndex++)
+ {
+ if(groupEntry->groupFilterTimer[timerIndex]>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime))
+ {
+ groupEntry->groupFilterTimer[timerIndex]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+
+ }
+ }
+ else /*means group and source specific query*/
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ for(i=0; i<numOfSrc; i++)
+ {
+
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr, groupEntry);
+
+ if(sourceEntry!=NULL)
+ {
+ for(timerIndex=0; timerIndex<MAX_SUPPORT_PORT_NUMBER; timerIndex++)
+ {
+ if(sourceEntry->portTimer[timerIndex]>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime))
+ {
+ sourceEntry->portTimer[timerIndex]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ }
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+ }
+ }
+ }
+
+
+ }
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+out:
+ return (~(1<<portNum) & ((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+}
+
+
+static void rtl_snoopQuerier(uint32 moduleIndex, uint32 ipVersion, uint32 portNum)
+{
+
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.querier.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.querierPresentInterval;/*update timer value*/
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.querier.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.querierPresentInterval;/*update timer value*/
+ }
+#endif
+ return;
+}
+
+
+/*Process Report Packet*/
+static uint32 rtl_processJoin(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf)
+{
+
+
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+
+ uint32 hashIndex=0;
+
+ uint32 multicastRouterPortMask=rtl_getMulticastRouterPortMask(moduleIndex, ipVersion, rtl_sysUpSeconds);
+
+ if(ipVersion==IP_VERSION4)
+ {
+ if(pktBuf[0]==0x12)
+ {
+ groupAddress[0]=ntohl(((struct igmpv1Pkt *)pktBuf)->groupAddr);
+ }
+
+ if(pktBuf[0]==0x16)
+ {
+ groupAddress[0]=ntohl(((struct igmpv2Pkt *)pktBuf)->groupAddr);
+ }
+
+ hashIndex=groupAddress[0]&rtl_hashMask;
+
+ }
+
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+
+ groupAddress[0]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[3]);
+
+ hashIndex=groupAddress[3]&rtl_hashMask;
+ }
+#endif
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ goto out;
+ }
+ else
+ {
+ /*set new multicast entry*/
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+ #else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ #endif
+
+ newGroupEntry->sourceList=NULL;
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ newGroupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+
+ /*must first link into hash table, then call the function of set rtl8306sdm, because of aggregator checking*/
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable, hashIndex);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable, hashIndex);
+ }
+#endif
+
+ }
+
+ }
+ else
+ {
+
+ sourceEntry=groupEntry->sourceList;
+ /*delete all the source list*/
+ while(sourceEntry!=NULL)
+ {
+ sourceEntry->portTimer[portNum]=0;
+ sourceEntry=sourceEntry->next;
+ }
+
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+
+ }
+
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+#endif
+
+out:
+ return (multicastRouterPortMask&(~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+}
+
+static uint32 rtl_processLeave(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf)
+{
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint32 multicastRouterPortMask=rtl_getMulticastRouterPortMask(moduleIndex, ipVersion, rtl_sysUpSeconds);
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct igmpv2Pkt *)pktBuf)->groupAddr);
+ hashIndex=groupAddress[0]&rtl_hashMask;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ groupAddress[0]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[3]);
+
+ hashIndex=groupAddress[3]&rtl_hashMask;
+ }
+#endif
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ /*lower the timer of the group*/
+ if(groupEntry!=NULL)
+ {
+
+ if(groupEntry->groupFilterTimer[portNum]>rtl_sysUpSeconds)
+ {
+
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds;
+ }
+ else
+ {
+ if(groupEntry->groupFilterTimer[portNum]>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime))
+ {
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ }
+
+ }
+
+ sourceEntry=groupEntry->sourceList;
+ while(sourceEntry)
+ {
+ if(sourceEntry->portTimer[portNum]>rtl_sysUpSeconds)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds;
+ }
+ else
+ {
+ if(sourceEntry->portTimer[portNum]>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime))
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ }
+
+ }
+
+ sourceEntry=sourceEntry->next;
+ }
+
+
+ }
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return (multicastRouterPortMask&(~(1<<portNum))&0x3f);
+}
+
+static int32 rtl_processIsInclude(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf)
+{
+
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+
+ uint16 numOfSrc=0;
+ uint32 *sourceAddr=NULL;
+
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[0]&rtl_hashMask;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[3]&rtl_hashMask;
+
+ }
+#endif
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+ else
+ {
+ /*set new multicast entry*/
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+#else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+#endif
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ newGroupEntry->sourceList=NULL;
+
+ /*end of set group entry*/
+
+ /*must first link into hash table, then call the function of set rtl8306sdm, because of aggregator checking*/
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable, hashIndex);
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable, hashIndex);
+ }
+#endif
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ newGroupEntry->groupFilterTimer[portNum]=0;
+ /*link the new source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+
+
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(newGroupEntry,newSourceEntry);
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+
+ }
+ else
+ {
+ newGroupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+
+
+ }
+
+
+ }
+ else /*means it can be found in the forward hash table*/
+ {
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ /*here to handle the source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,groupEntry);
+ if(sourceEntry==NULL)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(groupEntry,newSourceEntry);
+ }
+
+ }
+ else
+ {
+ /*just update source timer*/
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+
+ }
+ else
+ {
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+
+ }
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return SUCCESS;
+
+
+}
+
+static int32 rtl_processIsExclude(uint32 moduleIndex, uint32 ipVersion,uint32 portNum, uint8 *pktBuf)
+{
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint16 numOfSrc=0;
+ uint32 *sourceArray=NULL;
+ uint32 *sourceAddr=NULL;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceArray=&(((struct groupRecord *)pktBuf)->srcList);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[0]&rtl_hashMask;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceArray=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[3]&rtl_hashMask;
+
+ }
+#endif
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+ else
+ {
+ /*set new multicast entry*/
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+#else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+#endif
+
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ newGroupEntry->sourceList=NULL;
+ /*means the filter mode is exclude*/
+ newGroupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+
+ /*end of set group entry*/
+
+ /*must first link into hash table, then call the function of set rtl8306sdm, because of aggregator checking*/
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable, hashIndex);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable, hashIndex);
+ }
+#endif
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ /*link the new source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ /*time out the sources included in the MODE_IS_EXCLUDE report*/
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds;
+ rtl_linkSourceEntry(newGroupEntry,newSourceEntry);
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+
+ }
+
+ }
+
+ }
+ else /*means group address can be found in the forward hash table*/
+ {
+
+ if(groupEntry->groupFilterTimer[portNum]<=rtl_sysUpSeconds) /*means include mode*/
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ /*here to handle the source list*/
+
+ /*delete (A-B)*/
+ sourceEntry=groupEntry->sourceList;
+ while(sourceEntry)
+ {
+ if(rtl_searchSourceAddr(ipVersion,sourceEntry->sourceAddr,sourceArray, numOfSrc)== FALSE)
+ {
+ sourceEntry->portTimer[portNum]=0;
+ }
+ sourceEntry=sourceEntry->next;
+ }
+
+ /*(B-A) time out*/
+ for(j=0; j<numOfSrc; j++)
+ {
+
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,groupEntry);
+
+ if(sourceEntry==NULL)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds;
+ rtl_linkSourceEntry(groupEntry,newSourceEntry);
+ }
+
+ }
+ else
+ {
+ if(sourceEntry->portTimer[portNum]==0)
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds;
+ }
+ }
+
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+ }
+
+ }
+ else/*means exclude mode*/
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ /*here to handle the source list*/
+ /*delete (X-A) and delete (Y-A)*/
+ sourceEntry=groupEntry->sourceList;
+ while(sourceEntry)
+ {
+ if(rtl_searchSourceAddr(ipVersion,sourceEntry->sourceAddr,sourceArray, numOfSrc)== FALSE)
+ {
+ sourceEntry->portTimer[portNum]=0;
+ }
+ sourceEntry=sourceEntry->next;
+ }
+
+ /*A-X-Y=GMI*/
+ for(j=0; j<numOfSrc; j++)
+ {
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,groupEntry);
+
+ if(sourceEntry==NULL)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(groupEntry,newSourceEntry);
+ }
+
+ }
+ else
+ {
+ if(sourceEntry->portTimer[portNum]==0)
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+ }
+
+
+ }
+
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return SUCCESS;
+
+}
+
+static int32 rtl_processToInclude(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf)
+{
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint16 numOfSrc=0;
+ uint32 *sourceAddr=NULL;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[0]&rtl_hashMask;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[3]&rtl_hashMask;
+
+ }
+#endif
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+ else
+ {
+ /*set new multicast entry*/
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+ #else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ #endif
+
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ newGroupEntry->sourceList=NULL;
+
+ /*end of set group entry*/
+
+ /*must first link into hash table, then call the function of set rtl8306sdm, because of aggregator checking*/
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable, hashIndex);
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable, hashIndex);
+ }
+#endif
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ newGroupEntry->groupFilterTimer[portNum]=0;
+ /*link the new source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+
+
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(newGroupEntry,newSourceEntry);
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+
+ }
+ }
+ else
+ {
+ newGroupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+
+
+ }
+
+ }
+ else /*means it can be found in the forward hash table*/
+ {
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ /*here to handle the source list*/
+
+ for(j=0; j<numOfSrc; j++)
+ {
+
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,groupEntry);
+
+ if(sourceEntry==NULL)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(groupEntry,newSourceEntry);
+ }
+
+ }
+ else
+ {
+ /*just update source timer*/
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+
+ }
+
+ // if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE) /*lower the timer of (A-B) or (X-A)*/
+ // {
+ sourceEntry=groupEntry->sourceList;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ }
+#endif
+ while(sourceEntry)
+ {
+ if((rtl_searchSourceAddr(ipVersion, sourceEntry->sourceAddr, sourceAddr, numOfSrc)==FALSE)&&(sourceEntry->portTimer[portNum]>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime)))
+ {
+ if(sourceEntry->portTimer[portNum]>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime))
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+
+ }
+ sourceEntry=sourceEntry->next;
+ }
+
+ if(groupEntry->groupFilterTimer[portNum]>rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime) /*lower the group timer if in exclude mode*/
+ {
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+
+ }
+
+ if((numOfSrc==0)&&(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE))
+ {
+ if(groupEntry->groupFilterTimer[portNum]>rtl_sysUpSeconds)
+ {
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds;
+ }
+
+ sourceEntry=groupEntry->sourceList;
+
+ while(sourceEntry)
+ {
+ if(sourceEntry->portTimer[portNum]>rtl_sysUpSeconds)
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds;
+ }
+ sourceEntry=sourceEntry->next;
+ }
+
+ }
+ }
+ else
+ {
+ if((numOfSrc==0)&&(groupEntry->groupFilterTimer[portNum]>rtl_sysUpSeconds))
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds;
+ }
+ else
+ {
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ }
+ else
+ {
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+
+ }
+
+
+ }
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+return SUCCESS;
+
+}
+
+static int32 rtl_processToExclude(uint32 moduleIndex, uint32 ipVersion,uint32 portNum , uint8 *pktBuf)
+{
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint16 numOfSrc=0;
+ uint32 *sourceArray=NULL;
+ uint32 *sourceAddr=NULL;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceArray=&(((struct groupRecord *)pktBuf)->srcList);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[0]&rtl_hashMask;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceArray=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[3]&rtl_hashMask;
+
+ }
+#endif
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+ else
+ {
+ /*set new multicast entry*/
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+#else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+#endif
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ newGroupEntry->sourceList=NULL;
+
+ /*means the filter mode is exclude*/
+ newGroupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+
+ /*end of set group entry*/
+
+ /*must first link into hash table, then call the function of set rtl8306sdm, because of aggregator checking*/
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable, hashIndex);
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable, hashIndex);
+ }
+#endif
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ /*link the new source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ /*time out the sources included in the TO_EXCLUDE report */
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds;
+ rtl_linkSourceEntry(newGroupEntry,newSourceEntry);
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+
+ }
+
+ }
+
+
+ }
+
+ }
+ else /*means group address can be found in the forward hash table*/
+ {
+
+ if(groupEntry->groupFilterTimer[portNum]<=rtl_sysUpSeconds) /*means include mode*/
+ {
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ /*here to handle the source list*/
+ /*delete (A-B)*/
+ sourceEntry=groupEntry->sourceList;
+ while(sourceEntry)
+ {
+ if(rtl_searchSourceAddr(ipVersion,sourceEntry->sourceAddr,sourceArray, numOfSrc)== FALSE)
+ {
+ sourceEntry->portTimer[portNum]=0;
+ }
+ sourceEntry=sourceEntry->next;
+ }
+
+ /*(B-A) time out*/
+ for(j=0; j<numOfSrc; j++)
+ {
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,groupEntry);
+
+ if(sourceEntry==NULL)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+
+ /*B-A time out*/
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds;
+ rtl_linkSourceEntry(groupEntry,newSourceEntry);
+ }
+
+ }
+ else/*maybe include redundant sources*/
+ {
+ /*B-A time out*/
+ if(sourceEntry->portTimer[portNum]==0)
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds;
+ }
+
+ if(sourceEntry->portTimer[portNum]>rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime) /*lower the A*B timer if the cpu is router*/
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+
+ }
+
+ }
+ else/*means exclude mode*/
+ {
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ /*here to handle the source list*/
+ /*delete (X-A) and delete (Y-A)*/
+ sourceEntry=groupEntry->sourceList;
+ while(sourceEntry)
+ {
+ if(rtl_searchSourceAddr(ipVersion,sourceEntry->sourceAddr,sourceArray, numOfSrc)== FALSE)
+ {
+ sourceEntry->portTimer[portNum]=0;
+ }
+ sourceEntry=sourceEntry->next;
+ }
+
+ /*A-X-Y=filter timer*/
+ for(j=0; j<numOfSrc; j++)
+ {
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,groupEntry);
+
+ if(sourceEntry==NULL)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ rtl_linkSourceEntry(groupEntry,newSourceEntry);
+
+ }
+
+ }
+ else
+ {
+ if((sourceEntry->portTimer[portNum]==0)||(sourceEntry->portTimer[portNum]>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime)))
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+
+ }
+ }
+
+
+ }
+
+ /*switch to exclude mode or update exclude mode filter timer*/
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+
+
+
+ }
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return SUCCESS;
+}
+
+static int32 rtl_processAllow(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf)
+{
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint16 numOfSrc=0;
+ uint32 *sourceAddr=NULL;
+
+
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[0]&rtl_hashMask;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[3]&rtl_hashMask;
+
+ }
+#endif
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+ else
+ {
+ /*set new multicast entry*/
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+#else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+#endif
+
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ newGroupEntry->sourceList=NULL;
+
+ /*end of set group entry*/
+
+ /*must first link into hash table, then call the function of set rtl8306sdm, because of aggregator checking*/
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable, hashIndex);
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable, hashIndex);
+ }
+#endif
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ newGroupEntry->groupFilterTimer[portNum]=0;
+ /*link the new source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+
+
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(newGroupEntry,newSourceEntry);
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+ }
+ else
+ {
+ newGroupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;;
+ }
+
+ }
+
+
+
+ }
+ else /*means it can be found in the forward hash table*/
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ /*here to handle the source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,groupEntry);
+
+ if(sourceEntry==NULL)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(groupEntry,newSourceEntry);
+ }
+
+ }
+ else
+ {
+ /*just update source timer*/
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+ }
+ else
+ {
+ groupEntry->groupFilterTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;;
+ }
+
+ }
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return SUCCESS;
+}
+
+static int32 rtl_processBlock(uint32 moduleIndex, uint32 ipVersion,uint32 portNum, uint8 *pktBuf)
+{
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+// struct rtl_sourceEntry *nextSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint16 numOfSrc=0;
+ uint32 *sourceAddr=NULL;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[0]&rtl_hashMask;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ hashIndex=groupAddress[3]&rtl_hashMask;
+ }
+#endif
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ if(groupEntry!=NULL)
+ {
+
+ if(groupEntry->groupFilterTimer[portNum]>rtl_sysUpSeconds) /*means exclude mode*/
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ /*here to handle the source list*/
+ /*A-X-Y=filter timer*/
+ for(j=0; j<numOfSrc; j++)
+ {
+
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,groupEntry);
+
+ if(sourceEntry==NULL)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+ else
+ {
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+
+ if(groupEntry->groupFilterTimer[portNum]>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime))
+ {
+ newSourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ else
+ {
+ newSourceEntry->portTimer[portNum]=groupEntry->groupFilterTimer[portNum];
+ }
+
+ rtl_linkSourceEntry(groupEntry,newSourceEntry);
+
+ }
+
+ }
+ else
+ {
+
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds;
+ }
+ else
+ {
+ if((sourceEntry->portTimer[portNum]==0)||(sourceEntry->portTimer[portNum]>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime)))
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ }
+
+ }
+
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+
+ }
+
+ }
+ #if 0
+ else
+ {
+ groupEntry->groupFilterTimer[portIndex]=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;;
+ }
+ #endif
+ }
+ else /*means include mode*/
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE) /*process the special-group query if the cpu is router*/
+ {
+ for(j=0; j<numOfSrc; j++)
+ {
+
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,groupEntry);
+ if(sourceEntry!=NULL)
+ {
+
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds;
+ }
+ else
+ {
+ if((sourceEntry->portTimer[portNum]==0)||(sourceEntry->portTimer[portNum]>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime)))
+ {
+ sourceEntry->portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ }
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+
+ }
+
+ }
+
+ }
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return SUCCESS;
+
+}
+
+
+static uint32 rtl_processIgmpv3Mldv2Reports(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8 *pktBuf)
+{
+ uint32 i=0;
+ uint16 numOfRecords=0;
+ uint8 *groupRecords=NULL;
+ uint8 recordType=0xff;
+ uint16 numOfSrc=0;
+ int32 returnVal=0;
+ uint32 multicastRouterPortMask=rtl_getMulticastRouterPortMask(moduleIndex, ipVersion, rtl_sysUpSeconds);
+
+ if(ipVersion==IP_VERSION4)
+ {
+ numOfRecords=ntohs(((struct igmpv3Report *)pktBuf)->numOfRecords);
+ if(numOfRecords!=0)
+ {
+ groupRecords=(uint8 *)(&(((struct igmpv3Report *)pktBuf)->recordList));
+ }
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ numOfRecords=ntohs(((struct mldv2Report *)pktBuf)->numOfRecords);
+ if(numOfRecords!=0)
+ {
+ groupRecords=(uint8 *)(&(((struct mldv2Report *)pktBuf)->recordList));
+ }
+ }
+#endif
+
+ for(i=0; i<numOfRecords; i++)
+ {
+ if(ipVersion==IP_VERSION4)
+ {
+ recordType=((struct groupRecord *)groupRecords)->type;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ recordType=((struct mCastAddrRecord *)groupRecords)->type;
+ }
+#endif
+
+ switch(recordType)
+ {
+ case MODE_IS_INCLUDE:
+ returnVal=rtl_processIsInclude(moduleIndex, ipVersion, portNum, groupRecords);
+ break;
+
+ case MODE_IS_EXCLUDE:
+ returnVal=rtl_processIsExclude(moduleIndex, ipVersion, portNum, groupRecords);
+ break;
+
+ case CHANGE_TO_INCLUDE_MODE:
+ returnVal=rtl_processToInclude(moduleIndex, ipVersion, portNum, groupRecords);
+ break;
+
+ case CHANGE_TO_EXCLUDE_MODE:
+ returnVal=rtl_processToExclude(moduleIndex, ipVersion, portNum, groupRecords);
+ break;
+
+ case ALLOW_NEW_SOURCES:
+ returnVal=rtl_processAllow(moduleIndex, ipVersion, portNum, groupRecords);
+ break;
+
+ case BLOCK_OLD_SOURCES:
+ returnVal=rtl_processBlock(moduleIndex, ipVersion, portNum, groupRecords);
+ break;
+
+ default:break;
+
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ numOfSrc=ntohs(((struct groupRecord *)groupRecords)->numOfSrc);
+ /*shift pointer to another group record*/
+ groupRecords=groupRecords+8+numOfSrc*4+(((struct groupRecord *)(groupRecords))->auxLen)*4;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ numOfSrc=ntohs(((struct mCastAddrRecord *)groupRecords)->numOfSrc);
+ /*shift pointer to another group record*/
+ groupRecords=groupRecords+20+numOfSrc*16+(((struct mCastAddrRecord *)(groupRecords))->auxLen)*4;
+ }
+#endif
+ }
+
+ return (multicastRouterPortMask&(~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+
+}
+
+static uint32 rtl_processIgmpMld(uint32 moduleIndex, uint32 ipVersion, uint8* pktBuf, uint32 pktLen, uint32 portNum)
+{
+ uint32 fwdPortMask=0;
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ reportEventContext.moduleIndex=moduleIndex;
+ #endif
+
+ switch(pktBuf[0])
+ {
+ case IGMP_QUERY:
+ fwdPortMask=rtl_processQueries(moduleIndex, ipVersion, portNum, pktBuf, pktLen);
+ break;
+
+ case IGMPV1_REPORT:
+ fwdPortMask=rtl_processJoin(moduleIndex, ipVersion, portNum, pktBuf);
+ break;
+
+ case IGMPV2_REPORT:
+ fwdPortMask=rtl_processJoin(moduleIndex, ipVersion, portNum, pktBuf);
+ break;
+
+ case IGMPV2_LEAVE:
+ fwdPortMask=rtl_processLeave(moduleIndex, ipVersion, portNum, pktBuf);
+ break;
+
+ case IGMPV3_REPORT:
+ fwdPortMask=rtl_processIgmpv3Mldv2Reports(moduleIndex, ipVersion, portNum, pktBuf);
+ break;
+
+ case MLD_QUERY:
+ fwdPortMask=rtl_processQueries(moduleIndex, ipVersion, portNum, pktBuf, pktLen);
+ break;
+
+ case MLDV1_REPORT:
+ fwdPortMask=rtl_processJoin(moduleIndex, ipVersion, portNum, pktBuf);
+ break;
+
+ case MLDV1_DONE:
+ fwdPortMask=rtl_processLeave(moduleIndex, ipVersion, portNum, pktBuf);
+ break;
+
+ case MLDV2_REPORT:
+ fwdPortMask=rtl_processIgmpv3Mldv2Reports(moduleIndex, ipVersion, portNum, pktBuf);
+ break;
+
+ default:
+ fwdPortMask=((~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+ break;
+ }
+
+ return fwdPortMask;
+
+}
+
+
+
+static uint32 rtl_processDvmrp(uint32 moduleIndex, uint32 ipVersion, uint8* pktBuf, uint32 pktLen, uint32 portNum)
+{
+
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.dvmrpRouter.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.dvmrpRouterAgingTime; /*update timer*/
+ }
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=0;
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return ((~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+
+}
+
+static uint32 rtl_processMospf(uint32 moduleIndex,uint32 ipVersion, uint8* pktBuf, uint32 pktLen, uint32 portNum)
+{
+ struct ipv4MospfHdr *ipv4MospfHeader=(struct ipv4MospfHdr*)pktBuf;
+ struct ipv4MospfHello *ipv4HelloPkt=(struct ipv4MospfHello*)pktBuf;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ struct ipv6MospfHdr *ipv6MospfHeader=(struct ipv6MospfHdr*)pktBuf;
+ struct ipv6MospfHello *ipv6HelloPkt=(struct ipv6MospfHello*)pktBuf;
+#endif
+
+
+ if(ipVersion==IP_VERSION4)
+ {
+ /*mospf is built based on ospfv2*/
+ if((ipv4MospfHeader->version==2) && (ipv4MospfHeader->type==MOSPF_HELLO_TYPE))
+ {
+ if((ipv4HelloPkt->options & 0x04)!=0)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.mospfRouter.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.mospfRouterAgingTime; /*update timer*/
+ }
+ }
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ if((ipv6MospfHeader->version==3) && (ipv6MospfHeader->type==MOSPF_HELLO_TYPE))
+ {
+ if((ipv6HelloPkt->options[2] & 0x04)!=0)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.mospfRouter.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.mospfRouterAgingTime; /*update timer*/
+
+ }
+ }
+ }
+#endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=0;
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return ((~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+
+}
+
+static uint32 rtl_processPim(uint32 moduleIndex, uint32 ipVersion, uint8* pktBuf, uint32 pktLen, uint32 portNum)
+{
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.pimRouter.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.pimRouterAgingTime; /*update timer*/
+
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.pimRouter.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.pimRouterAgingTime; /*update timer*/
+ }
+#endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ reportEventContext.groupAddr[0]=0;
+ reportEventContext.sourceAddr[0]=0;
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return ((~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+}
+
+
+
+/*********************************************
+ External Function
+ *********************************************/
+
+
+//External called function by high level program
+/*
+@func int32 | rtl_registerIgmpSnoopingModule | API to register an igmp snooping module.
+@parm uint32 * | moduleIndex | Output parameter to return the igmp snooping module index.
+@rvalue SUCCESS | Register igmp snooping module successfully.
+@rvalue FAILED | Register igmp snooping module failed.
+*/
+int32 rtl_registerIgmpSnoopingModule(uint32 *moduleIndex)
+{
+ int32 i=0;
+ uint32 index=0xFFFFFFFF;
+
+ *moduleIndex=0xFFFFFFFF;
+
+ for(i=0; i<MAX_MCAST_MODULE_NUM; i++)
+ {
+ if(rtl_mCastModuleArray[i].enableSnooping==FALSE)
+ {
+ index=i;
+ break;
+ }
+ }
+
+ if(i>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+
+ if(rtl_mCastModuleArray[index].enableSnooping==FALSE)
+ {
+ /*initialize multicast Routers information*/
+ for(i=0; i<MAX_SUPPORT_PORT_NUMBER; i++)
+ {
+ rtl_mCastModuleArray[index].rtl_ipv4MulticastRouters.querier.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv4MulticastRouters.dvmrpRouter.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv4MulticastRouters.pimRouter.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv4MulticastRouters.mospfRouter.portTimer[i]=0;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ rtl_mCastModuleArray[index].rtl_ipv6MulticastRouters.querier.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv6MulticastRouters.dvmrpRouter.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv6MulticastRouters.pimRouter.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv6MulticastRouters.mospfRouter.portTimer[i]=0;
+#endif
+ }
+
+ /*initialize hash table*/
+ rtl_initHashTable(index, rtl_hashTableSize);
+
+ if((rtl_mCastModuleArray[index].rtl_ipv4HashTable==NULL) )
+ {
+ return FAILED;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(rtl_mCastModuleArray[index].rtl_ipv6HashTable==NULL)
+ {
+ return FAILED;
+ }
+#endif
+
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ memset(&rtl_mCastModuleArray[index].deviceInfo,0, sizeof(rtl_multicastDeviceInfo_t));
+#endif
+ for(i=0; i<6; i++)
+ {
+ rtl_mCastModuleArray[index].rtl_gatewayMac[i]=0;
+ }
+
+ rtl_mCastModuleArray[index]. rtl_gatewayIpv4Addr=0;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ for(i=0; i<4; i++)
+ {
+ rtl_mCastModuleArray[index].rtl_gatewayIpv6Addr[i]=0;
+ }
+#endif
+ rtl_mCastModuleArray[index].enableSourceList=TRUE;
+ rtl_mCastModuleArray[index].enableFastLeave=TRUE;
+ rtl_mCastModuleArray[index].enableSnooping=TRUE;
+ rtl_mCastModuleArray[index].unknownMCastFloodMap=0;
+ rtl_mCastModuleArray[index].staticRouterPortMask=0;
+
+#ifdef CONFIG_PROC_FS
+ rtl_mCastModuleArray[index].expireEventCnt=0;
+#endif
+ *moduleIndex=index;
+ return SUCCESS;
+ }
+ else
+ {
+ return FAILED;
+ }
+
+ *moduleIndex=index;
+ *moduleIndex=index;
+ return SUCCESS;
+}
+
+
+/*
+@func int32 | rtl_unregisterIgmpSnoopingModule | Unregister an igmp snooping module.
+@parm uint32 | moduleIndex | Igmp snooping module index.
+@rvalue SUCCESS |Unregister igmp snooping module successfully.
+@rvalue FAILED |Unregister igmp snooping module failed.
+@comm
+ This function should be called once a second to maintain multicast timer list.
+*/
+int32 rtl_unregisterIgmpSnoopingModule(uint32 moduleIndex)
+{
+ uint32 i=0;
+ struct rtl_groupEntry *groupEntryPtr=NULL;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv4Addr=0;
+
+ for(i=0; i<6; i++)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[i]=0;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ for(i=0;i<4;i++)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[i]=0;
+ }
+#endif
+
+ /*delete ipv4 multicast entry*/
+ for(i=0;i<rtl_hashTableSize;i++)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+
+ while(groupEntryPtr!=NULL)
+ {
+ rtl_deleteGroupEntry(groupEntryPtr, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+ }
+ }
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable=NULL;
+ memset(&(rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters), 0, sizeof(struct rtl_multicastRouters));
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ /*delete ipv6 multicast entry*/
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i];
+ while(groupEntryPtr!=NULL)
+ {
+ rtl_deleteGroupEntry(groupEntryPtr, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i];
+ }
+ }
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable=NULL;
+ memset(&(rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters), 0, sizeof(struct rtl_multicastRouters));
+#endif
+
+ rtl_mCastModuleArray[moduleIndex].enableSnooping=FALSE;
+ rtl_mCastModuleArray[moduleIndex].enableSourceList=TRUE;
+ rtl_mCastModuleArray[moduleIndex].enableFastLeave=TRUE;
+
+ rtl_mCastModuleArray[moduleIndex].unknownMCastFloodMap=0;
+ rtl_mCastModuleArray[moduleIndex].staticRouterPortMask=0;
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ memset(&rtl_mCastModuleArray[moduleIndex].deviceInfo,0,sizeof(rtl_multicastDeviceInfo_t));
+#endif
+ return SUCCESS;
+ }
+
+ return SUCCESS;
+
+}
+
+static void _rtl865x_configIgmpSnoopingExpire(int32 disableExpire)
+{
+ uint32 maxTime=0xffffffff;
+
+ if((rtl_mCastTimerParas.disableExpire==FALSE) && (disableExpire==TRUE))
+ {
+ rtl_mCastTimerParas.disableExpire=TRUE;
+ }
+
+ if((rtl_mCastTimerParas.disableExpire==TRUE) && (disableExpire==FALSE) )
+ {
+#if defined(__linux__) && defined(__KERNEL__)
+ struct timeval currentTimeVector;
+ do_gettimeofday(&currentTimeVector);
+ /*reset start time*/
+ if(currentTimeVector.tv_sec>=rtl_sysUpSeconds)
+ {
+ rtl_startTime=(uint32)(currentTimeVector.tv_sec)-rtl_sysUpSeconds;
+ }
+ else
+ {
+ /*avoid timer wrap back*/
+ rtl_startTime=maxTime-rtl_sysUpSeconds+(uint32)(currentTimeVector.tv_sec)+1;
+ }
+#endif
+ rtl_mCastTimerParas.disableExpire=FALSE;
+ }
+
+
+ return;
+}
+
+//External called function by high level program
+/*
+@func void | rtl_setMulticastParameters | API to config igmp snooping time parameters.
+@parm struct rtl_mCastTimerParameters | mCastTimerParameters |IGMP snooping time parameters to be set.
+*/
+void rtl_setMulticastParameters(struct rtl_mCastTimerParameters mCastTimerParameters)
+{
+ _rtl865x_configIgmpSnoopingExpire(mCastTimerParameters.disableExpire);
+
+ if(mCastTimerParameters.groupMemberAgingTime!=0)
+ {
+ rtl_mCastTimerParas.groupMemberAgingTime= mCastTimerParameters.groupMemberAgingTime;
+ }
+
+ if(mCastTimerParameters.lastMemberAgingTime!=0)
+ {
+ rtl_mCastTimerParas.lastMemberAgingTime= mCastTimerParameters.lastMemberAgingTime;
+ }
+
+ if(mCastTimerParameters.querierPresentInterval!=0)
+ {
+
+ rtl_mCastTimerParas.querierPresentInterval=mCastTimerParameters.querierPresentInterval;
+ }
+
+
+ if(mCastTimerParameters.dvmrpRouterAgingTime!=0)
+ {
+
+ rtl_mCastTimerParas.dvmrpRouterAgingTime=mCastTimerParameters.dvmrpRouterAgingTime;
+ }
+
+ if(mCastTimerParameters.mospfRouterAgingTime!=0)
+ {
+
+ rtl_mCastTimerParas.mospfRouterAgingTime=mCastTimerParameters.mospfRouterAgingTime;
+ }
+
+ if(mCastTimerParameters.pimRouterAgingTime!=0)
+ {
+
+ rtl_mCastTimerParas.pimRouterAgingTime=mCastTimerParameters.pimRouterAgingTime;
+ }
+
+ return;
+}
+
+/*
+@func int32 | rtl_configIgmpSnoopingModule | API to config local parameters of an igmp snooping module.
+@parm uint32 | moduleIndex | Input parameter to specify an igmp snooping module.
+@parm struct rtl_mCastSnoopingLocalConfig * | mCastSnoopingLocalConfig | Local parameters to be set to an igmp snooping module
+@rvalue SUCCESS | Configuration success.
+@rvalue FAILED | Configuration failed.
+*/
+int32 rtl_configIgmpSnoopingModule(uint32 moduleIndex, struct rtl_mCastSnoopingLocalConfig *mCastSnoopingLocalConfig)
+{
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(mCastSnoopingLocalConfig==NULL)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ rtl_mCastModuleArray[moduleIndex].enableSourceList=mCastSnoopingLocalConfig->enableSourceList;
+ rtl_mCastModuleArray[moduleIndex].enableFastLeave=mCastSnoopingLocalConfig->enableFastLeave;
+ rtl_mCastModuleArray[moduleIndex].unknownMCastFloodMap=mCastSnoopingLocalConfig->unknownMcastFloodMap;
+ rtl_mCastModuleArray[moduleIndex].staticRouterPortMask=mCastSnoopingLocalConfig->staticRouterPortMask;
+
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[0]=mCastSnoopingLocalConfig->gatewayMac[0];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[1]=mCastSnoopingLocalConfig->gatewayMac[1];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[2]=mCastSnoopingLocalConfig->gatewayMac[2];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[3]=mCastSnoopingLocalConfig->gatewayMac[3];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[4]=mCastSnoopingLocalConfig->gatewayMac[4];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[5]=mCastSnoopingLocalConfig->gatewayMac[5];
+
+
+
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv4Addr=mCastSnoopingLocalConfig->gatewayIpv4Addr;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[0]=mCastSnoopingLocalConfig->gatewayIpv6Addr[0];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[1]=mCastSnoopingLocalConfig->gatewayIpv6Addr[1];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[2]=mCastSnoopingLocalConfig->gatewayIpv6Addr[2];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[3]=mCastSnoopingLocalConfig->gatewayIpv6Addr[3];
+#endif
+ return SUCCESS;
+}
+
+/*
+@func int32 | rtl_maintainMulticastSnoopingTimerList | Maintain igmp snooping internal timer list.
+@parm uint32 | currentSystemTime |The current system time (unit: seconds).
+@rvalue SUCCESS |Always return SUCCESS.
+@comm
+ This function should be called every second
+*/
+int32 rtl_maintainMulticastSnoopingTimerList(uint32 currentSystemTime)
+{
+ /* maintain current time */
+ uint32 i=0;
+ uint32 maxTime=0xffffffff;
+
+ struct rtl_groupEntry* groupEntryPtr=NULL;
+ struct rtl_groupEntry* nextEntry=NULL;
+
+ uint32 moduleIndex;
+
+ if(rtl_mCastTimerParas.disableExpire==TRUE)
+ {
+ return SUCCESS;
+ }
+
+ /*handle timer conter overflow*/
+ if(currentSystemTime>rtl_startTime)
+ {
+ rtl_sysUpSeconds=currentSystemTime-rtl_startTime;
+ }
+ else
+ {
+ rtl_sysUpSeconds=(maxTime-rtl_startTime)+currentSystemTime+1;
+ }
+
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM; moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ strcpy(timerEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ timerEventContext.moduleIndex=moduleIndex;
+ #endif
+
+ /*maintain ipv4 group entry timer */
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+ /*scan the hash table*/
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!=NULL)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+ while(groupEntryPtr) /*traverse each group list*/
+ {
+ nextEntry=groupEntryPtr->next;
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ timerEventContext.groupAddr[0]=groupEntryPtr->groupAddr[0];
+ #endif
+ rtl_checkGroupEntryTimer(groupEntryPtr, rtl_mCastModuleArray[moduleIndex].enableSourceList, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ groupEntryPtr=nextEntry;/*because expired group entry will be cleared*/
+ }
+ }
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ /*maintain ipv6 group entry timer */
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+ /*scan the hash table*/
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable!=NULL)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i];
+ while(groupEntryPtr) /*traverse each group list*/
+ {
+ nextEntry=groupEntryPtr->next;
+ rtl_checkGroupEntryTimer(groupEntryPtr, rtl_mCastModuleArray[moduleIndex].enableSourceList, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ groupEntryPtr=nextEntry;/*because expired group entry will be cleared*/
+ }
+ }
+ }
+#endif
+
+ }
+ }
+ return SUCCESS;
+}
+
+
+/*
+@func int32 | rtl_igmpMldProcess | API to process an incoming igmp packet.
+@parm uint32 | moduleIndex | Igmp snooping module index.
+@parm uint8 * | macFrame | Data pointer of igmp mac frame.
+@parm uint32 | portNum | Input parameter to specify at which port this igmp packet was recieved
+@parm uint32 * | fwdPortMask | Output parameter to tell where to relay this igmp packet.
+@rvalue SUCCESS |Doing igmp snooping successfully.
+@rvalue FAILED |Doing igmp snooping failed.
+*/
+int32 rtl_igmpMldProcess(uint32 moduleIndex, uint8 * macFrame, uint32 portNum, uint32 *fwdPortMask)
+{
+
+ struct rtl_macFrameInfo macFrameInfo;
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ reportEventContext.portMask=1<<portNum;
+ #endif
+
+ *fwdPortMask=(~(1<<portNum)) & 0xFFFFFFFF;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ //rtl_parseMacFrame(moduleIndex, macFrame, TRUE, &macFrameInfo);
+ rtl_parseMacFrame(moduleIndex, macFrame, FALSE, &macFrameInfo);
+ if( rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ if(macFrameInfo.ipBuf==NULL)
+ {
+ return FAILED;
+ }
+
+ if((macFrameInfo.ipVersion!=IP_VERSION4) && (macFrameInfo.ipVersion!=IP_VERSION6))
+ {
+
+ return FAILED;
+ }
+
+#ifndef CONFIG_RTL_MLD_SNOOPING
+ if (macFrameInfo.ipVersion==IP_VERSION6)
+ {
+ return FAILED;
+ }
+#endif
+ /*port num starts from 0*/
+ if(portNum>=MAX_SUPPORT_PORT_NUMBER)
+ {
+ return FAILED;
+ }
+ #if 0
+ if(rtl_checkPortMask(pktPortMask)==FAILED)
+ {
+ return FAILED;
+ }
+ #endif
+ if(macFrameInfo.checksumFlag!=SUCCESS)
+ {
+ return FAILED;
+ }
+
+ switch(macFrameInfo.l3Protocol)
+ {
+
+ case IGMP_PROTOCOL:
+ *fwdPortMask=rtl_processIgmpMld(moduleIndex, (uint32)(macFrameInfo.ipVersion), macFrameInfo.l3PktBuf, macFrameInfo.l3PktLen, portNum);
+ break;
+
+ case ICMP_PROTOCOL:
+ *fwdPortMask=rtl_processIgmpMld(moduleIndex, (uint32)(macFrameInfo.ipVersion), macFrameInfo.l3PktBuf, macFrameInfo.l3PktLen, portNum);
+ break;
+
+
+ case DVMRP_PROTOCOL:
+ *fwdPortMask=rtl_processDvmrp(moduleIndex, (uint32)(macFrameInfo.ipVersion), macFrameInfo.l3PktBuf, macFrameInfo.l3PktLen, portNum);
+ break;
+
+ case MOSPF_PROTOCOL:
+ *fwdPortMask=rtl_processMospf(moduleIndex, (uint32)(macFrameInfo.ipVersion), macFrameInfo.l3PktBuf, macFrameInfo.l3PktLen,portNum);
+ break;
+
+ case PIM_PROTOCOL:
+ *fwdPortMask=rtl_processPim(moduleIndex, (uint32)(macFrameInfo.ipVersion), macFrameInfo.l3PktBuf, macFrameInfo.l3PktLen, portNum);
+ break;
+
+ default: break;
+ }
+
+ }
+
+ return SUCCESS;
+}
+
+
+/*
+@func int32 | rtl_getMulticastDataFwdPortMask | API to get multicast data forward port mask.
+@parm uint32 | moduleIndex | Igmp snooping module index.
+@parm struct rtl_multicastDataInfo * | multicastDataInfo | Multicast data related information.
+@parm uint32 * | fwdPortMask |Output parameter to tell where to forward this multicast data.
+@rvalue SUCCESS | Get multicast data forward port mask successfully.
+@rvalue FAILED | Get multicast data forward port mask failed.
+*/
+int32 rtl_getMulticastDataFwdPortMask(uint32 moduleIndex, struct rtl_multicastDataInfo *multicastDataInfo, uint32 *fwdPortMask)
+{
+ int32 retVal=FAILED;
+ struct rtl_multicastFwdInfo multicastFwdInfo;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(multicastDataInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ if(fwdPortMask==NULL)
+ {
+ return FAILED;
+ }
+
+ retVal=rtl_getMulticastDataFwdInfo( moduleIndex, multicastDataInfo, &multicastFwdInfo);
+
+ *fwdPortMask=multicastFwdInfo.fwdPortMask;
+
+ return retVal;
+
+}
+
+
+
+int32 rtl_getMulticastDataFwdInfo(uint32 moduleIndex, struct rtl_multicastDataInfo *multicastDataInfo, struct rtl_multicastFwdInfo *multicastFwdInfo)
+{
+
+ struct rtl_groupEntry * groupEntry=NULL;
+ uint32 multicastRouterPortMask=0;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(multicastDataInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ if(multicastFwdInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ memset(multicastFwdInfo, 0, sizeof(struct rtl_multicastFwdInfo));
+
+ if(multicastDataInfo->groupAddr[0]==RESERVE_MULTICAST_ADDR1)
+ {
+ multicastFwdInfo->reservedMCast=TRUE;
+ multicastFwdInfo->fwdPortMask=0xFFFFFFFF;
+ multicastFwdInfo->cpuFlag=TRUE;
+
+ return FAILED;
+ }
+
+ if(IN_MULTICAST_RESV1(multicastDataInfo->groupAddr[0]) )
+ {
+ multicastFwdInfo->reservedMCast=TRUE;
+ multicastFwdInfo->fwdPortMask=0xFFFFFFFF;
+ multicastFwdInfo->cpuFlag=TRUE;
+
+ return FAILED;
+ }
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex,multicastDataInfo->ipVersion, multicastDataInfo->groupAddr);
+
+ if(groupEntry==NULL)
+ {
+ multicastFwdInfo->unknownMCast=TRUE;
+ multicastFwdInfo->fwdPortMask= rtl_mCastModuleArray[moduleIndex].unknownMCastFloodMap;
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if((multicastFwdInfo->fwdPortMask & rtl_mCastModuleArray[moduleIndex].deviceInfo.swPortMask)!=0)
+ {
+ multicastFwdInfo->cpuFlag=TRUE;
+ }
+ #endif
+
+ return SUCCESS;
+ }
+ else
+ {
+ /*here to get multicast router port mask and forward port mask*/
+ //multicastRouterPortMask=rtl_getMulticastRouterPortMask(moduleIndex, multicastDataInfo->ipVersion, rtl_sysUpSeconds);
+ if(rtl_mCastModuleArray[moduleIndex].enableSourceList==TRUE)
+ {
+ multicastFwdInfo->fwdPortMask=rtl_getSourceFwdPortMask(groupEntry, multicastDataInfo->sourceIp, rtl_sysUpSeconds);
+ }
+ else
+ {
+ if(groupEntry!=NULL)
+ {
+ multicastFwdInfo->fwdPortMask=(uint32)rtl_getGroupFwdPortMask(groupEntry,0, rtl_sysUpSeconds);
+ }
+
+ }
+
+ multicastFwdInfo->fwdPortMask=(multicastFwdInfo->fwdPortMask|multicastRouterPortMask);
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if((multicastFwdInfo->fwdPortMask & rtl_mCastModuleArray[moduleIndex].deviceInfo.swPortMask)!=0)
+ {
+ multicastFwdInfo->cpuFlag=TRUE;
+ }
+ #endif
+
+ return SUCCESS;
+
+ }
+ return FAILED;
+
+}
+
+#if defined(__linux__) && defined(__KERNEL__)
+
+static void rtl_multicastSysTimerExpired(uint32 expireDada)
+{
+ struct timeval currentTimeVector;
+
+ do_gettimeofday(&currentTimeVector);
+ rtl_maintainMulticastSnoopingTimerList((uint32)(currentTimeVector.tv_sec));
+ mod_timer(&igmpSysTimer, jiffies+HZ);
+
+}
+
+static void rtl_multicastSysTimerInit(void)
+{
+ struct timeval startTimeVector;
+ do_gettimeofday(&startTimeVector);
+ rtl_startTime=(uint32)(startTimeVector.tv_sec);
+ rtl_sysUpSeconds=0;
+
+ init_timer(&igmpSysTimer);
+ igmpSysTimer.data=igmpSysTimer.expires;
+ igmpSysTimer.expires=jiffies+HZ;
+ igmpSysTimer.function=(void*)rtl_multicastSysTimerExpired;
+ add_timer(&igmpSysTimer);
+}
+
+static void rtl_multicastSysTimerDestroy(void)
+{
+ del_timer(&igmpSysTimer);
+}
+
+#endif
+
+int32 rtl_getDeviceIgmpSnoopingModuleIndex(rtl_multicastDeviceInfo_t *devInfo,uint32 *moduleIndex)
+{
+ int i;
+ *moduleIndex=0xFFFFFFFF;
+ if(devInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ for(i=0; i<MAX_MCAST_MODULE_NUM; i++)
+ {
+ if(rtl_mCastModuleArray[i].enableSnooping==TRUE)
+ {
+ if(strcmp(rtl_mCastModuleArray[i].deviceInfo.devName, devInfo->devName)==0)
+ {
+ *moduleIndex=i;
+ return SUCCESS;
+ }
+ }
+ }
+
+ return FAILED;
+}
+
+int32 rtl865x_getDeviceIgmpSnoopingModuleIndex(rtl_multicastDeviceInfo_t *devInfo,uint32 *moduleIndex)
+{
+ return rtl_getDeviceIgmpSnoopingModuleIndex(devInfo,moduleIndex);
+}
+
+
+/*
+@func int32 | rtl_setIgmpSnoopingModuleDevInfo | API to set igmp snooping module related device information.
+@parm uint32 | moduleIndex | Input parameter to specify igmp snooping module.
+@parm rtl_multicastDeviceInfo_t *| devInfo | Device information to be set.
+@rvalue SUCCESS |Setting success.
+@rvalue FAILED |Setting failed.
+*/
+int32 rtl_setIgmpSnoopingModuleDevInfo(uint32 moduleIndex,rtl_multicastDeviceInfo_t *devInfo)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(devInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ memcpy(&rtl_mCastModuleArray[moduleIndex].deviceInfo,devInfo, sizeof(rtl_multicastDeviceInfo_t));
+
+ return SUCCESS;
+}
+
+int32 rtl_setIgmpSnoopingModuleStaticRouterPortMask(uint32 moduleIndex,uint32 staticRouterPortMask)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+
+ rtl_mCastModuleArray[moduleIndex].staticRouterPortMask=staticRouterPortMask;
+
+ return SUCCESS;
+}
+
+int32 rtl_getgmpSnoopingModuleStaticRouterPortMask(uint32 moduleIndex,uint32 *staticRouterPortMask)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(staticRouterPortMask==NULL)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ *staticRouterPortMask=rtl_mCastModuleArray[moduleIndex].staticRouterPortMask;
+
+ return SUCCESS;
+}
+
+
+int32 rtl_setIgmpSnoopingModuleUnknownMCastFloodMap(uint32 moduleIndex,uint32 unknownMCastFloodMap)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ rtl_mCastModuleArray[moduleIndex].unknownMCastFloodMap=unknownMCastFloodMap;
+
+ return SUCCESS;
+}
+
+int32 rtl_getIgmpSnoopingModuleUnknownMCastFloodMap(uint32 moduleIndex,uint32 *unknownMCastFloodMap)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(unknownMCastFloodMap==NULL)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ *unknownMCastFloodMap=rtl_mCastModuleArray[moduleIndex].unknownMCastFloodMap;
+
+ return SUCCESS;
+}
+
+/*
+@func int32 | rtl_setIgmpSnoopingModuleDevInfo | API to get igmp snooping module related device information.
+@parm uint32 | moduleIndex | Input parameter to specify igmp snooping module
+@parm rtl_multicastDeviceInfo_t *| devInfo | Output parameter to store the device information of specified igmp snooping module.
+@rvalue SUCCESS |Geting success.
+@rvalue FAILED |Getting failed.
+*/
+int32 rtl_getIgmpSnoopingModuleDevInfo(uint32 moduleIndex,rtl_multicastDeviceInfo_t *devInfo)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(devInfo==NULL)
+ {
+ return FAILED;
+ }
+ memset(devInfo,0,sizeof(rtl_multicastDeviceInfo_t));
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ memcpy(devInfo,&rtl_mCastModuleArray[moduleIndex].deviceInfo, sizeof(rtl_multicastDeviceInfo_t));
+ return SUCCESS;
+}
+
+
+
+#ifdef CONFIG_PROC_FS
+int igmp_show(struct seq_file *s, void *v)
+{
+ int32 moduleIndex;
+ int i=0,j=0;
+ struct rtl_groupEntry *groupEntryPtr;
+ struct rtl_sourceEntry *sourceEntryPtr;
+ int groupCnt=0;
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM ;moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ groupCnt=0;
+ seq_printf(s, "---------------------------------------------\n");
+ seq_printf(s, "module index:%d,",moduleIndex);
+ #ifdef CONFIG_RTL_HARDWARE_MULTICAST
+ seq_printf(s, "device name:%s\n",rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ #endif
+ for(i=0;i<rtl_hashTableSize;i++)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+
+ while(groupEntryPtr!=NULL)
+ {
+ groupCnt++;
+ seq_printf(s, "[%d]group address:%d.%d.%d.%d\n",groupCnt,
+ groupEntryPtr->groupAddr[0]>>24, (groupEntryPtr->groupAddr[0]&0x00ff0000)>>16,
+ (groupEntryPtr->groupAddr[0]&0x0000ff00)>>8, (groupEntryPtr->groupAddr[0]&0xff));
+
+ for(j=0;j<MAX_SUPPORT_PORT_NUMBER;j++)
+ {
+ if(groupEntryPtr->groupFilterTimer[j]>=rtl_sysUpSeconds)
+ {
+ seq_printf(s, "\tgroup timer[port%d]:%d seconds\n",j,groupEntryPtr->groupFilterTimer[j]-rtl_sysUpSeconds);
+ }
+ else
+ {
+ //printk("\tgroup timer[port%d]:0 seconds\n",j);
+
+ }
+ }
+
+ sourceEntryPtr=groupEntryPtr->sourceList;
+ while(sourceEntryPtr!=NULL)
+ {
+ seq_printf(s, "\t\tsource address:%d.%d.%d.%d\n",
+ sourceEntryPtr->sourceAddr[0]>>24, (sourceEntryPtr->sourceAddr[0]&0x00ff0000)>>16,
+ (sourceEntryPtr->sourceAddr[0]&0x0000ff00)>>8, (sourceEntryPtr->sourceAddr[0]&0xff));
+ for(j=0;j<MAX_SUPPORT_PORT_NUMBER;j++)
+ {
+ if(sourceEntryPtr->portTimer[j]>=rtl_sysUpSeconds)
+ {
+ seq_printf(s, "\t\tsource timer[port%d]:%d seconds\n",j,sourceEntryPtr->portTimer[j]-rtl_sysUpSeconds);
+ }
+ else
+ {
+ //printk("\t\tsource timer[port%d]:0 seconds\n",j);
+ }
+ }
+ sourceEntryPtr=sourceEntryPtr->next;
+ }
+ seq_printf(s, "\n");
+ groupEntryPtr=groupEntryPtr->next;
+ }
+ }
+ seq_printf(s, "expire event cnt is %d\n",rtl_mCastModuleArray[moduleIndex].expireEventCnt);
+ seq_printf(s, "\n\n");
+ }
+ }
+
+ return SUCCESS;
+}
+#endif
+
+
+
+void rtl865x_igmpLinkStatusChangeCallback(uint32 moduleIndex, rtl_igmpPortInfo_t * portInfo)
+{
+ int i=0,j=0;
+ int32 clearFlag=FALSE;
+ struct rtl_groupEntry *groupEntryPtr;
+ struct rtl_sourceEntry *sourceEntryPtr;
+
+
+ if(portInfo==NULL)
+ {
+ return ;
+ }
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return ;
+ }
+
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+
+ for(i=0;i<rtl_hashTableSize;i++)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+
+ while(groupEntryPtr!=NULL)
+ {
+ clearFlag=FALSE;
+
+ for(j=0;j<MAX_SUPPORT_PORT_NUMBER;j++)
+ {
+ if(( (1<<j) & (portInfo->linkPortMask)) ==0)
+ {
+ if(groupEntryPtr->groupFilterTimer[j]!=0)
+ {
+ groupEntryPtr->groupFilterTimer[j]=0;
+ clearFlag=TRUE;
+ }
+ }
+
+ }
+
+ sourceEntryPtr=groupEntryPtr->sourceList;
+ while(sourceEntryPtr!=NULL)
+ {
+
+
+ for(j=0;j<MAX_SUPPORT_PORT_NUMBER;j++)
+ {
+ if(( (1<<j) & (portInfo->linkPortMask)) ==0)
+ {
+ if(sourceEntryPtr->portTimer[j]!=0)
+ {
+ sourceEntryPtr->portTimer[j]=0;
+ clearFlag=TRUE;
+ }
+ }
+
+ }
+ sourceEntryPtr=sourceEntryPtr->next;
+ }
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(clearFlag==TRUE)
+ {
+ strcpy(linkEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ linkEventContext.moduleIndex=moduleIndex;
+
+ linkEventContext.groupAddr[0]=groupEntryPtr->groupAddr[0];
+ linkEventContext.groupAddr[1]=groupEntryPtr->groupAddr[1];
+ linkEventContext.groupAddr[2]=groupEntryPtr->groupAddr[2];
+ linkEventContext.groupAddr[3]=groupEntryPtr->groupAddr[3];
+
+ linkEventContext.sourceAddr[0]=0;
+ linkEventContext.sourceAddr[1]=0;
+ linkEventContext.sourceAddr[2]=0;
+ linkEventContext.sourceAddr[3]=0;
+
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &linkEventContext);
+ }
+#endif
+
+ groupEntryPtr=groupEntryPtr->next;
+ }
+ }
+
+ }
+
+ return ;
+}
+
+int32 rtl_getGroupInfo(uint32 groupAddr, struct rtl_groupInfo * groupInfo)
+{
+ int32 moduleIndex;
+ int32 hashIndex;
+ struct rtl_groupEntry *groupEntryPtr;
+
+ if(groupInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ memset(groupInfo, 0 , sizeof(struct rtl_groupInfo));
+
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM ;moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ hashIndex=rtl_hashMask&groupAddr;
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[hashIndex];
+
+ while(groupEntryPtr!=NULL)
+ {
+ if(groupEntryPtr->groupAddr[0]==groupAddr)
+ {
+ groupInfo->ownerMask |= (1<<moduleIndex);
+ break;
+ }
+ groupEntryPtr=groupEntryPtr->next;
+ }
+
+ }
+ }
+
+ return SUCCESS;
+}
+
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_glue.c b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_glue.c
new file mode 100644
index 000000000..65ac56983
--- /dev/null
+++ b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_glue.c
@@ -0,0 +1,108 @@
+/*
+* Copyright c Realsil Semiconductor Corporation, 2006
+* All rights reserved.
+*
+* Program : IGMP glue file
+* Abstract :
+* Author :qinjunjie
+* Email:qinjunjie1980@hotmail.com
+*
+*/
+
+
+/* @doc RTL865X_IGMP_GlUE_API
+
+ @module rtl865x_igmpsnooping_glue.c - RTL865x Igmp Snooping Glue Function documentation |
+ This document lists the glue functions when porting multicast snooping to different platform.
+ @normal Jun-Jie Qin (qjj_qin@realsil.com.cn) <date>
+
+ Copyright <cp>2006 Realsil<tm> Semiconductor Cooperation, All Rights Reserved.
+
+ @head3 List of Symbols |
+ Here is a list of all functions and variables in this module.
+
+ @index | RTL8306_MULTICAST_GlUE_API
+*/
+
+
+
+#include <net/rtl/rtl_types.h>
+#include <net/rtl/rtl_glue.h>
+#include <net/rtl/rtl865x_igmpsnooping_glue.h>
+#include "../AsicDriver/rtl865xc_asicregs.h"
+
+#ifdef __linux__
+#include <linux/mm.h>
+#include <linux/gfp.h>
+#endif
+
+/*
+@func int32 | rtl_glueMutexLock | glue function for system mutex lock
+@rvalue 0| always return 0;
+@comm
+ user should modify this function to glue different OS.
+*/
+
+void rtl_glueMutexLock(void)
+{
+ //rtlglue_drvMutexLock();
+ return;
+}
+
+
+
+/*
+@func int32 | rtl_glueMutexUnlock | Glue function for system mutex unlock
+@rvalue 0| always return 0;
+@comm
+ User should modify this function to glue different OS.
+*/
+void rtl_glueMutexUnlock(void)
+{
+ //rtlglue_drvMutexUnlock();
+ return;
+}
+
+
+/*
+@func void* | rtl_glueMalloc | Glue function for memory allocation
+@parm uint32 | NBYTES | Specifies the number of memory bytes to be allocated
+@rvalue void*| The memory pointer after allocation
+@comm
+ User should modify this function according to different OS.
+*/
+void *rtl_glueMalloc(uint32 NBYTES)
+{
+#ifndef RTL_MULTICAST_SNOOPING_TEST
+ if(NBYTES==0) return NULL;
+ return (void *)kmalloc(NBYTES,GFP_ATOMIC);
+
+#else
+ return malloc(NBYTES);
+
+#endif
+
+}
+
+/*
+@func void | rtl_glueFree |Glue function for memory free
+@parm void * | APTR | Specifies the memory buffer to be freed
+@comm
+ User should modify this function according to different OS.
+*/
+void rtl_glueFree(void *APTR)
+{
+
+#ifndef RTL_MULTICAST_SNOOPING_TEST
+ kfree(APTR);
+#else
+ free(APTR);
+#endif
+
+}
+
+
+
+
+
+
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_local.h b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_local.h
new file mode 100644
index 000000000..bf7557e58
--- /dev/null
+++ b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_local.h
@@ -0,0 +1,575 @@
+/*
+* Copyright c Realsil Semiconductor Corporation, 2006
+* All rights reserved.
+*
+* Program : IGMP snooping function
+* Abstract :
+* Author :qinjunjie
+* Email:qinjunjie1980@hotmail.com
+*
+*/
+
+#ifndef RTL_MULTICASTV2_LOCAL_H
+#define RTL_MULTICASTV2_LOCAL_H
+
+ /* Macro declaration */
+
+
+/***********************************Utilities************************************************/
+#define IS_CLASSD_ADDR(ipv4addr) ((((uint32)(ipv4addr)) & 0xf0000000) == 0xe0000000)
+#define RESERVE_MULTICAST_ADDR1 0xEFFFFFFA
+/* ip 225.1.1.1 is not in the list of "http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xml",
+ but it is used by customer's VoIP phone device.
+ */
+#define RESERVE_MULTICAST_ADDR2 0xE1010101 //225.1.1.1
+#define IN_MULTICAST_RESV1(addr) ((((uint32)(addr)) & 0xFFFFFF00) == 0xe0000000) // 224.0.0.x
+#define IN_MULTICAST_RESV2(addr) ((((uint32)(addr)) & 0xFF000000) == 0xEF000000) // 239.0.0.0~239.255.255.255
+
+#define IS_IPV6_MULTICAST_ADDRESS(ipv6addr) ((ipv6addr[0] & 0xFF000000)==0xff000000)
+#define IS_IPV4_MULTICAST_ADDRESS(ipv4addr) (IS_CLASSD_ADDR(ipv4addr[0]))
+
+#define CONFIG_STATIC_RESERVED_MULTICAST
+#if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+#define STATIC_RESERVED_MULTICAST 0x01
+#endif
+
+#define PORT0_MASK 0x01
+#define PORT1_MASK 0x02
+#define PORT2_MASK 0x04
+#define PORT3_MASK 0x08
+#define PORT4_MASK 0x10
+#define PORT5_MASK 0x20
+
+#ifdef CONFIG_NEW_IGMP_IMPLEMENTATION
+#define MAX_SUPPORT_PORT_NUMBER 16
+#else
+#define MAX_SUPPORT_PORT_NUMBER 10
+#endif
+#define DEFAULT_HASH_TABLE_SIZE 64
+#define MAX_HASH_TABLE_SIZE 1024
+#define MAX_MCAST_MODULE_NUM 8
+
+#define NON_PORT_MASK 0x00
+#define IPV4_MCAST_MAC_MASK 0x007fffff
+#define IPV6_MCAST_MAC_MASK 0x00ffffff
+
+
+
+/* IGMP snooping default parameters */
+#define DEFAULT_MAX_GROUP_COUNT 256 /* default max group entry count **/
+#define DEFAULT_MAX_SOURCE_COUNT 300 /*default max source entry count*/
+#define DEFAULT_MAX_CLIENT_COUNT 256
+#define DEFAULT_MAX_FLOW_COUNT 256
+
+#define DEFAULT_GROUP_MEMBER_INTERVAL 260 /* IGMP group member interval, default is 260 seconds */
+#define DEFAULT_LAST_MEMBER_INTERVAL 10 /* IGMP last member query time, default is 2 seconds */
+#define DEFAULT_QUERIER_PRESENT_TIMEOUT 260 /* IGMP querier present timeout, default is 260 seconds */
+
+#define DEFAULT_MCAST_FLOW_EXPIRE_TIME 15
+
+#define DEFAULT_DVMRP_AGING_TIME 120
+#define DEFAULT_PIM_AGING_TIME 120
+#define DEFAULT_MOSPF_AGING_TIME 120
+
+#define DEFAULT_IPV4_UNKNOWN_MCAST_FLOOD_MAP 0x0
+#define DEFAULT_IPV6_UNKNOWN_MCAST_FLOOD_MAP 0xFFFFFFFF
+
+#define IP_VERSION4 4
+#define IP_VERSION6 6
+#define BOTH_IPV4_IPV6 0x46
+
+#define CPUTAGPROTOCOL 0x09
+#define VLAN_PROTOCOL_ID 0x8100
+
+#define IPV4_ETHER_TYPE 0x0800
+#define IPV6_ETHER_TYPE 0x86DD
+
+#define PPPOE_ETHER_TYPE 0x8864
+#define PPP_IPV4_PROTOCOL 0x0021
+#define PPP_IPV6_PROTOCOL 0x0057
+#define ROUTER_ALERT_OPTION 0x94040000
+
+#define HOP_BY_HOP_OPTIONS_HEADER 0
+#define ROUTING_HEADER 43
+#define FRAGMENT_HEADER 44
+#define DESTINATION_OPTION_HEADER 60
+#define NO_NEXT_HEADER 59
+#define ICMP_PROTOCOL 58
+
+#define DVMRP_ADDR 0xE0000004
+#define DVMRP_TYPE 0x13
+#define DVMRP_PROTOCOL 3
+
+#define PIM_PROTOCOL 103
+#define IPV4_PIM_ADDR 0xE000000D
+#define IS_IPV6_PIM_ADDR(ipv6addr) ((ipv6addr[0] == 0xFF020000)&&(ipv6addr[1] == 0x00000000)&&(ipv6addr[2] == 0x00000000)&&(ipv6addr[3] ==0x0000000D))
+
+#define MOSPF_PROTOCOL 89
+#define MOSPF_HELLO_TYPE 1
+#define IPV4_MOSPF_ADDR1 0xE0000005
+#define IPV4_MOSPF_ADDR2 0xE0000006
+#define IS_IPV6_MOSPF_ADDR1(ipv6addr) ((ipv6addr[0] == 0xFF020000)&&(ipv6addr[1] == 0x00000000)&&(ipv6addr[2] == 0x00000000)&&(ipv6addr[3] ==0x00000005))
+#define IS_IPV6_MOSPF_ADDR2(ipv6addr) ((ipv6addr[0] == 0xFF020000)&&(ipv6addr[1] == 0x00000000)&&(ipv6addr[2] == 0x00000000)&&(ipv6addr[3] ==0x00000006))
+
+
+#define IGMP_PROTOCOL 2
+#define IGMP_ALL_HOSTS_ADDR 0xE0000001 /*general query address*/
+#define IGMP_ALL_ROUTERS_ADDR 0xE0000002 /*leave report address*/
+#define IGMPV3_REPORT_ADDR 0xE0000016
+
+
+#define IS_MLD_ALL_HOSTS_ADDRESS(ipv6addr) ((ipv6addr[0] == 0xFF020000)&&(ipv6addr[1] == 0x00000000)&&(ipv6addr[2] == 0x00000000)&&(ipv6addr[3] ==0x00000001))
+
+
+#define IS_MLD_ALL__ROUTER_ADDRESS(ipv6addr) ((ipv6addr[0] == 0xFF020000)&&(ipv6addr[1] ==0x00000000)&&(ipv6addr[2] ==0x00000000)&&(ipv6addr[3] == 0x00000002))
+
+
+#define IS_MLDv2_REPORT_ADDRESS(ipv6addr) ((ipv6addr[0] == 0xFF020000)&&(ipv6addr[1] == 0x00000000)&&(ipv6addr[2] == 0x00000000)&&(ipv6addr[3] ==0x00000016))
+
+
+/* IGMP type */
+#define IGMP_QUERY 0x11
+#define IGMPV1_REPORT 0x12
+#define IGMPV2_REPORT 0x16
+#define IGMPV2_LEAVE 0x17
+#define IGMPV3_REPORT 0x22
+
+/* MLD type */
+#define MLD_QUERY 130
+#define MLDV1_REPORT 131
+#define MLDV1_DONE 132
+#define MLDV2_REPORT 143
+#define S_FLAG_MASK 0x08
+
+#define MODE_IS_INCLUDE 1
+#define MODE_IS_EXCLUDE 2
+#define CHANGE_TO_INCLUDE_MODE 3
+#define CHANGE_TO_EXCLUDE_MODE 4
+#define ALLOW_NEW_SOURCES 5
+#define BLOCK_OLD_SOURCES 6
+
+#define FILTER_MODE_INCLUDE 0
+#define FILTER_MODE_EXCLUDE 1
+
+ /* IGMP version */
+#define IGMP_V1 1
+#define IGMP_V2 2
+#define IGMP_V3 3
+
+#define MLD_V1 1
+#define MLD_V2 2
+
+
+#define IPV4_ROUTER_ALTER_OPTION 0x94040000
+#define IPV6_ROUTER_ALTER_OPTION 0x05020000
+#define IPV6_HEADER_LENGTH 40
+
+/**********************IGMPv3 exponential field decoding ******************************/
+#define RTL_IGMPV3_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
+#define RTL_IGMPV3_EXP(thresh, nbmant, nbexp, value) \
+ ((value) < (thresh) ? (value) : \
+ ((RTL_IGMPV3_MASK(value, nbmant) | (1<<(nbmant))) << \
+ (RTL_IGMPV3_MASK((value) >> (nbmant), nbexp) + (nbexp))))
+
+#define RTL_IGMPV3_QQIC(value) RTL_IGMPV3_EXP(0x80, 4, 3, value)
+#define RTL_IGMPV3_MRC(value) RTL_IGMPV3_EXP(0x80, 4, 3, value)
+/********************************************************************************/
+
+
+/**************************MLDv2 exponential field decoding ****************************/
+#define RTL_MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
+#define RTL_MLDV2_EXP(thresh, nbmant, nbexp, value)\
+ ((value) < (thresh) ? (value) : \
+ ((RTL_MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
+ (RTL_MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
+
+#define RTL_MLDV2_QQIC(value) RTL_MLDV2_EXP(0x80, 4, 3, value)
+#define RTL_MLDV2_MRC(value) RTL_MLDV2_EXP(0x8000, 12, 3, value)
+/*------------------------------------------------------------------------------*/
+
+struct ipv4Pkt
+{
+ uint8 vhl;
+ uint8 typeOfService;
+ uint16 length; /* total length */
+ uint16 identification; /* identification */
+ uint16 offset;
+ uint8 ttl; /* time to live */
+ uint8 protocol;
+ uint16 checksum;
+ uint32 sourceIp;
+ uint32 destinationIp;
+};
+
+struct igmpPkt{
+ uint8 type; /* type*/
+ uint8 maxRespTime; /*maximum response time,unit:0.1 seconds*/
+ uint16 checksum;
+ uint32 groupAddr;
+
+};
+
+struct igmpv1Pkt
+{
+ uint8 VersionType; /*4bits: version, 4bits:type*/
+ uint8 unused;
+ uint16 checkSum; /*IGMP packet checksum*/
+ uint32 groupAddr; /*multicast group address*/
+};
+
+struct igmpv2Pkt
+{
+ uint8 type; /* type*/
+ uint8 maxRespTime; /*maximum response time,unit:0.1 seconds*/
+ uint16 checkSum;
+ uint32 groupAddr;
+
+};
+
+struct igmpv3Query
+{
+ uint8 type; /*query type*/
+ uint8 maxRespCode; /*maximum response code*/
+ uint16 checkSum; /*IGMP checksum*/
+ uint32 groupAddr; /*multicast group address*/
+ uint8 rsq; /* 4bit: reserved, 1bit: suppress router-side processing, 3bit: querier's robustness variable*/
+ uint8 qqic; /* querier's query interval code */
+ uint16 numOfSrc; /* number of sources */
+ uint32 srcList; /* first entry of source list */
+};
+
+struct groupRecord
+{
+ uint8 type; /* Record Type */
+ uint8 auxLen; /* auxiliary data length, in uints of 32 bit words*/
+ uint16 numOfSrc; /* number of sources */
+ uint32 groupAddr; /* group address being reported */
+ uint32 srcList; /* first entry of source list */
+
+};
+
+struct igmpv3Report
+{
+ uint8 type; /* Report Type */
+ uint8 reserved1;
+ uint16 checkSum; /*IGMP checksum*/
+ uint16 reserved2;
+ uint16 numOfRecords; /* number of Group records */
+ struct groupRecord recordList; /*first entry of group record list*/
+};
+
+struct ipv6Pkt
+{
+ uint32 vtf; /*version(4bits), traffic class(8bits), and flow label(20bits)*/
+ uint16 payloadLenth; /* payload length */
+ uint8 nextHeader; /* next header */
+ uint8 hopLimit; /* hop limit*/
+ uint32 sourceAddr[4]; /*source address*/
+ uint32 destinationAddr[4]; /* destination address */
+};
+
+
+struct mldv1Pkt
+{
+ uint8 type;
+ uint8 code; /*initialize by sender, ignored by receiver*/
+ uint16 checkSum;
+ uint16 maxResDelay; /*maximum response delay,unit:0.001 second*/
+ uint16 reserved;
+ uint32 mCastAddr[4]; /*ipv6 multicast address*/
+};
+
+
+struct mldv2Query
+{
+ uint8 type;
+ uint8 code; /*initialize by sender, ignored by receiver*/
+ uint16 checkSum;
+ uint16 maxResCode; /*maximum response code,unit:0.001 second*/
+ uint16 reserved;
+ uint32 mCastAddr[4];
+ uint8 rsq; /* 4bits: reserved, 1bit: suppress router-side processing, 3bits: querier's robustness variable*/
+ uint8 qqic; /* querier's query interval code */
+ uint16 numOfSrc; /* number of sources */
+ uint32 srcList;
+};
+
+struct mCastAddrRecord
+{
+ uint8 type; /* Record Type */
+ uint8 auxLen; /* auxiliary data length, in uints of 32 bit words*/
+ uint16 numOfSrc; /* number of sources */
+ uint32 mCastAddr[4]; /* group address being reported */
+ uint32 srcList; /* first entry of source list */
+};
+
+struct mldv2Report
+{
+ uint8 type;
+ uint8 reserved1;
+ uint16 checkSum;
+ uint16 reserved2;
+ uint16 numOfRecords; /* number of multicast address records */
+ struct mCastAddrRecord recordList;
+};
+
+
+struct ipv4MospfHdr
+{
+ uint8 version;
+ uint8 type;
+ uint16 pktLen;
+ uint32 routerId;
+ uint32 areaId;
+ uint16 CheckSum;
+ uint16 auType;
+ uint32 authentication[2];
+};
+
+struct ipv4MospfHello
+{
+ struct ipv4MospfHdr hdr;
+ uint32 netWorkMask;
+ uint16 helloInterVal;
+ uint8 options; /* X-X-DC-EA-N/P-MC-E-X */
+ uint8 routerPriority;
+ uint32 routerDeadInterval;
+ uint32 designatedRouter;
+ uint32 backupDesignatedRouter;
+ uint32 neighbor;
+};
+
+struct ipv6MospfHdr
+{
+ uint8 version; /*vesion is 3*/
+ uint8 type;
+ uint16 pktLen;
+ uint32 routerId;
+ uint32 areaId;
+ uint16 CheckSum;
+ uint8 instanceId;
+ uint8 zeroData;
+
+};
+
+struct ipv6MospfHello
+{
+ struct ipv6MospfHdr hdr;
+ uint32 interfaceId;
+ uint8 routerPriority;
+ uint8 options[3]; /*X-X-DC-R-N-MC-E-V6 */
+ uint16 helloInterval;
+ uint16 routerDeadInterval;
+ uint32 designatedRouter;
+ uint32 backupDesignatedRouter;
+ uint32 neighbor;
+};
+
+struct ipv6PseudoHeader
+{
+ uint32 sourceAddr[4];
+ uint32 destinationAddr[4];
+ uint32 upperLayerPacketLength;
+ uint8 zeroData[3];
+ uint8 nextHeader;
+};
+
+struct ipv4PseudoHeader
+{
+ uint32 sourceAddr;
+ uint32 destinationAddr;
+ uint8 zero;
+ uint8 protocol;
+ uint16 payloadLen;
+};
+
+
+union pseudoHeader
+{
+ struct ipv6PseudoHeader ipv6_pHdr;
+ struct ipv4PseudoHeader ipv4_pHdr;
+};
+
+#ifdef CONFIG_NEW_IGMP_IMPLEMENTATION
+struct rtl_groupEntry
+{
+ struct rtl_groupEntry *previous;
+ struct rtl_groupEntry *next; /*Pointer of next group entry*/
+ uint32 ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ uint32 groupAddr[4];
+ #else
+ uint32 groupAddr[1];
+ #endif
+
+ struct rtl_clientEntry *clientList;
+#if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ uint32 attribute;
+ uint32 staticFwdPortMask;
+#endif
+};
+
+struct rtl_clientEntry
+{
+ uint16 igmpVersion;
+ uint16 portNum;
+ struct rtl_clientEntry *previous;
+ struct rtl_clientEntry *next; /*Pointer of next group entry*/
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ uint32 clientAddr[4]; /*client ip address*/
+ #else
+ uint32 clientAddr[1]; /*client ip address*/
+ #endif
+ struct rtl_sourceEntry *sourceList; /*this is the server source ip list*/
+ uint32 groupFilterTimer;
+ uint8 clientMacAddr[6];
+};
+
+
+struct rtl_sourceEntry
+{
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ uint32 sourceAddr[4]; /*D class IP multicast address*/
+ #else
+ uint32 sourceAddr[1]; /*D class IP multicast address*/
+ #endif
+ uint32 fwdState;
+ struct rtl_sourceEntry *previous;
+ struct rtl_sourceEntry *next; /*Pointer of next group entry*/
+ uint32 portTimer;
+};
+
+struct rtl_mcastFlowEntry
+{
+ struct rtl_mcastFlowEntry *previous;
+ struct rtl_mcastFlowEntry *next; /*Pointer of next group entry*/
+ uint32 ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ uint32 serverAddr[4];
+ uint32 groupAddr[4];
+ #else
+ uint32 serverAddr[1];
+ uint32 groupAddr[1];
+ #endif
+
+ struct rtl_multicastFwdInfo multicastFwdInfo;
+ uint32 refreshTime;
+};
+#else
+struct rtl_groupEntry
+{
+ struct rtl_groupEntry *previous;
+ struct rtl_groupEntry *next; /*Pointer of next group entry*/
+ struct rtl_sourceEntry *sourceList;
+ uint32 ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ uint32 groupAddr[4];
+ #else
+ uint32 groupAddr[1];
+ #endif
+ uint32 groupFilterTimer[MAX_SUPPORT_PORT_NUMBER];
+
+};
+
+struct rtl_sourceEntry
+{
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ uint32 sourceAddr[4]; /*D class IP multicast address*/
+ #else
+ uint32 sourceAddr[1]; /*D class IP multicast address*/
+ #endif
+ struct rtl_sourceEntry *previous;
+ struct rtl_sourceEntry *next; /*Pointer of next group entry*/
+ uint32 portTimer[MAX_SUPPORT_PORT_NUMBER];
+};
+#endif
+
+struct rtl_mcastRouter
+{
+ uint32 portTimer[MAX_SUPPORT_PORT_NUMBER];
+};
+
+
+struct rtl_macFrameInfo
+{
+ uint8 ipVersion;
+
+ uint32 srcIpAddr[4];
+ uint32 dstIpAddr[4];
+
+ uint8 *ipBuf;
+ uint16 ipHdrLen;
+ uint8 l3Protocol;
+ uint8 checksumFlag;
+ uint8 *l3PktBuf;
+ uint16 l3PktLen;
+ uint16 macFrameLen;
+ uint16 vlanTagFlag;
+ uint16 vlanTagID;
+ uint8 srcMacAddr[6];
+
+};
+
+
+struct rtl_multicastRouters
+{
+ struct rtl_mcastRouter querier;
+ struct rtl_mcastRouter dvmrpRouter;
+ struct rtl_mcastRouter mospfRouter;
+ struct rtl_mcastRouter pimRouter;
+
+};
+#ifdef CONFIG_NEW_IGMP_IMPLEMENTATION
+//#define CONFIG_RECORD_MCAST_FLOW
+#endif
+
+struct rtl_multicastModule
+{
+ uint8 enableSnooping;
+#ifdef CONFIG_NEW_IGMP_IMPLEMENTATION
+#else
+ uint8 enableSourceList;
+#endif
+ uint8 enableFastLeave;
+
+ uint32 ipv4UnknownMCastFloodMap;
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ uint32 ipv6UnknownMCastFloodMap;
+#endif
+ uint32 staticRouterPortMask;
+
+ rtl_multicastDeviceInfo_t deviceInfo;
+
+ struct rtl_multicastRouters rtl_ipv4MulticastRouters;
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ struct rtl_multicastRouters rtl_ipv6MulticastRouters;
+#endif
+
+ /*gateway infomation*/
+ uint8 rtl_gatewayMac[6];
+ uint32 rtl_gatewayIpv4Addr;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ uint32 rtl_gatewayIpv6Addr[4];
+#endif
+
+
+ /*hash table definition*/
+ struct rtl_groupEntry ** rtl_ipv4HashTable;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ struct rtl_groupEntry ** rtl_ipv6HashTable;
+#endif
+
+#ifdef CONFIG_RECORD_MCAST_FLOW
+ struct rtl_mcastFlowEntry **flowHashTable;
+#endif
+#ifdef CONFIG_PROC_FS
+ unsigned int expireEventCnt;
+#endif
+
+};
+
+
+#endif
+
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_new.c b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_new.c
new file mode 100644
index 000000000..a9d16c5af
--- /dev/null
+++ b/target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping_new.c
@@ -0,0 +1,6895 @@
+/*
+* Copyright c Realsil Semiconductor Corporation, 2009
+* All rights reserved.
+*
+* Program : igmp snooping function
+* Abstract :
+* Author :qinjunjie
+* Email:qinjunjie1980@hotmail.com
+*
+*/
+
+#ifdef __linux__
+#include <linux/config.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/seq_file.h>
+#endif
+#endif
+
+
+#include <net/rtl/rtl865x_igmpsnooping_glue.h>
+#include <net/rtl/rtl_glue.h>
+#include <net/rtl/rtl865x_igmpsnooping.h>
+#include "rtl865x_igmpsnooping_local.h"
+//#include "../common/assert.h"
+
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+#include "../common/rtl865x_eventMgr.h"
+#endif
+
+
+
+static struct rtl_multicastModule rtl_mCastModuleArray[MAX_MCAST_MODULE_NUM];
+#if defined(__linux__) && defined(__KERNEL__)
+static struct timer_list igmpSysTimer; /*igmp timer*/
+#endif
+/*global system resources declaration*/
+static uint32 rtl_totalMaxGroupCnt; /*maximum total group entry count, default is 100*/
+static uint32 rtl_totalMaxClientCnt; /*maximum total group entry count, default is 100*/
+static uint32 rtl_totalMaxSourceCnt; /*maximum total group entry count, default is 3000*/
+
+void *rtl_groupMemory=NULL;
+void *rtl_clientMemory=NULL;
+void *rtl_sourceMemory=NULL;
+void *rtl_mcastFlowMemory=NULL;
+
+static struct rtl_groupEntry *rtl_groupEntryPool=NULL;
+static struct rtl_clientEntry *rtl_clientEntryPool=NULL;
+static struct rtl_sourceEntry *rtl_sourceEntryPool=NULL;
+#ifdef CONFIG_RECORD_MCAST_FLOW
+static struct rtl_mcastFlowEntry *rtl_mcastFlowEntryPool=NULL;
+#endif
+static struct rtl_mCastTimerParameters rtl_mCastTimerParas; /*IGMP snooping parameters */
+
+static uint32 rtl_hashTableSize=0;
+static uint32 rtl_hashMask=0;
+
+/*the system up time*/
+static uint32 rtl_startTime;
+static uint32 rtl_sysUpSeconds;
+
+static rtl_multicastEventContext_t reportEventContext;
+static rtl_multicastEventContext_t timerEventContext;
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+static rtl_multicastEventContext_t linkEventContext;
+#endif
+
+
+/*******************************internal function declaration*****************************/
+
+
+/**************************
+ resource managment
+**************************/
+static struct rtl_groupEntry* rtl_initGroupEntryPool(uint32 poolSize);
+static struct rtl_groupEntry* rtl_allocateGroupEntry(void);
+static void rtl_freeGroupEntry(struct rtl_groupEntry* groupEntryPtr) ;
+
+
+static struct rtl_clientEntry* rtl_initClientEntryPool(uint32 poolSize);
+static struct rtl_clientEntry* rtl_allocateClientEntry(void);
+static void rtl_freeClientEntry(struct rtl_clientEntry* clientEntryPtr) ;
+
+static struct rtl_sourceEntry* rtl_initSourceEntryPool(uint32 poolSize);
+static struct rtl_sourceEntry* rtl_allocateSourceEntry(void);
+static void rtl_freeSourceEntry(struct rtl_sourceEntry* sourceEntryPtr) ;
+#ifdef CONFIG_RECORD_MCAST_FLOW
+static struct rtl_mcastFlowEntry* rtl_initMcastFlowEntryPool(uint32 poolSize);
+static struct rtl_mcastFlowEntry* rtl_allocateMcastFlowEntry(void);
+static void rtl_freeMcastFlowEntry(struct rtl_mcastFlowEntry* mcastFlowEntry) ;
+#endif
+/**********************************Structure Maintenance*************************/
+
+static struct rtl_groupEntry* rtl_searchGroupEntry(uint32 moduleIndex, uint32 ipVersion,uint32 *multicastAddr);
+static void rtl_linkGroupEntry(struct rtl_groupEntry* entryNode , struct rtl_groupEntry ** hashTable);
+static void rtl_unlinkGroupEntry(struct rtl_groupEntry* entryNode, struct rtl_groupEntry ** hashTable);
+static void rtl_clearGroupEntry(struct rtl_groupEntry* groupEntryPtr);
+
+
+static struct rtl_clientEntry* rtl_searchClientEntry(uint32 ipVersion,struct rtl_groupEntry* groupEntry, uint32 portNum, uint32 *clientAddr);
+static void rtl_linkClientEntry(struct rtl_groupEntry *groupEntry, struct rtl_clientEntry* clientEntry);
+static void rtl_unlinkClientEntry(struct rtl_groupEntry *groupEntry, struct rtl_clientEntry* clientEntry);
+static void rtl_clearClientEntry(struct rtl_clientEntry* clientEntryPtr);
+static void rtl_deleteClientEntry(struct rtl_groupEntry * groupEntry, struct rtl_clientEntry * clientEntry);
+
+static struct rtl_sourceEntry* rtl_searchSourceEntry(uint32 ipVersion, uint32 *sourceAddr, struct rtl_clientEntry *clientEntry);
+static void rtl_linkSourceEntry(struct rtl_clientEntry *clientEntry, struct rtl_sourceEntry* entryNode);
+static void rtl_unlinkSourceEntry(struct rtl_clientEntry *clientEntry, struct rtl_sourceEntry* entryNode);
+static void rtl_clearSourceEntry(struct rtl_sourceEntry* sourceEntryPtr);
+static void rtl_deleteSourceEntry(struct rtl_clientEntry *clientEntry, struct rtl_sourceEntry* sourceEntry);
+#ifdef CONFIG_RECORD_MCAST_FLOW
+static struct rtl_mcastFlowEntry* rtl_searchMcastFlowEntry(uint32 moduleIndex, uint32 ipVersion, uint32 *serverAddr,uint32 *groupAddr);
+static void rtl_linkMcastFlowEntry(struct rtl_mcastFlowEntry* mcastFlowEntry , struct rtl_mcastFlowEntry ** hashTable);
+static void rtl_unlinkMcastFlowEntry(struct rtl_mcastFlowEntry* mcastFlowEntry, struct rtl_mcastFlowEntry ** hashTable);
+static void rtl_clearMcastFlowEntry(struct rtl_mcastFlowEntry* mcastFlowEntry);
+static void rtl_deleteMcastFlowEntry( struct rtl_mcastFlowEntry* mcastFlowEntry, struct rtl_mcastFlowEntry ** hashTable);
+#endif
+static int32 rtl_checkMCastAddrMapping(uint32 ipVersion, uint32 *ipAddr, uint8* macAddr);
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+static int32 rtl_compareIpv6Addr(uint32* ipv6Addr1, uint32* ipv6Addr2);
+static uint16 rtl_ipv6L3Checksum(uint8 *pktBuf, uint32 pktLen, union pseudoHeader *ipv6PseudoHdr);
+#endif
+static int32 rtl_compareMacAddr(uint8* macAddr1, uint8* macAddr2);
+static uint16 rtl_checksum(uint8 *packetBuf, uint32 packetLen);
+static uint8 rtl_getClientFwdPortMask(struct rtl_clientEntry * clientEntry, uint32 sysTime);
+static void rtl_checkSourceTimer(struct rtl_clientEntry * clientEntry , struct rtl_sourceEntry * sourceEntry);
+static uint32 rtl_getGroupSourceFwdPortMask(struct rtl_groupEntry * groupEntry, uint32 * sourceAddr, uint32 sysTime);
+static uint32 rtl_getClientSourceFwdPortMask(uint32 ipVersion, struct rtl_clientEntry * clientEntry, uint32 * sourceAddr, uint32 sysTime);
+
+static void rtl_checkGroupEntryTimer(struct rtl_groupEntry * groupEntry, struct rtl_groupEntry ** hashTable);
+static void rtl_checkClientEntryTimer(struct rtl_groupEntry * groupEntry, struct rtl_clientEntry * clientEntry);
+
+static uint32 rtl_getMulticastRouterPortMask(uint32 moduleIndex, uint32 ipVersion, uint32 sysTime);
+
+
+/*hash table operation*/
+static int32 rtl_initHashTable(uint32 moduleIndex, uint32 hashTableSize);
+
+
+/************************************Pkt Process**********************************/
+/*MAC frame analyze function*/
+static void rtl_parseMacFrame(uint32 moduleIndex, uint8* MacFrame, uint32 verifyCheckSum, struct rtl_macFrameInfo* macInfo);
+
+/*Process Query Packet*/
+static void rtl_snoopQuerier(uint32 moduleIndex, uint32 ipVersion, uint32 portNum);
+static uint32 rtl_processQueries(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8* pktBuf, uint32 pktLen);
+/*Process Report Packet*/
+static uint32 rtl_processJoin(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint32 *clientAddr, uint8 *pktBuf); // process join report packet
+static uint32 rtl_processLeave(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint32 *clientAddr, uint8 *pktBuf); //process leave/done report packet
+static int32 rtl_processIsInclude(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint32 *clientAddr, uint8 *pktBuf); //process MODE_IS_INCLUDE report packet
+static int32 rtl_processIsExclude(uint32 moduleIndex, uint32 ipVersion,uint32 portNum, uint32 *clientAddr, uint8 *pktBuf); //process MODE_IS_EXCLUDE report packet
+static int32 rtl_processToInclude(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint32 *clientAddr, uint8 *pktBuf); //process CHANGE_TO_INCLUDE_MODE report packet
+static int32 rtl_processToExclude(uint32 moduleIndex, uint32 ipVersion,uint32 portNum , uint32 *clientAddr, uint8 *pktBuf); //process CHANGE_TO_EXCLUDE_MODE report packet
+static int32 rtl_processAllow(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint32 *clientAddr, uint8 *pktBuf); //process ALLOW_NEW_SOURCES report packet
+static int32 rtl_processBlock(uint32 moduleIndex, uint32 ipVersion,uint32 portNum, uint32 *clientAddr, uint8 *pktBuf);//process BLOCK_OLD_SOURCES report packet
+static uint32 rtl_processIgmpv3Mldv2Reports(uint32 moduleIndex, uint32 ipVersion, uint32 portNum,uint32 *clientAddr, uint8 *pktBuf);
+
+/*******************different protocol process function**********************************/
+static uint32 rtl_processIgmpMld(uint32 moduleIndex, uint32 ipVersion, uint32 portNum,uint32 *clientAddr, uint8* pktBuf, uint32 pktLen);
+static uint32 rtl_processDvmrp(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8* pktBuf, uint32 pktLen);
+static uint32 rtl_processMospf(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8* pktBuf, uint32 pktLen);
+static uint32 rtl_processPim(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8* pktBuf, uint32 pktLen);
+
+#ifdef CONFIG_RECORD_MCAST_FLOW
+static int32 rtl_recordMcastFlow(uint32 moduleIndex,uint32 ipVersion, uint32 *sourceIpAddr, uint32 *groupAddr, struct rtl_multicastFwdInfo * multicastFwdInfo);
+static void rtl_invalidateMCastFlow(uint32 moduleIndex,uint32 ipVersion, uint32 *groupAddr);
+static void rtl_doMcastFlowRecycle(uint32 moduleIndex,uint32 ipVersion);
+#endif
+
+#if defined(__linux__) && defined(__KERNEL__)
+static void rtl_multicastSysTimerExpired(uint32 expireDada);
+static void rtl_multicastSysTimerInit(void);
+static void rtl_multicastSysTimerDestroy(void);
+#endif
+
+static void rtl_deleteGroupEntry( struct rtl_groupEntry* groupEntry,struct rtl_groupEntry ** hashTable);
+/************************************************
+ Implementation
+ ************************************************/
+
+/**************************
+ Initialize
+**************************/
+
+int32 rtl_initMulticastSnooping(struct rtl_mCastSnoopingGlobalConfig mCastSnoopingGlobalConfig)
+{
+ int i,j;
+ uint32 maxHashTableSize=MAX_HASH_TABLE_SIZE;
+ for(i=0; i<MAX_MCAST_MODULE_NUM; i++)
+ {
+ memset(&(rtl_mCastModuleArray[i]), 0,sizeof(struct rtl_multicastModule));
+
+ for(j=0; j<6; j++)
+ {
+ rtl_mCastModuleArray[i].rtl_gatewayMac[j]=0;
+ }
+
+ rtl_mCastModuleArray[i].rtl_gatewayIpv4Addr=0;
+ rtl_mCastModuleArray[i].rtl_ipv4HashTable=NULL;
+
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ for(j=0; j<4; j++)
+ {
+ rtl_mCastModuleArray[i].rtl_gatewayIpv6Addr[j]=0;
+ }
+ rtl_mCastModuleArray[i].rtl_ipv6HashTable=NULL;
+ #endif
+#ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_mCastModuleArray[i].flowHashTable=NULL;
+#endif
+ rtl_mCastModuleArray[i].enableSnooping=FALSE;
+ rtl_mCastModuleArray[i].enableFastLeave=FALSE;
+
+ }
+
+
+ /*set multicast snooping parameters, use default value*/
+ if(mCastSnoopingGlobalConfig.groupMemberAgingTime==0)
+ {
+ rtl_mCastTimerParas.groupMemberAgingTime= DEFAULT_GROUP_MEMBER_INTERVAL;
+ }
+ else
+ {
+ rtl_mCastTimerParas.groupMemberAgingTime= mCastSnoopingGlobalConfig.groupMemberAgingTime;
+ }
+
+ if(mCastSnoopingGlobalConfig.lastMemberAgingTime==0)
+ {
+ rtl_mCastTimerParas.lastMemberAgingTime= 0;
+ }
+ else
+ {
+ rtl_mCastTimerParas.lastMemberAgingTime= mCastSnoopingGlobalConfig.lastMemberAgingTime;
+ }
+
+ if(mCastSnoopingGlobalConfig.querierPresentInterval==0)
+ {
+ rtl_mCastTimerParas.querierPresentInterval= DEFAULT_QUERIER_PRESENT_TIMEOUT;
+ }
+ else
+ {
+ rtl_mCastTimerParas.querierPresentInterval=mCastSnoopingGlobalConfig.querierPresentInterval;
+ }
+
+
+ if(mCastSnoopingGlobalConfig.dvmrpRouterAgingTime==0)
+ {
+ rtl_mCastTimerParas.dvmrpRouterAgingTime=DEFAULT_DVMRP_AGING_TIME;
+ }
+ else
+ {
+ rtl_mCastTimerParas.dvmrpRouterAgingTime=mCastSnoopingGlobalConfig.dvmrpRouterAgingTime;
+ }
+
+ if(mCastSnoopingGlobalConfig.mospfRouterAgingTime==0)
+ {
+ rtl_mCastTimerParas.mospfRouterAgingTime=DEFAULT_MOSPF_AGING_TIME;
+ }
+ else
+ {
+ rtl_mCastTimerParas.mospfRouterAgingTime=mCastSnoopingGlobalConfig.mospfRouterAgingTime;
+ }
+
+ if(mCastSnoopingGlobalConfig.pimRouterAgingTime==0)
+ {
+ rtl_mCastTimerParas.pimRouterAgingTime=DEFAULT_PIM_AGING_TIME;
+ }
+ else
+ {
+ rtl_mCastTimerParas.pimRouterAgingTime=mCastSnoopingGlobalConfig.pimRouterAgingTime;
+ }
+
+ /* set hash table size and hash mask*/
+ if(mCastSnoopingGlobalConfig.hashTableSize==0)
+ {
+ rtl_hashTableSize=DEFAULT_HASH_TABLE_SIZE; /*default hash table size*/
+ }
+ else
+ {
+ for(i=0;i<11;i++)
+ {
+ if(mCastSnoopingGlobalConfig.hashTableSize>=maxHashTableSize)
+ {
+ rtl_hashTableSize=maxHashTableSize;
+
+ break;
+ }
+ maxHashTableSize=maxHashTableSize>>1;
+
+ }
+ }
+
+ rtl_hashMask=rtl_hashTableSize-1;
+
+
+ rtl_groupMemory=NULL;
+ rtl_clientMemory=NULL;
+ rtl_sourceMemory=NULL;
+ rtl_mcastFlowMemory=NULL;
+
+ /*initialize group entry pool*/
+ if(mCastSnoopingGlobalConfig.maxGroupNum==0)
+ {
+ rtl_totalMaxGroupCnt=DEFAULT_MAX_GROUP_COUNT;
+ }
+ else
+ {
+ rtl_totalMaxGroupCnt=mCastSnoopingGlobalConfig.maxGroupNum;
+ }
+
+ rtl_groupEntryPool=rtl_initGroupEntryPool(rtl_totalMaxGroupCnt);
+ if(rtl_groupEntryPool==NULL)
+ {
+ return FAILED;
+ }
+
+ /*initialize client entry pool*/
+ if(mCastSnoopingGlobalConfig.maxClientNum==0)
+ {
+ rtl_totalMaxClientCnt=DEFAULT_MAX_CLIENT_COUNT;
+ }
+ else
+ {
+ rtl_totalMaxClientCnt=mCastSnoopingGlobalConfig.maxClientNum;
+ }
+
+ rtl_clientEntryPool=rtl_initClientEntryPool(rtl_totalMaxClientCnt);
+ if(rtl_clientEntryPool==NULL)
+ {
+ return FAILED;
+ }
+#ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_mcastFlowEntryPool=rtl_initMcastFlowEntryPool(DEFAULT_MAX_FLOW_COUNT);
+ if(rtl_mcastFlowEntryPool==NULL)
+ {
+ return FAILED;
+ }
+#endif
+ /*initialize source entry pool*/
+ if(mCastSnoopingGlobalConfig.maxSourceNum==0)
+ {
+ rtl_totalMaxSourceCnt=DEFAULT_MAX_SOURCE_COUNT;
+ }
+ else
+ {
+ rtl_totalMaxSourceCnt=mCastSnoopingGlobalConfig.maxSourceNum;
+ }
+
+ rtl_sourceEntryPool=rtl_initSourceEntryPool(rtl_totalMaxSourceCnt);
+ if(rtl_sourceEntryPool==NULL)
+ {
+ rtl_totalMaxSourceCnt=0;
+ return FAILED;
+ }
+
+#if defined(__linux__) && defined(__KERNEL__)
+ rtl_multicastSysTimerInit();
+#endif
+
+ return SUCCESS;
+
+}
+int32 rtl_flushAllIgmpRecord(void)
+{
+ /* maintain current time */
+ uint32 i=0;
+ struct rtl_groupEntry* groupEntryPtr=NULL;
+ struct rtl_groupEntry* nextGroupEntry=NULL;
+
+ uint32 moduleIndex;
+
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM; moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+
+ /*maintain ipv4 group entry timer */
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+ /*scan the hash table*/
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!=NULL)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+ while(groupEntryPtr) /*traverse each group list*/
+ {
+ nextGroupEntry=groupEntryPtr->next;
+
+ reportEventContext.moduleIndex=moduleIndex;
+ reportEventContext.ipVersion=IP_VERSION4;
+ reportEventContext.groupAddr[0]=groupEntryPtr->groupAddr[0];
+ reportEventContext.groupAddr[1]=0;
+ reportEventContext.groupAddr[2]=0;
+ reportEventContext.groupAddr[3]=0;
+
+ rtl_deleteGroupEntry(groupEntryPtr, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ #endif
+
+ groupEntryPtr=nextGroupEntry;
+ }
+ }
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ /*maintain ipv6 group entry timer */
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+ /*scan the hash table*/
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable!=NULL)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i];
+ while(groupEntryPtr) /*traverse each group list*/
+ {
+ nextGroupEntry=groupEntryPtr->next;
+
+ reportEventContext.moduleIndex=moduleIndex;
+ reportEventContext.ipVersion=IP_VERSION6;
+ reportEventContext.groupAddr[0]=groupEntryPtr->groupAddr[0];
+ reportEventContext.groupAddr[1]=groupEntryPtr->groupAddr[1];
+ reportEventContext.groupAddr[2]=groupEntryPtr->groupAddr[2];
+ reportEventContext.groupAddr[3]=groupEntryPtr->groupAddr[3];
+
+ rtl_deleteGroupEntry(groupEntryPtr, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ groupEntryPtr=nextGroupEntry;
+ }
+ }
+ }
+#endif
+
+ }
+ }
+ return SUCCESS;
+}
+
+static int32 rtl_setClientMacAddr(struct rtl_macFrameInfo *macFrameInfo)
+{
+ /* maintain current time */
+ uint32 i=0;
+ struct rtl_groupEntry* groupEntryPtr=NULL;
+ struct rtl_groupEntry* nextGroupEntry=NULL;
+ struct rtl_clientEntry* clientEntryPtr=NULL;
+
+ uint32 moduleIndex;
+
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM; moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+
+ /*maintain ipv4 group entry timer */
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+ /*scan the hash table*/
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!=NULL)
+ {
+
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+ while(groupEntryPtr) /*traverse each group list*/
+ {
+ nextGroupEntry=groupEntryPtr->next;
+ clientEntryPtr=groupEntryPtr->clientList;
+ while(clientEntryPtr!=NULL)
+ {
+
+ if(memcmp(clientEntryPtr->clientAddr, macFrameInfo->srcIpAddr,4)==0)
+ {
+ memcpy(clientEntryPtr->clientMacAddr,macFrameInfo->srcMacAddr,6);
+ }
+ clientEntryPtr=clientEntryPtr->next;
+ }
+ groupEntryPtr=nextGroupEntry;
+ }
+ }
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ /*maintain ipv6 group entry timer */
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+ /*scan the hash table*/
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable!=NULL)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i];
+ while(groupEntryPtr) /*traverse each group list*/
+ {
+ nextGroupEntry=groupEntryPtr->next;
+ clientEntryPtr=groupEntryPtr->clientList;
+ while(clientEntryPtr!=NULL)
+ {
+ if(memcmp(clientEntryPtr->clientAddr, macFrameInfo->srcIpAddr,16)==0)
+ {
+ memcpy(clientEntryPtr->clientMacAddr,macFrameInfo->srcMacAddr,6);
+ }
+ clientEntryPtr=clientEntryPtr->next;
+ }
+ groupEntryPtr=nextGroupEntry;
+ }
+ }
+ }
+#endif
+
+ }
+ }
+ return SUCCESS;
+}
+
+
+int32 rtl_delIgmpRecordByMacAddr(uint8 *macAddr)
+{
+ /* maintain current time */
+ uint32 i=0;
+ struct rtl_groupEntry* groupEntryPtr=NULL;
+ struct rtl_groupEntry* nextGroupEntry=NULL;
+ struct rtl_clientEntry* clientEntryPtr=NULL;
+ struct rtl_clientEntry* nextClientEntryPtr=NULL;
+
+ uint32 moduleIndex;
+ uint32 deleteFlag=FALSE;
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM; moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+
+ /*maintain ipv4 group entry timer */
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+ /*scan the hash table*/
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!=NULL)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+ while(groupEntryPtr) /*traverse each group list*/
+ {
+ deleteFlag=FALSE;
+ reportEventContext.moduleIndex=moduleIndex;
+ reportEventContext.ipVersion=IP_VERSION4;
+ reportEventContext.groupAddr[0]=groupEntryPtr->groupAddr[0];
+ reportEventContext.groupAddr[1]=0;
+ reportEventContext.groupAddr[2]=0;
+ reportEventContext.groupAddr[3]=0;
+
+ nextGroupEntry=groupEntryPtr->next;
+ clientEntryPtr=groupEntryPtr->clientList;
+ while(clientEntryPtr!=NULL)
+ {
+ nextClientEntryPtr=clientEntryPtr->next;
+ if(memcmp(clientEntryPtr->clientMacAddr,macAddr,6)==0)
+ {
+ rtl_deleteClientEntry(groupEntryPtr, clientEntryPtr);
+ deleteFlag=TRUE;
+ }
+ clientEntryPtr=nextClientEntryPtr;
+ }
+
+ if(deleteFlag==TRUE)
+ {
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ #endif
+ }
+ groupEntryPtr=nextGroupEntry;
+ }
+ }
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ /*maintain ipv6 group entry timer */
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+ /*scan the hash table*/
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable!=NULL)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i];
+ while(groupEntryPtr) /*traverse each group list*/
+ {
+ deleteFlag=FALSE;
+ reportEventContext.moduleIndex=moduleIndex;
+ reportEventContext.ipVersion=IP_VERSION6;
+ reportEventContext.groupAddr[0]=groupEntryPtr->groupAddr[0];
+ reportEventContext.groupAddr[1]=groupEntryPtr->groupAddr[1];
+ reportEventContext.groupAddr[2]=groupEntryPtr->groupAddr[2];
+ reportEventContext.groupAddr[3]=groupEntryPtr->groupAddr[3];
+
+ nextGroupEntry=groupEntryPtr->next;
+ clientEntryPtr=groupEntryPtr->clientList;
+ while(clientEntryPtr!=NULL)
+ {
+ nextClientEntryPtr=clientEntryPtr->next;
+ if(memcmp(clientEntryPtr->clientMacAddr,macAddr, 6)==0)
+ {
+ rtl_deleteClientEntry(groupEntryPtr, clientEntryPtr);
+ deleteFlag=TRUE;
+ }
+ clientEntryPtr=nextClientEntryPtr;
+ }
+
+ if(deleteFlag==TRUE)
+ {
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+ }
+
+ groupEntryPtr=nextGroupEntry;
+ }
+ }
+ }
+#endif
+
+ }
+ }
+ return SUCCESS;
+}
+
+static inline uint32 rtl_igmpHashAlgorithm(uint32 ipVersion,uint32 *groupAddr)
+{
+ uint32 hashIndex=0;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ /*to do:change hash algorithm*/
+ hashIndex=rtl_hashMask&groupAddr[0];
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ hashIndex=rtl_hashMask&groupAddr[3];
+ }
+#endif
+
+ return hashIndex;
+}
+
+int32 rtl_exitMulticastSnooping(void)
+{
+
+ uint32 moduleIndex;
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM; moduleIndex++)
+ {
+ rtl_unregisterIgmpSnoopingModule(moduleIndex);
+ }
+
+ rtl_hashTableSize=0;
+ rtl_hashMask=0;
+ memset(&rtl_mCastTimerParas,0,sizeof(struct rtl_mCastTimerParameters));
+
+ if(rtl_groupMemory!=NULL)
+ {
+ rtl_glueFree(rtl_groupMemory);
+ }
+
+ rtl_totalMaxGroupCnt=0;
+ rtl_groupMemory=NULL;
+ rtl_groupEntryPool=NULL;
+
+ if(rtl_clientMemory!=NULL)
+ {
+ rtl_glueFree(rtl_clientMemory);
+ }
+
+ rtl_totalMaxClientCnt=0;
+ rtl_clientMemory=NULL;
+ rtl_clientEntryPool=NULL;
+
+ if(rtl_sourceMemory!=NULL)
+ {
+ rtl_glueFree(rtl_sourceMemory);
+ }
+
+ rtl_totalMaxSourceCnt=0;
+ rtl_sourceMemory=NULL;
+ rtl_sourceEntryPool=NULL;
+
+#if defined(__linux__) && defined(__KERNEL__)
+ rtl_multicastSysTimerDestroy();
+#endif
+
+ return SUCCESS;
+
+}
+
+/*group entry memory management*/
+static struct rtl_groupEntry* rtl_initGroupEntryPool(uint32 poolSize)
+{
+
+ uint32 idx=0;
+ struct rtl_groupEntry *poolHead=NULL;
+ struct rtl_groupEntry *entryPtr=NULL;
+ rtl_glueMutexLock(); /* Lock resource */
+ if (poolSize == 0)
+ {
+ goto out;
+ }
+
+ /* Allocate memory */
+ poolHead = (struct rtl_groupEntry *)rtl_glueMalloc(sizeof(struct rtl_groupEntry) * poolSize);
+ rtl_groupMemory=(void *)poolHead;
+
+ if (poolHead != NULL)
+ {
+ memset(poolHead, 0, (poolSize * sizeof(struct rtl_groupEntry)));
+ entryPtr = poolHead;
+
+ /* link the whole group entry pool */
+ for (idx = 0 ; idx < poolSize ; idx++, entryPtr++)
+ {
+ if(idx==0)
+ {
+ entryPtr->previous=NULL;
+ if(idx == (poolSize - 1))
+ {
+ entryPtr->next=NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+ else
+ {
+ entryPtr->previous=entryPtr-1;
+ if (idx == (poolSize - 1))
+ {
+ entryPtr->next = NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+ }
+ }
+
+out:
+
+ rtl_glueMutexUnlock(); /* UnLock resource */
+ return poolHead;
+
+}
+
+// allocate a group entry from the group entry pool
+static struct rtl_groupEntry* rtl_allocateGroupEntry(void)
+{
+ struct rtl_groupEntry *ret = NULL;
+
+ rtl_glueMutexLock();
+ if (rtl_groupEntryPool!=NULL)
+ {
+ ret = rtl_groupEntryPool;
+ if(rtl_groupEntryPool->next!=NULL)
+ {
+ rtl_groupEntryPool->next->previous=NULL;
+ }
+ rtl_groupEntryPool = rtl_groupEntryPool->next;
+ memset(ret, 0, sizeof(struct rtl_groupEntry));
+ }
+
+ rtl_glueMutexUnlock();
+
+ return ret;
+}
+
+// free a group entry and link it back to the group entry pool, default is link to the pool head
+static void rtl_freeGroupEntry(struct rtl_groupEntry* groupEntryPtr)
+{
+ if (!groupEntryPtr)
+ {
+ return;
+ }
+
+ rtl_glueMutexLock();
+ groupEntryPtr->next = rtl_groupEntryPool;
+ if(rtl_groupEntryPool!=NULL)
+ {
+ rtl_groupEntryPool->previous=groupEntryPtr;
+ }
+ rtl_groupEntryPool=groupEntryPtr;
+ rtl_glueMutexUnlock();
+}
+
+/*client entry memory management*/
+static struct rtl_clientEntry* rtl_initClientEntryPool(uint32 poolSize)
+{
+
+ uint32 idx=0;
+ struct rtl_clientEntry *poolHead=NULL;
+ struct rtl_clientEntry *entryPtr=NULL;
+ rtl_glueMutexLock(); /* Lock resource */
+ if (poolSize == 0)
+ {
+ goto out;
+ }
+
+ /* Allocate memory */
+ poolHead = (struct rtl_clientEntry *)rtl_glueMalloc(sizeof(struct rtl_clientEntry) * poolSize);
+ rtl_clientMemory=(void *)poolHead;
+
+ if (poolHead != NULL)
+ {
+ memset(poolHead, 0, (poolSize * sizeof(struct rtl_clientEntry)));
+ entryPtr = poolHead;
+
+ /* link the whole group entry pool */
+ for (idx = 0 ; idx < poolSize ; idx++, entryPtr++)
+ {
+ if(idx==0)
+ {
+ entryPtr->previous=NULL;
+ if(idx == (poolSize - 1))
+ {
+ entryPtr->next=NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+ else
+ {
+ entryPtr->previous=entryPtr-1;
+ if (idx == (poolSize - 1))
+ {
+ entryPtr->next = NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+ }
+ }
+
+out:
+
+ rtl_glueMutexUnlock(); /* UnLock resource */
+ return poolHead;
+
+}
+
+
+// allocate a client entry from the client entry pool
+static struct rtl_clientEntry* rtl_allocateClientEntry(void)
+{
+ struct rtl_clientEntry *ret = NULL;
+
+ rtl_glueMutexLock();
+ if (rtl_clientEntryPool!=NULL)
+ {
+ ret = rtl_clientEntryPool;
+ if(rtl_clientEntryPool->next!=NULL)
+ {
+ rtl_clientEntryPool->next->previous=NULL;
+ }
+ rtl_clientEntryPool = rtl_clientEntryPool->next;
+ memset(ret, 0, sizeof(struct rtl_clientEntry));
+ }
+
+ rtl_glueMutexUnlock();
+
+ return ret;
+}
+
+// free a client entry and link it back to the client entry pool, default is link to the pool head
+static void rtl_freeClientEntry(struct rtl_clientEntry* clientEntryPtr)
+{
+ if (!clientEntryPtr)
+ {
+ return;
+ }
+
+ rtl_glueMutexLock();
+ clientEntryPtr->next = rtl_clientEntryPool;
+ if(rtl_clientEntryPool!=NULL)
+ {
+ rtl_clientEntryPool->previous=clientEntryPtr;
+ }
+ rtl_clientEntryPool=clientEntryPtr;
+ rtl_glueMutexUnlock();
+}
+
+/*source entry memory management*/
+static struct rtl_sourceEntry* rtl_initSourceEntryPool(uint32 poolSize)
+{
+
+ uint32 idx=0;
+ struct rtl_sourceEntry *poolHead=NULL;
+ struct rtl_sourceEntry *entryPtr=NULL;
+ rtl_glueMutexLock(); /* Lock resource */
+ if (poolSize == 0)
+ {
+ goto out;
+ }
+
+ /* Allocate memory */
+ poolHead = (struct rtl_sourceEntry *)rtl_glueMalloc(sizeof(struct rtl_sourceEntry) * poolSize);
+ rtl_sourceMemory=(void *)poolHead;
+ if (poolHead != NULL)
+ {
+ memset(poolHead, 0, (poolSize * sizeof(struct rtl_sourceEntry)));
+ entryPtr = poolHead;
+
+ /* link the whole source entry pool */
+ for (idx = 0 ; idx < poolSize ; idx++, entryPtr++)
+ {
+ if(idx==0)
+ {
+ entryPtr->previous=NULL;
+ if(idx == (poolSize - 1))
+ {
+ entryPtr->next=NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+ else
+ {
+ entryPtr->previous=entryPtr-1;
+ if (idx == (poolSize - 1))
+ {
+ entryPtr->next = NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+
+ }
+ }
+
+out:
+ rtl_glueMutexUnlock(); /* UnLock resource */
+ return poolHead;
+
+}
+
+
+// allocate a source entry from the source entry pool
+static struct rtl_sourceEntry* rtl_allocateSourceEntry(void)
+{
+ struct rtl_sourceEntry *ret = NULL;
+
+ rtl_glueMutexLock();
+ if (rtl_sourceEntryPool!=NULL)
+ {
+ ret = rtl_sourceEntryPool;
+ if(rtl_sourceEntryPool->next!=NULL)
+ {
+ rtl_sourceEntryPool->next->previous=NULL;
+ }
+ rtl_sourceEntryPool = rtl_sourceEntryPool->next;
+ memset(ret, 0, sizeof(struct rtl_sourceEntry));
+ }
+
+ rtl_glueMutexUnlock();
+
+ return ret;
+}
+
+// free a source entry and link it back to the source entry pool, default is link to the pool head
+static void rtl_freeSourceEntry(struct rtl_sourceEntry* sourceEntryPtr)
+{
+ if (!sourceEntryPtr)
+ {
+ return;
+ }
+
+ rtl_glueMutexLock();
+ sourceEntryPtr->next = rtl_sourceEntryPool;
+ if(rtl_sourceEntryPool!=NULL)
+ {
+ rtl_sourceEntryPool->previous=sourceEntryPtr;
+ }
+
+ rtl_sourceEntryPool=sourceEntryPtr;
+
+ rtl_glueMutexUnlock();
+}
+#ifdef CONFIG_RECORD_MCAST_FLOW
+/*multicast flow entry memory management*/
+static struct rtl_mcastFlowEntry* rtl_initMcastFlowEntryPool(uint32 poolSize)
+{
+
+ uint32 idx=0;
+ struct rtl_mcastFlowEntry *poolHead=NULL;
+ struct rtl_mcastFlowEntry *entryPtr=NULL;
+
+ rtl_glueMutexLock(); /* Lock resource */
+ if (poolSize == 0)
+ {
+ goto out;
+ }
+
+ /* Allocate memory */
+ poolHead = (struct rtl_mcastFlowEntry *)rtl_glueMalloc(sizeof(struct rtl_mcastFlowEntry) * poolSize);
+ rtl_mcastFlowMemory=(void *)poolHead;
+
+ if (poolHead != NULL)
+ {
+ memset(poolHead, 0, (poolSize * sizeof(struct rtl_mcastFlowEntry)));
+ entryPtr = poolHead;
+
+ /* link the whole group entry pool */
+ for (idx = 0 ; idx < poolSize ; idx++, entryPtr++)
+ {
+ if(idx==0)
+ {
+ entryPtr->previous=NULL;
+ if(idx == (poolSize - 1))
+ {
+ entryPtr->next=NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+ else
+ {
+ entryPtr->previous=entryPtr-1;
+ if (idx == (poolSize - 1))
+ {
+ entryPtr->next = NULL;
+ }
+ else
+ {
+ entryPtr->next = entryPtr + 1;
+ }
+ }
+ }
+ }
+
+out:
+
+ rtl_glueMutexUnlock(); /* UnLock resource */
+ return poolHead;
+
+}
+
+
+// allocate a multicast flow entry from the multicast flow pool
+static struct rtl_mcastFlowEntry* rtl_allocateMcastFlowEntry(void)
+{
+ struct rtl_mcastFlowEntry *ret = NULL;
+
+ rtl_glueMutexLock();
+ if (rtl_mcastFlowEntryPool!=NULL)
+ {
+ ret = rtl_mcastFlowEntryPool;
+ if(rtl_mcastFlowEntryPool->next!=NULL)
+ {
+ rtl_mcastFlowEntryPool->next->previous=NULL;
+ }
+ rtl_mcastFlowEntryPool = rtl_mcastFlowEntryPool->next;
+ memset(ret, 0, sizeof(struct rtl_mcastFlowEntry));
+ }
+
+ rtl_glueMutexUnlock();
+
+ return ret;
+}
+
+// free a multicast flow entry and link it back to the multicast flow entry pool, default is link to the pool head
+static void rtl_freeMcastFlowEntry(struct rtl_mcastFlowEntry* mcastFlowEntry)
+{
+ if (NULL==mcastFlowEntry)
+ {
+ return;
+ }
+
+ rtl_glueMutexLock();
+ mcastFlowEntry->next = rtl_mcastFlowEntryPool;
+ if(rtl_mcastFlowEntryPool!=NULL)
+ {
+ rtl_mcastFlowEntryPool->previous=mcastFlowEntry;
+ }
+ rtl_mcastFlowEntryPool=mcastFlowEntry;
+ rtl_glueMutexUnlock();
+}
+
+#endif
+
+/*********************************************
+ Group list operation
+ *********************************************/
+
+/* find a group address in a group list */
+
+struct rtl_groupEntry* rtl_searchGroupEntry(uint32 moduleIndex, uint32 ipVersion,uint32 *multicastAddr)
+{
+ struct rtl_groupEntry* groupPtr = NULL;
+ int32 hashIndex=0;
+
+ hashIndex=rtl_igmpHashAlgorithm(ipVersion, multicastAddr);
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[hashIndex];
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ groupPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[hashIndex];
+ }
+#endif
+
+ while (groupPtr!=NULL)
+ {
+ if(ipVersion==IP_VERSION4)
+ {
+ if(multicastAddr[0]==groupPtr->groupAddr[0])
+ {
+ return groupPtr;
+ }
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ if( (multicastAddr[0]==groupPtr->groupAddr[0])&&
+ (multicastAddr[1]==groupPtr->groupAddr[1])&&
+ (multicastAddr[2]==groupPtr->groupAddr[2])&&
+ (multicastAddr[3]==groupPtr->groupAddr[3])
+ )
+ {
+ return groupPtr;
+
+ }
+ }
+#endif
+ groupPtr = groupPtr->next;
+
+ }
+
+ return NULL;
+}
+
+
+/* link group Entry in the front of a group list */
+static void rtl_linkGroupEntry(struct rtl_groupEntry* groupEntry , struct rtl_groupEntry ** hashTable)
+{
+ uint32 hashIndex=0;
+
+ rtl_glueMutexLock();//Lock resource
+ hashIndex=rtl_igmpHashAlgorithm(groupEntry->ipVersion, groupEntry->groupAddr);
+ if(NULL==groupEntry)
+ {
+ return;
+ }
+
+ if(hashTable[hashIndex]!=NULL)
+ {
+ hashTable[hashIndex]->previous=groupEntry;
+ }
+ groupEntry->next = hashTable[hashIndex];
+ hashTable[hashIndex]=groupEntry;
+ hashTable[hashIndex]->previous=NULL;
+
+ rtl_glueMutexUnlock();//UnLock resource
+
+}
+
+
+/* unlink a group entry from group list */
+static void rtl_unlinkGroupEntry(struct rtl_groupEntry* groupEntry, struct rtl_groupEntry ** hashTable)
+{
+ uint32 hashIndex=0;
+
+ if(NULL==groupEntry)
+ {
+ return;
+ }
+
+ rtl_glueMutexLock(); /* lock resource*/
+
+ hashIndex=rtl_igmpHashAlgorithm(groupEntry->ipVersion, groupEntry->groupAddr);
+ /* unlink entry node*/
+ if(groupEntry==hashTable[hashIndex]) /*unlink group list head*/
+ {
+ hashTable[hashIndex]=groupEntry->next;
+ if(hashTable[hashIndex]!=NULL)
+ {
+ hashTable[hashIndex]->previous=NULL;
+ }
+ }
+ else
+ {
+ if(groupEntry->previous!=NULL)
+ {
+ groupEntry->previous->next=groupEntry->next;
+ }
+
+ if(groupEntry->next!=NULL)
+ {
+ groupEntry->next->previous=groupEntry->previous;
+ }
+ }
+
+ groupEntry->previous=NULL;
+ groupEntry->next=NULL;
+
+ rtl_glueMutexUnlock();//UnLock resource
+
+}
+
+
+/* clear the content of group entry */
+static void rtl_clearGroupEntry(struct rtl_groupEntry* groupEntry)
+{
+ rtl_glueMutexLock();
+ if (NULL!=groupEntry)
+ {
+ memset(groupEntry, 0, sizeof(struct rtl_groupEntry));
+ }
+ rtl_glueMutexUnlock();
+}
+
+/*********************************************
+ Client list operation
+ *********************************************/
+static struct rtl_clientEntry* rtl_searchClientEntry(uint32 ipVersion, struct rtl_groupEntry* groupEntry, uint32 portNum, uint32 *clientAddr)
+{
+ struct rtl_clientEntry* clientPtr = groupEntry->clientList;
+
+ if(clientAddr==NULL)
+ {
+ return NULL;
+ }
+ while (clientPtr!=NULL)
+ {
+ if(ipVersion==IP_VERSION4)
+ {
+ if((clientPtr->clientAddr[0]==clientAddr[0]))
+ {
+ if(portNum<MAX_SUPPORT_PORT_NUMBER)
+ {
+ /*update port number,in case of client change port*/
+ clientPtr->portNum=portNum;
+ }
+ return clientPtr;
+ }
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ if( ((clientPtr->clientAddr[0]==clientAddr[0])
+ &&(clientPtr->clientAddr[1]==clientAddr[1])
+ &&(clientPtr->clientAddr[2]==clientAddr[2])
+ &&(clientPtr->clientAddr[3]==clientAddr[3])))
+ {
+
+ if(portNum<MAX_SUPPORT_PORT_NUMBER)
+ {
+ /*update port number,in case of client change port*/
+ clientPtr->portNum=portNum;
+ }
+ return clientPtr;
+ }
+ }
+#endif
+ clientPtr = clientPtr->next;
+
+ }
+
+ return NULL;
+}
+
+uint32 rtl_getAllClientPortMask(struct rtl_groupEntry* groupEntry)
+{
+ uint32 clientPortMask=0;
+
+ struct rtl_clientEntry* clientPtr = groupEntry->clientList;
+
+ while (clientPtr!=NULL)
+ {
+
+ clientPortMask |=1<<(clientPtr->portNum);
+ clientPtr = clientPtr->next;
+ }
+
+ return clientPortMask;
+}
+/* link client Entry in the front of group client list */
+static void rtl_linkClientEntry(struct rtl_groupEntry *groupEntry, struct rtl_clientEntry* clientEntry )
+{
+ rtl_glueMutexLock();//Lock resource
+ if(NULL==clientEntry)
+ {
+ return;
+ }
+
+ if(NULL==groupEntry)
+ {
+ return;
+ }
+
+
+ if(groupEntry->clientList!=NULL)
+ {
+ groupEntry->clientList->previous=clientEntry;
+ }
+ clientEntry->next = groupEntry->clientList;
+
+ groupEntry->clientList=clientEntry;
+ groupEntry->clientList->previous=NULL;
+
+ rtl_glueMutexUnlock();//UnLock resource
+
+}
+
+
+/* unlink a client entry from group client list */
+static void rtl_unlinkClientEntry(struct rtl_groupEntry *groupEntry, struct rtl_clientEntry* clientEntry)
+{
+ if(NULL==clientEntry)
+ {
+ return;
+ }
+
+ if(NULL==groupEntry)
+ {
+ return;
+ }
+
+ rtl_glueMutexLock(); /* lock resource*/
+
+ /* unlink entry node*/
+ if(clientEntry==groupEntry->clientList) /*unlink group list head*/
+ {
+ groupEntry->clientList=groupEntry->clientList->next;
+ if(groupEntry->clientList!=NULL)
+ {
+ groupEntry->clientList->previous=NULL;
+ }
+
+ }
+ else
+ {
+ if(clientEntry->previous!=NULL)
+ {
+ clientEntry->previous->next=clientEntry->next;
+ }
+
+ if(clientEntry->next!=NULL)
+ {
+ clientEntry->next->previous=clientEntry->previous;
+ }
+ }
+
+ clientEntry->previous=NULL;
+ clientEntry->next=NULL;
+
+ rtl_glueMutexUnlock();//UnLock resource
+
+}
+
+
+/* clear the content of client entry */
+static void rtl_clearClientEntry(struct rtl_clientEntry* clientEntry)
+{
+ rtl_glueMutexLock();
+ if (NULL!=clientEntry)
+ {
+ memset(clientEntry, 0, sizeof(struct rtl_clientEntry));
+ }
+ rtl_glueMutexUnlock();
+}
+
+
+/*********************************************
+ source list operation
+ *********************************************/
+static struct rtl_sourceEntry* rtl_searchSourceEntry(uint32 ipVersion, uint32 *sourceAddr, struct rtl_clientEntry *clientEntry)
+{
+ struct rtl_sourceEntry *sourcePtr=clientEntry->sourceList;
+ while(sourcePtr!=NULL)
+ {
+ if(ipVersion==IP_VERSION4)
+ {
+ if(sourceAddr[0]==sourcePtr->sourceAddr[0])
+ {
+ return sourcePtr;
+ }
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ if( (sourceAddr[0]==sourcePtr->sourceAddr[0])&&
+ (sourceAddr[1]==sourcePtr->sourceAddr[1])&&
+ (sourceAddr[2]==sourcePtr->sourceAddr[2])&&
+ (sourceAddr[3]==sourcePtr->sourceAddr[3])
+ )
+ {
+ return sourcePtr;
+ }
+ }
+#endif
+ sourcePtr=sourcePtr->next;
+ }
+
+ return NULL;
+}
+
+#if 0
+static int32 rtl_searchSourceAddr(uint32 ipVersion, uint32 *sourceAddr, uint32 *sourceArray, uint32 elementCount)
+{
+ uint32 i=0;
+ uint32 *srcPtr=sourceArray;
+
+ for(i=0; i<elementCount; i++)
+ {
+ if(ipVersion==IP_VERSION4)
+ {
+ if(sourceAddr[0]==srcPtr[0])
+ {
+ return TRUE;
+ }
+ srcPtr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(ipVersion==IP_VERSION6)
+ {
+ if( (sourceAddr[0]==srcPtr[0])&&\
+ (sourceAddr[1]==srcPtr[1])&&\
+ (sourceAddr[2]==srcPtr[2])&&\
+ (sourceAddr[3]==srcPtr[3]))
+ {
+
+ return TRUE;
+ }
+
+ srcPtr=srcPtr+4;
+ }
+#endif
+ }
+
+ return FALSE;
+}
+#endif
+
+static void rtl_linkSourceEntry(struct rtl_clientEntry *clientEntry, struct rtl_sourceEntry* entryNode)
+{
+ if(NULL==entryNode)
+ {
+ return;
+ }
+
+ if(NULL==clientEntry)
+ {
+ return;
+ }
+
+ rtl_glueMutexLock(); /* lock resource*/
+
+ if(clientEntry->sourceList!=NULL)
+ {
+ clientEntry->sourceList->previous=entryNode;
+ }
+ entryNode->next=clientEntry->sourceList;
+ clientEntry->sourceList=entryNode;
+ clientEntry->sourceList->previous=NULL;
+
+ rtl_glueMutexUnlock(); /* lock resource*/
+}
+
+static void rtl_unlinkSourceEntry(struct rtl_clientEntry *clientEntry, struct rtl_sourceEntry* sourceEntry)
+{
+ if(NULL==sourceEntry)
+ {
+ return;
+ }
+
+ if(NULL==clientEntry)
+ {
+ return;
+ }
+
+ rtl_glueMutexLock(); /* lock resource*/
+ /* unlink entry node*/
+ if(sourceEntry==clientEntry->sourceList) /*unlink group list head*/
+ {
+
+ clientEntry->sourceList=sourceEntry->next;
+ if(clientEntry->sourceList!=NULL)
+ {
+ clientEntry->sourceList ->previous=NULL;
+ }
+ }
+ else
+ {
+ if(sourceEntry->previous!=NULL)
+ {
+ sourceEntry->previous->next=sourceEntry->next;
+ }
+
+ if(sourceEntry->next!=NULL)
+ {
+ sourceEntry->next->previous=sourceEntry->previous;
+ }
+ }
+
+ sourceEntry->previous=NULL;
+ sourceEntry->next=NULL;
+
+ rtl_glueMutexUnlock();//UnLock resource
+
+}
+
+static void rtl_clearSourceEntry(struct rtl_sourceEntry* sourceEntryPtr)
+{
+ rtl_glueMutexLock();
+ if (NULL!=sourceEntryPtr)
+ {
+ memset(sourceEntryPtr, 0, sizeof(struct rtl_sourceEntry));
+ }
+ rtl_glueMutexUnlock();
+}
+
+/*********************************************
+ multicast flow list operation
+ *********************************************/
+
+#ifdef CONFIG_RECORD_MCAST_FLOW
+static struct rtl_mcastFlowEntry* rtl_searchMcastFlowEntry(uint32 moduleIndex, uint32 ipVersion, uint32 *serverAddr,uint32 *groupAddr)
+{
+ struct rtl_mcastFlowEntry* mcastFlowPtr = NULL;
+ uint32 hashIndex=0;
+
+ if(NULL==serverAddr)
+ {
+ return NULL;
+ }
+
+ if(NULL==groupAddr)
+ {
+ return NULL;
+ }
+
+ hashIndex=rtl_igmpHashAlgorithm(ipVersion, groupAddr);
+
+ mcastFlowPtr=rtl_mCastModuleArray[moduleIndex].flowHashTable[hashIndex];
+ while (mcastFlowPtr!=NULL)
+ {
+
+ if(mcastFlowPtr->ipVersion!=ipVersion)
+ {
+ goto nextFlow;
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ if( (serverAddr[0]==mcastFlowPtr->serverAddr[0]) && (groupAddr[0]==mcastFlowPtr->groupAddr[0]) )
+ {
+ mcastFlowPtr->refreshTime=rtl_sysUpSeconds;
+ return mcastFlowPtr;
+ }
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+
+ if( (serverAddr[0]==mcastFlowPtr->serverAddr[0])
+ &&(serverAddr[0]==mcastFlowPtr->serverAddr[0])
+ &&(serverAddr[0]==mcastFlowPtr->serverAddr[0])
+ &&(serverAddr[0]==mcastFlowPtr->serverAddr[0])
+ &&(groupAddr[0]==mcastFlowPtr->groupAddr[0])
+ &&(groupAddr[1]==mcastFlowPtr->groupAddr[1])
+ &&(groupAddr[2]==mcastFlowPtr->groupAddr[2])
+ &&(groupAddr[3]==mcastFlowPtr->groupAddr[3]))
+ {
+ mcastFlowPtr->refreshTime=rtl_sysUpSeconds;
+ return mcastFlowPtr;
+ }
+ }
+
+nextFlow:
+#endif
+ mcastFlowPtr = mcastFlowPtr->next;
+
+ }
+
+ return NULL;
+}
+
+/* link multicast flow entry in the front of a forwarding flow list */
+static void rtl_linkMcastFlowEntry(struct rtl_mcastFlowEntry* mcastFlowEntry , struct rtl_mcastFlowEntry ** hashTable)
+{
+ uint32 hashIndex=0;
+ rtl_glueMutexLock();//Lock resource
+ if(NULL==mcastFlowEntry)
+ {
+ return;
+ }
+
+ if(NULL==hashTable)
+ {
+ return;
+ }
+
+ hashIndex=rtl_igmpHashAlgorithm(mcastFlowEntry->ipVersion, mcastFlowEntry->groupAddr);
+
+ if(hashTable[hashIndex]!=NULL)
+ {
+ hashTable[hashIndex]->previous=mcastFlowEntry;
+ }
+ mcastFlowEntry->next = hashTable[hashIndex];
+ hashTable[hashIndex]=mcastFlowEntry;
+ hashTable[hashIndex]->previous=NULL;
+
+ rtl_glueMutexUnlock();//UnLock resource
+ return;
+
+}
+
+/* unlink a multicast flow entry*/
+static void rtl_unlinkMcastFlowEntry(struct rtl_mcastFlowEntry* mcastFlowEntry, struct rtl_mcastFlowEntry ** hashTable)
+{
+ uint32 hashIndex=0;
+ if(NULL==mcastFlowEntry)
+ {
+ return;
+ }
+
+ hashIndex=rtl_igmpHashAlgorithm(mcastFlowEntry->ipVersion, mcastFlowEntry->groupAddr);
+
+ rtl_glueMutexLock(); /* lock resource*/
+ /* unlink entry node*/
+ if(mcastFlowEntry==hashTable[hashIndex]) /*unlink flow list head*/
+ {
+ hashTable[hashIndex]=mcastFlowEntry->next;
+ if(hashTable[hashIndex]!=NULL)
+ {
+ hashTable[hashIndex]->previous=NULL;
+ }
+ }
+ else
+ {
+ if(mcastFlowEntry->previous!=NULL)
+ {
+ mcastFlowEntry->previous->next=mcastFlowEntry->next;
+ }
+
+ if(mcastFlowEntry->next!=NULL)
+ {
+ mcastFlowEntry->next->previous=mcastFlowEntry->previous;
+ }
+ }
+
+ mcastFlowEntry->previous=NULL;
+ mcastFlowEntry->next=NULL;
+
+ rtl_glueMutexUnlock();//UnLock resource
+
+}
+
+
+/* clear the content of multicast flow entry */
+static void rtl_clearMcastFlowEntry(struct rtl_mcastFlowEntry* mcastFlowEntry)
+{
+ rtl_glueMutexLock();
+ if (NULL!=mcastFlowEntry)
+ {
+ memset(mcastFlowEntry, 0, sizeof(struct rtl_mcastFlowEntry));
+ }
+ rtl_glueMutexUnlock();
+}
+
+
+static void rtl_deleteMcastFlowEntry( struct rtl_mcastFlowEntry* mcastFlowEntry, struct rtl_mcastFlowEntry ** hashTable)
+{
+ if(mcastFlowEntry!=NULL)
+ {
+
+ rtl_unlinkMcastFlowEntry(mcastFlowEntry, hashTable);
+ rtl_clearMcastFlowEntry(mcastFlowEntry);
+ rtl_freeMcastFlowEntry(mcastFlowEntry);
+ }
+
+ return;
+}
+#endif
+
+/*****source entry/client entry/group entry/flow entry operation*****/
+
+static void rtl_deleteSourceEntry(struct rtl_clientEntry *clientEntry, struct rtl_sourceEntry* sourceEntry)
+{
+ if(clientEntry==NULL)
+ {
+ return;
+ }
+
+ if(sourceEntry!=NULL)
+ {
+ rtl_unlinkSourceEntry(clientEntry,sourceEntry);
+ rtl_clearSourceEntry(sourceEntry);
+ rtl_freeSourceEntry(sourceEntry);
+ }
+}
+
+static void rtl_deleteSourceList(struct rtl_clientEntry* clientEntry)
+{
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *nextSourceEntry=NULL;
+
+ sourceEntry=clientEntry->sourceList;
+ while(sourceEntry!=NULL)
+ {
+ nextSourceEntry=sourceEntry->next;
+ rtl_deleteSourceEntry(clientEntry,sourceEntry);
+ sourceEntry=nextSourceEntry;
+ }
+}
+
+static void rtl_deleteClientEntry(struct rtl_groupEntry* groupEntry,struct rtl_clientEntry *clientEntry)
+{
+ if(NULL==clientEntry)
+ {
+ return;
+ }
+
+ if(NULL==groupEntry)
+ {
+ return;
+ }
+
+ rtl_deleteSourceList(clientEntry);
+ rtl_unlinkClientEntry(groupEntry,clientEntry);
+ rtl_clearClientEntry(clientEntry);
+ rtl_freeClientEntry(clientEntry);
+ return;
+
+}
+
+static void rtl_deleteClientList(struct rtl_groupEntry* groupEntry)
+{
+
+ struct rtl_clientEntry *clientEntry=NULL;
+ struct rtl_clientEntry *nextClientEntry=NULL;
+
+ if(NULL==groupEntry)
+ {
+ return;
+ }
+
+ clientEntry=groupEntry->clientList;
+ while(clientEntry!=NULL)
+ {
+ nextClientEntry=clientEntry->next;
+ rtl_deleteClientEntry(groupEntry,clientEntry);
+ clientEntry=nextClientEntry;
+ }
+}
+
+
+static void rtl_deleteGroupEntry( struct rtl_groupEntry* groupEntry,struct rtl_groupEntry ** hashTable)
+{
+ if(groupEntry!=NULL)
+ {
+
+ rtl_deleteClientList(groupEntry);
+ rtl_unlinkGroupEntry(groupEntry, hashTable);
+ rtl_clearGroupEntry(groupEntry);
+ rtl_freeGroupEntry(groupEntry);
+
+ }
+
+}
+
+
+static int32 rtl_checkMCastAddrMapping(uint32 ipVersion, uint32 *ipAddr, uint8* macAddr)
+{
+ if(ipVersion==IP_VERSION4)
+ {
+ if(macAddr[0]!=0x01)
+ {
+ return FALSE;
+ }
+
+ if((macAddr[3]&0x7f)!=(uint8)((ipAddr[0]&0x007f0000)>>16))
+ {
+ return FALSE;
+ }
+
+ if(macAddr[4]!=(uint8)((ipAddr[0]&0x0000ff00)>>8))
+ {
+ return FALSE;
+ }
+
+ if(macAddr[5]!=(uint8)(ipAddr[0]&0x000000ff))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ if(macAddr[0]!=0x33)
+ {
+ return FALSE;
+ }
+
+ if(macAddr[1]!=0x33)
+ {
+ return FALSE;
+ }
+
+ if(macAddr[2]!=(uint8)((ipAddr[3]&0xff000000)>>24))
+ {
+ return FALSE;
+ }
+
+ if(macAddr[3]!=(uint8)((ipAddr[3]&0x00ff0000)>>16))
+ {
+ return FALSE;
+ }
+
+ if(macAddr[4]!=(uint8)((ipAddr[3]&0x0000ff00)>>8))
+ {
+ return FALSE;
+ }
+
+ if(macAddr[5]!=(uint8)(ipAddr[3]&0x000000ff))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+static int32 rtl_compareIpv6Addr(uint32* ipv6Addr1, uint32* ipv6Addr2)
+{
+ int i;
+ for(i=0; i<4; i++)
+ {
+ if(ipv6Addr1[i]!=ipv6Addr2[i])
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+#endif
+
+static int32 rtl_compareMacAddr(uint8* macAddr1, uint8* macAddr2)
+{
+ int i;
+ for(i=0; i<6; i++)
+ {
+ if(macAddr1[i]!=macAddr2[i])
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static uint16 rtl_checksum(uint8 *packetBuf, uint32 packetLen)
+{
+ /*note: the first bytes of packetBuf should be two bytes aligned*/
+ uint32 checksum=0;
+ uint32 count=packetLen;
+ uint16 *ptr= (uint16 *) (packetBuf);
+
+ while(count>1)
+ {
+ checksum+= ntohs(*ptr);
+ ptr++;
+ count -= 2;
+ }
+
+ if(count>0)
+ {
+ checksum+= *(packetBuf+packetLen-1)<<8; /*the last odd byte is treated as bit 15~8 of unsigned short*/
+ }
+
+ /* Roll over carry bits */
+ checksum = (checksum >> 16) + (checksum & 0xffff);
+ checksum += (checksum >> 16);
+
+ /* Return checksum */
+ return ((uint16) ~ checksum);
+
+}
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+static uint16 rtl_ipv6L3Checksum(uint8 *pktBuf, uint32 pktLen, union pseudoHeader *ipv6PseudoHdr)
+{
+ uint32 checksum=0;
+ uint32 count=pktLen;
+ uint16 *ptr;
+
+ /*compute ipv6 pseudo-header checksum*/
+ ptr= (uint16 *) (ipv6PseudoHdr);
+ for(count=0; count<20; count++) /*the pseudo header is 40 bytes long*/
+ {
+ checksum+= ntohs(*ptr);
+ ptr++;
+ }
+
+ /*compute the checksum of mld buffer*/
+ count=pktLen;
+ ptr=(uint16 *) (pktBuf);
+ while(count>1)
+ {
+ checksum+= ntohs(*ptr);
+ ptr++;
+ count -= 2;
+ }
+
+ if(count>0)
+ {
+ checksum+= *(pktBuf+pktLen-1)<<8; /*the last odd byte is treated as bit 15~8 of unsigned short*/
+ }
+
+ /* Roll over carry bits */
+ checksum = (checksum >> 16) + (checksum & 0xffff);
+ checksum += (checksum >> 16);
+
+ /* Return checksum */
+ return ((uint16) ~ checksum);
+
+}
+#endif
+
+
+static uint8 rtl_getClientFwdPortMask(struct rtl_clientEntry * clientEntry, uint32 sysTime)
+{
+
+ uint8 portMask=(1<<clientEntry->portNum);
+ uint8 fwdPortMask=0;
+
+ struct rtl_sourceEntry * sourcePtr=NULL;;
+
+ if(clientEntry->groupFilterTimer>sysTime) /*exclude mode never expired*/
+ {
+ fwdPortMask|=portMask;
+ }
+ else/*include mode*/
+ {
+ sourcePtr=clientEntry->sourceList;
+ while(sourcePtr!=NULL)
+ {
+ if(sourcePtr->portTimer>sysTime)
+ {
+ fwdPortMask|=portMask;
+ break;
+ }
+ sourcePtr=sourcePtr->next;
+
+ }
+
+ }
+
+ return fwdPortMask;
+}
+
+static void rtl_checkSourceTimer(struct rtl_clientEntry * clientEntry , struct rtl_sourceEntry * sourceEntry)
+{
+ uint8 deleteFlag=FALSE;
+ uint8 oldFwdState,newFwdState;
+
+ oldFwdState=sourceEntry->fwdState;
+
+ if(sourceEntry->portTimer<=rtl_sysUpSeconds) /*means time out*/
+ {
+ if(clientEntry->groupFilterTimer<=rtl_sysUpSeconds) /* include mode*/
+ {
+ deleteFlag=TRUE;
+ }
+
+ sourceEntry->fwdState=FALSE;
+ }
+ else
+ {
+ deleteFlag=FALSE;
+ sourceEntry->fwdState=TRUE;
+ }
+
+ newFwdState=sourceEntry->fwdState;
+
+ if(deleteFlag==TRUE) /*means INCLUDE mode and expired*/
+ {
+ rtl_deleteSourceEntry(clientEntry,sourceEntry);
+ }
+
+ if((deleteFlag==TRUE) || (newFwdState!=oldFwdState))
+ {
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(timerEventContext.moduleIndex, timerEventContext.ipVersion, timerEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(timerEventContext.ipVersion==IP_VERSION4)
+ {
+#ifdef CONFIG_PROC_FS
+ rtl_mCastModuleArray[timerEventContext.moduleIndex].expireEventCnt++;
+#endif
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &timerEventContext);
+ }
+ #endif
+ }
+
+}
+
+static uint32 rtl_getClientSourceFwdPortMask(uint32 ipVersion, struct rtl_clientEntry * clientEntry,uint32 *sourceAddr, uint32 sysTime)
+{
+ uint8 portMask=(1<<clientEntry->portNum);
+ uint8 fwdPortMask=0;
+ struct rtl_sourceEntry * sourceEntry=NULL;
+ if(clientEntry==NULL)
+ {
+ return 0xFFFFFFFF; /*broadcast*/
+ }
+ else
+ {
+ sourceEntry=rtl_searchSourceEntry(ipVersion,sourceAddr, clientEntry);
+
+ if(clientEntry->groupFilterTimer<=sysTime) /*include mode*/
+ {
+ if(sourceEntry!=NULL)
+ {
+ if( sourceEntry->portTimer>sysTime)
+ {
+ fwdPortMask|=portMask;
+ }
+ }
+ }
+ else/*exclude mode*/
+ {
+ if(sourceEntry==NULL)
+ {
+ fwdPortMask|=portMask;
+ }
+ else
+ {
+ if(sourceEntry->portTimer>sysTime)
+ {
+ fwdPortMask|=portMask;
+ }
+ }
+ }
+
+ return fwdPortMask;
+
+ }
+}
+
+static uint32 rtl_getGroupSourceFwdPortMask(struct rtl_groupEntry * groupEntry,uint32 *sourceAddr, uint32 sysTime)
+{
+ uint8 fwdPortMask=0;
+ struct rtl_clientEntry * clientEntry=NULL;
+ if(groupEntry==NULL)
+ {
+ return 0xFFFFFFFF; /*broadcast*/
+ }
+
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if(groupEntry->attribute==STATIC_RESERVED_MULTICAST)
+ {
+ return groupEntry->staticFwdPortMask;
+ }
+ #endif
+
+ clientEntry=groupEntry->clientList;
+ while(clientEntry!=NULL)
+ {
+ fwdPortMask|= rtl_getClientSourceFwdPortMask(groupEntry->ipVersion, clientEntry, sourceAddr, sysTime);
+ clientEntry=clientEntry->next;
+ }
+
+ return fwdPortMask;
+}
+
+
+static void rtl_checkClientEntryTimer(struct rtl_groupEntry * groupEntry, struct rtl_clientEntry * clientEntry)
+{
+ uint8 oldFwdPortMask=0;
+ uint8 newFwdPortMask=0;
+ struct rtl_sourceEntry *sourceEntry=clientEntry->sourceList;
+ struct rtl_sourceEntry *nextSourceEntry=NULL;
+
+ oldFwdPortMask=rtl_getClientFwdPortMask(clientEntry, rtl_sysUpSeconds);
+
+ while(sourceEntry!=NULL)
+ {
+ nextSourceEntry=sourceEntry->next;
+ rtl_checkSourceTimer(clientEntry, sourceEntry);
+ sourceEntry=nextSourceEntry;
+ }
+
+ newFwdPortMask=rtl_getClientFwdPortMask(clientEntry, rtl_sysUpSeconds);
+
+
+ if(newFwdPortMask==0) /*none active port*/
+ {
+ rtl_deleteClientEntry(groupEntry,clientEntry);
+ }
+
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if((groupEntry!=NULL) && (groupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ return;
+ }
+ #endif
+
+ if((oldFwdPortMask!=newFwdPortMask) || (newFwdPortMask==0))
+ {
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(timerEventContext.moduleIndex, timerEventContext.ipVersion, timerEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(timerEventContext.ipVersion==IP_VERSION4)
+ {
+#ifdef CONFIG_PROC_FS
+ rtl_mCastModuleArray[timerEventContext.moduleIndex].expireEventCnt++;
+#endif
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &timerEventContext);
+ }
+ #endif
+
+ }
+
+}
+
+static void rtl_checkGroupEntryTimer(struct rtl_groupEntry * groupEntry, struct rtl_groupEntry ** hashTable)
+{
+ uint32 deleteFlag=FALSE;
+ struct rtl_clientEntry *clientEntry=groupEntry->clientList;
+ struct rtl_clientEntry *nextClientEntry=NULL;
+
+
+ while(clientEntry!=NULL)
+ {
+ nextClientEntry=clientEntry->next;
+ timerEventContext.portMask=1<<(clientEntry->portNum);
+ rtl_checkClientEntryTimer(groupEntry, clientEntry);
+ clientEntry=nextClientEntry;
+ }
+
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if((groupEntry!=NULL) && (groupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ return;
+ }
+ #endif
+
+ if(groupEntry->clientList==NULL) /*none active client*/
+ {
+ deleteFlag=TRUE;
+ rtl_deleteGroupEntry(groupEntry,hashTable);
+ }
+
+ if(deleteFlag==TRUE)
+ {
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(timerEventContext.moduleIndex, timerEventContext.ipVersion, timerEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(timerEventContext.ipVersion==IP_VERSION4)
+ {
+#ifdef CONFIG_PROC_FS
+ rtl_mCastModuleArray[timerEventContext.moduleIndex].expireEventCnt++;
+#endif
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &timerEventContext);
+ }
+ #endif
+
+ }
+
+}
+
+
+
+static int32 rtl_initHashTable(uint32 moduleIndex, uint32 hashTableSize)
+{
+ uint32 i=0;
+
+ /* Allocate memory */
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable = (struct rtl_groupEntry **)rtl_glueMalloc(4 * hashTableSize);
+
+ if (rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!= NULL)
+ {
+ for (i = 0 ; i < hashTableSize ; i++)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i]=NULL;
+ }
+
+ }
+ else
+ {
+ return FAILED;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable= (struct rtl_groupEntry **)rtl_glueMalloc(4 * hashTableSize);
+ if (rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable!=NULL)
+ {
+ for (i = 0 ; i < hashTableSize ; i++)
+ {
+
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i]=NULL;
+ }
+ }
+ else
+ {
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!=NULL)
+ {
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+
+ return FAILED;
+
+ }
+#endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_mCastModuleArray[moduleIndex].flowHashTable= (struct rtl_mcastFlowEntry **)rtl_glueMalloc(4 * hashTableSize);
+
+ if (rtl_mCastModuleArray[moduleIndex].flowHashTable!=NULL)
+ {
+ for (i = 0 ; i < hashTableSize ; i++)
+ {
+
+ rtl_mCastModuleArray[moduleIndex].flowHashTable[i]=NULL;
+ }
+ }
+ else
+ {
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!=NULL)
+ {
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable!=NULL)
+ {
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ }
+#endif
+ return FAILED;
+
+
+ }
+ #endif
+return SUCCESS;
+
+}
+
+
+
+/**************************
+ Utility
+**************************/
+static void rtl_parseMacFrame(uint32 moduleIndex, uint8* macFrame, uint32 verifyCheckSum, struct rtl_macFrameInfo* macInfo)
+{
+
+//MAC Frame :DA(6 bytes)+SA(6 bytes)+ CPU tag(4 bytes) + VlAN tag(Optional, 4 bytes)
+// +Type(IPv4:0x0800, IPV6:0x86DD, PPPOE:0x8864, 2 bytes )+Data(46~1500 bytes)+CRC(4 bytes)
+
+ uint8 *ptr=macFrame;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ int i=0;
+ uint8 nextHeader=0;
+ uint16 extensionHdrLen=0;
+ uint8 routingHead=FALSE;
+
+ uint8 optionDataLen=0;
+ uint8 optionType=0;
+ uint32 ipv6RAO=0;
+#endif
+
+ uint32 ipAddr[4]={0,0,0,0};
+ union pseudoHeader pHeader;
+
+ memset(macInfo,0,sizeof(struct rtl_macFrameInfo));
+ memset(&pHeader, 0, sizeof(union pseudoHeader));
+
+ memcpy(macInfo->srcMacAddr, ptr+6,6);
+
+ ptr=ptr+12;
+
+
+ /*check the presence of VLAN tag*/
+ if(*(int16 *)(ptr)==(int16)htons(VLAN_PROTOCOL_ID))
+ {
+ ptr=ptr+4;
+ }
+
+ /*ignore packet with PPPOE header*/
+ if(*(int16 *)(ptr)==(int16)htons(PPPOE_ETHER_TYPE))
+ {
+ return;
+ }
+
+
+ /*check the presence of ipv4 type*/
+ if(*(int16 *)(ptr)==(int16)htons(IPV4_ETHER_TYPE))
+ {
+ ptr=ptr+2;
+ macInfo->ipBuf=ptr;
+ macInfo->ipVersion=IP_VERSION4;
+ }
+ else
+ {
+ /*check the presence of ipv4 type*/
+ if(*(int16 *)(ptr)==(int16)htons(IPV6_ETHER_TYPE))
+ {
+ ptr=ptr+2;
+ macInfo->ipBuf=ptr;
+ macInfo->ipVersion=IP_VERSION6;
+ }
+ }
+
+ if((macInfo->ipVersion!=IP_VERSION4) && (macInfo->ipVersion!=IP_VERSION6))
+ {
+ return;
+ }
+ macInfo->checksumFlag=FAILED;
+
+ if(macInfo->ipVersion==IP_VERSION4)
+ {
+ macInfo->ipHdrLen=(uint16)((((struct ipv4Pkt *)(macInfo->ipBuf))->vhl&0x0f)<<2);
+ macInfo->l3PktLen=ntohs(((struct ipv4Pkt *)(macInfo->ipBuf))->length)-macInfo->ipHdrLen;
+ ptr=ptr+macInfo->ipHdrLen;
+ macInfo->l3PktBuf=ptr;
+ macInfo->macFrameLen=(uint16)((ptr-macFrame)+macInfo->l3PktLen);
+ macInfo->srcIpAddr[0]=ntohl(((struct ipv4Pkt *)(macInfo->ipBuf))->sourceIp);
+ macInfo->dstIpAddr[0]=ntohl(((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp);
+/*distinguish different IGMP packet:
+ ip_header_length destination_ip igmp_packet_length igmp_type group_address
+IGMPv1_general_query: 20 224.0.0.1 8 0x11 0
+IGMPv2_general_query: 24 224.0.0.1 8 0x11 0
+IGMPv2_group_specific_query: 24 224.0.0.1 8 0x11 !=0
+IGMPv3 _query: 24 224.0.0.1 >=12 0x11 according_to_different_situation
+
+IGMPv1_join: 20 actual_multicast_address 8 0x12 actual_multicast_address
+IGMPv2_join: 24 actual_multicast_address 8 0x16 actual_multicast_address
+IGMPv2_leave: 24 actual_multicast_address 8 0x17 actual_multicast_address
+IGMPv3_report: 24 actual_multicast_address >=12 0x22 actual_multicast_address*/
+
+ /* parse IGMP type and version*/
+ if(((struct ipv4Pkt *)(macInfo->ipBuf))->protocol==IGMP_PROTOCOL)
+ {
+ /*check DVMRP*/
+ if((macInfo->l3PktBuf[0]==DVMRP_TYPE) && (((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp==htonl(DVMRP_ADDR)) )
+ {
+ macInfo->l3Protocol=DVMRP_PROTOCOL;
+ }
+ else
+ {
+ /*means unicast*/
+ if((macFrame[0]&0x01)==0)
+ {
+ if(rtl_compareMacAddr(macFrame, rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac)==TRUE)
+ {
+ if(((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp==htonl(rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv4Addr))
+ {
+ macInfo->l3Protocol=IGMP_PROTOCOL;
+ goto otherpro;
+ }
+ }
+
+ }
+ else /*means multicast*/
+ {
+ ipAddr[0]=ntohl(((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp);
+ if(rtl_checkMCastAddrMapping(IP_VERSION4,ipAddr,macFrame)==TRUE)
+ {
+ macInfo->l3Protocol=IGMP_PROTOCOL;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+ }
+
+otherpro:
+ if(((struct ipv4Pkt *)(macInfo->ipBuf))->protocol==MOSPF_PROTOCOL &&\
+ ((((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp==htonl(IPV4_MOSPF_ADDR1)) ||\
+ (((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp==htonl(IPV4_MOSPF_ADDR2))))
+ {
+ macInfo->l3Protocol=MOSPF_PROTOCOL;
+ }
+
+ if(((struct ipv4Pkt *)(macInfo->ipBuf))->protocol==PIM_PROTOCOL && (((struct ipv4Pkt *)(macInfo->ipBuf))->destinationIp==htonl(IPV4_PIM_ADDR)))
+ {
+ macInfo->l3Protocol=PIM_PROTOCOL;
+ }
+
+ if(verifyCheckSum==TRUE)
+ {
+ if(rtl_checksum(macInfo->l3PktBuf, macInfo->l3PktLen)!=0)
+ {
+ macInfo->checksumFlag=FAILED;
+ }
+ else
+ {
+ macInfo->checksumFlag=SUCCESS;
+ }
+ }
+ else
+ {
+ macInfo->checksumFlag=SUCCESS;
+ }
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(macInfo->ipVersion==IP_VERSION6)
+ {
+ macInfo->srcIpAddr[0]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->sourceAddr[0]);
+ macInfo->srcIpAddr[1]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->sourceAddr[1]);
+ macInfo->srcIpAddr[2]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->sourceAddr[2]);
+ macInfo->srcIpAddr[3]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->sourceAddr[3]);
+
+ macInfo->dstIpAddr[0]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[0]);
+ macInfo->dstIpAddr[1]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[1]);
+ macInfo->dstIpAddr[2]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[2]);
+ macInfo->dstIpAddr[3]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[3]);
+
+ macInfo->macFrameLen=(uint16)(ptr-macFrame+IPV6_HEADER_LENGTH+ntohs(((struct ipv6Pkt *)(macInfo->ipBuf))->payloadLenth));
+ macInfo->ipHdrLen=IPV6_HEADER_LENGTH;
+
+ nextHeader=((struct ipv6Pkt *)(macInfo->ipBuf))->nextHeader;
+ ptr=ptr+IPV6_HEADER_LENGTH;
+ while((ptr-macInfo->ipBuf)<(ntohs(((struct ipv6Pkt *)(macInfo->ipBuf))->payloadLenth)+IPV6_HEADER_LENGTH))
+ {
+ switch(nextHeader)
+ {
+ case HOP_BY_HOP_OPTIONS_HEADER:
+ /*parse hop-by-hop option*/
+ nextHeader=ptr[0];
+ extensionHdrLen=((uint16)(ptr[1])+1)*8;
+ ptr=ptr+2;
+
+ while((ptr-macInfo->ipBuf-40)<extensionHdrLen)
+ {
+ optionType=ptr[0];
+ /*pad1 option*/
+ if(optionType==0)
+ {
+ ptr=ptr+1;
+ continue;
+ }
+
+ /*padN option*/
+ if(optionType==1)
+ {
+ optionDataLen=ptr[1];
+ ptr=ptr+optionDataLen+2;
+ continue;
+ }
+
+ /*router alter option*/
+ if(ntohl(*(uint32 *)(ptr))==IPV6_ROUTER_ALTER_OPTION)
+ {
+ ipv6RAO=IPV6_ROUTER_ALTER_OPTION;
+ ptr=ptr+4;
+ continue;
+ }
+
+ /*other TLV option*/
+ if((optionType!=0) && (optionType!=1))
+ {
+ optionDataLen=ptr[1];
+ ptr=ptr+optionDataLen+2;
+ continue;
+ }
+
+
+ }
+ /*
+ if((ptr-macInfo->ipBuf-40)!=extensionHdrLen)
+ {
+ rtl_gluePrintf("ipv6 packet parse error\n");
+ }*/
+
+ break;
+
+ case ROUTING_HEADER:
+ nextHeader=ptr[0];
+ extensionHdrLen=((uint16)(ptr[1])+1)*8;
+
+
+ if (ptr[3]>0)
+ {
+ ptr=ptr+extensionHdrLen;
+ for(i=0; i<4; i++)
+ {
+ pHeader.ipv6_pHdr.destinationAddr[i]=*((uint32 *)(ptr)-4+i);
+
+ }
+ routingHead=TRUE;
+
+
+ }
+ else
+ {
+ ptr=ptr+extensionHdrLen;
+ }
+
+
+
+ break;
+
+ case FRAGMENT_HEADER:
+ nextHeader=ptr[0];
+ ptr=ptr+8;
+ break;
+
+ case DESTINATION_OPTION_HEADER:
+ nextHeader=ptr[0];
+ extensionHdrLen=((uint16)(ptr[1])+1)*8;
+ ptr=ptr+extensionHdrLen;
+ break;
+
+ case ICMP_PROTOCOL:
+ nextHeader=NO_NEXT_HEADER;
+ macInfo->l3PktLen=ntohs(((struct ipv6Pkt *)(macInfo->ipBuf))->payloadLenth)-(uint16)(ptr-macInfo->ipBuf-IPV6_HEADER_LENGTH);
+ macInfo->l3PktBuf=ptr;
+ if((ptr[0]==MLD_QUERY) ||(ptr[0]==MLDV1_REPORT) ||(ptr[0]==MLDV1_DONE) ||(ptr[0]==MLDV2_REPORT))
+ {
+ /*means multicast*/
+ if( (macFrame[0]==0x33)&&\
+ (macFrame[1]==0x33))
+ {
+ ipAddr[0]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[0]);
+ ipAddr[1]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[1]);
+ ipAddr[2]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[2]);
+ ipAddr[3]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[3]);
+
+ if(rtl_checkMCastAddrMapping(IP_VERSION6, ipAddr, macFrame)==TRUE)
+ {
+ macInfo->l3Protocol=ICMP_PROTOCOL;
+ }
+
+ }
+ else /*means multicast*/
+ {
+
+ ipAddr[0]=htonl(rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[0]);
+ ipAddr[1]=htonl(rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[1]);
+ ipAddr[2]=htonl(rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[2]);
+ ipAddr[3]=htonl(rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[3]);
+ if( (rtl_compareMacAddr(macFrame, rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac)==TRUE) &&\
+ (rtl_compareIpv6Addr(((struct ipv6Pkt *)macInfo->ipBuf)->destinationAddr, ipAddr) == TRUE))
+ {
+ macInfo->l3Protocol=ICMP_PROTOCOL;
+ }
+
+
+ }
+
+ /*
+ if(ipv6RAO!=IPV6_ROUTER_ALTER_OPTION)
+ {
+ rtl_gluePrintf("router alter option error\n");
+ }*/
+ }
+
+
+ break;
+
+ case PIM_PROTOCOL:
+ nextHeader=NO_NEXT_HEADER;
+ macInfo->l3PktLen=ntohs(((struct ipv6Pkt *)(macInfo->ipBuf))->payloadLenth)-(uint16)(ptr-macInfo->ipBuf-IPV6_HEADER_LENGTH);
+ macInfo->l3PktBuf=ptr;
+
+ ipAddr[0]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[0]);
+ ipAddr[1]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[1]);
+ ipAddr[2]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[2]);
+ ipAddr[3]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[3]);
+ if(IS_IPV6_PIM_ADDR(ipAddr))
+ {
+ macInfo->l3Protocol=PIM_PROTOCOL;
+ }
+
+ break;
+
+ case MOSPF_PROTOCOL:
+ nextHeader=NO_NEXT_HEADER;
+ macInfo->l3PktLen=ntohs(((struct ipv6Pkt *)(macInfo->ipBuf))->payloadLenth)-(uint16)(ptr-macInfo->ipBuf-IPV6_HEADER_LENGTH);
+ macInfo->l3PktBuf=ptr;
+
+ ipAddr[0]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[0]);
+ ipAddr[1]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[1]);
+ ipAddr[2]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[2]);
+ ipAddr[3]=ntohl(((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[3]);
+
+ if(IS_IPV6_MOSPF_ADDR1(ipAddr) || IS_IPV6_MOSPF_ADDR2(ipAddr))
+ {
+ macInfo->l3Protocol=MOSPF_PROTOCOL;
+ }
+
+ break;
+
+ default:
+ goto out;
+ break;
+ }
+
+ }
+
+out:
+
+
+ if(verifyCheckSum==TRUE)
+ {
+ if(macInfo->l3PktBuf==NULL)
+ {
+ return;
+ }
+
+ /*generate pseudo header*/
+ for(i=0; i<4; i++)
+ {
+ pHeader.ipv6_pHdr.sourceAddr[i]=((struct ipv6Pkt *)(macInfo->ipBuf))->sourceAddr[i];
+
+ }
+
+ if(routingHead==FALSE)
+ {
+ for(i=0;i<4;i++)
+ {
+ pHeader.ipv6_pHdr.destinationAddr[i]=((struct ipv6Pkt *)(macInfo->ipBuf))->destinationAddr[i];
+ }
+ }
+
+
+ pHeader.ipv6_pHdr.nextHeader=macInfo->l3Protocol;
+ pHeader.ipv6_pHdr.upperLayerPacketLength=htonl((uint32)(macInfo->l3PktLen));
+ pHeader.ipv6_pHdr.zeroData[0]=0;
+ pHeader.ipv6_pHdr.zeroData[1]=0;
+ pHeader.ipv6_pHdr.zeroData[2]=0;
+
+ /*verify checksum*/
+ if(rtl_ipv6L3Checksum(macInfo->l3PktBuf, macInfo->l3PktLen,&pHeader)!=0)
+ {
+ macInfo->checksumFlag=FAILED;
+ }
+ else
+ {
+ macInfo->checksumFlag=SUCCESS;
+ }
+ }
+ else
+ {
+ macInfo->checksumFlag=SUCCESS;
+ }
+ }
+#endif
+ return;
+}
+
+
+static uint32 rtl_getMulticastRouterPortMask(uint32 moduleIndex, uint32 ipVersion, uint32 sysTime)
+{
+ uint32 portIndex=0;
+ uint8 portMaskn=PORT0_MASK;
+ uint32 routerPortmask=0;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ for(portIndex=0; portIndex<MAX_SUPPORT_PORT_NUMBER; portIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.querier.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.dvmrpRouter.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.mospfRouter.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.pimRouter.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+ portMaskn=portMaskn<<1; /*shift to next port mask*/
+
+ }
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ for(portIndex=0; portIndex<MAX_SUPPORT_PORT_NUMBER; portIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.querier.portTimer[portIndex]>sysTime)
+ {
+
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.mospfRouter.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.pimRouter.portTimer[portIndex]>sysTime)
+ {
+ routerPortmask=routerPortmask|portMaskn;
+ }
+
+ portMaskn=portMaskn<<1; /*shift to next port mask*/
+
+ }
+
+ }
+#endif
+
+ routerPortmask= routerPortmask |rtl_mCastModuleArray[moduleIndex].staticRouterPortMask;
+
+ return routerPortmask;
+}
+
+static uint32 rtl_processQueries(uint32 moduleIndex,uint32 ipVersion, uint32 portNum, uint8* pktBuf, uint32 pktLen)
+{
+ #if 0
+ struct rtl_groupEntry *groupEntry=NULL;
+ struct rtl_clientEntry * clientEntry=NULL;
+ struct rtl_sourceEntry*sourceEntry=NULL;
+ uint32 i=0;
+ #endif
+ uint32 groupAddress[4]={0,0,0,0};
+ uint32 suppressFlag=0;
+ uint32 *sourceAddr=NULL;
+ uint32 numOfSrc=0;
+
+
+ /*querier timer update and election process*/
+ rtl_snoopQuerier(moduleIndex, ipVersion, portNum);
+
+ if(ipVersion==IP_VERSION4)
+ {
+ if(pktLen>=12) /*means igmpv3 query*/
+ {
+ groupAddress[0]=ntohl(((struct igmpv3Query*)pktBuf)->groupAddr);
+ suppressFlag=((struct igmpv3Query*)pktBuf)->rsq & S_FLAG_MASK;
+ sourceAddr=&(((struct igmpv3Query*)pktBuf)->srcList);
+ numOfSrc=(uint32)ntohs(((struct igmpv3Query*)pktBuf)->numOfSrc);
+
+ }
+ else
+ {
+ groupAddress[0]=ntohl(((struct igmpv2Pkt *)pktBuf)->groupAddr);
+ }
+
+ if(groupAddress[0]==0) /*means general query*/
+ {
+ goto out;
+ }
+ else
+ {
+ // hashIndex=rtl_igmpHashAlgorithm(ipVersion, groupAddress);
+ }
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ if(pktLen>=28) /*means mldv2 query*/
+ {
+ groupAddress[0]=ntohl(((struct mldv2Query*)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mldv2Query*)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mldv2Query*)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mldv2Query*)pktBuf)->mCastAddr[3]);
+
+ suppressFlag=((struct mldv2Query*)pktBuf)->rsq & S_FLAG_MASK;
+ sourceAddr=&(((struct mldv2Query*)pktBuf)->srcList);
+ numOfSrc=(uint32)ntohs(((struct mldv2Query*)pktBuf)->numOfSrc);
+
+ }
+ else /*means mldv1 query*/
+ {
+ groupAddress[0]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[3]);
+
+ }
+
+ if( (groupAddress[0]==0)&&
+ (groupAddress[1]==0)&&
+ (groupAddress[2]==0)&&
+ (groupAddress[3]==0) )/*means general query*/
+ {
+ goto out;
+ }
+ else
+ {
+ // hashIndex=rtl_igmpHashAlgorithm(ipVersion, groupAddress);
+ }
+ }
+#endif
+ if(suppressFlag==0)
+ {
+ /*ignore group specific query handling*/
+ #if 0
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ if((groupEntry!=NULL))
+ {
+
+ if(numOfSrc==0) /*means group specific query*/
+ {
+ clientEntry=groupEntry->clientList;
+ while(clientEntry!=NULL)
+ {
+ if(clientEntry->groupFilterTimer>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime))
+ {
+ clientEntry->groupFilterTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ clientEntry=clientEntry->next;
+ }
+
+ }
+ else /*means group and source specific query*/
+ {
+ clientEntry=groupEntry->clientList;
+ while(clientEntry!=NULL)
+ {
+ for(i=0; i<numOfSrc; i++)
+ {
+
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr, clientEntry);
+
+ if(sourceEntry!=NULL)
+ {
+ if(sourceEntry->portTimer>(rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime))
+ {
+ sourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+
+ clientEntry=clientEntry->next;
+ }
+
+ }
+ }
+ #endif
+
+ }
+
+
+ reportEventContext.ipVersion=ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.groupAddr[1]=groupAddress[1];
+ reportEventContext.groupAddr[2]=groupAddress[2];
+ reportEventContext.groupAddr[3]=groupAddress[3];
+ #else
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ #endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+out:
+ return (~(1<<portNum) & ((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+}
+
+
+static void rtl_snoopQuerier(uint32 moduleIndex, uint32 ipVersion, uint32 portNum)
+{
+
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.querier.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.querierPresentInterval;/*update timer value*/
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.querier.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.querierPresentInterval;/*update timer value*/
+ }
+#endif
+ return;
+}
+
+
+/*Process Report Packet*/
+static uint32 rtl_processJoin(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint32 *clientAddr, uint8 *pktBuf)
+{
+
+
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_clientEntry* clientEntry=NULL;
+ struct rtl_clientEntry* newClientEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint32 multicastRouterPortMask=rtl_getMulticastRouterPortMask(moduleIndex, ipVersion, rtl_sysUpSeconds);
+ uint32 allClientPortMask=0;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ if(pktBuf[0]==0x12)
+ {
+ groupAddress[0]=ntohl(((struct igmpv1Pkt *)pktBuf)->groupAddr);
+ }
+
+ if(pktBuf[0]==0x16)
+ {
+ groupAddress[0]=ntohl(((struct igmpv2Pkt *)pktBuf)->groupAddr);
+ }
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+
+ groupAddress[0]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[3]);
+ }
+#endif
+
+ hashIndex=rtl_igmpHashAlgorithm(ipVersion, groupAddress);
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ goto out;
+ }
+
+ assert(newGroupEntry->clientList==NULL);
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+#else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+#endif
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ }
+#endif
+ groupEntry=newGroupEntry;
+
+ }
+
+ clientEntry=rtl_searchClientEntry(ipVersion, groupEntry, portNum, clientAddr);
+ if(clientEntry==NULL)
+ {
+ newClientEntry=rtl_allocateClientEntry();
+ if(newClientEntry==NULL)
+ {
+ rtl_gluePrintf("run out of client entry!\n");
+ goto out;
+ }
+
+ assert(newClientEntry->sourceList==NULL);
+ newClientEntry->portNum=portNum;
+ newClientEntry->igmpVersion=IGMP_V2;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+
+ }
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+ newClientEntry->clientAddr[1]=clientAddr[1];
+ newClientEntry->clientAddr[2]=clientAddr[2];
+ newClientEntry->clientAddr[3]=clientAddr[3];
+
+ }
+ #endif
+
+ rtl_linkClientEntry(groupEntry, newClientEntry);
+ clientEntry=newClientEntry;
+ }
+
+
+ rtl_deleteSourceList(clientEntry);
+ clientEntry->igmpVersion=IGMP_V2;
+ clientEntry->groupFilterTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+
+ allClientPortMask=rtl_getAllClientPortMask( groupEntry);
+
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if((groupEntry!=NULL) && (groupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ goto out;
+ }
+ #endif
+
+ reportEventContext.ipVersion=ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.groupAddr[1]=groupAddress[1];
+ reportEventContext.groupAddr[2]=groupAddress[2];
+ reportEventContext.groupAddr[3]=groupAddress[3];
+ #else
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ #endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+out:
+ return (((~allClientPortMask)| multicastRouterPortMask) & (~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+ //return (multicastRouterPortMask&(~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+}
+
+static uint32 rtl_processLeave(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint32 *clientAddr, uint8 *pktBuf)
+{
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_clientEntry *clientEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *nextSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+// uint32 multicastRouterPortMask=rtl_getMulticastRouterPortMask(moduleIndex, ipVersion, rtl_sysUpSeconds);
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct igmpv2Pkt *)pktBuf)->groupAddr);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ groupAddress[0]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mldv1Pkt *)pktBuf)->mCastAddr[3]);
+ }
+#endif
+
+ hashIndex=rtl_igmpHashAlgorithm(ipVersion, groupAddress);
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+
+ if(groupEntry!=NULL)
+ {
+ clientEntry=rtl_searchClientEntry( ipVersion, groupEntry, portNum, clientAddr);
+ if(clientEntry!=NULL)
+ {
+
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ rtl_deleteClientEntry(groupEntry, clientEntry);
+ }
+ else
+ {
+ while(sourceEntry!=NULL)
+ {
+ nextSourceEntry=sourceEntry->next;
+ if(sourceEntry->portTimer>rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime)
+ {
+ sourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ sourceEntry=nextSourceEntry;
+ }
+
+ if(clientEntry->groupFilterTimer>rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime)
+ {
+ clientEntry->groupFilterTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+
+ }
+
+ }
+
+ }
+
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if((groupEntry!=NULL) && (groupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ goto out;
+ }
+ #endif
+
+ reportEventContext.ipVersion=ipVersion;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.groupAddr[1]=groupAddress[1];
+ reportEventContext.groupAddr[2]=groupAddress[2];
+ reportEventContext.groupAddr[3]=groupAddress[3];
+#else
+ reportEventContext.groupAddr[0]=groupAddress[0];
+#endif
+
+ if((groupEntry!=NULL) && (groupEntry->clientList==NULL))
+ {
+ rtl_deleteGroupEntry(groupEntry,rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+
+ }
+ #endif
+
+#if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+out:
+#endif
+ return ((~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+ //return (multicastRouterPortMask&(~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+
+}
+
+static int32 rtl_processIsInclude(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint32 *clientAddr, uint8 *pktBuf)
+{
+
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_clientEntry* clientEntry=NULL;
+ struct rtl_clientEntry* newClientEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+
+ uint16 numOfSrc=0;
+ uint32 *sourceAddr=NULL;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ }
+#endif
+
+ hashIndex=rtl_igmpHashAlgorithm(ipVersion, groupAddress);
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+
+ assert(newGroupEntry->clientList==NULL);
+ /*set new multicast entry*/
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+#else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+#endif
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ }
+#endif
+ groupEntry=newGroupEntry;
+ }
+
+ /*from here groupEntry is the same as newGroupEntry*/
+ clientEntry=rtl_searchClientEntry(ipVersion, groupEntry, portNum, clientAddr);
+
+ if(clientEntry==NULL)
+ {
+ newClientEntry=rtl_allocateClientEntry();
+ if(newClientEntry==NULL)
+ {
+ rtl_gluePrintf("run out of client entry!\n");
+ return FAILED;
+ }
+
+ assert(newClientEntry->sourceList==NULL);
+ newClientEntry->sourceList=NULL;
+ newClientEntry->igmpVersion=IGMP_V3;
+ newClientEntry->portNum=portNum;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+ }
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+ newClientEntry->clientAddr[1]=clientAddr[1];
+ newClientEntry->clientAddr[2]=clientAddr[2];
+ newClientEntry->clientAddr[3]=clientAddr[3];
+
+ }
+ #endif
+
+ rtl_linkClientEntry(groupEntry, newClientEntry);
+ clientEntry=newClientEntry;
+ }
+
+ /*from here client entry is the same as the newClientEntry*/
+ rtl_deleteSourceList(clientEntry);
+ clientEntry->igmpVersion=IGMP_V3;
+ clientEntry->groupFilterTimer=rtl_sysUpSeconds;
+ assert(clientEntry->sourceList==NULL);
+
+ /*here to handle the source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ newSourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(clientEntry,newSourceEntry);
+
+ }
+
+
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if((groupEntry!=NULL) && (groupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ return SUCCESS;
+ }
+ #endif
+
+
+ reportEventContext.ipVersion=ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.groupAddr[1]=groupAddress[1];
+ reportEventContext.groupAddr[2]=groupAddress[2];
+ reportEventContext.groupAddr[3]=groupAddress[3];
+ #else
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ #endif
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+
+
+ return SUCCESS;
+}
+
+static int32 rtl_processIsExclude(uint32 moduleIndex, uint32 ipVersion,uint32 portNum, uint32 *clientAddr, uint8 *pktBuf)
+{
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_clientEntry* clientEntry=NULL;
+ struct rtl_clientEntry* newClientEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint16 numOfSrc=0;
+ uint32 *sourceArray=NULL;
+ uint32 *sourceAddr=NULL;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceArray=&(((struct groupRecord *)pktBuf)->srcList);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceArray=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ }
+#endif
+
+ hashIndex=rtl_igmpHashAlgorithm( ipVersion, groupAddress);
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+
+ assert(newGroupEntry->clientList==NULL);
+ /*set new multicast entry*/
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+#else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+#endif
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ }
+#endif
+ groupEntry=newGroupEntry;
+ }
+
+ /*from here groupEntry is the same as newGroupEntry*/
+ clientEntry=rtl_searchClientEntry(ipVersion, groupEntry, portNum, clientAddr);
+ if(clientEntry==NULL)
+ {
+ newClientEntry=rtl_allocateClientEntry();
+ if(newClientEntry==NULL)
+ {
+ rtl_gluePrintf("run out of client entry!\n");
+ return FAILED;
+ }
+
+ assert(newClientEntry->sourceList==NULL);
+
+ newClientEntry->sourceList=NULL;
+ newClientEntry->igmpVersion=IGMP_V3;
+ newClientEntry->portNum=portNum;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+ }
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+ newClientEntry->clientAddr[1]=clientAddr[1];
+ newClientEntry->clientAddr[2]=clientAddr[2];
+ newClientEntry->clientAddr[3]=clientAddr[3];
+
+ }
+ #endif
+
+ rtl_linkClientEntry(groupEntry, newClientEntry);
+ clientEntry=newClientEntry;
+
+ }
+
+ /*from here clientEntry is the same as newClientEntry*/
+
+ /*flush the old source list*/
+ rtl_deleteSourceList( clientEntry);
+ clientEntry->igmpVersion=IGMP_V3;
+ clientEntry->groupFilterTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ assert(clientEntry->sourceList==NULL);
+
+ /*link the new source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ /*time out the sources included in the MODE_IS_EXCLUDE report*/
+ newSourceEntry->portTimer=rtl_sysUpSeconds;
+ rtl_linkSourceEntry(clientEntry,newSourceEntry);
+
+ }
+
+
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if((groupEntry!=NULL) && (groupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ return SUCCESS;
+ }
+ #endif
+
+ reportEventContext.ipVersion=ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.groupAddr[1]=groupAddress[1];
+ reportEventContext.groupAddr[2]=groupAddress[2];
+ reportEventContext.groupAddr[3]=groupAddress[3];
+ #else
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ #endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+
+ }
+ #endif
+
+ return SUCCESS;
+
+}
+
+static int32 rtl_processToInclude(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint32 *clientAddr, uint8 *pktBuf)
+{
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_clientEntry* clientEntry=NULL;
+ struct rtl_clientEntry* newClientEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *nextSourceEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint16 numOfSrc=0;
+ uint32 *sourceAddr=NULL;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+
+ }
+#endif
+
+ hashIndex=rtl_igmpHashAlgorithm(ipVersion, groupAddress);
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+#else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+#endif
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ }
+#endif
+ groupEntry=newGroupEntry;
+ }
+
+ /*from here groupEntry is the same as newGroupEntry*/
+ clientEntry=rtl_searchClientEntry(ipVersion, groupEntry, portNum, clientAddr);
+
+ if(clientEntry==NULL)
+ {
+
+ newClientEntry=rtl_allocateClientEntry();
+ if(newClientEntry==NULL)
+ {
+ rtl_gluePrintf("run out of client entry!\n");
+ return FAILED;
+ }
+
+ assert(newClientEntry->sourceList==NULL);
+ newClientEntry->sourceList=NULL;
+ newClientEntry->igmpVersion=IGMP_V3;
+ newClientEntry->portNum=portNum;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+
+ }
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+ newClientEntry->clientAddr[1]=clientAddr[1];
+ newClientEntry->clientAddr[2]=clientAddr[2];
+ newClientEntry->clientAddr[3]=clientAddr[3];
+
+ }
+ #endif
+
+ rtl_linkClientEntry(groupEntry, newClientEntry);
+ clientEntry=newClientEntry;
+ }
+
+ /*here to handle the source list*/
+
+ clientEntry->igmpVersion=IGMP_V3;
+
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ clientEntry->groupFilterTimer=rtl_sysUpSeconds;
+ rtl_deleteSourceList(clientEntry);
+ /*link the new source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ newSourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(clientEntry,newSourceEntry);
+ }
+
+ }
+ else
+ {
+
+ while(sourceEntry!=NULL)
+ {
+ nextSourceEntry=sourceEntry->next;
+ if(sourceEntry->portTimer>rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime)
+ {
+ sourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ sourceEntry=nextSourceEntry;
+ }
+
+ /*add new source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr, clientEntry);
+ if(sourceEntry!=NULL)
+ {
+ sourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+ else
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(clientEntry,newSourceEntry);
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+
+ if(clientEntry->groupFilterTimer>rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime)
+ {
+ clientEntry->groupFilterTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+
+ }
+
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if((groupEntry!=NULL) && (groupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ return SUCCESS;
+ }
+ #endif
+
+ reportEventContext.ipVersion=ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.groupAddr[1]=groupAddress[1];
+ reportEventContext.groupAddr[2]=groupAddress[2];
+ reportEventContext.groupAddr[3]=groupAddress[3];
+ #else
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ #endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+
+ }
+ #endif
+
+ return SUCCESS;
+
+}
+
+static int32 rtl_processToExclude(uint32 moduleIndex, uint32 ipVersion,uint32 portNum , uint32 *clientAddr, uint8 *pktBuf)
+{
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_clientEntry* clientEntry=NULL;
+ struct rtl_clientEntry* newClientEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint16 numOfSrc=0;
+ uint32 *sourceArray=NULL;
+ uint32 *sourceAddr=NULL;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceArray=&(((struct groupRecord *)pktBuf)->srcList);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceArray=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ }
+#endif
+
+ hashIndex=rtl_igmpHashAlgorithm(ipVersion, groupAddress);
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+#else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+#endif
+
+
+ newGroupEntry->ipVersion=ipVersion;
+ assert(newGroupEntry->clientList==NULL);
+
+
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ }
+#endif
+ groupEntry=newGroupEntry;
+ }
+
+ clientEntry=rtl_searchClientEntry(ipVersion, groupEntry, portNum, clientAddr);
+ if(clientEntry==NULL)
+ {
+ newClientEntry=rtl_allocateClientEntry();
+ if(newClientEntry==NULL)
+ {
+ rtl_gluePrintf("run out of client entry!\n");
+ return FAILED;
+ }
+
+ assert(newClientEntry->sourceList==NULL);
+ newClientEntry->sourceList=NULL;
+ newClientEntry->igmpVersion=IGMP_V3;
+ newClientEntry->portNum=portNum;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+ }
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+ newClientEntry->clientAddr[1]=clientAddr[1];
+ newClientEntry->clientAddr[2]=clientAddr[2];
+ newClientEntry->clientAddr[3]=clientAddr[3];
+
+ }
+ #endif
+
+ rtl_linkClientEntry(groupEntry, newClientEntry);
+ clientEntry=newClientEntry;
+ }
+
+ /*flush the old source list*/
+ rtl_deleteSourceList( clientEntry);
+ clientEntry->igmpVersion=IGMP_V3;
+ clientEntry->groupFilterTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+
+ /*link the new source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ /*time out the sources included in the MODE_IS_EXCLUDE report*/
+ newSourceEntry->portTimer=rtl_sysUpSeconds;
+ rtl_linkSourceEntry(clientEntry,newSourceEntry);
+
+ }
+
+
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if((groupEntry!=NULL) && (groupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ return SUCCESS;
+ }
+ #endif
+
+ reportEventContext.ipVersion=ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.groupAddr[1]=groupAddress[1];
+ reportEventContext.groupAddr[2]=groupAddress[2];
+ reportEventContext.groupAddr[3]=groupAddress[3];
+ #else
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ #endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+
+ }
+ #endif
+
+ return SUCCESS;
+}
+
+static int32 rtl_processAllow(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint32 *clientAddr, uint8 *pktBuf)
+{
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+ struct rtl_clientEntry* clientEntry=NULL;
+ struct rtl_clientEntry* newClientEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+ uint32 hashIndex=0;
+ uint16 numOfSrc=0;
+ uint32 *sourceAddr=NULL;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ }
+#endif
+
+ hashIndex=rtl_igmpHashAlgorithm( ipVersion, groupAddress);
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+
+ if(groupEntry==NULL) /*means new group address, create new group entry*/
+ {
+ newGroupEntry=rtl_allocateGroupEntry();
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+ newGroupEntry->groupAddr[1]=groupAddress[1];
+ newGroupEntry->groupAddr[2]=groupAddress[2];
+ newGroupEntry->groupAddr[3]=groupAddress[3];
+#else
+ newGroupEntry->groupAddr[0]=groupAddress[0];
+#endif
+
+
+ newGroupEntry->ipVersion=ipVersion;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ }
+#endif
+
+ groupEntry=newGroupEntry;
+ }
+
+ clientEntry=rtl_searchClientEntry(ipVersion, groupEntry, portNum, clientAddr);
+
+ if(clientEntry==NULL)
+ {
+ newClientEntry=rtl_allocateClientEntry();
+ if(newClientEntry==NULL)
+ {
+ rtl_gluePrintf("run out of client entry!\n");
+ return FAILED;
+ }
+
+
+ assert(newClientEntry->sourceList==NULL);
+ newClientEntry->sourceList=NULL;
+ newClientEntry->portNum=portNum;
+ newClientEntry->igmpVersion=IGMP_V3;
+ newClientEntry->groupFilterTimer=rtl_sysUpSeconds;
+ if(ipVersion==IP_VERSION4)
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+ }
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newClientEntry->clientAddr[0]=clientAddr[0];
+ newClientEntry->clientAddr[1]=clientAddr[1];
+ newClientEntry->clientAddr[2]=clientAddr[2];
+ newClientEntry->clientAddr[3]=clientAddr[3];
+
+ }
+ #endif
+
+ rtl_linkClientEntry(groupEntry, newClientEntry);
+ clientEntry=newClientEntry;
+ }
+
+ clientEntry->igmpVersion=IGMP_V3;
+
+ /*here to handle the source list*/
+ for(j=0; j<numOfSrc; j++)
+ {
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,clientEntry);
+
+ if(sourceEntry==NULL)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ rtl_linkSourceEntry(clientEntry,newSourceEntry);
+
+ }
+ else
+ {
+ /*just update source timer*/
+ sourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.groupMemberAgingTime;
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+
+
+#if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if((groupEntry!=NULL) && (groupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ return SUCCESS;
+ }
+#endif
+
+ reportEventContext.ipVersion=ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.groupAddr[1]=groupAddress[1];
+ reportEventContext.groupAddr[2]=groupAddress[2];
+ reportEventContext.groupAddr[3]=groupAddress[3];
+ #else
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ #endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+
+ }
+ #endif
+
+ return SUCCESS;
+}
+
+static int32 rtl_processBlock(uint32 moduleIndex, uint32 ipVersion,uint32 portNum, uint32 *clientAddr, uint8 *pktBuf)
+{
+ uint32 j=0;
+ uint32 groupAddress[4]={0, 0, 0, 0};
+
+ struct rtl_groupEntry* groupEntry=NULL;
+ struct rtl_clientEntry* clientEntry=NULL;
+ //struct rtl_clientEntry* newClientEntry=NULL;
+ struct rtl_sourceEntry *sourceEntry=NULL;
+ struct rtl_sourceEntry *newSourceEntry=NULL;
+
+
+ uint32 hashIndex=0;
+ uint16 numOfSrc=0;
+ uint32 *sourceAddr=NULL;
+
+ if(ipVersion==IP_VERSION4)
+ {
+ groupAddress[0]=ntohl(((struct groupRecord *)pktBuf)->groupAddr);
+ numOfSrc=ntohs(((struct groupRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct groupRecord *)pktBuf)->srcList);
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+
+ groupAddress[0]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[0]);
+ groupAddress[1]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[1]);
+ groupAddress[2]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[2]);
+ groupAddress[3]=ntohl(((struct mCastAddrRecord *)pktBuf)->mCastAddr[3]);
+
+ numOfSrc=ntohs(((struct mCastAddrRecord *)pktBuf)->numOfSrc);
+ sourceAddr=&(((struct mCastAddrRecord *)pktBuf)->srcList);
+ }
+#endif
+
+ hashIndex=rtl_igmpHashAlgorithm( ipVersion, groupAddress);
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex, ipVersion, groupAddress);
+
+ if(groupEntry==NULL)
+ {
+ goto out;
+ }
+
+ clientEntry=rtl_searchClientEntry(ipVersion, groupEntry, portNum, clientAddr);
+ if(clientEntry==NULL)
+ {
+ goto out;
+ }
+
+ clientEntry->igmpVersion=IGMP_V3;
+
+ if(clientEntry->groupFilterTimer>rtl_sysUpSeconds) /*means exclude mode*/
+ {
+
+ for(j=0; j<numOfSrc; j++)
+ {
+
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,clientEntry);
+
+ if(sourceEntry==NULL)
+ {
+ newSourceEntry=rtl_allocateSourceEntry();
+ if(newSourceEntry==NULL)
+ {
+ rtl_gluePrintf("run out of source entry!\n");
+ return FAILED;
+ }
+
+
+ if(ipVersion==IP_VERSION4)
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ newSourceEntry->sourceAddr[0]=sourceAddr[0];
+ newSourceEntry->sourceAddr[1]=sourceAddr[1];
+ newSourceEntry->sourceAddr[2]=sourceAddr[2];
+ newSourceEntry->sourceAddr[3]=sourceAddr[3];
+ }
+#endif
+ newSourceEntry->portTimer=rtl_sysUpSeconds;
+ rtl_linkSourceEntry(clientEntry,newSourceEntry);
+ }
+ else
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ sourceEntry->portTimer=rtl_sysUpSeconds;
+ }
+ else
+ {
+ if(sourceEntry->portTimer>rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime)
+ {
+ sourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+ }
+ }
+
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+
+ }
+ else /*means include mode*/
+ {
+
+ for(j=0; j<numOfSrc; j++)
+ {
+ sourceEntry=rtl_searchSourceEntry(ipVersion, sourceAddr,clientEntry);
+ if(sourceEntry!=NULL)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ sourceEntry->portTimer=rtl_sysUpSeconds;
+ }
+ else
+ {
+ if(sourceEntry->portTimer>rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime)
+ {
+ sourceEntry->portTimer=rtl_sysUpSeconds+rtl_mCastTimerParas.lastMemberAgingTime;
+ }
+
+ }
+
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ sourceAddr++;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ sourceAddr=sourceAddr+4;
+ }
+#endif
+ }
+
+ }
+
+#if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if((groupEntry!=NULL) && (groupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ return SUCCESS;
+ }
+#endif
+
+out:
+
+ reportEventContext.ipVersion=ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ reportEventContext.groupAddr[1]=groupAddress[1];
+ reportEventContext.groupAddr[2]=groupAddress[2];
+ reportEventContext.groupAddr[3]=groupAddress[3];
+ #else
+ reportEventContext.groupAddr[0]=groupAddress[0];
+ #endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ if(rtl_mCastModuleArray[moduleIndex].enableFastLeave==TRUE)
+ {
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+
+ }
+ #endif
+
+ return SUCCESS;
+
+}
+
+
+static uint32 rtl_processIgmpv3Mldv2Reports(uint32 moduleIndex, uint32 ipVersion, uint32 portNum,uint32 *clientAddr, uint8 *pktBuf)
+{
+ uint32 i=0;
+ uint16 numOfRecords=0;
+ uint8 *groupRecords=NULL;
+ uint8 recordType=0xff;
+ uint16 numOfSrc=0;
+ int32 returnVal=0;
+ //uint32 multicastRouterPortMask=rtl_getMulticastRouterPortMask(moduleIndex, ipVersion, rtl_sysUpSeconds);
+
+ if(ipVersion==IP_VERSION4)
+ {
+ numOfRecords=ntohs(((struct igmpv3Report *)pktBuf)->numOfRecords);
+ if(numOfRecords!=0)
+ {
+ groupRecords=(uint8 *)(&(((struct igmpv3Report *)pktBuf)->recordList));
+ }
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ numOfRecords=ntohs(((struct mldv2Report *)pktBuf)->numOfRecords);
+ if(numOfRecords!=0)
+ {
+ groupRecords=(uint8 *)(&(((struct mldv2Report *)pktBuf)->recordList));
+ }
+ }
+#endif
+
+ for(i=0; i<numOfRecords; i++)
+ {
+ if(ipVersion==IP_VERSION4)
+ {
+ recordType=((struct groupRecord *)groupRecords)->type;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ recordType=((struct mCastAddrRecord *)groupRecords)->type;
+ }
+#endif
+
+ switch(recordType)
+ {
+ case MODE_IS_INCLUDE:
+ returnVal=rtl_processIsInclude(moduleIndex, ipVersion, portNum, clientAddr, groupRecords);
+ break;
+
+ case MODE_IS_EXCLUDE:
+ returnVal=rtl_processIsExclude(moduleIndex, ipVersion, portNum, clientAddr, groupRecords);
+ break;
+
+ case CHANGE_TO_INCLUDE_MODE:
+ returnVal=rtl_processToInclude(moduleIndex, ipVersion, portNum, clientAddr, groupRecords);
+ break;
+
+ case CHANGE_TO_EXCLUDE_MODE:
+ returnVal=rtl_processToExclude(moduleIndex, ipVersion, portNum, clientAddr, groupRecords);
+ break;
+
+ case ALLOW_NEW_SOURCES:
+ returnVal=rtl_processAllow(moduleIndex, ipVersion, portNum, clientAddr, groupRecords);
+ break;
+
+ case BLOCK_OLD_SOURCES:
+ returnVal=rtl_processBlock(moduleIndex, ipVersion, portNum, clientAddr ,groupRecords);
+ break;
+
+ default:break;
+
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ numOfSrc=ntohs(((struct groupRecord *)groupRecords)->numOfSrc);
+ /*shift pointer to another group record*/
+ groupRecords=groupRecords+8+numOfSrc*4+(((struct groupRecord *)(groupRecords))->auxLen)*4;
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ numOfSrc=ntohs(((struct mCastAddrRecord *)groupRecords)->numOfSrc);
+ /*shift pointer to another group record*/
+ groupRecords=groupRecords+20+numOfSrc*16+(((struct mCastAddrRecord *)(groupRecords))->auxLen)*4;
+ }
+#endif
+ }
+
+ /*no report supress, due to multiple group record in igmpv3 report*/
+ return ((~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+ //return (multicastRouterPortMask&(~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+
+}
+
+static uint32 rtl_processIgmpMld(uint32 moduleIndex, uint32 ipVersion, uint32 portNum,uint32 *clientAddr, uint8* pktBuf, uint32 pktLen)
+{
+ uint32 fwdPortMask=0;
+
+ reportEventContext.moduleIndex=moduleIndex;
+
+ switch(pktBuf[0])
+ {
+ case IGMP_QUERY:
+ fwdPortMask=rtl_processQueries(moduleIndex, ipVersion, portNum, pktBuf, pktLen);
+ break;
+
+ case IGMPV1_REPORT:
+ fwdPortMask=rtl_processJoin(moduleIndex, ipVersion, portNum,clientAddr,pktBuf);
+ break;
+
+ case IGMPV2_REPORT:
+ fwdPortMask=rtl_processJoin(moduleIndex, ipVersion, portNum,clientAddr, pktBuf);
+ break;
+
+ case IGMPV2_LEAVE:
+ fwdPortMask=rtl_processLeave(moduleIndex, ipVersion, portNum, clientAddr,pktBuf);
+ break;
+
+ case IGMPV3_REPORT:
+ fwdPortMask=rtl_processIgmpv3Mldv2Reports(moduleIndex, ipVersion, portNum, clientAddr, pktBuf);
+ break;
+
+ case MLD_QUERY:
+ fwdPortMask=rtl_processQueries(moduleIndex, ipVersion, portNum, pktBuf, pktLen);
+ break;
+
+ case MLDV1_REPORT:
+ fwdPortMask=rtl_processJoin(moduleIndex, ipVersion, portNum, clientAddr, pktBuf);
+ break;
+
+ case MLDV1_DONE:
+ fwdPortMask=rtl_processLeave(moduleIndex, ipVersion, portNum, clientAddr, pktBuf);
+ break;
+
+ case MLDV2_REPORT:
+ fwdPortMask=rtl_processIgmpv3Mldv2Reports(moduleIndex, ipVersion, portNum, clientAddr, pktBuf);
+ break;
+
+ default:
+ fwdPortMask=((~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+ break;
+ }
+
+ return fwdPortMask;
+
+}
+
+
+
+static uint32 rtl_processDvmrp(uint32 moduleIndex, uint32 ipVersion,uint32 portNum, uint8* pktBuf, uint32 pktLen)
+{
+
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.dvmrpRouter.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.dvmrpRouterAgingTime; /*update timer*/
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+
+ reportEventContext.ipVersion=ipVersion;
+ reportEventContext.groupAddr[0]=0;
+ reportEventContext.groupAddr[1]=0;
+ reportEventContext.groupAddr[2]=0;
+ reportEventContext.groupAddr[3]=0;
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ #endif
+ }
+
+ return ((~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+
+}
+
+static uint32 rtl_processMospf(uint32 moduleIndex,uint32 ipVersion,uint32 portNum, uint8* pktBuf, uint32 pktLen)
+{
+ struct ipv4MospfHdr *ipv4MospfHeader=(struct ipv4MospfHdr*)pktBuf;
+ struct ipv4MospfHello *ipv4HelloPkt=(struct ipv4MospfHello*)pktBuf;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ struct ipv6MospfHdr *ipv6MospfHeader=(struct ipv6MospfHdr*)pktBuf;
+ struct ipv6MospfHello *ipv6HelloPkt=(struct ipv6MospfHello*)pktBuf;
+#endif
+
+
+ if(ipVersion==IP_VERSION4)
+ {
+ /*mospf is built based on ospfv2*/
+ if((ipv4MospfHeader->version==2) && (ipv4MospfHeader->type==MOSPF_HELLO_TYPE))
+ {
+ if((ipv4HelloPkt->options & 0x04)!=0)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.mospfRouter.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.mospfRouterAgingTime; /*update timer*/
+ }
+ }
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ if((ipv6MospfHeader->version==3) && (ipv6MospfHeader->type==MOSPF_HELLO_TYPE))
+ {
+ if((ipv6HelloPkt->options[2] & 0x04)!=0)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.mospfRouter.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.mospfRouterAgingTime; /*update timer*/
+
+ }
+ }
+ }
+#endif
+
+
+
+ reportEventContext.ipVersion=ipVersion;
+ reportEventContext.groupAddr[0]=0;
+ reportEventContext.groupAddr[1]=0;
+ reportEventContext.groupAddr[2]=0;
+ reportEventContext.groupAddr[3]=0;
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return ((~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+
+}
+
+static uint32 rtl_processPim(uint32 moduleIndex, uint32 ipVersion, uint32 portNum, uint8* pktBuf, uint32 pktLen)
+{
+ if(ipVersion==IP_VERSION4)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters.pimRouter.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.pimRouterAgingTime; /*update timer*/
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters.pimRouter.portTimer[portNum]=rtl_sysUpSeconds+rtl_mCastTimerParas.pimRouterAgingTime; /*update timer*/
+ }
+#endif
+
+
+
+ reportEventContext.ipVersion=ipVersion;
+ reportEventContext.groupAddr[0]=0;
+ reportEventContext.groupAddr[1]=0;
+ reportEventContext.groupAddr[2]=0;
+ reportEventContext.groupAddr[3]=0;
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(ipVersion==IP_VERSION4)
+ {
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return ((~(1<<portNum))&((1<<MAX_SUPPORT_PORT_NUMBER)-1));
+}
+
+
+
+/*********************************************
+ External Function
+ *********************************************/
+
+
+//External called function by high level program
+
+int32 rtl_registerIgmpSnoopingModule(uint32 *moduleIndex)
+{
+ int32 i=0;
+ uint32 index=0xFFFFFFFF;
+
+ *moduleIndex=0xFFFFFFFF;
+
+ for(i=0; i<MAX_MCAST_MODULE_NUM; i++)
+ {
+ if(rtl_mCastModuleArray[i].enableSnooping==FALSE)
+ {
+ index=i;
+ break;
+ }
+ }
+
+ if(i>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+
+ if(rtl_mCastModuleArray[index].enableSnooping==FALSE)
+ {
+ /*initialize multicast Routers information*/
+ for(i=0; i<MAX_SUPPORT_PORT_NUMBER; i++)
+ {
+ rtl_mCastModuleArray[index].rtl_ipv4MulticastRouters.querier.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv4MulticastRouters.dvmrpRouter.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv4MulticastRouters.pimRouter.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv4MulticastRouters.mospfRouter.portTimer[i]=0;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ rtl_mCastModuleArray[index].rtl_ipv6MulticastRouters.querier.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv6MulticastRouters.dvmrpRouter.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv6MulticastRouters.pimRouter.portTimer[i]=0;
+ rtl_mCastModuleArray[index].rtl_ipv6MulticastRouters.mospfRouter.portTimer[i]=0;
+#endif
+ }
+
+ /*initialize hash table*/
+ rtl_initHashTable(index, rtl_hashTableSize);
+
+ if((rtl_mCastModuleArray[index].rtl_ipv4HashTable==NULL) )
+ {
+ return FAILED;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if(rtl_mCastModuleArray[index].rtl_ipv6HashTable==NULL)
+ {
+ return FAILED;
+ }
+#endif
+
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ memset(&rtl_mCastModuleArray[index].deviceInfo,0, sizeof(rtl_multicastDeviceInfo_t));
+#endif
+ for(i=0; i<6; i++)
+ {
+ rtl_mCastModuleArray[index].rtl_gatewayMac[i]=0;
+ }
+
+ rtl_mCastModuleArray[index]. rtl_gatewayIpv4Addr=0;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ for(i=0; i<4; i++)
+ {
+ rtl_mCastModuleArray[index].rtl_gatewayIpv6Addr[i]=0;
+ }
+#endif
+ rtl_mCastModuleArray[index].enableFastLeave=FALSE;
+ rtl_mCastModuleArray[index].enableSnooping=TRUE;
+ rtl_mCastModuleArray[index].ipv4UnknownMCastFloodMap=DEFAULT_IPV4_UNKNOWN_MCAST_FLOOD_MAP;
+ rtl_mCastModuleArray[index].ipv6UnknownMCastFloodMap=DEFAULT_IPV6_UNKNOWN_MCAST_FLOOD_MAP;
+ rtl_mCastModuleArray[index].staticRouterPortMask=0;
+#ifdef CONFIG_PROC_FS
+ rtl_mCastModuleArray[index].expireEventCnt=0;
+#endif
+ *moduleIndex=index;
+
+ return SUCCESS;
+ }
+ else
+ {
+ return FAILED;
+ }
+
+ *moduleIndex=index;
+ *moduleIndex=index;
+ return SUCCESS;
+}
+
+
+
+int32 rtl_unregisterIgmpSnoopingModule(uint32 moduleIndex)
+{
+ uint32 i=0;
+ struct rtl_groupEntry *groupEntryPtr=NULL;
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ struct rtl_mcastFlowEntry *mcastFlowEntryPtr=NULL;
+ #endif
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv4Addr=0;
+
+ for(i=0; i<6; i++)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[i]=0;
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ for(i=0;i<4;i++)
+ {
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[i]=0;
+ }
+#endif
+
+ /*delete ipv4 multicast entry*/
+ for(i=0;i<rtl_hashTableSize;i++)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+
+ while(groupEntryPtr!=NULL)
+ {
+ rtl_deleteGroupEntry(groupEntryPtr, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+ }
+ }
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable=NULL;
+ memset(&(rtl_mCastModuleArray[moduleIndex].rtl_ipv4MulticastRouters), 0, sizeof(struct rtl_multicastRouters));
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ /*delete ipv6 multicast entry*/
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i];
+ while(groupEntryPtr!=NULL)
+ {
+ rtl_deleteGroupEntry(groupEntryPtr, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i];
+ }
+ }
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable=NULL;
+ memset(&(rtl_mCastModuleArray[moduleIndex].rtl_ipv6MulticastRouters), 0, sizeof(struct rtl_multicastRouters));
+#endif
+
+#ifdef CONFIG_RECORD_MCAST_FLOW
+ /*delete multicast flow entry*/
+ for(i=0;i<rtl_hashTableSize;i++)
+ {
+ mcastFlowEntryPtr=rtl_mCastModuleArray[moduleIndex].flowHashTable[i];
+
+ while(mcastFlowEntryPtr!=NULL)
+ {
+ rtl_deleteMcastFlowEntry(mcastFlowEntryPtr, rtl_mCastModuleArray[moduleIndex].flowHashTable);
+ mcastFlowEntryPtr=rtl_mCastModuleArray[moduleIndex].flowHashTable[i];
+ }
+ }
+ rtl_glueFree(rtl_mCastModuleArray[moduleIndex].flowHashTable);
+ rtl_mCastModuleArray[moduleIndex].flowHashTable=NULL;
+#endif
+ rtl_mCastModuleArray[moduleIndex].enableSnooping=FALSE;
+ rtl_mCastModuleArray[moduleIndex].enableFastLeave=FALSE;
+ rtl_mCastModuleArray[moduleIndex].ipv4UnknownMCastFloodMap=0;
+ rtl_mCastModuleArray[moduleIndex].ipv6UnknownMCastFloodMap=0;
+ rtl_mCastModuleArray[moduleIndex].staticRouterPortMask=0;
+
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ memset(&rtl_mCastModuleArray[moduleIndex].deviceInfo,0,sizeof(rtl_multicastDeviceInfo_t));
+#endif
+ return SUCCESS;
+ }
+
+ return SUCCESS;
+
+}
+
+static void _rtl865x_configIgmpSnoopingExpire(int32 disableExpire)
+{
+ uint32 maxTime=0xffffffff;
+
+ if((rtl_mCastTimerParas.disableExpire==FALSE) && (disableExpire==TRUE))
+ {
+ rtl_mCastTimerParas.disableExpire=TRUE;
+ }
+
+ if((rtl_mCastTimerParas.disableExpire==TRUE) && (disableExpire==FALSE) )
+ {
+#if defined(__linux__) && defined(__KERNEL__)
+ struct timeval currentTimeVector;
+ do_gettimeofday(&currentTimeVector);
+ /*reset start time*/
+ if(currentTimeVector.tv_sec>=rtl_sysUpSeconds)
+ {
+ rtl_startTime=(uint32)(currentTimeVector.tv_sec)-rtl_sysUpSeconds;
+ }
+ else
+ {
+ /*avoid timer wrap back*/
+ rtl_startTime=maxTime-rtl_sysUpSeconds+(uint32)(currentTimeVector.tv_sec)+1;
+ }
+#endif
+ rtl_mCastTimerParas.disableExpire=FALSE;
+ }
+
+
+ return;
+}
+
+//External called function by high level program
+void rtl_setMulticastParameters(struct rtl_mCastTimerParameters mCastTimerParameters)
+{
+ _rtl865x_configIgmpSnoopingExpire(mCastTimerParameters.disableExpire);
+
+ if(mCastTimerParameters.groupMemberAgingTime!=0)
+ {
+ rtl_mCastTimerParas.groupMemberAgingTime= mCastTimerParameters.groupMemberAgingTime;
+ }
+
+ if(mCastTimerParameters.lastMemberAgingTime!=0)
+ {
+ rtl_mCastTimerParas.lastMemberAgingTime= mCastTimerParameters.lastMemberAgingTime;
+ }
+
+ if(mCastTimerParameters.querierPresentInterval!=0)
+ {
+
+ rtl_mCastTimerParas.querierPresentInterval=mCastTimerParameters.querierPresentInterval;
+ }
+
+
+ if(mCastTimerParameters.dvmrpRouterAgingTime!=0)
+ {
+
+ rtl_mCastTimerParas.dvmrpRouterAgingTime=mCastTimerParameters.dvmrpRouterAgingTime;
+ }
+
+ if(mCastTimerParameters.mospfRouterAgingTime!=0)
+ {
+
+ rtl_mCastTimerParas.mospfRouterAgingTime=mCastTimerParameters.mospfRouterAgingTime;
+ }
+
+ if(mCastTimerParameters.pimRouterAgingTime!=0)
+ {
+
+ rtl_mCastTimerParas.pimRouterAgingTime=mCastTimerParameters.pimRouterAgingTime;
+ }
+
+ return;
+}
+
+
+int32 rtl_configIgmpSnoopingModule(uint32 moduleIndex, struct rtl_mCastSnoopingLocalConfig *mCastSnoopingLocalConfig)
+{
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(mCastSnoopingLocalConfig==NULL)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ rtl_mCastModuleArray[moduleIndex].enableFastLeave=mCastSnoopingLocalConfig->enableFastLeave;
+ rtl_mCastModuleArray[moduleIndex].ipv4UnknownMCastFloodMap=mCastSnoopingLocalConfig->ipv4UnknownMcastFloodMap;
+ rtl_mCastModuleArray[moduleIndex].ipv6UnknownMCastFloodMap=mCastSnoopingLocalConfig->ipv6UnknownMcastFloodMap;
+ rtl_mCastModuleArray[moduleIndex].staticRouterPortMask=mCastSnoopingLocalConfig->staticRouterPortMask;
+
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[0]=mCastSnoopingLocalConfig->gatewayMac[0];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[1]=mCastSnoopingLocalConfig->gatewayMac[1];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[2]=mCastSnoopingLocalConfig->gatewayMac[2];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[3]=mCastSnoopingLocalConfig->gatewayMac[3];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[4]=mCastSnoopingLocalConfig->gatewayMac[4];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayMac[5]=mCastSnoopingLocalConfig->gatewayMac[5];
+
+
+
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv4Addr=mCastSnoopingLocalConfig->gatewayIpv4Addr;
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[0]=mCastSnoopingLocalConfig->gatewayIpv6Addr[0];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[1]=mCastSnoopingLocalConfig->gatewayIpv6Addr[1];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[2]=mCastSnoopingLocalConfig->gatewayIpv6Addr[2];
+ rtl_mCastModuleArray[moduleIndex].rtl_gatewayIpv6Addr[3]=mCastSnoopingLocalConfig->gatewayIpv6Addr[3];
+#endif
+ return SUCCESS;
+}
+
+/*
+@func int32 | rtl_maintainMulticastSnoopingTimerList | Multicast snooping timer list maintenance function.
+@parm uint32 | currentSystemTime |The current system time (unit: seconds).
+@rvalue SUCCESS |Always return SUCCESS.
+@comm
+ This function should be called once a second to maintain multicast timer list.
+*/
+int32 rtl_maintainMulticastSnoopingTimerList(uint32 currentSystemTime)
+{
+ /* maintain current time */
+ uint32 i=0;
+ uint32 maxTime=0xffffffff;
+
+ struct rtl_groupEntry* groupEntryPtr=NULL;
+ struct rtl_groupEntry* nextEntry=NULL;
+
+ uint32 moduleIndex;
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM; moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ if((currentSystemTime%DEFAULT_MCAST_FLOW_EXPIRE_TIME)==0)
+ {
+ rtl_doMcastFlowRecycle(moduleIndex, BOTH_IPV4_IPV6);
+ }
+
+ }
+ }
+ #endif
+
+ if(rtl_mCastTimerParas.disableExpire==TRUE)
+ {
+ return SUCCESS;
+ }
+
+ /*handle timer conter overflow*/
+ if(currentSystemTime>rtl_startTime)
+ {
+ rtl_sysUpSeconds=currentSystemTime-rtl_startTime;
+ }
+ else
+ {
+ rtl_sysUpSeconds=(maxTime-rtl_startTime)+currentSystemTime+1;
+ }
+
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM; moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ strcpy(timerEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ timerEventContext.moduleIndex=moduleIndex;
+ #endif
+
+ /*maintain ipv4 group entry timer */
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+ /*scan the hash table*/
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable!=NULL)
+ {
+ timerEventContext.ipVersion=IP_VERSION4;
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[i];
+ while(groupEntryPtr) /*traverse each group list*/
+ {
+ nextEntry=groupEntryPtr->next;
+ timerEventContext.groupAddr[0]=groupEntryPtr->groupAddr[0];
+ timerEventContext.groupAddr[1]=0;
+ timerEventContext.groupAddr[2]=0;
+ timerEventContext.groupAddr[3]=0;
+ rtl_checkGroupEntryTimer(groupEntryPtr, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ groupEntryPtr=nextEntry;/*because expired group entry will be cleared*/
+ }
+ }
+ }
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ /*maintain ipv6 group entry timer */
+ for(i=0; i<rtl_hashTableSize; i++)
+ {
+ /*scan the hash table*/
+ if(rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable!=NULL)
+ {
+ timerEventContext.ipVersion=IP_VERSION6;
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[i];
+ while(groupEntryPtr) /*traverse each group list*/
+ {
+ nextEntry=groupEntryPtr->next;
+ timerEventContext.groupAddr[0]=groupEntryPtr->groupAddr[0];
+ timerEventContext.groupAddr[1]=groupEntryPtr->groupAddr[1];
+ timerEventContext.groupAddr[2]=groupEntryPtr->groupAddr[2];
+ timerEventContext.groupAddr[3]=groupEntryPtr->groupAddr[3];
+ rtl_checkGroupEntryTimer(groupEntryPtr, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ groupEntryPtr=nextEntry;/*because expired group entry will be cleared*/
+ }
+ }
+ }
+#endif
+
+ }
+ }
+ return SUCCESS;
+}
+
+
+
+int32 rtl_igmpMldProcess(uint32 moduleIndex, uint8 * macFrame, uint32 portNum, uint32 *fwdPortMask)
+{
+
+ struct rtl_macFrameInfo macFrameInfo;
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ reportEventContext.portMask=1<<portNum;
+ #endif
+
+ *fwdPortMask=(~(1<<portNum)) & 0xFFFFFFFF;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ //rtl_parseMacFrame(moduleIndex, macFrame, TRUE, &macFrameInfo);
+ rtl_parseMacFrame(moduleIndex, macFrame, FALSE, &macFrameInfo);
+ if( rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ if(macFrameInfo.ipBuf==NULL)
+ {
+ return FAILED;
+ }
+
+ if((macFrameInfo.ipVersion!=IP_VERSION4) && (macFrameInfo.ipVersion!=IP_VERSION6))
+ {
+
+ return FAILED;
+ }
+
+#ifndef CONFIG_RTL_MLD_SNOOPING
+ if (macFrameInfo.ipVersion==IP_VERSION6)
+ {
+ return FAILED;
+ }
+#endif
+ /*port num starts from 0*/
+ if(portNum>=MAX_SUPPORT_PORT_NUMBER)
+ {
+ return FAILED;
+ }
+
+ if(macFrameInfo.checksumFlag!=SUCCESS)
+ {
+ return FAILED;
+ }
+
+ switch(macFrameInfo.l3Protocol)
+ {
+
+ case IGMP_PROTOCOL:
+ *fwdPortMask=rtl_processIgmpMld(moduleIndex, (uint32)(macFrameInfo.ipVersion), portNum, macFrameInfo.srcIpAddr, macFrameInfo.l3PktBuf, macFrameInfo.l3PktLen);
+ break;
+
+ case ICMP_PROTOCOL:
+ *fwdPortMask=rtl_processIgmpMld(moduleIndex, (uint32)(macFrameInfo.ipVersion),portNum, macFrameInfo.srcIpAddr, macFrameInfo.l3PktBuf, macFrameInfo.l3PktLen);
+ break;
+
+
+ case DVMRP_PROTOCOL:
+ *fwdPortMask=rtl_processDvmrp(moduleIndex, (uint32)(macFrameInfo.ipVersion), portNum, macFrameInfo.l3PktBuf, macFrameInfo.l3PktLen);
+ break;
+
+ case MOSPF_PROTOCOL:
+ *fwdPortMask=rtl_processMospf(moduleIndex, (uint32)(macFrameInfo.ipVersion), portNum, macFrameInfo.l3PktBuf, macFrameInfo.l3PktLen);
+ break;
+
+ case PIM_PROTOCOL:
+ *fwdPortMask=rtl_processPim(moduleIndex, (uint32)(macFrameInfo.ipVersion),portNum, macFrameInfo.l3PktBuf, macFrameInfo.l3PktLen);
+ break;
+
+ default: break;
+ }
+
+ rtl_setClientMacAddr(&macFrameInfo);
+ }
+
+ return SUCCESS;
+}
+
+#ifdef CONFIG_RECORD_MCAST_FLOW
+static int32 rtl_recordMcastFlow(uint32 moduleIndex,uint32 ipVersion, uint32 *sourceIpAddr, uint32 *groupAddr, struct rtl_multicastFwdInfo * multicastFwdInfo)
+{
+ struct rtl_mcastFlowEntry *mcastFlowEntry=NULL;
+
+ if(multicastFwdInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ mcastFlowEntry=rtl_searchMcastFlowEntry(moduleIndex, ipVersion, sourceIpAddr, groupAddr);
+
+ if(mcastFlowEntry==NULL)
+ {
+
+ mcastFlowEntry=rtl_allocateMcastFlowEntry();
+ if(mcastFlowEntry==NULL)
+ {
+ rtl_doMcastFlowRecycle(moduleIndex, ipVersion);
+
+ mcastFlowEntry=rtl_allocateMcastFlowEntry();
+ if(mcastFlowEntry==NULL)
+ {
+ rtl_gluePrintf("run out of multicast flow entry!\n");
+ return FAILED;
+ }
+ }
+
+ if(ipVersion==IP_VERSION4)
+ {
+ mcastFlowEntry->serverAddr[0]=sourceIpAddr[0];
+ mcastFlowEntry->groupAddr[0]=groupAddr[0];
+
+ }
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ mcastFlowEntry->serverAddr[0]=sourceIpAddr[0];
+ mcastFlowEntry->serverAddr[1]=sourceIpAddr[1];
+ mcastFlowEntry->serverAddr[2]=sourceIpAddr[2];
+ mcastFlowEntry->serverAddr[3]=sourceIpAddr[3];
+
+ mcastFlowEntry->groupAddr[0]=groupAddr[0];
+ mcastFlowEntry->groupAddr[1]=groupAddr[1];
+ mcastFlowEntry->groupAddr[2]=groupAddr[2];
+ mcastFlowEntry->groupAddr[3]=groupAddr[3];
+ }
+#endif
+
+ mcastFlowEntry->ipVersion=ipVersion;
+
+ memcpy(&mcastFlowEntry->multicastFwdInfo, multicastFwdInfo, sizeof(struct rtl_multicastFwdInfo ));
+
+ mcastFlowEntry->refreshTime=rtl_sysUpSeconds;
+
+ rtl_linkMcastFlowEntry(mcastFlowEntry, rtl_mCastModuleArray[moduleIndex].flowHashTable);
+
+ return SUCCESS;
+
+ }
+ else
+ {
+ /*update forward port mask information */
+ memcpy(&mcastFlowEntry->multicastFwdInfo, multicastFwdInfo, sizeof(struct rtl_multicastFwdInfo ));
+ mcastFlowEntry->refreshTime=rtl_sysUpSeconds;
+ return SUCCESS;
+ }
+
+ return SUCCESS;
+}
+
+static void rtl_invalidateMCastFlow(uint32 moduleIndex,uint32 ipVersion, uint32 *groupAddr)
+{
+ uint32 hashIndex;
+ struct rtl_mcastFlowEntry* mcastFlowEntry = NULL;
+ struct rtl_mcastFlowEntry* nextMcastFlowEntry = NULL;
+
+ if(NULL==groupAddr)
+ {
+ return ;
+ }
+
+
+ hashIndex=rtl_igmpHashAlgorithm(ipVersion, groupAddr);
+
+ mcastFlowEntry=rtl_mCastModuleArray[moduleIndex].flowHashTable[hashIndex];
+
+ while (mcastFlowEntry!=NULL)
+ {
+ nextMcastFlowEntry=mcastFlowEntry->next;
+
+ if(ipVersion==mcastFlowEntry->ipVersion)
+ {
+
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if((groupAddr[0]==0)&&(groupAddr[1]==0)&&(groupAddr[2]==0)&&(groupAddr[3]==0))
+#else
+ if(groupAddr[0]==0)
+#endif
+ {
+ rtl_deleteMcastFlowEntry(mcastFlowEntry, rtl_mCastModuleArray[moduleIndex].flowHashTable);
+ }
+ else
+ {
+#ifdef CONFIG_RTL_MLD_SNOOPING
+ if ( (mcastFlowEntry->groupAddr[0]==groupAddr[0])&&(mcastFlowEntry->groupAddr[1]==groupAddr[1])&&
+ (mcastFlowEntry->groupAddr[2]==groupAddr[2])&&(mcastFlowEntry->groupAddr[3]==groupAddr[3]) )
+#else
+ if(mcastFlowEntry->groupAddr[0] == groupAddr[0])
+#endif
+ {
+ rtl_deleteMcastFlowEntry(mcastFlowEntry, rtl_mCastModuleArray[moduleIndex].flowHashTable);
+ }
+ }
+
+
+
+ }
+
+ mcastFlowEntry = nextMcastFlowEntry;
+ }
+
+ return ;
+
+}
+
+static void rtl_doMcastFlowRecycle(uint32 moduleIndex, uint32 ipVersion)
+{
+ uint32 i;
+ uint32 freeCnt=0;
+ struct rtl_mcastFlowEntry* mcastFlowEntry = NULL;
+ struct rtl_mcastFlowEntry* nextMcastFlowEntry = NULL;
+ struct rtl_mcastFlowEntry* oldestMcastFlowEntry = NULL;
+
+
+ for (i = 0 ; i < rtl_hashTableSize ; i++)
+ {
+ mcastFlowEntry=rtl_mCastModuleArray[moduleIndex].flowHashTable[i];
+
+ if(oldestMcastFlowEntry==NULL)
+ {
+ oldestMcastFlowEntry=mcastFlowEntry;
+ }
+
+ while (mcastFlowEntry!=NULL)
+ {
+ nextMcastFlowEntry=mcastFlowEntry->next;
+ /*keep the most recently used entry*/
+ if((mcastFlowEntry->refreshTime+DEFAULT_MCAST_FLOW_EXPIRE_TIME) < rtl_sysUpSeconds)
+ {
+ rtl_deleteMcastFlowEntry(mcastFlowEntry, rtl_mCastModuleArray[moduleIndex].flowHashTable);
+ freeCnt++;
+ }
+ mcastFlowEntry=nextMcastFlowEntry;
+
+ }
+ }
+
+ if(freeCnt>0)
+ {
+ return;
+ }
+
+ /*if too many concurrent flow,we have to do LRU*/
+ for (i = 0 ; i < rtl_hashTableSize ; i++)
+ {
+ mcastFlowEntry=rtl_mCastModuleArray[moduleIndex].flowHashTable[i];
+
+ if(oldestMcastFlowEntry==NULL)
+ {
+ oldestMcastFlowEntry=mcastFlowEntry;
+ }
+
+ while (mcastFlowEntry!=NULL)
+ {
+ nextMcastFlowEntry=mcastFlowEntry->next;
+ if(mcastFlowEntry->refreshTime < oldestMcastFlowEntry->refreshTime)
+ {
+ oldestMcastFlowEntry=mcastFlowEntry;
+ }
+
+ mcastFlowEntry=nextMcastFlowEntry;
+
+ }
+ }
+
+ if(oldestMcastFlowEntry!=NULL)
+ {
+ rtl_deleteMcastFlowEntry(oldestMcastFlowEntry, rtl_mCastModuleArray[moduleIndex].flowHashTable);
+
+ }
+
+ return ;
+
+}
+
+#endif
+#if 0
+int32 rtl_getMulticastDataFwdPortMask(uint32 moduleIndex, struct rtl_multicastDataInfo *multicastDataInfo, uint32 *fwdPortMask)
+{
+ int32 retVal=FAILED;
+ struct rtl_multicastFwdInfo multicastFwdInfo;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(multicastDataInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ if(fwdPortMask==NULL)
+ {
+ return FAILED;
+ }
+
+ retVal=rtl_getMulticastDataFwdInfo( moduleIndex, multicastDataInfo, &multicastFwdInfo);
+
+ *fwdPortMask=multicastFwdInfo.fwdPortMask;
+
+ if(retVal==SUCCESS)
+ {
+ if(multicastFwdInfo.unknownMCast==TRUE)
+ {
+ return FAILED;
+ }
+ else
+ {
+ return SUCCESS;
+ }
+ }
+
+ return FAILED;
+
+}
+#endif
+
+int32 rtl_getMulticastDataFwdInfo(uint32 moduleIndex, struct rtl_multicastDataInfo *multicastDataInfo, struct rtl_multicastFwdInfo *multicastFwdInfo)
+{
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ struct rtl_mcastFlowEntry *mcastFlowEntry=NULL;
+ #endif
+ struct rtl_groupEntry * groupEntry=NULL;
+ uint32 multicastRouterPortMask=0;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(multicastDataInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ if(multicastFwdInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ memset(multicastFwdInfo, 0, sizeof(struct rtl_multicastFwdInfo));
+
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ mcastFlowEntry=rtl_searchMcastFlowEntry( moduleIndex, multicastDataInfo->ipVersion, multicastDataInfo->sourceIp, multicastDataInfo->groupAddr);
+ if(mcastFlowEntry!=NULL)
+ {
+ memcpy(multicastFwdInfo, &mcastFlowEntry->multicastFwdInfo, sizeof(struct rtl_multicastFwdInfo));
+ return SUCCESS;
+ }
+ #endif
+
+ groupEntry=rtl_searchGroupEntry(moduleIndex,multicastDataInfo->ipVersion, multicastDataInfo->groupAddr);
+
+ if(groupEntry==NULL)
+ {
+ if( (multicastDataInfo->groupAddr[0]==RESERVE_MULTICAST_ADDR1) ||
+ (multicastDataInfo->groupAddr[0]==RESERVE_MULTICAST_ADDR2) )
+ {
+ multicastFwdInfo->unknownMCast=FALSE;
+ multicastFwdInfo->reservedMCast=TRUE;
+ multicastFwdInfo->fwdPortMask=0xFFFFFFFF;
+ multicastFwdInfo->cpuFlag=TRUE;
+
+ return FAILED;
+ }
+ #if 0
+ else if(IN_MULTICAST_RESV1(multicastDataInfo->groupAddr[0]) )
+ {
+ multicastFwdInfo->unknownMCast=FALSE;
+ multicastFwdInfo->reservedMCast=TRUE;
+ multicastFwdInfo->fwdPortMask=0xFFFFFFFF;
+ multicastFwdInfo->cpuFlag=TRUE;
+
+ return FAILED;
+ }
+ #endif
+
+
+ multicastFwdInfo->unknownMCast=TRUE;
+ if(multicastDataInfo->ipVersion==IP_VERSION4)
+ {
+ multicastFwdInfo->fwdPortMask= rtl_mCastModuleArray[moduleIndex].ipv4UnknownMCastFloodMap;
+ }
+ else if (multicastDataInfo->ipVersion==IP_VERSION6)
+ {
+ multicastFwdInfo->fwdPortMask= rtl_mCastModuleArray[moduleIndex].ipv6UnknownMCastFloodMap;
+ }
+ else
+ {
+ multicastFwdInfo->fwdPortMask=0xFFFFFFFF;
+ }
+
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if((multicastFwdInfo->fwdPortMask & rtl_mCastModuleArray[moduleIndex].deviceInfo.swPortMask)!=0)
+ {
+ multicastFwdInfo->cpuFlag=TRUE;
+ }
+ #endif
+
+ return FAILED;
+ }
+ else
+ {
+ /*step1: handle user specified static reserved multicast entry*/
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if(groupEntry->attribute==STATIC_RESERVED_MULTICAST)
+ {
+ multicastFwdInfo->unknownMCast=FALSE;
+ multicastFwdInfo->reservedMCast=TRUE;
+ multicastFwdInfo->cpuFlag=TRUE;
+ multicastFwdInfo->fwdPortMask=groupEntry->staticFwdPortMask;
+ multicastFwdInfo->fwdPortMask=(multicastFwdInfo->fwdPortMask|multicastRouterPortMask);
+ return FAILED;
+ }
+ #endif
+
+ /*step 2: handle hard-coded reserved multicast address*/
+ if( (multicastDataInfo->groupAddr[0]==RESERVE_MULTICAST_ADDR1) ||
+ (multicastDataInfo->groupAddr[0]==RESERVE_MULTICAST_ADDR2) )
+ {
+ multicastFwdInfo->unknownMCast=FALSE;
+ multicastFwdInfo->reservedMCast=TRUE;
+ multicastFwdInfo->fwdPortMask=0xFFFFFFFF;
+ multicastFwdInfo->cpuFlag=TRUE;
+ return FAILED;
+ }
+ #if 0
+ else if(IN_MULTICAST_RESV1(multicastDataInfo->groupAddr[0]) )
+ {
+ multicastFwdInfo->unknownMCast=FALSE;
+ multicastFwdInfo->reservedMCast=TRUE;
+ multicastFwdInfo->fwdPortMask=0xFFFFFFFF;
+ multicastFwdInfo->cpuFlag=TRUE;
+
+ return FAILED;
+ }
+ #endif
+
+ /*step3:handle normal multicast address */
+
+ /*here to get multicast router port mask and forward port mask*/
+ //multicastRouterPortMask=rtl_getMulticastRouterPortMask(moduleIndex, multicastDataInfo->ipVersion, rtl_sysUpSeconds);
+ multicastFwdInfo->fwdPortMask=rtl_getGroupSourceFwdPortMask(groupEntry, multicastDataInfo->sourceIp, rtl_sysUpSeconds);
+ multicastFwdInfo->fwdPortMask=(multicastFwdInfo->fwdPortMask|multicastRouterPortMask);
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if((multicastFwdInfo->fwdPortMask & rtl_mCastModuleArray[moduleIndex].deviceInfo.swPortMask)!=0)
+ {
+ multicastFwdInfo->cpuFlag=TRUE;
+ }
+ #endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_recordMcastFlow(moduleIndex,multicastDataInfo->ipVersion, multicastDataInfo->sourceIp, multicastDataInfo->groupAddr, multicastFwdInfo);
+ #endif
+ return SUCCESS;
+
+ }
+ return FAILED;
+
+}
+#if defined(__linux__) && defined(__KERNEL__)
+
+static void rtl_multicastSysTimerExpired(uint32 expireDada)
+{
+ struct timeval currentTimeVector;
+
+ do_gettimeofday(&currentTimeVector);
+ rtl_maintainMulticastSnoopingTimerList((uint32)(currentTimeVector.tv_sec));
+ mod_timer(&igmpSysTimer, jiffies+HZ);
+
+}
+
+static void rtl_multicastSysTimerInit(void)
+{
+ struct timeval startTimeVector;
+ do_gettimeofday(&startTimeVector);
+ rtl_startTime=(uint32)(startTimeVector.tv_sec);
+ rtl_sysUpSeconds=0;
+
+ init_timer(&igmpSysTimer);
+ igmpSysTimer.data=igmpSysTimer.expires;
+ igmpSysTimer.expires=jiffies+HZ;
+ igmpSysTimer.function=(void*)rtl_multicastSysTimerExpired;
+ add_timer(&igmpSysTimer);
+}
+
+static void rtl_multicastSysTimerDestroy(void)
+{
+ del_timer(&igmpSysTimer);
+}
+
+#endif
+
+int32 rtl_getDeviceIgmpSnoopingModuleIndex(rtl_multicastDeviceInfo_t *devInfo,uint32 *moduleIndex)
+{
+ int i;
+ *moduleIndex=0xFFFFFFFF;
+ if(devInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ for(i=0; i<MAX_MCAST_MODULE_NUM; i++)
+ {
+ if(rtl_mCastModuleArray[i].enableSnooping==TRUE)
+ {
+ if(strcmp(rtl_mCastModuleArray[i].deviceInfo.devName, devInfo->devName)==0)
+ {
+ *moduleIndex=i;
+ return SUCCESS;
+ }
+ }
+ }
+
+ return FAILED;
+}
+
+int32 rtl865x_getDeviceIgmpSnoopingModuleIndex(rtl_multicastDeviceInfo_t *devInfo,uint32 *moduleIndex)
+{
+ return rtl_getDeviceIgmpSnoopingModuleIndex(devInfo,moduleIndex);
+}
+
+int32 rtl_setIgmpSnoopingModuleDevInfo(uint32 moduleIndex,rtl_multicastDeviceInfo_t *devInfo)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(devInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ memcpy(&rtl_mCastModuleArray[moduleIndex].deviceInfo,devInfo, sizeof(rtl_multicastDeviceInfo_t));
+
+ return SUCCESS;
+}
+
+int32 rtl_getIgmpSnoopingModuleDevInfo(uint32 moduleIndex,rtl_multicastDeviceInfo_t *devInfo)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(devInfo==NULL)
+ {
+ return FAILED;
+ }
+ memset(devInfo,0,sizeof(rtl_multicastDeviceInfo_t));
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ memcpy(devInfo,&rtl_mCastModuleArray[moduleIndex].deviceInfo, sizeof(rtl_multicastDeviceInfo_t));
+ return SUCCESS;
+}
+
+int32 rtl_setIgmpSnoopingModuleStaticRouterPortMask(uint32 moduleIndex,uint32 staticRouterPortMask)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ rtl_mCastModuleArray[moduleIndex].staticRouterPortMask=staticRouterPortMask;
+
+ return SUCCESS;
+}
+
+int32 rtl_getgmpSnoopingModuleStaticRouterPortMask(uint32 moduleIndex,uint32 *staticRouterPortMask)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(staticRouterPortMask==NULL)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ *staticRouterPortMask=rtl_mCastModuleArray[moduleIndex].staticRouterPortMask;
+
+ return SUCCESS;
+}
+
+
+static int32 rtl_syncAllIpv4UnknownMCastFlow(uint32 moduleIndex)
+{
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ /*maintain ipv4 group entry timer */
+ reportEventContext.moduleIndex=moduleIndex;
+ reportEventContext.ipVersion=IP_VERSION4;
+ reportEventContext.groupAddr[0]=0;
+ reportEventContext.groupAddr[1]=0;
+ reportEventContext.groupAddr[2]=0;
+ reportEventContext.groupAddr[3]=0;
+
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ #endif
+
+ }
+ return SUCCESS;
+}
+
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+static int32 rtl_syncAllIpv6UnknownMCastFlow(uint32 moduleIndex)
+{
+ reportEventContext.moduleIndex=moduleIndex;
+ reportEventContext.ipVersion=IP_VERSION6;
+ reportEventContext.groupAddr[0]=0;
+ reportEventContext.groupAddr[1]=0;
+ reportEventContext.groupAddr[2]=0;
+ reportEventContext.groupAddr[3]=0;
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+ }
+
+ return SUCCESS;
+}
+#endif
+
+int32 rtl_setIpv4UnknownMCastFloodMap(uint32 moduleIndex,uint32 unknownMCastFloodMap)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ rtl_mCastModuleArray[moduleIndex].ipv4UnknownMCastFloodMap=unknownMCastFloodMap;
+
+ rtl_syncAllIpv4UnknownMCastFlow(moduleIndex);
+ return SUCCESS;
+}
+
+int32 rtl_getIpv4UnknownMCastFloodMap(uint32 moduleIndex,uint32 *unknownMCastFloodMap)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(unknownMCastFloodMap==NULL)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ *unknownMCastFloodMap=rtl_mCastModuleArray[moduleIndex].ipv4UnknownMCastFloodMap;
+
+ return SUCCESS;
+}
+
+#ifdef CONFIG_RTL_MLD_SNOOPING
+int32 rtl_setIpv6UnknownMCastFloodMap(uint32 moduleIndex,uint32 unknownMCastFloodMap)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ rtl_mCastModuleArray[moduleIndex].ipv6UnknownMCastFloodMap=unknownMCastFloodMap;
+
+ rtl_syncAllIpv6UnknownMCastFlow(moduleIndex);
+
+ return SUCCESS;
+}
+
+int32 rtl_getIpv6UnknownMCastFloodMap(uint32 moduleIndex,uint32 *unknownMCastFloodMap)
+{
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(unknownMCastFloodMap==NULL)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ *unknownMCastFloodMap=rtl_mCastModuleArray[moduleIndex].ipv6UnknownMCastFloodMap;
+
+ return SUCCESS;
+}
+#endif
+
+int32 rtl_setIgmpSnoopingModuleUnknownMCastFloodMap(uint32 moduleIndex,uint32 unknownMCastFloodMap)
+{
+ rtl_setIpv4UnknownMCastFloodMap( moduleIndex, unknownMCastFloodMap);
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ rtl_setIpv6UnknownMCastFloodMap( moduleIndex, unknownMCastFloodMap);
+ #endif
+ return SUCCESS;
+}
+
+#if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+static int32 rtl_addStaticGroupEntry(uint32 moduleIndex, struct rtl_groupEntry* groupEntry)
+{
+ struct rtl_groupEntry* existGroupEntry=NULL;
+ struct rtl_groupEntry* newGroupEntry=NULL;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ if(groupEntry==NULL)
+ {
+ return FAILED;
+ }
+
+ if((groupEntry->ipVersion!=IP_VERSION4) && (groupEntry->ipVersion!=IP_VERSION6))
+ {
+ return FAILED;
+ }
+
+ if(groupEntry->ipVersion==IP_VERSION4)
+ {
+ if((groupEntry->groupAddr[0]!=0) && (!IS_CLASSD_ADDR(groupEntry->groupAddr[0])))
+ {
+ return FAILED;
+ }
+ }
+ else if(groupEntry->ipVersion==IP_VERSION6)
+ {
+ /*need to complete ipv6 address range */
+ }
+
+ /*set unknown multicast default forwarding configuration*/
+ if(groupEntry->ipVersion==IP_VERSION4)
+ {
+ if(groupEntry->groupAddr[0]==0)
+ {
+ rtl_setIpv4UnknownMCastFloodMap(moduleIndex,groupEntry->staticFwdPortMask);
+ return SUCCESS;
+ }
+ }
+ else if(groupEntry->ipVersion==IP_VERSION6)
+ {
+ if( (groupEntry->groupAddr[0]==0) &&
+ (groupEntry->groupAddr[0]==0) &&
+ (groupEntry->groupAddr[0]==0) &&
+ (groupEntry->groupAddr[0]==0) )
+ {
+ rtl_setIpv6UnknownMCastFloodMap(moduleIndex,groupEntry->staticFwdPortMask);
+ return SUCCESS;
+ }
+ }
+
+
+ existGroupEntry=rtl_searchGroupEntry(moduleIndex, groupEntry->ipVersion, groupEntry->groupAddr);
+ if(existGroupEntry!=NULL)
+ {
+ existGroupEntry->attribute=STATIC_RESERVED_MULTICAST;
+ existGroupEntry->staticFwdPortMask=groupEntry->staticFwdPortMask;
+ }
+ else
+ {
+
+ newGroupEntry=rtl_allocateGroupEntry();
+
+ if(newGroupEntry==NULL)
+ {
+ rtl_gluePrintf("run out of group entry!\n");
+ return FAILED;
+ }
+
+ assert(newGroupEntry->clientList==NULL);
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ newGroupEntry->groupAddr[0]=groupEntry->groupAddr[0];
+ newGroupEntry->groupAddr[1]=groupEntry->groupAddr[1];
+ newGroupEntry->groupAddr[2]=groupEntry->groupAddr[2];
+ newGroupEntry->groupAddr[3]=groupEntry->groupAddr[3];
+ #else
+ newGroupEntry->groupAddr[0]=groupEntry->groupAddr[0];
+ #endif
+
+ newGroupEntry->ipVersion=groupEntry->ipVersion;
+ newGroupEntry->attribute=STATIC_RESERVED_MULTICAST;
+ newGroupEntry->staticFwdPortMask=groupEntry->staticFwdPortMask;
+
+ if(groupEntry->ipVersion==IP_VERSION4)
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable);
+ }
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ else
+ {
+ rtl_linkGroupEntry(newGroupEntry, rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable);
+ }
+ #endif
+ }
+
+ reportEventContext.moduleIndex=moduleIndex;
+ reportEventContext.ipVersion=groupEntry->ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupEntry->groupAddr[0];
+ reportEventContext.groupAddr[1]=groupEntry->groupAddr[1];
+ reportEventContext.groupAddr[2]=groupEntry->groupAddr[2];
+ reportEventContext.groupAddr[3]=groupEntry->groupAddr[3];
+ #else
+ reportEventContext.groupAddr[0]=groupEntry->groupAddr[0];
+ #endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(groupEntry->ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+
+ return SUCCESS;
+}
+
+static int32 rtl_delStaticGroupEntry(uint32 moduleIndex,struct rtl_groupEntry* groupEntry)
+{
+ struct rtl_groupEntry* existGroupEntry=NULL;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ if(groupEntry==NULL)
+ {
+ return FAILED;
+ }
+
+ if((groupEntry->ipVersion!=IP_VERSION4) && (groupEntry->ipVersion!=IP_VERSION6))
+ {
+ return FAILED;
+ }
+
+ if(groupEntry->ipVersion==IP_VERSION4)
+ {
+ if((groupEntry->groupAddr[0]!=0) && (!IS_CLASSD_ADDR(groupEntry->groupAddr[0])))
+ {
+ return FAILED;
+ }
+ }
+ else if(groupEntry->ipVersion==IP_VERSION6)
+ {
+ /*to-do:check ipv6 address range */
+ }
+
+ if(groupEntry->ipVersion==IP_VERSION4)
+ {
+ if(groupEntry->groupAddr[0]==0)
+ {
+ rtl_mCastModuleArray[moduleIndex].ipv4UnknownMCastFloodMap=DEFAULT_IPV4_UNKNOWN_MCAST_FLOOD_MAP;
+ return SUCCESS;
+ }
+ }
+ else if(groupEntry->ipVersion==IP_VERSION6)
+ {
+ if( (groupEntry->groupAddr[0]==0) &&
+ (groupEntry->groupAddr[0]==0) &&
+ (groupEntry->groupAddr[0]==0) &&
+ (groupEntry->groupAddr[0]==0) )
+ {
+ rtl_mCastModuleArray[moduleIndex].ipv6UnknownMCastFloodMap=DEFAULT_IPV6_UNKNOWN_MCAST_FLOOD_MAP;
+ return SUCCESS;
+ }
+ }
+
+ existGroupEntry=rtl_searchGroupEntry(moduleIndex, groupEntry->ipVersion, groupEntry->groupAddr);
+ if((existGroupEntry!=NULL) && (existGroupEntry->attribute==STATIC_RESERVED_MULTICAST))
+ {
+ existGroupEntry->attribute=0;
+ existGroupEntry->staticFwdPortMask=0;
+
+ reportEventContext.moduleIndex=moduleIndex;
+ reportEventContext.ipVersion=groupEntry->ipVersion;
+ #ifdef CONFIG_RTL_MLD_SNOOPING
+ reportEventContext.groupAddr[0]=groupEntry->groupAddr[0];
+ reportEventContext.groupAddr[1]=groupEntry->groupAddr[1];
+ reportEventContext.groupAddr[2]=groupEntry->groupAddr[2];
+ reportEventContext.groupAddr[3]=groupEntry->groupAddr[3];
+ #else
+ reportEventContext.groupAddr[0]=groupEntry->groupAddr[0];
+ #endif
+
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ rtl_invalidateMCastFlow(reportEventContext.moduleIndex, reportEventContext.ipVersion, reportEventContext.groupAddr);
+ #endif
+
+ #if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(groupEntry->ipVersion==IP_VERSION4)
+ {
+ /*we only support ipv4 hardware multicast*/
+ strcpy(reportEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &reportEventContext);
+ }
+ #endif
+ }
+
+ return SUCCESS;
+}
+
+int32 rtl_addSpecialMCast(uint32 moduleIndex, uint32 ipVersion, uint32 *groupAddr, uint32 fwdPortMask)
+{
+
+ struct rtl_groupEntry groupEntry;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+ if(groupAddr==NULL)
+ {
+ return FAILED;
+ }
+
+ if((ipVersion!=IP_VERSION4) && (ipVersion!=IP_VERSION6))
+ {
+ return FAILED;
+ }
+
+ memset(&groupEntry, 0 ,sizeof(struct rtl_groupEntry));
+ groupEntry.ipVersion=ipVersion;
+
+ if(ipVersion ==IP_VERSION4)
+ {
+ groupEntry.groupAddr[0]=groupAddr[0];
+ }
+ else
+ {
+ groupEntry.groupAddr[0]=groupAddr[0];
+ groupEntry.groupAddr[1]=groupAddr[1];
+ groupEntry.groupAddr[2]=groupAddr[2];
+ groupEntry.groupAddr[3]=groupAddr[3];
+ }
+
+ groupEntry.staticFwdPortMask=fwdPortMask;
+
+ return rtl_addStaticGroupEntry(moduleIndex, &groupEntry);
+}
+
+int32 rtl_delSpecialMCast(uint32 moduleIndex, uint32 ipVersion, uint32 *groupAddr)
+{
+
+ struct rtl_groupEntry groupEntry;
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return FAILED;
+ }
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==FALSE)
+ {
+ return FAILED;
+ }
+
+
+ if((ipVersion!=IP_VERSION4) && (ipVersion!=IP_VERSION6))
+ {
+ return FAILED;
+ }
+
+ memset(&groupEntry, 0 ,sizeof(struct rtl_groupEntry));
+ groupEntry.ipVersion=ipVersion;
+
+ if(ipVersion ==IP_VERSION4)
+ {
+ groupEntry.groupAddr[0]=groupAddr[0];
+ }
+ else
+ {
+ groupEntry.groupAddr[0]=groupAddr[0];
+ groupEntry.groupAddr[1]=groupAddr[1];
+ groupEntry.groupAddr[2]=groupAddr[2];
+ groupEntry.groupAddr[3]=groupAddr[3];
+ }
+
+ return rtl_delStaticGroupEntry(moduleIndex, &groupEntry);
+}
+#endif
+
+#ifdef CONFIG_PROC_FS
+int igmp_show(struct seq_file *s, void *v)
+{
+ int32 moduleIndex;
+ int32 hashIndex,groupCnt,clientCnt;
+ struct rtl_groupEntry *groupEntryPtr;
+ struct rtl_clientEntry* clientEntry=NULL;
+ struct rtl_sourceEntry *sourceEntryPtr;
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ int32 flowCnt;
+ struct rtl_mcastFlowEntry *mcastFlowEntry=NULL;
+ #endif
+
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM ;moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ seq_printf(s, "-------------------------------------------------------------------------\n");
+ seq_printf(s, "module index:%d, ",moduleIndex);
+ #ifdef CONFIG_RTL_HARDWARE_MULTICAST
+ seq_printf(s, "device:%s, portMask:0x%x,",rtl_mCastModuleArray[moduleIndex].deviceInfo.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.portMask);
+ #endif
+ seq_printf(s, "ipv4[0x%x]",rtl_mCastModuleArray[moduleIndex].ipv4UnknownMCastFloodMap);
+ #if defined (CONFIG_RTL_MLD_SNOOPING)
+ seq_printf(s, "ipv6[0x%x]\n",rtl_mCastModuleArray[moduleIndex].ipv6UnknownMCastFloodMap);
+ #endif
+ seq_printf(s, "\n");
+ seq_printf(s,"igmp list:\n");
+ groupCnt=0;
+ for(hashIndex=0;hashIndex<rtl_hashTableSize;hashIndex++)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[hashIndex];
+ while(groupEntryPtr!=NULL)
+ {
+ groupCnt++;
+ seq_printf(s, " [%d] Group address:%d.%d.%d.%d",groupCnt,//hashIndex
+ groupEntryPtr->groupAddr[0]>>24, (groupEntryPtr->groupAddr[0]&0x00ff0000)>>16,
+ (groupEntryPtr->groupAddr[0]&0x0000ff00)>>8, (groupEntryPtr->groupAddr[0]&0xff));
+
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if(groupEntryPtr->attribute==STATIC_RESERVED_MULTICAST)
+ {
+ seq_printf(s, " <static> portMask:0x%x",groupEntryPtr->staticFwdPortMask);
+ }
+ #endif
+ seq_printf(s, "\n");
+
+ clientEntry=groupEntryPtr->clientList;
+
+ clientCnt=0;
+ while (clientEntry!=NULL)
+ {
+
+ clientCnt++;
+ seq_printf(s, " <%d>%d.%d.%d.%d\\port %d\\IGMPv%d\\",clientCnt,
+ clientEntry->clientAddr[0]>>24, (clientEntry->clientAddr[0]&0x00ff0000)>>16,
+ (clientEntry->clientAddr[0]&0x0000ff00)>>8, clientEntry->clientAddr[0]&0xff,clientEntry->portNum, clientEntry->igmpVersion);
+
+ seq_printf(s, "%s",(clientEntry->groupFilterTimer>rtl_sysUpSeconds)?"EXCLUDE":"INCLUDE");
+ if(clientEntry->groupFilterTimer>rtl_sysUpSeconds)
+ {
+ seq_printf(s, ":%ds",clientEntry->groupFilterTimer-rtl_sysUpSeconds);
+ }
+ else
+ {
+ seq_printf(s, ":0s");
+ }
+
+ sourceEntryPtr=clientEntry->sourceList;
+ if(sourceEntryPtr!=NULL)
+ {
+ seq_printf(s, "\\source list:");
+ }
+
+ while(sourceEntryPtr!=NULL)
+ {
+ seq_printf(s, "%d.%d.%d.%d:",
+ sourceEntryPtr->sourceAddr[0]>>24, (sourceEntryPtr->sourceAddr[0]&0x00ff0000)>>16,
+ (sourceEntryPtr->sourceAddr[0]&0x0000ff00)>>8, (sourceEntryPtr->sourceAddr[0]&0xff));
+
+ if(sourceEntryPtr->portTimer>rtl_sysUpSeconds)
+ {
+ seq_printf(s, "%ds",sourceEntryPtr->portTimer-rtl_sysUpSeconds);
+ }
+ else
+ {
+ seq_printf(s, "0s");
+ }
+
+ if(sourceEntryPtr->next!=NULL)
+ {
+ seq_printf(s, ", ");
+ }
+
+ sourceEntryPtr=sourceEntryPtr->next;
+ }
+
+
+ seq_printf(s, "\n");
+ clientEntry = clientEntry->next;
+ }
+
+ seq_printf(s, "\n");
+ groupEntryPtr=groupEntryPtr->next;
+ }
+
+ }
+ if(groupCnt==0)
+ {
+ seq_printf(s," <empty>\n");
+ }
+
+#if defined (CONFIG_RTL_MLD_SNOOPING)
+ seq_printf(s, "\n\n");
+ seq_printf(s, "mld list:\n");
+ groupCnt=0;
+ for(hashIndex=0;hashIndex<rtl_hashTableSize;hashIndex++)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[hashIndex];
+ while(groupEntryPtr!=NULL)
+ {
+ groupCnt++;
+ seq_printf(s, " [%d] Group address:%x%x%x%x%x%x%x%x-%x%x%x%x%x%x%x%x-%x%x%x%x%x%x%x%x-%x%x%x%x%x%x%x%x",groupCnt,
+ (groupEntryPtr->groupAddr[0])>>28,(groupEntryPtr->groupAddr[0]<<4)>>28, (groupEntryPtr->groupAddr[0]<<8)>>28,(groupEntryPtr->groupAddr[0]<<12)>>28,
+ (groupEntryPtr->groupAddr[0]<<16)>>28,(groupEntryPtr->groupAddr[0]<<20)>>28,(groupEntryPtr->groupAddr[0]<<24)>>28, (groupEntryPtr->groupAddr[0]<<28)>>28,
+ (groupEntryPtr->groupAddr[1])>>28,(groupEntryPtr->groupAddr[1]<<4)>>28, (groupEntryPtr->groupAddr[1]<<8)>>28,(groupEntryPtr->groupAddr[1]<<12)>>28,
+ (groupEntryPtr->groupAddr[1]<<16)>>28,(groupEntryPtr->groupAddr[1]<<20)>>28,(groupEntryPtr->groupAddr[1]<<24)>>28, (groupEntryPtr->groupAddr[1]<<28)>>28,
+ (groupEntryPtr->groupAddr[2])>>28,(groupEntryPtr->groupAddr[2]<<4)>>28, (groupEntryPtr->groupAddr[2]<<8)>>28,(groupEntryPtr->groupAddr[2]<<12)>>28,
+ (groupEntryPtr->groupAddr[2]<<16)>>28,(groupEntryPtr->groupAddr[2]<<20)>>28,(groupEntryPtr->groupAddr[2]<<24)>>28, (groupEntryPtr->groupAddr[2]<<28)>>28,
+ (groupEntryPtr->groupAddr[3])>>28,(groupEntryPtr->groupAddr[3]<<4)>>28, (groupEntryPtr->groupAddr[3]<<8)>>28,(groupEntryPtr->groupAddr[3]<<12)>>28,
+ (groupEntryPtr->groupAddr[3]<<16)>>28,(groupEntryPtr->groupAddr[3]<<20)>>28,(groupEntryPtr->groupAddr[3]<<24)>>28, (groupEntryPtr->groupAddr[3]<<28)>>28);
+ #if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ if(groupEntryPtr->attribute==STATIC_RESERVED_MULTICAST)
+ {
+ seq_printf(s, " <static> portMask:0x%x",groupEntryPtr->staticFwdPortMask);
+ }
+ #endif
+ seq_printf(s, "\n");
+ clientEntry=groupEntryPtr->clientList;
+
+ clientCnt=0;
+ while (clientEntry!=NULL)
+ {
+
+ clientCnt++;
+ seq_printf(s, " <%d>%x%x%x%x%x%x%x%x-%x%x%x%x%x%x%x%x-%x%x%x%x%x%x%x%x-%x%x%x%x%x%x%x%x\\port %d\\MLDv%d\\",clientCnt,
+ (clientEntry->clientAddr[0])>>28,(clientEntry->clientAddr[0]<<4)>>28, (clientEntry->clientAddr[0]<<8)>>28,(clientEntry->clientAddr[0]<<12)>>28,
+ (clientEntry->clientAddr[0]<<16)>>28,(clientEntry->clientAddr[0]<<20)>>28,(clientEntry->clientAddr[0]<<24)>>28, (clientEntry->clientAddr[0]<<28)>>28,
+ (clientEntry->clientAddr[1])>>28,(clientEntry->clientAddr[1]<<4)>>28, (clientEntry->clientAddr[1]<<8)>>28,(clientEntry->clientAddr[1]<<12)>>28,
+ (clientEntry->clientAddr[1]<<16)>>28,(clientEntry->clientAddr[1]<<20)>>28,(clientEntry->clientAddr[1]<<24)>>28, (clientEntry->clientAddr[1]<<28)>>28,
+ (clientEntry->clientAddr[2])>>28,(clientEntry->clientAddr[2]<<4)>>28, (clientEntry->clientAddr[2]<<8)>>28,(clientEntry->clientAddr[2]<<12)>>28,
+ (clientEntry->clientAddr[2]<<16)>>28,(clientEntry->clientAddr[2]<<20)>>28,(clientEntry->clientAddr[2]<<24)>>28, (clientEntry->clientAddr[2]<<28)>>28,
+ (clientEntry->clientAddr[3])>>28,(clientEntry->clientAddr[3]<<4)>>28, (clientEntry->clientAddr[3]<<8)>>28,(clientEntry->clientAddr[3]<<12)>>28,
+ (clientEntry->clientAddr[3]<<16)>>28,(clientEntry->clientAddr[3]<<20)>>28,(clientEntry->clientAddr[3]<<24)>>28, (clientEntry->clientAddr[3]<<28)>>28,
+ clientEntry->portNum, clientEntry->igmpVersion);
+
+ seq_printf(s, "%s",(clientEntry->groupFilterTimer>rtl_sysUpSeconds)?"EXCLUDE":"INCLUDE");
+ if(clientEntry->groupFilterTimer>rtl_sysUpSeconds)
+ {
+ seq_printf(s, ":%ds",clientEntry->groupFilterTimer-rtl_sysUpSeconds);
+ }
+ else
+ {
+ seq_printf(s, ":0s");
+ }
+
+ sourceEntryPtr=clientEntry->sourceList;
+ if(sourceEntryPtr!=NULL)
+ {
+ seq_printf(s, "\\source list:");
+ }
+
+ while(sourceEntryPtr!=NULL)
+ {
+ seq_printf(s, "%x%x%x%x%x%x%x%x-%x%x%x%x%x%x%x%x-%x%x%x%x%x%x%x%x-%x%x%x%x%x%x%x%x:",
+ (sourceEntryPtr->sourceAddr[0])>>28,(sourceEntryPtr->sourceAddr[0]<<4)>>28, (sourceEntryPtr->sourceAddr[0]<<8)>>28,(sourceEntryPtr->sourceAddr[0]<<12)>>28,
+ (sourceEntryPtr->sourceAddr[0]<<16)>>28,(sourceEntryPtr->sourceAddr[0]<<20)>>28,(sourceEntryPtr->sourceAddr[0]<<24)>>28, (sourceEntryPtr->sourceAddr[0]<<28)>>28,
+ (sourceEntryPtr->sourceAddr[1])>>28,(sourceEntryPtr->sourceAddr[1]<<4)>>28, (sourceEntryPtr->sourceAddr[1]<<8)>>28,(sourceEntryPtr->sourceAddr[1]<<12)>>28,
+ (sourceEntryPtr->sourceAddr[1]<<16)>>28,(sourceEntryPtr->sourceAddr[1]<<20)>>28,(sourceEntryPtr->sourceAddr[1]<<24)>>28, (sourceEntryPtr->sourceAddr[1]<<28)>>28,
+ (sourceEntryPtr->sourceAddr[2])>>28,(sourceEntryPtr->sourceAddr[2]<<4)>>28, (sourceEntryPtr->sourceAddr[2]<<8)>>28,(sourceEntryPtr->sourceAddr[2]<<12)>>28,
+ (sourceEntryPtr->sourceAddr[2]<<16)>>28,(sourceEntryPtr->sourceAddr[2]<<20)>>28,(sourceEntryPtr->sourceAddr[2]<<24)>>28, (sourceEntryPtr->sourceAddr[2]<<28)>>28,
+ (sourceEntryPtr->sourceAddr[3])>>28,(sourceEntryPtr->sourceAddr[3]<<4)>>28, (sourceEntryPtr->sourceAddr[3]<<8)>>28,(sourceEntryPtr->sourceAddr[3]<<12)>>28,
+ (sourceEntryPtr->sourceAddr[3]<<16)>>28,(sourceEntryPtr->sourceAddr[3]<<20)>>28,(sourceEntryPtr->sourceAddr[3]<<24)>>28, (sourceEntryPtr->sourceAddr[3]<<28)>>28);
+
+ if(sourceEntryPtr->portTimer>rtl_sysUpSeconds)
+ {
+ seq_printf(s, "%ds",sourceEntryPtr->portTimer-rtl_sysUpSeconds);
+ }
+ else
+ {
+ seq_printf(s, "0s");
+ }
+
+ if(sourceEntryPtr->next!=NULL)
+ {
+ seq_printf(s, ", ");
+ }
+
+ sourceEntryPtr=sourceEntryPtr->next;
+ }
+
+ seq_printf(s, "\n");
+ clientEntry = clientEntry->next;
+ }
+
+ seq_printf(s, "\n");
+ groupEntryPtr=groupEntryPtr->next;
+ }
+
+ }
+ if(groupCnt==0)
+ {
+ seq_printf(s," <empty>\n");
+ }
+#endif
+#ifdef CONFIG_RECORD_MCAST_FLOW
+ seq_printf(s,"ipv4 flow list:\n");
+ flowCnt=1;
+ for(hashIndex=0;hashIndex<rtl_hashTableSize;hashIndex++)
+ {
+
+ /*to dump multicast flow information*/
+ mcastFlowEntry=rtl_mCastModuleArray[moduleIndex].flowHashTable[hashIndex];
+
+ while(mcastFlowEntry!=NULL)
+ {
+ if(mcastFlowEntry->ipVersion==IP_VERSION4)
+ {
+ seq_printf(s, " [%d] %d.%d.%d.%d-->",flowCnt,
+ mcastFlowEntry->serverAddr[0]>>24, (mcastFlowEntry->serverAddr[0]&0x00ff0000)>>16,
+ (mcastFlowEntry->serverAddr[0]&0x0000ff00)>>8, (mcastFlowEntry->serverAddr[0]&0xff));
+
+ seq_printf(s, "%d.%d.%d.%d-->",
+ mcastFlowEntry->groupAddr[0]>>24, (mcastFlowEntry->groupAddr[0]&0x00ff0000)>>16,
+ (mcastFlowEntry->groupAddr[0]&0x0000ff00)>>8, (mcastFlowEntry->groupAddr[0]&0xff));
+
+ seq_printf(s, "port mask:0x%x\n",mcastFlowEntry->multicastFwdInfo.fwdPortMask);
+ }
+
+ flowCnt++;
+ mcastFlowEntry=mcastFlowEntry->next;
+ }
+
+ }
+ seq_printf(s, "ipv6 flow list:\n");
+ flowCnt=1;
+ for(hashIndex=0;hashIndex<rtl_hashTableSize;hashIndex++)
+ {
+
+ /*to dump multicast flow information*/
+ mcastFlowEntry=rtl_mCastModuleArray[moduleIndex].flowHashTable[hashIndex];
+
+ while(mcastFlowEntry!=NULL)
+ {
+ if(mcastFlowEntry->ipVersion==IP_VERSION6)
+ {
+ seq_printf(s, " [%d] %x-%x-%x-%x-->",flowCnt,
+ mcastFlowEntry->serverAddr[0], mcastFlowEntry->serverAddr[1],
+ mcastFlowEntry->serverAddr[2], (mcastFlowEntry->serverAddr[3]);
+
+ seq_printf(s, "%x-%x-%x-%x-->",
+ mcastFlowEntry->groupAddr[1], mcastFlowEntry->groupAddr[1],
+ mcastFlowEntry->groupAddr[2], mcastFlowEntry->groupAddr[3];
+
+ seq_printf(s, "port mask:0x%x\n",mcastFlowEntry->multicastFwdInfo.fwdPortMask);
+ }
+
+ flowCnt++;
+ mcastFlowEntry=mcastFlowEntry->next;
+ }
+
+ }
+#endif
+ }
+ }
+
+ seq_printf(s, "------------------------------------------------------------------\n");
+ return SUCCESS;
+}
+
+
+int igmp_write(struct file *file, const char __user *buffer, size_t count, loff_t *data)
+
+{
+#if defined (CONFIG_STATIC_RESERVED_MULTICAST)
+ char tmp[256];
+
+ char *strptr, *cmd_addr;
+ char *tokptr;
+ uint32 allModuleFlag=FALSE;
+ uint32 moduleIndex=0xFFFFFFFF;
+ uint32 ipAddr[4];
+ int cnt;
+
+ struct rtl_groupEntry groupEntry;
+
+
+ if (count < 5)
+ return -EFAULT;
+
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ tmp[count] = '\0';
+ strptr=tmp;
+ cmd_addr = strsep(&strptr," ");
+ if (cmd_addr==NULL)
+ {
+ goto errout;
+ }
+
+ if ( (!memcmp(cmd_addr, "add", 3)) ||
+ (!memcmp(cmd_addr, "Add", 3)) ||
+ (!memcmp(cmd_addr, "ADD", 3)) )
+ {
+
+
+ tokptr = strsep(&strptr," ");
+ if (tokptr==NULL)
+ {
+ goto errout;
+ }
+
+ if( (!memcmp(tokptr, "all", 3)) ||
+ (!memcmp(tokptr, "All", 3)) ||
+ (!memcmp(tokptr, "ALL", 3)) )
+ {
+ allModuleFlag=TRUE;
+ }
+ else
+ {
+ allModuleFlag=FALSE;
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM ;moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ if(strcmp(rtl_mCastModuleArray[moduleIndex].deviceInfo.devName,tokptr)==0)
+ {
+ break;
+ }
+ }
+ }
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ goto errout;
+ }
+ }
+
+ tokptr = strsep(&strptr," ");
+ if (tokptr==NULL)
+ {
+ goto errout;
+ }
+
+ if( (!memcmp(tokptr, "ipv4", 4)) ||
+ (!memcmp(tokptr, "Ipv4", 4)) ||
+ (!memcmp(tokptr, "IPV4", 4)) )
+ {
+ groupEntry.ipVersion=IP_VERSION4;
+ }
+ else if ( (!memcmp(tokptr, "ipv6", 4)) ||
+ (!memcmp(tokptr, "Ipv6", 4)) ||
+ (!memcmp(tokptr, "IPV6", 4)) )
+ {
+ groupEntry.ipVersion=IP_VERSION6;
+
+ }
+ else
+ {
+ goto errout;
+ }
+
+ if(groupEntry.ipVersion==IP_VERSION4)
+ {
+ tokptr = strsep(&strptr," ");
+ if (tokptr==NULL)
+ {
+ goto errout;
+ }
+
+ cnt = sscanf(tokptr, "%d.%d.%d.%d", &ipAddr[0], &ipAddr[1], &ipAddr[2], &ipAddr[3]);
+
+ groupEntry.groupAddr[0]=(ipAddr[0]<<24)|(ipAddr[1]<<16)|(ipAddr[2]<<8)|(ipAddr[3]);
+ groupEntry.groupAddr[1]=0;
+ groupEntry.groupAddr[2]=0;
+ groupEntry.groupAddr[3]=0;
+
+
+
+ }
+ else if (groupEntry.ipVersion==IP_VERSION6)
+ {
+ tokptr = strsep(&strptr," ");
+ if (tokptr==NULL)
+ {
+ goto errout;
+ }
+
+ cnt = sscanf(tokptr, "0x%x-%x-%x-%x", &ipAddr[0], &ipAddr[1], &ipAddr[2], &ipAddr[3]);
+
+ groupEntry.groupAddr[0]=ipAddr[0];
+ groupEntry.groupAddr[1]=ipAddr[1];
+ groupEntry.groupAddr[2]=ipAddr[2];
+ groupEntry.groupAddr[3]=ipAddr[3];
+ }
+
+
+ tokptr = strsep(&strptr," ");
+ if (tokptr==NULL)
+ {
+ goto errout;
+ }
+
+ groupEntry.staticFwdPortMask=simple_strtol(tokptr, NULL, 0);
+ if(allModuleFlag==TRUE)
+ {
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM ;moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ rtl_addStaticGroupEntry(moduleIndex, &groupEntry);
+ }
+ }
+
+ }
+ else
+ {
+ rtl_addStaticGroupEntry(moduleIndex, &groupEntry);
+ }
+
+ }
+ else if ( (!memcmp(cmd_addr, "del", 3)) ||
+ (!memcmp(cmd_addr, "Del", 3)) ||
+ (!memcmp(cmd_addr, "DEL", 3)) )
+ {
+ tokptr = strsep(&strptr," ");
+ if (tokptr==NULL)
+ {
+ goto errout;
+ }
+
+ if( (!memcmp(tokptr, "all", 3)) ||
+ (!memcmp(tokptr, "All", 3)) ||
+ (!memcmp(tokptr, "ALL", 3)) )
+ {
+ allModuleFlag=TRUE;
+ }
+ else
+ {
+ allModuleFlag=FALSE;
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM ;moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ if(strcmp(rtl_mCastModuleArray[moduleIndex].deviceInfo.devName,tokptr)==0)
+ {
+ break;
+ }
+ }
+ }
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ goto errout;
+ }
+ }
+
+ tokptr = strsep(&strptr," ");
+ if (tokptr==NULL)
+ {
+ goto errout;
+ }
+
+ if( (!memcmp(tokptr, "ipv4", 4)) ||
+ (!memcmp(tokptr, "Ipv4", 4)) ||
+ (!memcmp(tokptr, "IPV4", 4)) )
+ {
+ groupEntry.ipVersion=IP_VERSION4;
+ }
+ else if ( (!memcmp(tokptr, "ipv6", 4)) ||
+ (!memcmp(tokptr, "Ipv6", 4)) ||
+ (!memcmp(tokptr, "IPV6", 4)) )
+ {
+ groupEntry.ipVersion=IP_VERSION6;
+
+ }
+ else
+ {
+ goto errout;
+ }
+
+ if(groupEntry.ipVersion==IP_VERSION4)
+ {
+ tokptr = strsep(&strptr," ");
+ if (tokptr==NULL)
+ {
+ goto errout;
+ }
+ cnt = sscanf(tokptr, "%d.%d.%d.%d", &ipAddr[0], &ipAddr[1], &ipAddr[2], &ipAddr[3]);
+
+ groupEntry.groupAddr[0]=(ipAddr[0]<<24)|(ipAddr[1]<<16)|(ipAddr[2]<<8)|(ipAddr[3]);
+ groupEntry.groupAddr[1]=0;
+ groupEntry.groupAddr[2]=0;
+ groupEntry.groupAddr[3]=0;
+
+
+
+ }
+ else if (groupEntry.ipVersion==IP_VERSION6)
+ {
+ tokptr = strsep(&strptr," ");
+ if (tokptr==NULL)
+ {
+ goto errout;
+ }
+ cnt = sscanf(tokptr, "0x%x-%x-%x-%x", &ipAddr[0], &ipAddr[1], &ipAddr[2], &ipAddr[3]);
+
+ groupEntry.groupAddr[0]=ipAddr[0];
+ groupEntry.groupAddr[1]=ipAddr[1];
+ groupEntry.groupAddr[2]=ipAddr[2];
+ groupEntry.groupAddr[3]=ipAddr[3];
+ }
+
+ if(allModuleFlag==TRUE)
+ {
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM ;moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ rtl_delStaticGroupEntry(moduleIndex, &groupEntry);
+ }
+ }
+
+ }
+ else
+ {
+ rtl_delStaticGroupEntry(moduleIndex, &groupEntry);
+ }
+
+ }
+ else if ( (!memcmp(cmd_addr, "flush", 4)) ||
+ (!memcmp(cmd_addr, "Flush", 4)) ||
+ (!memcmp(cmd_addr, "FLUSH", 4)) )
+ {
+ rtl_flushAllIgmpRecord();
+ }
+ else
+ {
+errout:
+ printk("error input!\n");
+ }
+
+
+ }
+#endif
+ return count;
+}
+#endif
+
+void rtl865x_igmpLinkStatusChangeCallback(uint32 moduleIndex, rtl_igmpPortInfo_t * portInfo)
+{
+ int32 hashIndex;
+ int32 clearFlag=FALSE;
+ struct rtl_groupEntry *groupEntryPtr;
+ struct rtl_clientEntry* clientEntry=NULL;
+ struct rtl_clientEntry* nextClientEntry=NULL;
+ #ifdef CONFIG_RECORD_MCAST_FLOW
+ struct rtl_mcastFlowEntry *mcastFlowEntry, *nextMcastFlowEntry;
+ #endif
+
+ if(portInfo==NULL)
+ {
+ return ;
+ }
+
+ if(moduleIndex>=MAX_MCAST_MODULE_NUM)
+ {
+ return ;
+ }
+
+#ifdef CONFIG_RECORD_MCAST_FLOW
+ for(hashIndex=0;hashIndex<rtl_hashTableSize;hashIndex++)
+ {
+
+ mcastFlowEntry=rtl_mCastModuleArray[moduleIndex].flowHashTable[hashIndex];
+
+ while(mcastFlowEntry!=NULL)
+ {
+ nextMcastFlowEntry=mcastFlowEntry->next;
+
+ /*clear multicast forward flow cache*/
+ rtl_deleteMcastFlowEntry( mcastFlowEntry, rtl_mCastModuleArray[moduleIndex].flowHashTable);
+
+ mcastFlowEntry=nextMcastFlowEntry;
+ }
+
+ }
+#endif
+
+
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+
+ for(hashIndex=0;hashIndex<rtl_hashTableSize;hashIndex++)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[hashIndex];
+ while(groupEntryPtr!=NULL)
+ {
+ clientEntry=groupEntryPtr->clientList;
+ while (clientEntry!=NULL)
+ {
+ /*save next client entry first*/
+ nextClientEntry=clientEntry->next;
+ if(((1<<clientEntry->portNum) & portInfo->linkPortMask)==0)
+ {
+ rtl_deleteClientEntry(groupEntryPtr,clientEntry);
+ clearFlag=TRUE;
+ }
+
+
+ clientEntry = nextClientEntry;
+ }
+#if defined (CONFIG_RTL_HARDWARE_MULTICAST)
+ if(clearFlag==TRUE)
+ {
+ strcpy(linkEventContext.devName,rtl_mCastModuleArray[moduleIndex].deviceInfo.devName);
+ linkEventContext.moduleIndex=moduleIndex;
+
+ linkEventContext.groupAddr[0]=groupEntryPtr->groupAddr[0];
+ linkEventContext.groupAddr[1]=groupEntryPtr->groupAddr[1];
+ linkEventContext.groupAddr[2]=groupEntryPtr->groupAddr[2];
+ linkEventContext.groupAddr[3]=groupEntryPtr->groupAddr[3];
+
+ linkEventContext.sourceAddr[0]=0;
+ linkEventContext.sourceAddr[1]=0;
+ linkEventContext.sourceAddr[2]=0;
+ linkEventContext.sourceAddr[3]=0;
+
+ rtl865x_raiseEvent(EVENT_UPDATE_MCAST, &linkEventContext);
+ }
+#endif
+ groupEntryPtr=groupEntryPtr->next;
+ }
+
+ }
+
+#if defined (CONFIG_RTL_MLD_SNOOPING)
+ for(hashIndex=0;hashIndex<rtl_hashTableSize;hashIndex++)
+ {
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv6HashTable[hashIndex];
+ while(groupEntryPtr!=NULL)
+ {
+ clientEntry=groupEntryPtr->clientList;
+ while (clientEntry!=NULL)
+ {
+ /*save next client entry first*/
+ nextClientEntry=clientEntry->next;
+ if(((1<<clientEntry->portNum) & portInfo->linkPortMask)==0)
+ {
+ rtl_deleteClientEntry(groupEntryPtr,clientEntry);
+ }
+
+ clientEntry = nextClientEntry;
+ }
+ groupEntryPtr=groupEntryPtr->next;
+ }
+
+ }
+#endif
+
+ }
+
+
+
+ return ;
+}
+
+
+int32 rtl_getGroupInfo(uint32 groupAddr, struct rtl_groupInfo * groupInfo)
+{
+ int32 moduleIndex;
+ int32 hashIndex;
+ struct rtl_groupEntry *groupEntryPtr;
+
+ if(groupInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ memset(groupInfo, 0 , sizeof(struct rtl_groupInfo));
+
+ for(moduleIndex=0; moduleIndex<MAX_MCAST_MODULE_NUM ;moduleIndex++)
+ {
+ if(rtl_mCastModuleArray[moduleIndex].enableSnooping==TRUE)
+ {
+ hashIndex=rtl_hashMask&groupAddr;
+ groupEntryPtr=rtl_mCastModuleArray[moduleIndex].rtl_ipv4HashTable[hashIndex];
+
+ while(groupEntryPtr!=NULL)
+ {
+ if(groupEntryPtr->groupAddr[0]==groupAddr)
+ {
+ groupInfo->ownerMask |= (1<<moduleIndex);
+ break;
+ }
+ groupEntryPtr=groupEntryPtr->next;
+ }
+
+ }
+ }
+
+ return SUCCESS;
+}
+