diff options
Diffstat (limited to 'target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping.c')
-rw-r--r-- | target/linux/realtek/files/drivers/net/rtl819x/igmpsnooping/rtl865x_igmpsnooping.c | 5078 |
1 files changed, 5078 insertions, 0 deletions
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; +} + |