| #include "headers.h" |
| |
| static BOOLEAN MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule, |
| struct bcm_ipv6_hdr *pstIpv6Header); |
| static BOOLEAN MatchDestIpv6Address(struct bcm_classifier_rule *pstClassifierRule, |
| struct bcm_ipv6_hdr *pstIpv6Header); |
| static VOID DumpIpv6Header(struct bcm_ipv6_hdr *pstIpv6Header); |
| |
| static UCHAR *GetNextIPV6ChainedHeader(UCHAR **ppucPayload, |
| UCHAR *pucNextHeader, BOOLEAN *bParseDone, USHORT *pusPayloadLength) |
| { |
| UCHAR *pucRetHeaderPtr = NULL; |
| UCHAR *pucPayloadPtr = NULL; |
| USHORT usNextHeaderOffset = 0 ; |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); |
| |
| if ((ppucPayload == NULL) || (*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(struct bcm_ipv6_options_hdr); |
| } |
| break; |
| |
| case IPV6HDR_TYPE_ROUTING: |
| { |
| struct bcm_ipv6_routing_hdr *pstIpv6RoutingHeader; |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, |
| DBG_LVL_ALL, "\nIPv6 Routing Header"); |
| pstIpv6RoutingHeader = (struct bcm_ipv6_routing_hdr *)pucPayloadPtr; |
| usNextHeaderOffset += sizeof(struct bcm_ipv6_routing_hdr); |
| 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(struct bcm_ipv6_fragment_hdr); |
| |
| } |
| break; |
| case IPV6HDR_TYPE_DESTOPTS: |
| { |
| struct bcm_ipv6_dest_options_hdr *pstIpv6DestOptsHdr = (struct bcm_ipv6_dest_options_hdr *)pucPayloadPtr; |
| int nTotalOptions = pstIpv6DestOptsHdr->ucHdrExtLen; |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, |
| DBG_LVL_ALL, |
| "\nIPv6 DestOpts Header Header"); |
| usNextHeaderOffset += sizeof(struct bcm_ipv6_dest_options_hdr); |
| usNextHeaderOffset += nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ; |
| |
| } |
| break; |
| case IPV6HDR_TYPE_AUTHENTICATION: |
| { |
| struct bcm_ipv6_authentication_hdr *pstIpv6AuthHdr = (struct bcm_ipv6_authentication_hdr *)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, "\nICMP 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; |
| struct bcm_mini_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; |
| } |
| |
| |
| /* |
| * Arg 1 struct bcm_mini_adapter *Adapter is a pointer ot the driver contorl structure |
| * Arg 2 PVOID pcIpHeader is a pointer to the IP header of the packet |
| */ |
| USHORT IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader, |
| struct bcm_classifier_rule *pstClassifierRule) |
| { |
| USHORT ushDestPort = 0; |
| USHORT ushSrcPort = 0; |
| UCHAR ucNextProtocolAboveIP = 0; |
| struct bcm_ipv6_hdr *pstIpv6Header = NULL; |
| BOOLEAN bClassificationSucceed = FALSE; |
| |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, |
| DBG_LVL_ALL, "IpVersion6 ==========>\n"); |
| |
| pstIpv6Header = (struct bcm_ipv6_hdr *)pcIpHeader; |
| |
| DumpIpv6Header(pstIpv6Header); |
| |
| /* |
| * Try to get the next higher layer protocol |
| * and the Ports Nos if TCP or UDP |
| */ |
| ucNextProtocolAboveIP = GetIpv6ProtocolPorts((UCHAR *)(pcIpHeader + sizeof(struct bcm_ipv6_hdr)), |
| &ushSrcPort, |
| &ushDestPort, |
| pstIpv6Header->usPayloadLength, |
| pstIpv6Header->ucNextHeader); |
| |
| do { |
| if (pstClassifierRule->ucDirection == 0) { |
| /* |
| * 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 (bClassificationSucceed == TRUE) { |
| INT iMatchedSFQueueIndex = 0; |
| iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID); |
| if (iMatchedSFQueueIndex >= NO_OF_QUEUES) { |
| bClassificationSucceed = FALSE; |
| } else { |
| if (Adapter->PackInfo[iMatchedSFQueueIndex].bActive == FALSE) |
| bClassificationSucceed = FALSE; |
| } |
| } |
| |
| return bClassificationSucceed; |
| } |
| |
| |
| static BOOLEAN MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule, |
| struct bcm_ipv6_hdr *pstIpv6Header) |
| { |
| UINT uiLoopIndex = 0; |
| UINT uiIpv6AddIndex = 0; |
| UINT uiIpv6AddrNoLongWords = 4; |
| ULONG aulSrcIP[4]; |
| struct bcm_mini_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 (uiCountIPSrcAddresses == 0) |
| 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(struct bcm_classifier_rule *pstClassifierRule, |
| struct bcm_ipv6_hdr *pstIpv6Header) |
| { |
| UINT uiLoopIndex = 0; |
| UINT uiIpv6AddIndex = 0; |
| UINT uiIpv6AddrNoLongWords = 4; |
| ULONG aulDestIP[4]; |
| struct bcm_mini_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 (uiCountIPDestinationAddresses == 0) |
| 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; |
| struct bcm_mini_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(struct bcm_ipv6_hdr *pstIpv6Header) |
| { |
| UCHAR ucVersion; |
| UCHAR ucPrio; |
| struct bcm_mini_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---"); |
| |
| |
| } |