]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/bcm/IPv6Protocol.c
Merge branch 'master' into tk71
[mv-sheeva.git] / drivers / staging / bcm / IPv6Protocol.c
diff --git a/drivers/staging/bcm/IPv6Protocol.c b/drivers/staging/bcm/IPv6Protocol.c
new file mode 100644 (file)
index 0000000..91b6fbe
--- /dev/null
@@ -0,0 +1,404 @@
+#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 Recieved 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 Recieved 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---");
+
+
+}