/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2014 QLogic Corporation
* The contents of this file are subject to the terms of the
* QLogic End User License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the License at
* http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
* QLogic_End_User_Software_License.txt
* See the License for the specific language governing permissions
* and limitations under the License.
*/
/*
* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
*/
#include "bnxe.h"
int BnxeRouteTxRing(um_device_t * pUM,
mblk_t * pMblk)
{
u32_t numRings = pUM->devParams.numRings;
int ring = 0;
uint8_t * pHdr;
mblk_t * pTmpMblk;
size_t mblkLen;
ushort_t etype;
size_t eHdrSize;
if (!numRings)
{
return 0;
}
/*
* Need enough space to cover the ethernet header (+vlan), max ip header,
* and the first 4 bytes of the TCP/IP header (src/dst ports).
*/
size_t hdrs_size;
uint8_t hdrs_buf[sizeof(struct ether_vlan_header) +
IP_MAX_HDR_LENGTH +
sizeof(uint32_t)];
switch (pUM->devParams.routeTxRingPolicy)
{
case BNXE_ROUTE_RING_TCPUDP:
pHdr = pMblk->b_rptr;
etype = ntohs(((struct ether_header *)pHdr)->ether_type);
if (etype == ETHERTYPE_VLAN)
{
etype = ntohs(((struct ether_vlan_header *)pHdr)->ether_type);
eHdrSize = sizeof(struct ether_vlan_header);
}
else
{
eHdrSize = sizeof(struct ether_header);
}
if (etype == ETHERTYPE_IP)
{
mblkLen = MBLKL(pMblk);
pHdr = NULL;
if (mblkLen > (eHdrSize + sizeof(uint8_t)))
{
pHdr = (pMblk->b_rptr + eHdrSize);
mblkLen -= eHdrSize;
pHdr = (mblkLen > (((*pHdr & 0x0f) << 2) + sizeof(uint32_t))) ?
pMblk->b_rptr : NULL;
}
if (pHdr == NULL)
{
/* copy the header so it's contiguous in the local hdrs_buf */
pTmpMblk = pMblk;
hdrs_size = 0;
while (pTmpMblk && (hdrs_size < sizeof(hdrs_buf)))
{
mblkLen = MBLKL(pTmpMblk);
if (mblkLen >= (sizeof(hdrs_buf) - hdrs_size))
{
mblkLen = (sizeof(hdrs_buf) - hdrs_size);
}
bcopy(pTmpMblk->b_rptr, &hdrs_buf[hdrs_size], mblkLen);
hdrs_size += mblkLen;
pTmpMblk = pTmpMblk->b_cont;
}
pHdr = hdrs_buf;
}
pHdr += eHdrSize;
if (!(pHdr[6] & 0x3f) && !(pHdr[7] & 0xff))
{
switch (pHdr[9])
{
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_ESP:
/* source and destination ports */
pHdr += (((*pHdr) & 0x0f) << 2);
ring = ((u32_t)(pHdr[0] ^ pHdr[1] ^ pHdr[2] ^ pHdr[3]) %
numRings);
break;
case IPPROTO_AH:
/* security parameters index */
pHdr += (((*pHdr) & 0x0f) << 2);
ring = ((pHdr[4] ^ pHdr[5] ^ pHdr[6] ^ pHdr[7]) %
numRings);
break;
default:
/* last byte of the destination IP address */
ring = (pHdr[19] % numRings);
break;
}
}
else
{
/* fragmented packet */
ring = (pHdr[19] % numRings);
}
}
else
{
ring = (pMblk->b_band % numRings);
}
break;
case BNXE_ROUTE_RING_DEST_MAC:
/* last byte of dst mac addr */
pHdr = pMblk->b_rptr;
ring = (pHdr[5] % numRings);
break;
case BNXE_ROUTE_RING_MSG_PRIO:
ring = (pMblk->b_band % numRings);
break;
case BNXE_ROUTE_RING_NONE:
default:
ring = 0;
break;
}
return ring;
}