#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---"); }