blob: 680658f97f0a20b5433d3409951dc4c7604f241d [file] [log] [blame]
/*
*************************************************************************
* Ralink Tech Inc.
* 5F., No.36, Taiyuan St., Jhubei City,
* Hsinchu County 302,
* Taiwan, R.O.C.
*
* (c) Copyright 2002-2007, Ralink Technology, Inc.
*
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
*************************************************************************
*/
#ifdef IGMP_SNOOP_SUPPORT
#include "../rt_config.h"
#include "../ipv6.h"
#include "../igmp_snoop.h"
static inline void initFreeEntryList(
IN PMULTICAST_FILTER_TABLE pMulticastFilterTable,
IN PLIST_HEADER pList)
{
int i;
for (i = 0; i < FREE_MEMBER_POOL_SIZE; i++)
insertTailList(pList, (PLIST_ENTRY)&(pMulticastFilterTable->freeMemberPool[i]));
return;
}
static inline PMEMBER_ENTRY AllocaGrpMemberEntry(
IN PMULTICAST_FILTER_TABLE pMulticastFilterTable)
{
PMEMBER_ENTRY pMemberEntry;
RTMP_SEM_LOCK(&pMulticastFilterTable->FreeMemberPoolTabLock);
pMemberEntry = (PMEMBER_ENTRY)removeHeadList(&pMulticastFilterTable->freeEntryList);
RTMP_SEM_UNLOCK(&pMulticastFilterTable->FreeMemberPoolTabLock);
return (PMEMBER_ENTRY)pMemberEntry;
}
static inline VOID FreeGrpMemberEntry(
IN PMULTICAST_FILTER_TABLE pMulticastFilterTable,
IN PMEMBER_ENTRY pEntry)
{
RTMP_SEM_LOCK(&pMulticastFilterTable->FreeMemberPoolTabLock);
insertTailList(&pMulticastFilterTable->freeEntryList, (PLIST_ENTRY)pEntry);
RTMP_SEM_UNLOCK(&pMulticastFilterTable->FreeMemberPoolTabLock);
}
static VOID IGMPTableDisplay(
IN PRTMP_ADAPTER pAd);
static BOOLEAN isIgmpMacAddr(
IN PUCHAR pMacAddr);
static VOID InsertIgmpMember(
IN PMULTICAST_FILTER_TABLE pMulticastFilterTable,
IN PLIST_HEADER pList,
IN PUCHAR pMemberAddr);
static VOID DeleteIgmpMember(
IN PMULTICAST_FILTER_TABLE pMulticastFilterTable,
IN PLIST_HEADER pList,
IN PUCHAR pMemberAddr);
static VOID DeleteIgmpMemberList(
IN PMULTICAST_FILTER_TABLE pMulticastFilterTable,
IN PLIST_HEADER pList);
/*
==========================================================================
Description:
This routine init the entire IGMP table.
==========================================================================
*/
VOID MulticastFilterTableInit(
IN PMULTICAST_FILTER_TABLE *ppMulticastFilterTable)
{
// Initialize MAC table and allocate spin lock
*ppMulticastFilterTable = kmalloc(sizeof(MULTICAST_FILTER_TABLE), MEM_ALLOC_FLAG);
if (*ppMulticastFilterTable == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for Multicase filter table, size=%d\n",
__FUNCTION__, sizeof(MULTICAST_FILTER_TABLE)));
return;
}
NdisZeroMemory(*ppMulticastFilterTable, sizeof(MULTICAST_FILTER_TABLE));
NdisAllocateSpinLock(&((*ppMulticastFilterTable)->MulticastFilterTabLock));
NdisAllocateSpinLock(&((*ppMulticastFilterTable)->FreeMemberPoolTabLock));
initList(&((*ppMulticastFilterTable)->freeEntryList));
initFreeEntryList(*ppMulticastFilterTable, &((*ppMulticastFilterTable)->freeEntryList));
return;
}
/*
==========================================================================
Description:
This routine reset the entire IGMP table.
==========================================================================
*/
VOID MultiCastFilterTableReset(
IN PMULTICAST_FILTER_TABLE *ppMulticastFilterTable)
{
if(*ppMulticastFilterTable == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Multicase filter table is not ready.\n", __FUNCTION__));
return;
}
NdisFreeSpinLock(&((*ppMulticastFilterTable)->FreeMemberPoolTabLock));
NdisFreeSpinLock(&((*ppMulticastFilterTable)->MulticastFilterTabLock));
kfree(*ppMulticastFilterTable);
*ppMulticastFilterTable = NULL;
}
/*
==========================================================================
Description:
Display all entrys in IGMP table
==========================================================================
*/
static VOID IGMPTableDisplay(
IN PRTMP_ADAPTER pAd)
{
int i;
MULTICAST_FILTER_TABLE_ENTRY *pEntry = NULL;
PMULTICAST_FILTER_TABLE pMulticastFilterTable = pAd->pMulticastFilterTable;
if (pMulticastFilterTable == NULL)
{
DBGPRINT(RT_DEBUG_OFF, ("%s Multicase filter table is not ready.\n", __FUNCTION__));
return;
}
// if FULL, return
if (pMulticastFilterTable->Size == 0)
{
DBGPRINT(RT_DEBUG_ERROR, ("Table empty.\n"));
return;
}
// allocate one MAC entry
RTMP_SEM_LOCK(&pMulticastFilterTable->MulticastFilterTabLock);
for (i = 0; i< MAX_LEN_OF_MULTICAST_FILTER_TABLE; i++)
{
// pick up the first available vacancy
if (pMulticastFilterTable->Content[i].Valid == TRUE)
{
PMEMBER_ENTRY pMemberEntry = NULL;
pEntry = &pMulticastFilterTable->Content[i];
DBGPRINT(RT_DEBUG_OFF, ("IF(%s) entry #%d, type=%s, GrpId=(%02x:%02x:%02x:%02x:%02x:%02x) memberCnt=%d\n",
RTMP_OS_NETDEV_GET_DEVNAME(pEntry->net_dev), i, (pEntry->type==0 ? "static":"dynamic"),
PRINT_MAC(pEntry->Addr), IgmpMemberCnt(&pEntry->MemberList)));
pMemberEntry = (PMEMBER_ENTRY)pEntry->MemberList.pHead;
while (pMemberEntry)
{
DBGPRINT(RT_DEBUG_OFF, ("member mac=(%02x:%02x:%02x:%02x:%02x:%02x)\n",
PRINT_MAC(pMemberEntry->Addr)));
pMemberEntry = pMemberEntry->pNext;
}
}
}
RTMP_SEM_UNLOCK(&pMulticastFilterTable->MulticastFilterTabLock);
return;
}
/*
==========================================================================
Description:
Add and new entry into MAC table
==========================================================================
*/
BOOLEAN MulticastFilterTableInsertEntry(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pGrpId,
IN PUCHAR pMemberAddr,
IN PNET_DEV dev,
IN MulticastFilterEntryType type)
{
UCHAR HashIdx;
int i;
MULTICAST_FILTER_TABLE_ENTRY *pEntry = NULL, *pCurrEntry, *pPrevEntry;
PMEMBER_ENTRY pMemberEntry;
PMULTICAST_FILTER_TABLE pMulticastFilterTable = pAd->pMulticastFilterTable;
if (pMulticastFilterTable == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Multicase filter table is not ready.\n", __FUNCTION__));
return FALSE;
}
// if FULL, return
if (pMulticastFilterTable->Size >= MAX_LEN_OF_MULTICAST_FILTER_TABLE)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Multicase filter table full. max-entries = %d\n",
__FUNCTION__, MAX_LEN_OF_MULTICAST_FILTER_TABLE));
return FALSE;
}
// check the rule is in table already or not.
if ((pEntry = MulticastFilterTableLookup(pMulticastFilterTable, pGrpId, dev)))
{
// doesn't indicate member mac address.
if(pMemberAddr == NULL)
{
return FALSE;
}
pMemberEntry = (PMEMBER_ENTRY)pEntry->MemberList.pHead;
while (pMemberEntry)
{
if (MAC_ADDR_EQUAL(pMemberAddr, pMemberEntry->Addr))
{
DBGPRINT(RT_DEBUG_ERROR, ("%s: already in Members list.\n", __FUNCTION__));
return FALSE;
}
pMemberEntry = pMemberEntry->pNext;
}
}
RTMP_SEM_LOCK(&pMulticastFilterTable->MulticastFilterTabLock);
do
{
ULONG Now;
// the multicast entry already exist but doesn't include the member yet.
if (pEntry != NULL && pMemberAddr != NULL)
{
InsertIgmpMember(pMulticastFilterTable, &pEntry->MemberList, pMemberAddr);
break;
}
// allocate one MAC entry
for (i = 0; i < MAX_LEN_OF_MULTICAST_FILTER_TABLE; i++)
{
// pick up the first available vacancy
pEntry = &pMulticastFilterTable->Content[i];
NdisGetSystemUpTime(&Now);
if ((pEntry->Valid == TRUE) && (pEntry->type == MCAT_FILTER_DYNAMIC)
&& ((Now - pEntry->lastTime) > IGMPMAC_TB_ENTRY_AGEOUT_TIME))
{
PMULTICAST_FILTER_TABLE_ENTRY pHashEntry;
HashIdx = MULTICAST_ADDR_HASH_INDEX(pEntry->Addr);
pHashEntry = pMulticastFilterTable->Hash[HashIdx];
if ((pEntry->net_dev == pHashEntry->net_dev)
&& MAC_ADDR_EQUAL(pEntry->Addr, pHashEntry->Addr))
{
pMulticastFilterTable->Hash[HashIdx] = pHashEntry->pNext;
pMulticastFilterTable->Size --;
DBGPRINT(RT_DEBUG_TRACE, ("MCastFilterTableDeleteEntry 1 - Total= %d\n", pMulticastFilterTable->Size));
} else
{
while (pHashEntry->pNext)
{
pPrevEntry = pHashEntry;
pHashEntry = pHashEntry->pNext;
if ((pEntry->net_dev == pHashEntry->net_dev)
&& MAC_ADDR_EQUAL(pEntry->Addr, pHashEntry->Addr))
{
pPrevEntry->pNext = pHashEntry->pNext;
pMulticastFilterTable->Size --;
DBGPRINT(RT_DEBUG_TRACE, ("MCastFilterTableDeleteEntry 2 - Total= %d\n", pMulticastFilterTable->Size));
break;
}
}
}
pEntry->Valid = FALSE;
DeleteIgmpMemberList(pMulticastFilterTable, &pEntry->MemberList);
}
if (pEntry->Valid == FALSE)
{
NdisZeroMemory(pEntry, sizeof(MULTICAST_FILTER_TABLE_ENTRY));
pEntry->Valid = TRUE;
COPY_MAC_ADDR(pEntry->Addr, pGrpId);
pEntry->net_dev = dev;
NdisGetSystemUpTime(&Now);
pEntry->lastTime = Now;
pEntry->type = type;
initList(&pEntry->MemberList);
if (pMemberAddr != NULL)
InsertIgmpMember(pMulticastFilterTable, &pEntry->MemberList, pMemberAddr);
pMulticastFilterTable->Size ++;
DBGPRINT(RT_DEBUG_TRACE, ("MulticastFilterTableInsertEntry -IF(%s) allocate entry #%d, Total= %d\n", RTMP_OS_NETDEV_GET_DEVNAME(dev), i, pMulticastFilterTable->Size));
break;
}
}
// add this MAC entry into HASH table
if (pEntry)
{
HashIdx = MULTICAST_ADDR_HASH_INDEX(pGrpId);
if (pMulticastFilterTable->Hash[HashIdx] == NULL)
{
pMulticastFilterTable->Hash[HashIdx] = pEntry;
} else
{
pCurrEntry = pMulticastFilterTable->Hash[HashIdx];
while (pCurrEntry->pNext != NULL)
pCurrEntry = pCurrEntry->pNext;
pCurrEntry->pNext = pEntry;
}
}
}while(FALSE);
RTMP_SEM_UNLOCK(&pMulticastFilterTable->MulticastFilterTabLock);
return TRUE;
}
/*
==========================================================================
Description:
Delete a specified client from MAC table
==========================================================================
*/
BOOLEAN MulticastFilterTableDeleteEntry(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pGrpId,
IN PUCHAR pMemberAddr,
IN PNET_DEV dev)
{
USHORT HashIdx;
MULTICAST_FILTER_TABLE_ENTRY *pEntry, *pPrevEntry;
PMULTICAST_FILTER_TABLE pMulticastFilterTable = pAd->pMulticastFilterTable;
USHORT Aid = MCAST_WCID;
SST Sst = SST_ASSOC;
UCHAR PsMode = PWR_ACTIVE, Rate;
if (pMulticastFilterTable == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Multicase filter table is not ready.\n", __FUNCTION__));
return FALSE;
}
RTMP_SEM_LOCK(&pMulticastFilterTable->MulticastFilterTabLock);
do
{
HashIdx = MULTICAST_ADDR_HASH_INDEX(pGrpId);
pPrevEntry = pEntry = pMulticastFilterTable->Hash[HashIdx];
while (pEntry && pEntry->Valid)
{
if ((pEntry->net_dev == dev)
&& MAC_ADDR_EQUAL(pEntry->Addr, pGrpId))
break;
else
{
pPrevEntry = pEntry;
pEntry = pEntry->pNext;
}
}
// check the rule is in table already or not.
if (pEntry && (pMemberAddr != NULL))
{
if(APSsPsInquiry(pAd, pMemberAddr, &Sst, &Aid, &PsMode, &Rate))
DeleteIgmpMember(pMulticastFilterTable, &pEntry->MemberList, pMemberAddr);
if (IgmpMemberCnt(&pEntry->MemberList) > 0)
break;
}
if (pEntry)
{
if (pEntry == pMulticastFilterTable->Hash[HashIdx])
{
pMulticastFilterTable->Hash[HashIdx] = pEntry->pNext;
DeleteIgmpMemberList(pMulticastFilterTable, &pEntry->MemberList);
NdisZeroMemory(pEntry, sizeof(MULTICAST_FILTER_TABLE_ENTRY));
pMulticastFilterTable->Size --;
DBGPRINT(RT_DEBUG_TRACE, ("MCastFilterTableDeleteEntry 1 - Total= %d\n", pMulticastFilterTable->Size));
}
else
{
pPrevEntry->pNext = pEntry->pNext;
DeleteIgmpMemberList(pMulticastFilterTable, &pEntry->MemberList);
NdisZeroMemory(pEntry, sizeof(MULTICAST_FILTER_TABLE_ENTRY));
pMulticastFilterTable->Size --;
DBGPRINT(RT_DEBUG_TRACE, ("MCastFilterTableDeleteEntry 2 - Total= %d\n", pMulticastFilterTable->Size));
}
}
else
{
DBGPRINT(RT_DEBUG_ERROR, ("%s: the Group doesn't exist.\n", __FUNCTION__));
}
} while(FALSE);
RTMP_SEM_UNLOCK(&pMulticastFilterTable->MulticastFilterTabLock);
return TRUE;
}
/*
==========================================================================
Description:
Look up the MAC address in the IGMP table. Return NULL if not found.
Return:
pEntry - pointer to the MAC entry; NULL is not found
==========================================================================
*/
PMULTICAST_FILTER_TABLE_ENTRY MulticastFilterTableLookup(
IN PMULTICAST_FILTER_TABLE pMulticastFilterTable,
IN PUCHAR pAddr,
IN PNET_DEV dev)
{
ULONG HashIdx, Now;
PMULTICAST_FILTER_TABLE_ENTRY pEntry = NULL, pPrev = NULL;
if (pMulticastFilterTable == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Multicase filter table is not ready.\n", __FUNCTION__));
return NULL;
}
RTMP_SEM_LOCK(&pMulticastFilterTable->MulticastFilterTabLock);
HashIdx = MULTICAST_ADDR_HASH_INDEX(pAddr);
pEntry = pPrev = pMulticastFilterTable->Hash[HashIdx];
while (pEntry && pEntry->Valid)
{
if ((pEntry->net_dev == dev)
&& MAC_ADDR_EQUAL(pEntry->Addr, pAddr))
{
NdisGetSystemUpTime(&Now);
pEntry->lastTime = Now;
break;
}
else
{
NdisGetSystemUpTime(&Now);
if ((pEntry->Valid == TRUE) && (pEntry->type == MCAT_FILTER_DYNAMIC)
&& RTMP_TIME_AFTER(Now, pEntry->lastTime+IGMPMAC_TB_ENTRY_AGEOUT_TIME))
{
// Remove the aged entry
if (pEntry == pMulticastFilterTable->Hash[HashIdx])
{
pMulticastFilterTable->Hash[HashIdx] = pEntry->pNext;
pPrev = pMulticastFilterTable->Hash[HashIdx];
DeleteIgmpMemberList(pMulticastFilterTable, &pEntry->MemberList);
NdisZeroMemory(pEntry, sizeof(MULTICAST_FILTER_TABLE_ENTRY));
pMulticastFilterTable->Size --;
pEntry = pPrev;
DBGPRINT(RT_DEBUG_TRACE, ("MCastFilterTableDeleteEntry 2 - Total= %d\n", pMulticastFilterTable->Size));
}
else
{
pPrev->pNext = pEntry->pNext;
DeleteIgmpMemberList(pMulticastFilterTable, &pEntry->MemberList);
NdisZeroMemory(pEntry, sizeof(MULTICAST_FILTER_TABLE_ENTRY));
pMulticastFilterTable->Size --;
pEntry = (pPrev == NULL ? NULL: pPrev->pNext);
DBGPRINT(RT_DEBUG_TRACE, ("MCastFilterTableDeleteEntry 2 - Total= %d\n", pMulticastFilterTable->Size));
}
}
else
{
pPrev = pEntry;
pEntry = pEntry->pNext;
}
}
}
RTMP_SEM_UNLOCK(&pMulticastFilterTable->MulticastFilterTabLock);
return pEntry;
}
VOID IGMPSnooping(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pDstMacAddr,
IN PUCHAR pSrcMacAddr,
IN PUCHAR pIpHeader,
IN PNET_DEV pDev)
{
INT i;
INT IpHeaderLen;
UCHAR GroupType;
UINT16 numOfGroup;
UCHAR IgmpVerType;
PUCHAR pIgmpHeader;
PUCHAR pGroup;
UCHAR AuxDataLen;
UINT16 numOfSources;
PUCHAR pGroupIpAddr;
UCHAR GroupMacAddr[6];
PUCHAR pGroupMacAddr = (PUCHAR)&GroupMacAddr;
if(isIgmpPkt(pDstMacAddr, pIpHeader))
{
IpHeaderLen = (*(pIpHeader + 2) & 0x0f) * 4;
pIgmpHeader = pIpHeader + 2 + IpHeaderLen;
IgmpVerType = (UCHAR)(*(pIgmpHeader));
DBGPRINT(RT_DEBUG_TRACE, ("IGMP type=%0x\n", IgmpVerType));
switch(IgmpVerType)
{
case IGMP_V1_MEMBERSHIP_REPORT: // IGMP version 1 membership report.
case IGMP_V2_MEMBERSHIP_REPORT: // IGMP version 2 membership report.
pGroupIpAddr = (PUCHAR)(pIgmpHeader + 4);
ConvertMulticastIP2MAC(pGroupIpAddr, (PUCHAR *)&pGroupMacAddr, ETH_P_IP);
DBGPRINT(RT_DEBUG_TRACE, ("IGMP Group=%02x:%02x:%02x:%02x:%02x:%02x\n",
GroupMacAddr[0], GroupMacAddr[1], GroupMacAddr[2], GroupMacAddr[3], GroupMacAddr[4], GroupMacAddr[5]));
MulticastFilterTableInsertEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev, MCAT_FILTER_DYNAMIC);
break;
case IGMP_LEAVE_GROUP: // IGMP version 1 and version 2 leave group.
pGroupIpAddr = (PUCHAR)(pIgmpHeader + 4);
ConvertMulticastIP2MAC(pGroupIpAddr, (PUCHAR *)&pGroupMacAddr, ETH_P_IP);
DBGPRINT(RT_DEBUG_TRACE, ("IGMP Group=%02x:%02x:%02x:%02x:%02x:%02x\n",
GroupMacAddr[0], GroupMacAddr[1], GroupMacAddr[2], GroupMacAddr[3], GroupMacAddr[4], GroupMacAddr[5]));
MulticastFilterTableDeleteEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev);
break;
case IGMP_V3_MEMBERSHIP_REPORT: // IGMP version 3 membership report.
numOfGroup = ntohs(*((UINT16 *)(pIgmpHeader + 6)));
pGroup = (PUCHAR)(pIgmpHeader + 8);
for (i=0; i < numOfGroup; i++)
{
GroupType = (UCHAR)(*pGroup);
AuxDataLen = (UCHAR)(*(pGroup + 1));
numOfSources = ntohs(*((UINT16 *)(pGroup + 2)));
pGroupIpAddr = (PUCHAR)(pGroup + 4);
DBGPRINT(RT_DEBUG_TRACE, ("IGMPv3 Type=%d, ADL=%d, numOfSource=%d\n", GroupType, AuxDataLen, numOfSources));
ConvertMulticastIP2MAC(pGroupIpAddr, (PUCHAR *)&pGroupMacAddr, ETH_P_IP);
DBGPRINT(RT_DEBUG_TRACE, ("IGMP Group=%02x:%02x:%02x:%02x:%02x:%02x\n",
GroupMacAddr[0], GroupMacAddr[1], GroupMacAddr[2], GroupMacAddr[3], GroupMacAddr[4], GroupMacAddr[5]));
do
{
if((GroupType == MODE_IS_EXCLUDE) || (GroupType == CHANGE_TO_EXCLUDE_MODE) || (GroupType == ALLOW_NEW_SOURCES))
{
MulticastFilterTableInsertEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev, MCAT_FILTER_DYNAMIC);
break;
}
if((GroupType == MODE_IS_INCLUDE) || (GroupType == BLOCK_OLD_SOURCES))
{
MulticastFilterTableDeleteEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev);
break;
}
if((GroupType == CHANGE_TO_INCLUDE_MODE))
{
if(numOfSources == 0)
MulticastFilterTableDeleteEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev);
else
MulticastFilterTableInsertEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev, MCAT_FILTER_DYNAMIC);
break;
}
} while(FALSE);
pGroup += (8 + (numOfSources * 4) + AuxDataLen);
}
break;
default:
DBGPRINT(RT_DEBUG_TRACE, ("unknow IGMP Type=%d\n", IgmpVerType));
break;
}
}
return;
}
static BOOLEAN isIgmpMacAddr(
IN PUCHAR pMacAddr)
{
if((pMacAddr[0] == 0x01)
&& (pMacAddr[1] == 0x00)
&& (pMacAddr[2] == 0x5e))
return TRUE;
return FALSE;
}
BOOLEAN isIgmpPkt(
IN PUCHAR pDstMacAddr,
IN PUCHAR pIpHeader)
{
UINT16 IpProtocol = ntohs(*((UINT16 *)(pIpHeader)));
UCHAR IgmpProtocol;
if(!isIgmpMacAddr(pDstMacAddr))
return FALSE;
if(IpProtocol == ETH_P_IP)
{
IgmpProtocol = (UCHAR)*(pIpHeader + 11);
if(IgmpProtocol == IGMP_PROTOCOL_DESCRIPTOR)
return TRUE;
}
return FALSE;
}
static VOID InsertIgmpMember(
IN PMULTICAST_FILTER_TABLE pMulticastFilterTable,
IN PLIST_HEADER pList,
IN PUCHAR pMemberAddr)
{
PMEMBER_ENTRY pMemberEntry;
if(pList == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s: membert list doesn't exist.\n", __FUNCTION__));
return;
}
if (pMemberAddr == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s: invalid member.\n", __FUNCTION__));
return;
}
if((pMemberEntry = (PMEMBER_ENTRY)AllocaGrpMemberEntry(pMulticastFilterTable)) != NULL)
{
NdisZeroMemory(pMemberEntry, sizeof(MEMBER_ENTRY));
COPY_MAC_ADDR(pMemberEntry->Addr, pMemberAddr);
insertTailList(pList, (PLIST_ENTRY)pMemberEntry);
DBGPRINT(RT_DEBUG_TRACE, ("%s Member Mac=%02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__,
pMemberEntry->Addr[0], pMemberEntry->Addr[1], pMemberEntry->Addr[2],
pMemberEntry->Addr[3], pMemberEntry->Addr[4], pMemberEntry->Addr[5]));
}
return;
}
static VOID DeleteIgmpMember(
IN PMULTICAST_FILTER_TABLE pMulticastFilterTable,
IN PLIST_HEADER pList,
IN PUCHAR pMemberAddr)
{
PMEMBER_ENTRY pCurEntry;
if((pList == NULL) || (pList->pHead == NULL))
{
DBGPRINT(RT_DEBUG_ERROR, ("%s: membert list doesn't exist.\n", __FUNCTION__));
return;
}
if (pMemberAddr == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s: invalid member.\n", __FUNCTION__));
return;
}
pCurEntry = (PMEMBER_ENTRY)pList->pHead;
while (pCurEntry)
{
if(MAC_ADDR_EQUAL(pMemberAddr, pCurEntry->Addr))
{
delEntryList(pList, (PLIST_ENTRY)pCurEntry);
FreeGrpMemberEntry(pMulticastFilterTable, pCurEntry);
break;
}
pCurEntry = pCurEntry->pNext;
}
return;
}
static VOID DeleteIgmpMemberList(
IN PMULTICAST_FILTER_TABLE pMulticastFilterTable,
IN PLIST_HEADER pList)
{
PMEMBER_ENTRY pCurEntry, pPrvEntry;
if((pList == NULL) || (pList->pHead == NULL))
{
DBGPRINT(RT_DEBUG_ERROR, ("%s: membert list doesn't exist.\n", __FUNCTION__));
return;
}
pPrvEntry = pCurEntry = (PMEMBER_ENTRY)pList->pHead;
while (pCurEntry)
{
delEntryList(pList, (PLIST_ENTRY)pCurEntry);
pPrvEntry = pCurEntry;
pCurEntry = pCurEntry->pNext;
FreeGrpMemberEntry(pMulticastFilterTable, pPrvEntry);
}
initList(pList);
return;
}
UCHAR IgmpMemberCnt(
IN PLIST_HEADER pList)
{
if(pList == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s: membert list doesn't exist.\n", __FUNCTION__));
return 0;
}
return getListSize(pList);
}
VOID IgmpGroupDelMembers(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pMemberAddr,
IN PNET_DEV pDev)
{
INT i;
MULTICAST_FILTER_TABLE_ENTRY *pEntry = NULL;
PMULTICAST_FILTER_TABLE pMulticastFilterTable = pAd->pMulticastFilterTable;
for (i = 0; i < MAX_LEN_OF_MULTICAST_FILTER_TABLE; i++)
{
// pick up the first available vacancy
pEntry = &pMulticastFilterTable->Content[i];
if (pEntry->Valid == TRUE)
{
if(pMemberAddr != NULL)
{
RTMP_SEM_LOCK(&pMulticastFilterTable->MulticastFilterTabLock);
DeleteIgmpMember(pMulticastFilterTable, &pEntry->MemberList, pMemberAddr);
RTMP_SEM_UNLOCK(&pMulticastFilterTable->MulticastFilterTabLock);
}
if((pEntry->type == MCAT_FILTER_DYNAMIC)
&& (IgmpMemberCnt(&pEntry->MemberList) == 0))
MulticastFilterTableDeleteEntry(pAd, pEntry->Addr, pMemberAddr, pDev);
}
}
}
INT Set_IgmpSn_Enable_Proc(
IN PRTMP_ADAPTER pAd,
IN PSTRING arg)
{
UINT Enable;
POS_COOKIE pObj;
UCHAR ifIndex;
PNET_DEV pDev;
pObj = (POS_COOKIE) pAd->OS_Cookie;
ifIndex = pObj->ioctl_if;
pDev = (ifIndex == MAIN_MBSSID) ? (pAd->net_dev) : (pAd->ApCfg.MBSSID[ifIndex].MSSIDDev);
Enable = (UINT) simple_strtol(arg, 0, 10);
pAd->ApCfg.MBSSID[ifIndex].IgmpSnoopEnable = (BOOLEAN)(Enable == 0 ? 0 : 1);
DBGPRINT(RT_DEBUG_TRACE, ("%s::(%s) %s\n", __FUNCTION__, RTMP_OS_NETDEV_GET_DEVNAME(pDev), Enable == TRUE ? "Enable IGMP Snooping":"Disable IGMP Snooping"));
return TRUE;
}
INT Set_IgmpSn_AddEntry_Proc(
IN PRTMP_ADAPTER pAd,
IN PSTRING arg)
{
INT i;
BOOLEAN bGroupId = 1;
PSTRING value;
PSTRING thisChar;
UCHAR IpAddr[4];
UCHAR Addr[ETH_LENGTH_OF_ADDRESS];
UCHAR GroupId[ETH_LENGTH_OF_ADDRESS];
PUCHAR *pAddr = (PUCHAR *)&Addr;
PNET_DEV pDev;
POS_COOKIE pObj;
UCHAR ifIndex;
pObj = (POS_COOKIE) pAd->OS_Cookie;
ifIndex = pObj->ioctl_if;
pDev = (ifIndex == MAIN_MBSSID) ? (pAd->net_dev) : (pAd->ApCfg.MBSSID[ifIndex].MSSIDDev);
while ((thisChar = strsep((char **)&arg, "-")) != NULL)
{
// refuse the Member if it's not a MAC address.
if((bGroupId == 0) && (strlen(thisChar) != 17))
continue;
if(strlen(thisChar) == 17) //Mac address acceptable format 01:02:03:04:05:06 length 17
{
for (i=0, value = rstrtok(thisChar,":"); value; value = rstrtok(NULL,":"))
{
if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) )
return FALSE; //Invalid
AtoH(value, &Addr[i++], 1);
}
if(i != 6)
return FALSE; //Invalid
}
else
{
for (i=0, value = rstrtok(thisChar,"."); value; value = rstrtok(NULL,"."))
{
if((strlen(value) > 0) && (strlen(value) <= 3))
{
int ii;
for(ii=0; ii<strlen(value); ii++)
if (!isxdigit(*(value + ii)))
return FALSE;
}
else
return FALSE; //Invalid
IpAddr[i] = (UCHAR)simple_strtol(value, NULL, 10);
i++;
}
if(i != 4)
return FALSE; //Invalid
ConvertMulticastIP2MAC(IpAddr, (PUCHAR *)&pAddr, ETH_P_IP);
}
if(bGroupId == 1)
COPY_MAC_ADDR(GroupId, Addr);
// Group-Id must be a MCAST address.
if((bGroupId == 1) && IS_MULTICAST_MAC_ADDR(Addr))
MulticastFilterTableInsertEntry(pAd, GroupId, NULL, pDev, MCAT_FILTER_STATIC);
// Group-Member must be a UCAST address.
else if ((bGroupId == 0) && !IS_MULTICAST_MAC_ADDR(Addr))
MulticastFilterTableInsertEntry(pAd, GroupId, Addr, pDev, MCAT_FILTER_STATIC);
else
{
DBGPRINT(RT_DEBUG_TRACE, ("%s (%2X:%2X:%2X:%2X:%2X:%2X) is not a acceptable address.\n",
__FUNCTION__, Addr[0], Addr[1], Addr[2], Addr[3], Addr[4], Addr[5]));
return FALSE;
}
bGroupId = 0;
DBGPRINT(RT_DEBUG_TRACE, ("%s (%2X:%2X:%2X:%2X:%2X:%2X)\n",
__FUNCTION__, Addr[0], Addr[1], Addr[2], Addr[3], Addr[4], Addr[5]));
}
return TRUE;
}
INT Set_IgmpSn_DelEntry_Proc(
IN PRTMP_ADAPTER pAd,
IN PSTRING arg)
{
INT i, memberCnt = 0;
BOOLEAN bGroupId = 1;
PSTRING value;
PSTRING thisChar;
UCHAR IpAddr[4];
UCHAR Addr[ETH_LENGTH_OF_ADDRESS];
UCHAR GroupId[ETH_LENGTH_OF_ADDRESS];
PUCHAR *pAddr = (PUCHAR *)&Addr;
PNET_DEV pDev;
POS_COOKIE pObj;
UCHAR ifIndex;
pObj = (POS_COOKIE) pAd->OS_Cookie;
ifIndex = pObj->ioctl_if;
pDev = (ifIndex == MAIN_MBSSID) ? (pAd->net_dev) : (pAd->ApCfg.MBSSID[ifIndex].MSSIDDev);
while ((thisChar = strsep((char **)&arg, "-")) != NULL)
{
// refuse the Member if it's not a MAC address.
if((bGroupId == 0) && (strlen(thisChar) != 17))
continue;
if(strlen(thisChar) == 17) //Mac address acceptable format 01:02:03:04:05:06 length 17
{
for (i=0, value = rstrtok(thisChar,":"); value; value = rstrtok(NULL,":"))
{
if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) )
return FALSE; //Invalid
AtoH(value, &Addr[i++], 1);
}
if(i != 6)
return FALSE; //Invalid
}
else
{
for (i=0, value = rstrtok(thisChar,"."); value; value = rstrtok(NULL,"."))
{
if((strlen(value) > 0) && (strlen(value) <= 3))
{
int ii;
for(ii=0; ii<strlen(value); ii++)
if (!isxdigit(*(value + ii)))
return FALSE;
}
else
return FALSE; //Invalid
IpAddr[i] = (UCHAR)simple_strtol(value, NULL, 10);
i++;
}
if(i != 4)
return FALSE; //Invalid
ConvertMulticastIP2MAC(IpAddr, (PUCHAR *)&pAddr, ETH_P_IP);
}
if(bGroupId == 1)
COPY_MAC_ADDR(GroupId, Addr);
else
memberCnt++;
if (memberCnt > 0 )
MulticastFilterTableDeleteEntry(pAd, (PUCHAR)GroupId, Addr, pDev);
bGroupId = 0;
}
if(memberCnt == 0)
MulticastFilterTableDeleteEntry(pAd, (PUCHAR)GroupId, NULL, pDev);
DBGPRINT(RT_DEBUG_TRACE, ("%s (%2X:%2X:%2X:%2X:%2X:%2X)\n",
__FUNCTION__, Addr[0], Addr[1], Addr[2], Addr[3], Addr[4], Addr[5]));
return TRUE;
}
INT Set_IgmpSn_TabDisplay_Proc(
IN PRTMP_ADAPTER pAd,
IN PSTRING arg)
{
IGMPTableDisplay(pAd);
return TRUE;
}
void rtmp_read_igmp_snoop_from_file(
IN PRTMP_ADAPTER pAd,
PSTRING tmpbuf,
PSTRING buffer)
{
PSTRING macptr;
INT i=0;
//IgmpSnEnable
if(RTMPGetKeyParameter("IgmpSnEnable", tmpbuf, 128, buffer, TRUE))
{
for (i = 0, macptr = rstrtok(tmpbuf,";"); (macptr && i < pAd->ApCfg.BssidNum); macptr = rstrtok(NULL,";"), i++)
{
if ((strncmp(macptr, "0", 1) == 0))
pAd->ApCfg.MBSSID[i].IgmpSnoopEnable = FALSE;
else if ((strncmp(macptr, "1", 1) == 0))
pAd->ApCfg.MBSSID[i].IgmpSnoopEnable = TRUE;
else
pAd->ApCfg.MBSSID[i].IgmpSnoopEnable = FALSE;
DBGPRINT(RT_DEBUG_TRACE, ("MBSSID[%d].Enable=%d\n", i, pAd->ApCfg.MBSSID[i].IgmpSnoopEnable));
}
}
}
NDIS_STATUS IgmpPktInfoQuery(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pSrcBufVA,
IN PNDIS_PACKET pPacket,
IN UCHAR apidx,
OUT BOOLEAN *pInIgmpGroup,
OUT PMULTICAST_FILTER_TABLE_ENTRY *ppGroupEntry)
{
if(IS_MULTICAST_MAC_ADDR(pSrcBufVA))
{
BOOLEAN IgmpMldPkt = FALSE;
PUCHAR pIpHeader = pSrcBufVA + 12;
if(ntohs(*((UINT16 *)(pIpHeader))) == ETH_P_IPV6)
IgmpMldPkt = isMldPkt(pSrcBufVA, pIpHeader, NULL, NULL);
else
IgmpMldPkt = isIgmpPkt(pSrcBufVA, pIpHeader);
if (IgmpMldPkt)
{
*ppGroupEntry = NULL;
}
else if ((*ppGroupEntry = MulticastFilterTableLookup(pAd->pMulticastFilterTable, pSrcBufVA,
pAd->ApCfg.MBSSID[apidx].MSSIDDev)) == NULL)
{
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return NDIS_STATUS_FAILURE;
}
*pInIgmpGroup = TRUE;
}
else if (IS_BROADCAST_MAC_ADDR(pSrcBufVA))
{
PUCHAR pDstIpAddr = pSrcBufVA + 30; // point to Destination of Ip address of IP header.
UCHAR GroupMacAddr[6];
PUCHAR pGroupMacAddr = (PUCHAR)&GroupMacAddr;
ConvertMulticastIP2MAC(pDstIpAddr, (PUCHAR *)&pGroupMacAddr, ETH_P_IP);
if ((*ppGroupEntry = MulticastFilterTableLookup(pAd->pMulticastFilterTable, pGroupMacAddr,
pAd->ApCfg.MBSSID[apidx].MSSIDDev)) != NULL)
{
*pInIgmpGroup = TRUE;
}
}
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS IgmpPktClone(
IN PRTMP_ADAPTER pAd,
IN PNDIS_PACKET pPacket,
IN UCHAR QueIdx,
IN PMULTICAST_FILTER_TABLE_ENTRY pGroupEntry)
{
PNDIS_PACKET pSkbClone = NULL;
PMEMBER_ENTRY pMemberEntry = (PMEMBER_ENTRY)pGroupEntry->MemberList.pHead;
MAC_TABLE_ENTRY *pMacEntry = NULL;
USHORT Aid;
SST Sst = SST_ASSOC;
UCHAR PsMode = PWR_ACTIVE;
UCHAR Rate;
unsigned long IrqFlags;
// check all members of the IGMP group.
while(pMemberEntry != NULL)
{
pMacEntry = APSsPsInquiry(pAd, pMemberEntry->Addr, &Sst, &Aid, &PsMode, &Rate);
if (pMacEntry && (Sst == SST_ASSOC) && (PsMode != PWR_SAVE))
{
pSkbClone = skb_clone(RTPKT_TO_OSPKT(pPacket), MEM_ALLOC_FLAG);
if(pSkbClone)
{
RTMP_SET_PACKET_WCID(pSkbClone, (UCHAR)Aid);
// Pkt type must set to PKTSRC_NDIS.
// It cause of the deason that APHardTransmit()
// doesn't handle PKTSRC_DRIVER pkt type in version 1.3.0.0.
RTMP_SET_PACKET_SOURCE(pSkbClone, PKTSRC_NDIS);
}
else
{
pMemberEntry = pMemberEntry->pNext;
continue;
}
// insert the pkt to TxSwQueue.
if (pAd->TxSwQueue[QueIdx].Number >= MAX_PACKETS_IN_QUEUE)
{
#ifdef BLOCK_NET_IF
StopNetIfQueue(pAd, QueIdx, pSkbClone);
#endif // BLOCK_NET_IF //
RELEASE_NDIS_PACKET(pAd, pSkbClone, NDIS_STATUS_FAILURE);
return NDIS_STATUS_FAILURE;
}
else
{
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
InsertTailQueueAc(pAd, pMacEntry, &pAd->TxSwQueue[QueIdx], PACKET_TO_QUEUE_ENTRY(pSkbClone));
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
}
}
pMemberEntry = pMemberEntry->pNext;
}
return NDIS_STATUS_SUCCESS;
}
static inline BOOLEAN isMldMacAddr(
IN PUCHAR pMacAddr)
{
return ((pMacAddr[0] == 0x33) && (pMacAddr[1] == 0x33)) ? TRUE : FALSE;
}
static inline BOOLEAN IsSupportedMldMsg(
IN UINT8 MsgType)
{
BOOLEAN result = FALSE;
switch(MsgType)
{
case MLD_V1_LISTENER_REPORT:
case MLD_V1_LISTENER_DONE:
case MLD_V2_LISTERNER_REPORT:
result = TRUE;
break;
default:
result = FALSE;
break;
}
return result;
}
BOOLEAN isMldPkt(
IN PUCHAR pDstMacAddr,
IN PUCHAR pIpHeader,
OUT UINT8 *pProtoType,
OUT PUCHAR *pMldHeader)
{
BOOLEAN result = FALSE;
UINT16 IpProtocol = ntohs(*((UINT16 *)(pIpHeader)));
if(!isMldMacAddr(pDstMacAddr))
return FALSE;
if(IpProtocol != ETH_P_IPV6)
return FALSE;
// skip protocol (2 Bytes).
pIpHeader += 2;
do
{
PRT_IPV6_HDR pIpv6Hdr = (PRT_IPV6_HDR)(pIpHeader);
UINT8 nextProtocol = pIpv6Hdr->nextHdr;
UINT32 offset = IPV6_HDR_LEN;
while(nextProtocol != IPV6_NEXT_HEADER_ICMPV6)
{
if(IPv6ExtHdrHandle((RT_IPV6_EXT_HDR *)(pIpHeader + offset), &nextProtocol, &offset) == FALSE)
break;
}
if(nextProtocol == IPV6_NEXT_HEADER_ICMPV6)
{
PRT_ICMPV6_HDR pICMPv6Hdr = (PRT_ICMPV6_HDR)(pIpHeader + offset);
if (IsSupportedMldMsg(pICMPv6Hdr->type) == TRUE)
{
if (pProtoType != NULL)
*pProtoType = pICMPv6Hdr->type;
if (pMldHeader != NULL)
*pMldHeader = (PUCHAR)pICMPv6Hdr;
result = TRUE;
}
}
}while(FALSE);
return result;
}
/* MLD v1 messages have the following format:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Maximum Response Delay | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Multicast Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/* Version 3 Membership Report Message
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type = 143 | Reserved | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved | Number of Group Records (M) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. Multicast Address Record [1] .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. Multicast Address Record [2] .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| . |
. . .
| . |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. Multicast Address Record [M] .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
where each Group Record has the following internal format:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Record Type | Aux Data Len | Number of Sources (N) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
* *
| |
* Multicast Address *
| |
* *
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
* *
| |
* Source Address [1] *
| |
* *
| |
+- -+
| |
* *
| |
* Source Address [2] *
| |
* *
| |
+- -+
. . .
. . .
. . .
+- -+
| |
* *
| |
* Source Address [N] *
| |
* *
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. Auxiliary Data .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
VOID MLDSnooping(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pDstMacAddr,
IN PUCHAR pSrcMacAddr,
IN PUCHAR pIpHeader,
IN PNET_DEV pDev)
{
INT i;
UCHAR GroupType;
UINT16 numOfGroup;
PUCHAR pGroup;
UCHAR AuxDataLen;
UINT16 numOfSources;
PUCHAR pGroupIpAddr;
UCHAR GroupMacAddr[6];
PUCHAR pGroupMacAddr = (PUCHAR)&GroupMacAddr;
UINT8 MldType;
PUCHAR pMldHeader;
if(isMldPkt(pDstMacAddr, pIpHeader, &MldType, &pMldHeader) == TRUE)
{
DBGPRINT(RT_DEBUG_TRACE, ("MLD type=%0x\n", MldType));
switch(MldType)
{
case MLD_V1_LISTENER_REPORT:
// skip Type(1 Byte), code(1 Byte), checksum(2 Bytes), Maximum Rsp Delay(2 Bytes), Reserve(2 Bytes).
pGroupIpAddr = (PUCHAR)(pMldHeader + 8);
ConvertMulticastIP2MAC(pGroupIpAddr, (PUCHAR *)&pGroupMacAddr, ETH_P_IPV6);
DBGPRINT(RT_DEBUG_TRACE, ("Group Id=%02x:%02x:%02x:%02x:%02x:%02x\n",
GroupMacAddr[0], GroupMacAddr[1], GroupMacAddr[2], GroupMacAddr[3], GroupMacAddr[4], GroupMacAddr[5]));
MulticastFilterTableInsertEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev, MCAT_FILTER_DYNAMIC);
break;
case MLD_V1_LISTENER_DONE:
// skip Type(1 Byte), code(1 Byte), checksum(2 Bytes), Maximum Rsp Delay(2 Bytes), Reserve(2 Bytes).
pGroupIpAddr = (PUCHAR)(pMldHeader + 8);
ConvertMulticastIP2MAC(pGroupIpAddr, (PUCHAR *)&pGroupMacAddr, ETH_P_IPV6);
DBGPRINT(RT_DEBUG_TRACE, ("Group Id=%02x:%02x:%02x:%02x:%02x:%02x\n",
GroupMacAddr[0], GroupMacAddr[1], GroupMacAddr[2], GroupMacAddr[3], GroupMacAddr[4], GroupMacAddr[5]));
MulticastFilterTableDeleteEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev);
break;
case MLD_V2_LISTERNER_REPORT: // IGMP version 3 membership report.
numOfGroup = ntohs(*((UINT16 *)(pMldHeader + 6)));
pGroup = (PUCHAR)(pMldHeader + 8);
for (i=0; i < numOfGroup; i++)
{
GroupType = (UCHAR)(*pGroup);
AuxDataLen = (UCHAR)(*(pGroup + 1));
numOfSources = ntohs(*((UINT16 *)(pGroup + 2)));
pGroupIpAddr = (PUCHAR)(pGroup + 4);
DBGPRINT(RT_DEBUG_TRACE, ("MLDv2 Type=%d, ADL=%d, numOfSource=%d\n", GroupType, AuxDataLen, numOfSources));
ConvertMulticastIP2MAC(pGroupIpAddr, (PUCHAR *)&pGroupMacAddr, ETH_P_IPV6);
DBGPRINT(RT_DEBUG_TRACE, ("MLD Group=%02x:%02x:%02x:%02x:%02x:%02x\n",
GroupMacAddr[0], GroupMacAddr[1], GroupMacAddr[2], GroupMacAddr[3], GroupMacAddr[4], GroupMacAddr[5]));
do
{
if((GroupType == MODE_IS_EXCLUDE) || (GroupType == CHANGE_TO_EXCLUDE_MODE) || (GroupType == ALLOW_NEW_SOURCES))
{
MulticastFilterTableInsertEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev, MCAT_FILTER_DYNAMIC);
break;
}
if((GroupType == MODE_IS_INCLUDE) || (GroupType == BLOCK_OLD_SOURCES))
{
MulticastFilterTableDeleteEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev);
break;
}
if((GroupType == CHANGE_TO_INCLUDE_MODE))
{
if(numOfSources == 0)
MulticastFilterTableDeleteEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev);
else
MulticastFilterTableInsertEntry(pAd, GroupMacAddr, pSrcMacAddr, pDev, MCAT_FILTER_DYNAMIC);
break;
}
} while(FALSE);
// skip 4 Bytes (Record Type, Aux Data Len, Number of Sources) + a IPv6 address.
pGroup += (4 + IPV6_ADDR_LEN + (numOfSources * 16) + AuxDataLen);
}
break;
default:
DBGPRINT(RT_DEBUG_TRACE, ("unknow MLD Type=%d\n", MldType));
break;
}
}
return;
}
#endif // IGMP_SNOOP_SUPPORT //