When a packet which needs segmentation is received, the header for each segment is being calculated, i.e. IP length, checksum, TCP seq, TCP checksum.
The problem with the current code is that it wrongly assumes that the Ethernet frame payload is always an IPv4 packet. This patch checks the EtherType field of the Ethernet frame to see which protocol is encapsulated in its payload, IPv4 or IPv6, and calculates accordingly the segment's header. Signed-off-by: Sorin Vinturis <svintu...@cloudbasesolutions.com> --- datapath-windows/ovsext/BufferMgmt.c | 91 ++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/datapath-windows/ovsext/BufferMgmt.c b/datapath-windows/ovsext/BufferMgmt.c index 3189e9b..085a551 100644 --- a/datapath-windows/ovsext/BufferMgmt.c +++ b/datapath-windows/ovsext/BufferMgmt.c @@ -1122,11 +1122,10 @@ static NDIS_STATUS FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber, BOOLEAN lastPacket, UINT16 packetCounter) { - EthHdr *dstEth; - IPHdr *dstIP; - TCPHdr *dstTCP; - PMDL mdl; - PUINT8 bufferStart; + EthHdr *dstEth = NULL; + TCPHdr *dstTCP = NULL; + PMDL mdl = NULL; + PUINT8 bufferStart = NULL; mdl = NET_BUFFER_FIRST_MDL(nb); @@ -1135,21 +1134,64 @@ FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber, return NDIS_STATUS_RESOURCES; } dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb)); - ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) - >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr)); - dstIP = (IPHdr *)((PCHAR)dstEth + sizeof *dstEth); - dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4); - ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) - >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP)); - - /* 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 */ + + switch (dstEth->Type) { + case ETH_TYPE_IPV4_NBO: + { + IPHdr *dstIP = NULL; + + ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) + >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr)); + dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth)); + dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4); + ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) + >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP)); + + /* 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 = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0); + + /* Fix TCP checksum */ + UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP); + dstTCP->check = IPPseudoChecksum(&dstIP->saddr, + &dstIP->daddr, + IPPROTO_TCP, + csumLength); + dstTCP->check = CalculateChecksumNB(nb, + csumLength, + sizeof(*dstEth) + dstIP->ihl * 4); + break; + } + case ETH_TYPE_IPV6_NBO: + { + IPv6Hdr *dstIP = NULL; + + ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) + >= sizeof(EthHdr) + sizeof(IPv6Hdr) + sizeof(TCPHdr)); + dstIP = (IPv6Hdr *)((PCHAR)dstEth + sizeof(*dstEth)); + dstTCP = (TCPHdr *)((PCHAR)dstIP + sizeof(IPv6Hdr)); + ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) + >= sizeof(EthHdr) + sizeof(IPv6Hdr) + TCP_HDR_LEN(dstTCP)); + + /* Fix IP length */ + ASSERT(dstIP->nexthdr == IPPROTO_TCP); + dstIP->payload_len = htons(segmentSize + sizeof(IPv6Hdr) + TCP_HDR_LEN(dstTCP)); + + /* Fix TCP checksum */ + UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP); + dstTCP->check = IPv6PseudoChecksum((UINT32*)&dstIP->saddr, + (UINT32*)&dstIP->daddr, + IPPROTO_TCP, + csumLength); + dstTCP->check = CalculateChecksumNB(nb, + csumLength, + sizeof(*dstEth) + sizeof(IPv6Hdr)); + break; + } + } + dstTCP->seq = htonl(seqNumber); /* @@ -1164,15 +1206,6 @@ FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber, dstTCP->psh = lastPacket; } - UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP); - dstTCP->check = IPPseudoChecksum(&dstIP->saddr, - &dstIP->daddr, - IPPROTO_TCP, - csumLength); - dstTCP->check = CalculateChecksumNB(nb, - csumLength, - sizeof *dstEth + dstIP->ihl * 4); - return STATUS_SUCCESS; } -- 1.9.0.msysgit.0 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev