* --------------------------------------------------------------------------
*/
static NDIS_STATUS
-FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber)
+FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
+ BOOLEAN lastPacket, UINT16 packetCounter)
{
EthHdr *dstEth;
IPHdr *dstIP;
/* Fix IP length and checksum */
ASSERT(dstIP->protocol == IPPROTO_TCP);
dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
+ dstIP->id += packetCounter;
dstIP->check = 0;
dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);
/* Fix TCP checksum */
dstTCP->seq = htonl(seqNumber);
- dstTCP->check =
- IPPseudoChecksum((UINT32 *)&dstIP->saddr,
- (UINT32 *)&dstIP->daddr,
- IPPROTO_TCP, segmentSize + TCP_HDR_LEN(dstTCP));
+
+ /*
+ * Set the TCP FIN and PSH bit only for the last packet
+ * More information can be found under:
+ * https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx
+ */
+ if (dstTCP->fin) {
+ dstTCP->fin = lastPacket;
+ }
+ if (dstTCP->psh) {
+ dstTCP->psh = lastPacket;
+ }
+
+ UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
+ dstTCP->check = IPPseudoChecksum(&dstIP->saddr,
+ &dstIP->daddr,
+ IPPROTO_TCP,
+ csumLength);
dstTCP->check = CalculateChecksumNB(nb,
- (UINT16)(NET_BUFFER_DATA_LENGTH(nb) - sizeof *dstEth - dstIP->ihl * 4),
- sizeof *dstEth + dstIP->ihl * 4);
+ csumLength,
+ sizeof *dstEth + dstIP->ihl * 4);
+
return STATUS_SUCCESS;
}
NDIS_STATUS status;
UINT16 segmentSize;
ULONG copiedSize;
+ UINT16 packetCounter = 0;
srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
goto nblcopy_error;
}
- status = FixSegmentHeader(newNb, segmentSize, seqNumber);
+ status = FixSegmentHeader(newNb, segmentSize, seqNumber,
+ NET_BUFFER_NEXT_NB(newNb) == NULL,
+ packetCounter);
if (status != NDIS_STATUS_SUCCESS) {
goto nblcopy_error;
}
/* Move on to the next segment */
size -= segmentSize;
seqNumber += segmentSize;
+ packetCounter++;
}
status = OvsAllocateNBLContext(context, newNbl);
{
UINT64 sum = 0, val;
UINT64 *src = (UINT64 *)start;
- union {
- UINT32 val;
- UINT8 b8[4];
- } tmp;
-
while (totalLength > 7) {
val = *src;
- sum += (val >> 32) + (val & 0xffffffff);
+ sum += val;
+ if (sum < val) sum++;
src++;
totalLength -= 8;
}
+
+ start = (UINT8 *)src;
+
if (totalLength > 3) {
- sum += *(UINT32 *)src;
- src = (UINT64 *)((UINT8 *)src + 4);
+ UINT32 val = *(UINT32 *)start;
+ sum += val;
+ if (sum < val) sum++;
+ start += 4;
totalLength -= 4;
}
- start = (UINT8 *)src;
- tmp.val = 0;
- switch (totalLength) {
- case 3:
- tmp.b8[2] = start[2];
- case 2:
- tmp.b8[1] = start[1];
- case 1:
- tmp.b8[0] = start[0];
- sum += tmp.val;
+
+ if (totalLength > 1) {
+ UINT16 val = *(UINT16 *)start;
+ sum += val;
+ if (sum < val) sum++;
+ start += 2;
+ totalLength -= 2;
}
- sum = (isEvenStart ? sum : swap64(sum)) + initial;
+
+ if (totalLength > 0) {
+ UINT8 val = *start;
+ sum += val;
+ if (sum < val) sum++;
+ start += 1;
+ totalLength -= 1;
+ }
+ ASSERT(totalLength == 0);
+
+ if (!isEvenStart) {
+ sum = _byteswap_uint64(sum);
+ }
+
+ sum += initial;
+ if (sum < initial) sum++;
+
return sum;
}
ULONG firstMdlLen;
/* Running count of bytes in remainder of the MDLs including current. */
ULONG packetLen;
+ BOOLEAN swapEnd = 1 & csumDataLen;
if ((nb == NULL) || (csumDataLen == 0)
|| (offset >= NET_BUFFER_DATA_LENGTH(nb))
while (csumDataLen && (currentMdl != NULL)) {
ASSERT(mdlLen < 65536);
csLen = MIN((UINT16) mdlLen, csumDataLen);
- //XXX Not handling odd bytes yet.
- ASSERT(((csLen & 0x1) == 0) || csumDataLen <= mdlLen);
- csum = CalculateOnesComplement(src, csLen, csum, TRUE);
+ csum = CalculateOnesComplement(src, csLen, csum, !(1 & csumDataLen));
fold64(csum);
csumDataLen -= csLen;
}
}
+ fold64(csum);
ASSERT(csumDataLen == 0);
ASSERT((csum & ~0xffff) == 0);
- return (UINT16) ~csum;
+ csum = (UINT16)~csum;
+ if (swapEnd) {
+ return _byteswap_ushort((UINT16)csum);
+ }
+ return (UINT16)csum;
}
/*
if (vxlanPort->filterID != 0) {
status = OvsTunnelFilterDelete(irp,
- vxlanPort->filterID,
- callback,
- tunnelContext);
+ vxlanPort->filterID,
+ callback,
+ tunnelContext);
} else {
OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG);
vport->priv = NULL;
*/
curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
packetLength = NET_BUFFER_DATA_LENGTH(curNb);
+
if (layers->isTcp) {
NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo;
tsoInfo.Value = NET_BUFFER_LIST_INFO(curNbl,
- TcpLargeSendNetBufferListInfo);
- OVS_LOG_TRACE("MSS %u packet len %u", tsoInfo.LsoV1Transmit.MSS, packetLength);
+ TcpLargeSendNetBufferListInfo);
+ OVS_LOG_TRACE("MSS %u packet len %u", tsoInfo.LsoV1Transmit.MSS,
+ packetLength);
if (tsoInfo.LsoV1Transmit.MSS) {
OVS_LOG_TRACE("l4Offset %d", layers->l4Offset);
*newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
- tsoInfo.LsoV1Transmit.MSS, headRoom);
+ tsoInfo.LsoV1Transmit.MSS, headRoom);
if (*newNbl == NULL) {
OVS_LOG_ERROR("Unable to segment NBL");
return NDIS_STATUS_FAILURE;
}
+ /* Clear out LSO flags after this point */
+ NET_BUFFER_LIST_INFO(*newNbl, TcpLargeSendNetBufferListInfo) = 0;
}
}
OVS_LOG_ERROR("Unable to copy NBL");
return NDIS_STATUS_FAILURE;
}
+ /*
+ * To this point we do not have VXLAN offloading.
+ * Apply defined checksums
+ */
+ curNb = NET_BUFFER_LIST_FIRST_NB(*newNbl);
+ curMdl = NET_BUFFER_CURRENT_MDL(curNb);
+ bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority);
+ if (!bufferStart) {
+ status = NDIS_STATUS_RESOURCES;
+ goto ret_error;
+ }
+
+ NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
+ csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl,
+ TcpIpChecksumNetBufferListInfo);
+
+ bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
+
+ if (layers->isIPv4) {
+ IPHdr *ip = (IPHdr *)(bufferStart + layers->l3Offset);
+
+ if (csumInfo.Transmit.IpHeaderChecksum) {
+ ip->check = 0;
+ ip->check = IPChecksum((UINT8 *)ip, 4 * ip->ihl, 0);
+ }
+
+ if (layers->isTcp && csumInfo.Transmit.TcpChecksum) {
+ UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset);
+ TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset);
+ tcp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr,
+ IPPROTO_TCP, csumLength);
+ tcp->check = CalculateChecksumNB(curNb, csumLength,
+ (UINT32)(layers->l4Offset));
+ } else if (layers->isUdp && csumInfo.Transmit.UdpChecksum) {
+ UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset);
+ UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip);
+ udp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr,
+ IPPROTO_UDP, csumLength);
+ udp->check = CalculateChecksumNB(curNb, csumLength,
+ (UINT32)(layers->l4Offset));
+ }
+ } else if (layers->isIPv6) {
+ IPv6Hdr *ip = (IPv6Hdr *)(bufferStart + layers->l3Offset);
+
+ if (layers->isTcp && csumInfo.Transmit.TcpChecksum) {
+ UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset);
+ TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset);
+ tcp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr,
+ (UINT32 *) &ip->daddr,
+ IPPROTO_TCP, csumLength);
+ tcp->check = CalculateChecksumNB(curNb, csumLength,
+ (UINT32)(layers->l4Offset));
+ } else if (layers->isUdp && csumInfo.Transmit.UdpChecksum) {
+ UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset);
+ UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip);
+ udp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr,
+ (UINT32 *) &ip->daddr,
+ IPPROTO_UDP, csumLength);
+ udp->check = CalculateChecksumNB(curNb, csumLength,
+ (UINT32)(layers->l4Offset));
+ }
+ }
+ /* Clear out TcpIpChecksumNetBufferListInfo flag */
+ NET_BUFFER_LIST_INFO(*newNbl, TcpIpChecksumNetBufferListInfo) = 0;
}
curNbl = *newNbl;
sizeof ethHdr->Destination + sizeof ethHdr->Source);
ethHdr->Type = htons(ETH_TYPE_IPV4);
- // XXX: question: there are fields in the OvsIPv4TunnelKey for ttl and such,
- // should we use those values instead? or will they end up being
- // uninitialized;
/* IP header */
ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr);
ASSERT(tunKey->src == fwdInfo->srcIpAddr || tunKey->src == 0);
ipHdr->saddr = fwdInfo->srcIpAddr;
ipHdr->daddr = fwdInfo->dstIpAddr;
+
ipHdr->check = 0;
ipHdr->check = IPChecksum((UINT8 *)ipHdr, sizeof *ipHdr, 0);