diff options
Diffstat (limited to 'target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping')
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(¤tTimeVector); + /*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(¤tTimeVector); + 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(¤tTimeVector); + /*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(¤tTimeVector); + 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; +} + |