blob: 5b4fd372ec367a4a818ddf34e9921b27eea36987 [file] [log] [blame]
#include "headers.h"
static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
static VOID DumpIpv6Header(IPV6Header *pstIpv6Header);
static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader,BOOLEAN *bParseDone,USHORT *pusPayloadLength)
{
UCHAR *pucRetHeaderPtr = NULL;
UCHAR *pucPayloadPtr = NULL;
USHORT usNextHeaderOffset = 0 ;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
if((NULL == ppucPayload) || (*pusPayloadLength == 0) || (*bParseDone))
{
*bParseDone = TRUE;
return NULL;
}
pucRetHeaderPtr = *ppucPayload;
pucPayloadPtr = *ppucPayload;
if(!pucRetHeaderPtr || !pucPayloadPtr)
{
*bParseDone = TRUE;
return NULL;
}
//Get the Nextt Header Type
*bParseDone = FALSE;
switch(*pucNextHeader)
{
case IPV6HDR_TYPE_HOPBYHOP:
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 HopByHop Header");
usNextHeaderOffset+=sizeof(IPV6HopByHopOptionsHeader);
}
break;
case IPV6HDR_TYPE_ROUTING:
{
IPV6RoutingHeader *pstIpv6RoutingHeader;
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Routing Header");
pstIpv6RoutingHeader = (IPV6RoutingHeader *)pucPayloadPtr;
usNextHeaderOffset += sizeof(IPV6RoutingHeader);
usNextHeaderOffset += pstIpv6RoutingHeader->ucNumAddresses * IPV6_ADDRESS_SIZEINBYTES;
}
break;
case IPV6HDR_TYPE_FRAGMENTATION:
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Fragmentation Header");
usNextHeaderOffset+= sizeof(IPV6FragmentHeader);
}
break;
case IPV6HDR_TYPE_DESTOPTS:
{
IPV6DestOptionsHeader *pstIpv6DestOptsHdr = (IPV6DestOptionsHeader *)pucPayloadPtr;
int nTotalOptions = pstIpv6DestOptsHdr->ucHdrExtLen;
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 DestOpts Header Header");
usNextHeaderOffset+= sizeof(IPV6DestOptionsHeader);
usNextHeaderOffset+= nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ;
}
break;
case IPV6HDR_TYPE_AUTHENTICATION:
{
IPV6AuthenticationHeader *pstIpv6AuthHdr = (IPV6AuthenticationHeader *)pucPayloadPtr;
int nHdrLen = pstIpv6AuthHdr->ucLength;
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Authentication Header");
usNextHeaderOffset+= nHdrLen * 4;
}
break;
case IPV6HDR_TYPE_ENCRYPTEDSECURITYPAYLOAD:
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Encrypted Security Payload Header");
*bParseDone = TRUE;
}
break;
case IPV6_ICMP_HDR_TYPE:
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " ICMP Header");
*bParseDone = TRUE;
}
break;
case TCP_HEADER_TYPE:
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nTCP Header");
*bParseDone = TRUE;
}
break;
case UDP_HEADER_TYPE:
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nUDP Header");
*bParseDone = TRUE;
}
break;
default :
{
*bParseDone = TRUE;
}
break;
}
if(*bParseDone == FALSE)
{
if(*pusPayloadLength <= usNextHeaderOffset)
{
*bParseDone = TRUE;
}
else
{
*pucNextHeader = *pucPayloadPtr;
pucPayloadPtr+=usNextHeaderOffset;
(*pusPayloadLength)-=usNextHeaderOffset;
}
}
*ppucPayload = pucPayloadPtr;
return pucRetHeaderPtr;
}
static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload,USHORT *pusSrcPort,USHORT *pusDestPort,USHORT usPayloadLength,UCHAR ucNextHeader)
{
UCHAR *pIpv6HdrScanContext = pucPayload;
BOOLEAN bDone = FALSE;
UCHAR ucHeaderType =0;
UCHAR *pucNextHeader = NULL;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
if( !pucPayload || (usPayloadLength == 0))
{
return 0;
}
*pusSrcPort = *pusDestPort = 0;
ucHeaderType = ucNextHeader;
while(!bDone)
{
pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext,&ucHeaderType,&bDone,&usPayloadLength);
if(bDone)
{
if((ucHeaderType==TCP_HEADER_TYPE) || (ucHeaderType == UDP_HEADER_TYPE))
{
*pusSrcPort=*((PUSHORT)(pucNextHeader));
*pusDestPort=*((PUSHORT)(pucNextHeader+2));
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nProtocol Ports - Src Port :0x%x Dest Port : 0x%x",ntohs(*pusSrcPort),ntohs(*pusDestPort));
}
break;
}
}
return ucHeaderType;
}
USHORT IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
PVOID pcIpHeader, /**<Pointer to the IP Hdr of the packet*/
S_CLASSIFIER_RULE *pstClassifierRule )
{
USHORT ushDestPort = 0;
USHORT ushSrcPort = 0;
UCHAR ucNextProtocolAboveIP =0;
IPV6Header *pstIpv6Header = NULL;
BOOLEAN bClassificationSucceed = FALSE;
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "IpVersion6 ==========>\n");
pstIpv6Header = (IPV6Header *)pcIpHeader;
DumpIpv6Header(pstIpv6Header);
//Try to get the next higher layer protocol and the Ports Nos if TCP or UDP
ucNextProtocolAboveIP = GetIpv6ProtocolPorts((UCHAR *)(pcIpHeader + sizeof(IPV6Header)),
&ushSrcPort,
&ushDestPort,
pstIpv6Header->usPayloadLength,
pstIpv6Header->ucNextHeader);
do
{
if(0 == pstClassifierRule->ucDirection)
{
//cannot be processed for classification.
// it is a down link connection
break;
}
if(!pstClassifierRule->bIpv6Protocol)
{
//We are looking for Ipv6 Classifiers . Lets ignore this classifier and try the next one.
break;
}
bClassificationSucceed=MatchSrcIpv6Address(pstClassifierRule,pstIpv6Header);
if(!bClassificationSucceed)
break;
bClassificationSucceed=MatchDestIpv6Address(pstClassifierRule,pstIpv6Header);
if(!bClassificationSucceed)
break;
//Match the protocol type.For IPv6 the next protocol at end of Chain of IPv6 prot headers
bClassificationSucceed=MatchProtocol(pstClassifierRule,ucNextProtocolAboveIP);
if(!bClassificationSucceed)
break;
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Protocol Matched");
if((ucNextProtocolAboveIP == TCP_HEADER_TYPE) || (ucNextProtocolAboveIP == UDP_HEADER_TYPE))
{
//Match Src Port
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Source Port:%x\n",ntohs(ushSrcPort));
bClassificationSucceed=MatchSrcPort(pstClassifierRule,ntohs(ushSrcPort));
if(!bClassificationSucceed)
break;
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Src Port Matched");
//Match Dest Port
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n",ntohs(ushDestPort));
bClassificationSucceed=MatchDestPort(pstClassifierRule,ntohs(ushDestPort));
if(!bClassificationSucceed)
break;
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Dest Port Matched");
}
}while(0);
if(TRUE==bClassificationSucceed)
{
INT iMatchedSFQueueIndex = 0;
iMatchedSFQueueIndex = SearchSfid(Adapter,pstClassifierRule->ulSFID);
if(iMatchedSFQueueIndex >= NO_OF_QUEUES)
{
bClassificationSucceed = FALSE;
}
else
{
if(FALSE == Adapter->PackInfo[iMatchedSFQueueIndex].bActive)
{
bClassificationSucceed = FALSE;
}
}
}
return bClassificationSucceed;
}
static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
{
UINT uiLoopIndex=0;
UINT uiIpv6AddIndex=0;
UINT uiIpv6AddrNoLongWords = 4;
ULONG aulSrcIP[4];
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
/*
//This is the no. of Src Addresses ie Range of IP Addresses contained
//in the classifier rule for which we need to match
*/
UINT uiCountIPSrcAddresses = (UINT)pstClassifierRule->ucIPSourceAddressLength;
if(0 == uiCountIPSrcAddresses)
return TRUE;
//First Convert the Ip Address in the packet to Host Endian order
for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
{
aulSrcIP[uiIpv6AddIndex]=ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]);
}
for(uiLoopIndex=0;uiLoopIndex<uiCountIPSrcAddresses;uiLoopIndex+=uiIpv6AddrNoLongWords)
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Address In Received Packet : \n ");
DumpIpv6Address(aulSrcIP);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Mask In Classifier Rule: \n");
DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex]);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Address In Classifier Rule : \n");
DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex]);
for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
{
if((pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex])
!= pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex])
{
//Match failed for current Ipv6 Address.Try next Ipv6 Address
break;
}
if(uiIpv6AddIndex == uiIpv6AddrNoLongWords-1)
{
//Match Found
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Ipv6 Src Ip Address Matched\n");
return TRUE;
}
}
}
return FALSE;
}
static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
{
UINT uiLoopIndex=0;
UINT uiIpv6AddIndex=0;
UINT uiIpv6AddrNoLongWords = 4;
ULONG aulDestIP[4];
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
/*
//This is the no. of Destination Addresses ie Range of IP Addresses contained
//in the classifier rule for which we need to match
*/
UINT uiCountIPDestinationAddresses = (UINT)pstClassifierRule->ucIPDestinationAddressLength;
if(0 == uiCountIPDestinationAddresses)
return TRUE;
//First Convert the Ip Address in the packet to Host Endian order
for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
{
aulDestIP[uiIpv6AddIndex]=ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]);
}
for(uiLoopIndex=0;uiLoopIndex<uiCountIPDestinationAddresses;uiLoopIndex+=uiIpv6AddrNoLongWords)
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Address In Received Packet : \n ");
DumpIpv6Address(aulDestIP);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Mask In Classifier Rule: \n");
DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex]);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Address In Classifier Rule : \n");
DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex]);
for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
{
if((pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex])
!= pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex])
{
//Match failed for current Ipv6 Address.Try next Ipv6 Address
break;
}
if(uiIpv6AddIndex == uiIpv6AddrNoLongWords-1)
{
//Match Found
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Ipv6 Destination Ip Address Matched\n");
return TRUE;
}
}
}
return FALSE;
}
VOID DumpIpv6Address(ULONG *puIpv6Address)
{
UINT uiIpv6AddrNoLongWords = 4;
UINT uiIpv6AddIndex=0;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, ":%lx",puIpv6Address[uiIpv6AddIndex]);
}
}
static VOID DumpIpv6Header(IPV6Header *pstIpv6Header)
{
UCHAR ucVersion;
UCHAR ucPrio ;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "----Ipv6 Header---");
ucVersion = pstIpv6Header->ucVersionPrio & 0xf0;
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Version : %x \n",ucVersion);
ucPrio = pstIpv6Header->ucVersionPrio & 0x0f;
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Priority : %x \n",ucPrio);
//BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Flow Label : %x \n",(pstIpv6Header->ucVersionPrio &0xf0);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Payload Length : %x \n",ntohs(pstIpv6Header->usPayloadLength));
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Next Header : %x \n",pstIpv6Header->ucNextHeader);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Hop Limit : %x \n",pstIpv6Header->ucHopLimit);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Src Address :\n");
DumpIpv6Address(pstIpv6Header->ulSrcIpAddress);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Dest Address :\n");
DumpIpv6Address(pstIpv6Header->ulDestIpAddress);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "----Ipv6 Header End---");
}