1 /*
2  * This file contains SW Implementation of checksum computation for IP,TCP,UDP
3  *
4  * Copyright (c) 2008-2017 Red Hat, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met :
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and / or other materials provided with the distribution.
14  * 3. Neither the names of the copyright holders nor the names of their contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 #include "ndis56common.h"
30 
31 #ifdef WPP_EVENT_TRACING
32 #include "sw-offload.tmh"
33 #endif
34 #include <sal.h>
35 
36 // till IP header size is 8 bit
37 #define MAX_SUPPORTED_IPV6_HEADERS  (256 - 4)
38 
39 typedef ULONG IPV6_ADDRESS[4];
40 
41 // IPv6 Header RFC 2460 (40 bytes)
42 typedef struct _tagIPv6Header {
43     UCHAR       ip6_ver_tc;            // traffic class(low nibble), version (high nibble)
44     UCHAR       ip6_tc_fl;             // traffic class(high nibble), flow label
45     USHORT      ip6_fl;                // flow label, the rest
46     USHORT      ip6_payload_len;       // length of following headers and payload
47     UCHAR       ip6_next_header;       // next header type
48     UCHAR       ip6_hoplimit;          // hop limit
49     IPV6_ADDRESS ip6_src_address;    //
50     IPV6_ADDRESS ip6_dst_address;    //
51 } IPv6Header;
52 
53 typedef union
54 {
55     IPv6Header v6;
56     IPv4Header v4;
57 } IPHeader;
58 
59 // IPv6 Header RFC 2460 (n*8 bytes)
60 typedef struct _tagIPv6ExtHeader {
61     UCHAR       ip6ext_next_header;     // next header type
62     UCHAR       ip6ext_hdr_len;         // length of this header in 8 bytes unit, not including first 8 bytes
63     USHORT      options;                //
64 } IPv6ExtHeader;
65 
66 // IP Pseudo Header RFC 768
67 typedef struct _tagIPv4PseudoHeader {
68     ULONG       ipph_src;               // Source address
69     ULONG       ipph_dest;              // Destination address
70     UCHAR       ipph_zero;              // 0
71     UCHAR       ipph_protocol;          // TCP/UDP
72     USHORT      ipph_length;            // TCP/UDP length
73 }tIPv4PseudoHeader;
74 
75 // IPv6 Pseudo Header RFC 2460
76 typedef struct _tagIPv6PseudoHeader {
77     IPV6_ADDRESS ipph_src;              // Source address
78     IPV6_ADDRESS ipph_dest;             // Destination address
79     ULONG        ipph_length;               // TCP/UDP length
80     UCHAR        z1;                // 0
81     UCHAR        z2;                // 0
82     UCHAR        z3;                // 0
83     UCHAR        ipph_protocol;             // TCP/UDP
84 }tIPv6PseudoHeader;
85 
86 
87 #define PROTOCOL_TCP                    6
88 #define PROTOCOL_UDP                    17
89 
90 
91 #define IP_HEADER_LENGTH(pHeader)  (((pHeader)->ip_verlen & 0x0F) << 2)
92 #define TCP_HEADER_LENGTH(pHeader) ((pHeader->tcp_flags & 0xF0) >> 2)
93 
94 
95 
96 static __inline USHORT CheckSumCalculator(ULONG val, PVOID buffer, ULONG len)
97 {
98     PUSHORT pus = (PUSHORT)buffer;
99     ULONG count = len >> 1;
100     while (count--) val += *pus++;
101     if (len & 1) val += (USHORT)*(PUCHAR)pus;
102     val = (((val >> 16) | (val << 16)) + val) >> 16;
103     return (USHORT)~val;
104 }
105 
106 
107 /******************************************
108     IP header checksum calculator
109 *******************************************/
110 static __inline VOID CalculateIpChecksum(IPv4Header *pIpHeader)
111 {
112     pIpHeader->ip_xsum = 0;
113     pIpHeader->ip_xsum = CheckSumCalculator(0, pIpHeader, IP_HEADER_LENGTH(pIpHeader));
114 }
115 
116 static __inline tTcpIpPacketParsingResult
117 ProcessTCPHeader(tTcpIpPacketParsingResult _res, PVOID pIpHeader, ULONG len, USHORT ipHeaderSize)
118 {
119     ULONG tcpipDataAt;
120     tTcpIpPacketParsingResult res = _res;
121     tcpipDataAt = ipHeaderSize + sizeof(TCPHeader);
122     res.xxpStatus = ppresXxpIncomplete;
123     res.TcpUdp = ppresIsTCP;
124 
125     if (len >= tcpipDataAt)
126     {
127         TCPHeader *pTcpHeader = (TCPHeader *)RtlOffsetToPointer(pIpHeader, ipHeaderSize);
128         res.xxpStatus = ppresXxpKnown;
129         tcpipDataAt = ipHeaderSize + TCP_HEADER_LENGTH(pTcpHeader);
130         res.XxpIpHeaderSize = tcpipDataAt;
131     }
132     else
133     {
134         DPrintf(2, ("tcp: %d < min headers %d", len, tcpipDataAt));
135     }
136     return res;
137 }
138 
139 static __inline tTcpIpPacketParsingResult
140 ProcessUDPHeader(tTcpIpPacketParsingResult _res, PVOID pIpHeader, ULONG len, USHORT ipHeaderSize)
141 {
142     tTcpIpPacketParsingResult res = _res;
143     ULONG udpDataStart = ipHeaderSize + sizeof(UDPHeader);
144     res.xxpStatus = ppresXxpIncomplete;
145     res.TcpUdp = ppresIsUDP;
146     res.XxpIpHeaderSize = udpDataStart;
147     if (len >= udpDataStart)
148     {
149         UDPHeader *pUdpHeader = (UDPHeader *)RtlOffsetToPointer(pIpHeader, ipHeaderSize);
150         USHORT datagramLength = swap_short(pUdpHeader->udp_length);
151         res.xxpStatus = ppresXxpKnown;
152         // may be full or not, but the datagram length is known
153         DPrintf(2, ("udp: len %d, datagramLength %d", len, datagramLength));
154     }
155     return res;
156 }
157 
158 static __inline tTcpIpPacketParsingResult
159 QualifyIpPacket(IPHeader *pIpHeader, ULONG len)
160 {
161     tTcpIpPacketParsingResult res;
162     UCHAR  ver_len = pIpHeader->v4.ip_verlen;
163     UCHAR  ip_version = (ver_len & 0xF0) >> 4;
164     USHORT ipHeaderSize = 0;
165     USHORT fullLength = 0;
166     res.value = 0;
167 
168     if (ip_version == 4)
169     {
170         ipHeaderSize = (ver_len & 0xF) << 2;
171         fullLength = swap_short(pIpHeader->v4.ip_length);
172         DPrintf(3, ("ip_version %d, ipHeaderSize %d, protocol %d, iplen %d",
173             ip_version, ipHeaderSize, pIpHeader->v4.ip_protocol, fullLength));
174         res.ipStatus = (ipHeaderSize >= sizeof(IPv4Header)) ? ppresIPV4 : ppresNotIP;
175         if (len < ipHeaderSize) res.ipCheckSum = ppresIPTooShort;
176         if (fullLength) {}
177         else
178         {
179             DPrintf(2, ("ip v.%d, iplen %d", ip_version, fullLength));
180         }
181     }
182     else if (ip_version == 6)
183     {
184         UCHAR nextHeader = pIpHeader->v6.ip6_next_header;
185         BOOLEAN bParsingDone = FALSE;
186         ipHeaderSize = sizeof(pIpHeader->v6);
187         res.ipStatus = ppresIPV6;
188         res.ipCheckSum = ppresCSOK;
189         fullLength = swap_short(pIpHeader->v6.ip6_payload_len);
190         fullLength += ipHeaderSize;
191         while (nextHeader != 59)
192         {
193             IPv6ExtHeader *pExt;
194             switch (nextHeader)
195             {
196                 case PROTOCOL_TCP:
197                     bParsingDone = TRUE;
198                     res.xxpStatus = ppresXxpKnown;
199                     res.TcpUdp = ppresIsTCP;
200                     res.xxpFull = len >= fullLength ? 1 : 0;
201                     res = ProcessTCPHeader(res, pIpHeader, len, ipHeaderSize);
202                     break;
203                 case PROTOCOL_UDP:
204                     bParsingDone = TRUE;
205                     res.xxpStatus = ppresXxpKnown;
206                     res.TcpUdp = ppresIsUDP;
207                     res.xxpFull = len >= fullLength ? 1 : 0;
208                     res = ProcessUDPHeader(res, pIpHeader, len, ipHeaderSize);
209                     break;
210                     //existing extended headers
211                 case 0:
212                     __fallthrough;
213                 case 60:
214                     __fallthrough;
215                 case 43:
216                     __fallthrough;
217                 case 44:
218                     __fallthrough;
219                 case 51:
220                     __fallthrough;
221                 case 50:
222                     __fallthrough;
223                 case 135:
224                     if (len >= ((ULONG)ipHeaderSize + 8))
225                     {
226                         pExt = (IPv6ExtHeader *)((PUCHAR)pIpHeader + ipHeaderSize);
227                         nextHeader = pExt->ip6ext_next_header;
228                         ipHeaderSize += 8;
229                         ipHeaderSize += pExt->ip6ext_hdr_len * 8;
230                     }
231                     else
232                     {
233                         DPrintf(0, ("[%s] ERROR: Break in the middle of ext. headers(len %d, hdr > %d)", __FUNCTION__, len, ipHeaderSize));
234                         res.ipStatus = ppresNotIP;
235                         bParsingDone = TRUE;
236                     }
237                     break;
238                     //any other protocol
239                 default:
240                     res.xxpStatus = ppresXxpOther;
241                     bParsingDone = TRUE;
242                     break;
243             }
244             if (bParsingDone)
245                 break;
246         }
247         if (ipHeaderSize <= MAX_SUPPORTED_IPV6_HEADERS)
248         {
249             DPrintf(3, ("ip_version %d, ipHeaderSize %d, protocol %d, iplen %d",
250                 ip_version, ipHeaderSize, nextHeader, fullLength));
251             res.ipHeaderSize = ipHeaderSize;
252         }
253         else
254         {
255             DPrintf(0, ("[%s] ERROR: IP chain is too large (%d)", __FUNCTION__, ipHeaderSize));
256             res.ipStatus = ppresNotIP;
257         }
258     }
259 
260     if (res.ipStatus == ppresIPV4)
261     {
262         res.ipHeaderSize = ipHeaderSize;
263         res.xxpFull = len >= fullLength ? 1 : 0;
264         // bit "more fragments" or fragment offset mean the packet is fragmented
265         res.IsFragment = (pIpHeader->v4.ip_offset & ~0xC0) != 0;
266         switch (pIpHeader->v4.ip_protocol)
267         {
268             case PROTOCOL_TCP:
269             {
270                 res = ProcessTCPHeader(res, pIpHeader, len, ipHeaderSize);
271             }
272             break;
273         case PROTOCOL_UDP:
274             {
275                 res = ProcessUDPHeader(res, pIpHeader, len, ipHeaderSize);
276             }
277             break;
278         default:
279             res.xxpStatus = ppresXxpOther;
280             break;
281         }
282     }
283     return res;
284 }
285 
286 static __inline USHORT GetXxpHeaderAndPayloadLen(IPHeader *pIpHeader, tTcpIpPacketParsingResult res)
287 {
288     if (res.ipStatus == ppresIPV4)
289     {
290         USHORT headerLength = IP_HEADER_LENGTH(&pIpHeader->v4);
291         USHORT len = swap_short(pIpHeader->v4.ip_length);
292         return len - headerLength;
293     }
294     if (res.ipStatus == ppresIPV6)
295     {
296         USHORT fullLength = swap_short(pIpHeader->v6.ip6_payload_len);
297         return fullLength + sizeof(pIpHeader->v6) - (USHORT)res.ipHeaderSize;
298     }
299     return 0;
300 }
301 
302 static __inline USHORT CalculateIpv4PseudoHeaderChecksum(IPv4Header *pIpHeader, USHORT headerAndPayloadLen)
303 {
304     tIPv4PseudoHeader ipph;
305     USHORT checksum;
306     ipph.ipph_src  = pIpHeader->ip_src;
307     ipph.ipph_dest = pIpHeader->ip_dest;
308     ipph.ipph_zero = 0;
309     ipph.ipph_protocol = pIpHeader->ip_protocol;
310     ipph.ipph_length = swap_short(headerAndPayloadLen);
311     checksum = CheckSumCalculator(0, &ipph, sizeof(ipph));
312     return ~checksum;
313 }
314 
315 
316 static __inline USHORT CalculateIpv6PseudoHeaderChecksum(IPv6Header *pIpHeader, USHORT headerAndPayloadLen)
317 {
318     tIPv6PseudoHeader ipph;
319     USHORT checksum;
320     ipph.ipph_src[0]  = pIpHeader->ip6_src_address[0];
321     ipph.ipph_src[1]  = pIpHeader->ip6_src_address[1];
322     ipph.ipph_src[2]  = pIpHeader->ip6_src_address[2];
323     ipph.ipph_src[3]  = pIpHeader->ip6_src_address[3];
324     ipph.ipph_dest[0] = pIpHeader->ip6_dst_address[0];
325     ipph.ipph_dest[1] = pIpHeader->ip6_dst_address[1];
326     ipph.ipph_dest[2] = pIpHeader->ip6_dst_address[2];
327     ipph.ipph_dest[3] = pIpHeader->ip6_dst_address[3];
328     ipph.z1 = ipph.z2 = ipph.z3 = 0;
329     ipph.ipph_protocol = pIpHeader->ip6_next_header;
330     ipph.ipph_length = swap_short(headerAndPayloadLen);
331     checksum = CheckSumCalculator(0, &ipph, sizeof(ipph));
332     return ~checksum;
333 }
334 
335 static __inline USHORT CalculateIpPseudoHeaderChecksum(IPHeader *pIpHeader,
336                                                        tTcpIpPacketParsingResult res,
337                                                        USHORT headerAndPayloadLen)
338 {
339     if (res.ipStatus == ppresIPV4)
340         return CalculateIpv4PseudoHeaderChecksum(&pIpHeader->v4, headerAndPayloadLen);
341     if (res.ipStatus == ppresIPV6)
342         return CalculateIpv6PseudoHeaderChecksum(&pIpHeader->v6, headerAndPayloadLen);
343     return 0;
344 }
345 
346 static __inline BOOLEAN
347 CompareNetCheckSumOnEndSystem(USHORT computedChecksum, USHORT arrivedChecksum)
348 {
349     //According to RFC 1624 sec. 3
350     //Checksum verification mechanism should treat 0xFFFF
351     //checksum value from received packet as 0x0000
352     if(arrivedChecksum == 0xFFFF)
353         arrivedChecksum = 0;
354 
355     return computedChecksum == arrivedChecksum;
356 }
357 
358 /******************************************
359   Calculates IP header checksum calculator
360   it can be already calculated
361   the header must be complete!
362 *******************************************/
363 static __inline tTcpIpPacketParsingResult
364 VerifyIpChecksum(
365     IPv4Header *pIpHeader,
366     tTcpIpPacketParsingResult known,
367     BOOLEAN bFix)
368 {
369     tTcpIpPacketParsingResult res = known;
370     if (res.ipCheckSum != ppresIPTooShort)
371     {
372         USHORT saved = pIpHeader->ip_xsum;
373         CalculateIpChecksum(pIpHeader);
374         res.ipCheckSum = CompareNetCheckSumOnEndSystem(pIpHeader->ip_xsum, saved) ? ppresCSOK : ppresCSBad;
375         if (!bFix)
376             pIpHeader->ip_xsum = saved;
377         else
378             res.fixedIpCS = res.ipCheckSum == ppresCSBad;
379     }
380     return res;
381 }
382 
383 /*********************************************
384 Calculates UDP checksum, assuming the checksum field
385 is initialized with pseudoheader checksum
386 **********************************************/
387 static VOID CalculateUdpChecksumGivenPseudoCS(UDPHeader *pUdpHeader, ULONG udpLength)
388 {
389     pUdpHeader->udp_xsum = CheckSumCalculator(0, pUdpHeader, udpLength);
390 }
391 
392 /*********************************************
393 Calculates TCP checksum, assuming the checksum field
394 is initialized with pseudoheader checksum
395 **********************************************/
396 static __inline VOID CalculateTcpChecksumGivenPseudoCS(TCPHeader *pTcpHeader, ULONG tcpLength)
397 {
398     pTcpHeader->tcp_xsum = CheckSumCalculator(0, pTcpHeader, tcpLength);
399 }
400 
401 /************************************************
402 Checks (and fix if required) the TCP checksum
403 sets flags in result structure according to verification
404 TcpPseudoOK if valid pseudo CS was found
405 TcpOK if valid TCP checksum was found
406 ************************************************/
407 static __inline tTcpIpPacketParsingResult
408 VerifyTcpChecksum( IPHeader *pIpHeader, ULONG len, tTcpIpPacketParsingResult known, ULONG whatToFix)
409 {
410     USHORT  phcs;
411     tTcpIpPacketParsingResult res = known;
412     TCPHeader *pTcpHeader = (TCPHeader *)RtlOffsetToPointer(pIpHeader, res.ipHeaderSize);
413     USHORT saved = pTcpHeader->tcp_xsum;
414     USHORT xxpHeaderAndPayloadLen = GetXxpHeaderAndPayloadLen(pIpHeader, res);
415     if (len >= res.ipHeaderSize)
416     {
417         phcs = CalculateIpPseudoHeaderChecksum(pIpHeader, res, xxpHeaderAndPayloadLen);
418         res.xxpCheckSum = CompareNetCheckSumOnEndSystem(phcs, saved) ?  ppresPCSOK : ppresCSBad;
419         if (res.xxpCheckSum != ppresPCSOK || whatToFix)
420         {
421             if (whatToFix & pcrFixPHChecksum)
422             {
423                 if (len >= (ULONG)(res.ipHeaderSize + sizeof(*pTcpHeader)))
424                 {
425                     pTcpHeader->tcp_xsum = phcs;
426                     res.fixedXxpCS = res.xxpCheckSum != ppresPCSOK;
427                 }
428                 else
429                     res.xxpStatus = ppresXxpIncomplete;
430             }
431             else if (res.xxpFull)
432             {
433                 //USHORT ipFullLength = swap_short(pIpHeader->v4.ip_length);
434                 pTcpHeader->tcp_xsum = phcs;
435                 CalculateTcpChecksumGivenPseudoCS(pTcpHeader, xxpHeaderAndPayloadLen);
436                 if (CompareNetCheckSumOnEndSystem(pTcpHeader->tcp_xsum, saved))
437                     res.xxpCheckSum = ppresCSOK;
438 
439                 if (!(whatToFix & pcrFixXxpChecksum))
440                     pTcpHeader->tcp_xsum = saved;
441                 else
442                     res.fixedXxpCS =
443                         res.xxpCheckSum == ppresCSBad || res.xxpCheckSum == ppresPCSOK;
444             }
445             else if (whatToFix)
446             {
447                 res.xxpStatus = ppresXxpIncomplete;
448             }
449         }
450         else if (res.xxpFull)
451         {
452             // we have correct PHCS and we do not need to fix anything
453             // there is a very small chance that it is also good TCP CS
454             // in such rare case we give a priority to TCP CS
455             CalculateTcpChecksumGivenPseudoCS(pTcpHeader, xxpHeaderAndPayloadLen);
456             if (CompareNetCheckSumOnEndSystem(pTcpHeader->tcp_xsum, saved))
457                 res.xxpCheckSum = ppresCSOK;
458             pTcpHeader->tcp_xsum = saved;
459         }
460     }
461     else
462         res.ipCheckSum = ppresIPTooShort;
463     return res;
464 }
465 
466 /************************************************
467 Checks (and fix if required) the UDP checksum
468 sets flags in result structure according to verification
469 UdpPseudoOK if valid pseudo CS was found
470 UdpOK if valid UDP checksum was found
471 ************************************************/
472 static __inline tTcpIpPacketParsingResult
473 VerifyUdpChecksum( IPHeader *pIpHeader, ULONG len, tTcpIpPacketParsingResult known, ULONG whatToFix)
474 {
475     USHORT  phcs;
476     tTcpIpPacketParsingResult res = known;
477     UDPHeader *pUdpHeader = (UDPHeader *)RtlOffsetToPointer(pIpHeader, res.ipHeaderSize);
478     USHORT saved = pUdpHeader->udp_xsum;
479     USHORT xxpHeaderAndPayloadLen = GetXxpHeaderAndPayloadLen(pIpHeader, res);
480     if (len >= res.ipHeaderSize)
481     {
482         phcs = CalculateIpPseudoHeaderChecksum(pIpHeader, res, xxpHeaderAndPayloadLen);
483         res.xxpCheckSum = CompareNetCheckSumOnEndSystem(phcs, saved) ?  ppresPCSOK : ppresCSBad;
484         if (whatToFix & pcrFixPHChecksum)
485         {
486             if (len >= (ULONG)(res.ipHeaderSize + sizeof(UDPHeader)))
487             {
488                 pUdpHeader->udp_xsum = phcs;
489                 res.fixedXxpCS = res.xxpCheckSum != ppresPCSOK;
490             }
491             else
492                 res.xxpStatus = ppresXxpIncomplete;
493         }
494         else if (res.xxpCheckSum != ppresPCSOK || (whatToFix & pcrFixXxpChecksum))
495         {
496             if (res.xxpFull)
497             {
498                 pUdpHeader->udp_xsum = phcs;
499                 CalculateUdpChecksumGivenPseudoCS(pUdpHeader, xxpHeaderAndPayloadLen);
500                 if (CompareNetCheckSumOnEndSystem(pUdpHeader->udp_xsum, saved))
501                     res.xxpCheckSum = ppresCSOK;
502 
503                 if (!(whatToFix & pcrFixXxpChecksum))
504                     pUdpHeader->udp_xsum = saved;
505                 else
506                     res.fixedXxpCS =
507                         res.xxpCheckSum == ppresCSBad || res.xxpCheckSum == ppresPCSOK;
508             }
509             else
510                 res.xxpCheckSum = ppresXxpIncomplete;
511         }
512         else if (res.xxpFull)
513         {
514             // we have correct PHCS and we do not need to fix anything
515             // there is a very small chance that it is also good UDP CS
516             // in such rare case we give a priority to UDP CS
517             CalculateUdpChecksumGivenPseudoCS(pUdpHeader, xxpHeaderAndPayloadLen);
518             if (CompareNetCheckSumOnEndSystem(pUdpHeader->udp_xsum, saved))
519                 res.xxpCheckSum = ppresCSOK;
520             pUdpHeader->udp_xsum = saved;
521         }
522     }
523     else
524         res.ipCheckSum = ppresIPTooShort;
525 
526     return res;
527 }
528 
529 static LPCSTR __inline GetPacketCase(tTcpIpPacketParsingResult res)
530 {
531     static const char *const IPCaseName[4] = { "not tested", "Non-IP", "IPv4", "IPv6" };
532     if (res.xxpStatus == ppresXxpKnown) return res.TcpUdp == ppresIsTCP ?
533         (res.ipStatus == ppresIPV4 ? "TCPv4" : "TCPv6") :
534         (res.ipStatus == ppresIPV4 ? "UDPv4" : "UDPv6");
535     if (res.xxpStatus == ppresXxpIncomplete) return res.TcpUdp == ppresIsTCP ? "Incomplete TCP" : "Incomplete UDP";
536     if (res.xxpStatus == ppresXxpOther) return "IP";
537     return  IPCaseName[res.ipStatus];
538 }
539 
540 static LPCSTR __inline GetIPCSCase(tTcpIpPacketParsingResult res)
541 {
542     static const char *const CSCaseName[4] = { "not tested", "(too short)", "OK", "Bad" };
543     return CSCaseName[res.ipCheckSum];
544 }
545 
546 static LPCSTR __inline GetXxpCSCase(tTcpIpPacketParsingResult res)
547 {
548     static const char *const CSCaseName[4] = { "-", "PCS", "CS", "Bad" };
549     return CSCaseName[res.xxpCheckSum];
550 }
551 
552 static __inline VOID PrintOutParsingResult(
553     tTcpIpPacketParsingResult res,
554     int level,
555     LPCSTR procname)
556 {
557     DPrintf(level, ("[%s] %s packet IPCS %s%s, checksum %s%s", procname,
558         GetPacketCase(res),
559         GetIPCSCase(res),
560         res.fixedIpCS ? "(fixed)" : "",
561         GetXxpCSCase(res),
562         res.fixedXxpCS ? "(fixed)" : ""));
563 }
564 
565 tTcpIpPacketParsingResult ParaNdis_CheckSumVerify(PVOID buffer, ULONG size, ULONG flags, LPCSTR caller)
566 {
567     tTcpIpPacketParsingResult res = QualifyIpPacket(buffer, size);
568     if (res.ipStatus == ppresIPV4)
569     {
570         if (flags & pcrIpChecksum)
571             res = VerifyIpChecksum(buffer, res, (flags & pcrFixIPChecksum) != 0);
572         if(res.xxpStatus == ppresXxpKnown)
573         {
574             if (res.TcpUdp == ppresIsTCP) /* TCP */
575             {
576                 if(flags & pcrTcpV4Checksum)
577                 {
578                     res = VerifyTcpChecksum(buffer, size, res, flags & (pcrFixPHChecksum | pcrFixTcpV4Checksum));
579                 }
580             }
581             else /* UDP */
582             {
583                 if (flags & pcrUdpV4Checksum)
584                 {
585                     res = VerifyUdpChecksum(buffer, size, res, flags & (pcrFixPHChecksum | pcrFixUdpV4Checksum));
586                 }
587             }
588         }
589     }
590     else if (res.ipStatus == ppresIPV6)
591     {
592         if(res.xxpStatus == ppresXxpKnown)
593         {
594             if (res.TcpUdp == ppresIsTCP) /* TCP */
595             {
596                 if(flags & pcrTcpV6Checksum)
597                 {
598                     res = VerifyTcpChecksum(buffer, size, res, flags & (pcrFixPHChecksum | pcrFixTcpV6Checksum));
599                 }
600             }
601             else /* UDP */
602             {
603                 if (flags & pcrUdpV6Checksum)
604                 {
605                     res = VerifyUdpChecksum(buffer, size, res, flags & (pcrFixPHChecksum | pcrFixUdpV6Checksum));
606                 }
607             }
608         }
609     }
610     PrintOutParsingResult(res, 1, caller);
611     return res;
612 }
613 
614 tTcpIpPacketParsingResult ParaNdis_ReviewIPPacket(PVOID buffer, ULONG size, LPCSTR caller)
615 {
616     tTcpIpPacketParsingResult res = QualifyIpPacket(buffer, size);
617     PrintOutParsingResult(res, 1, caller);
618     return res;
619 }
620