1366 lines
41 KiB
C
1366 lines
41 KiB
C
|
/*
|
||
|
*************************************************************************
|
||
|
* 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 //
|