Watt-32 tcp/ip  2.2 dev-rel.10
chksum.c
Go to the documentation of this file.
1 
7 #include <stdio.h>
8 #include <stdlib.h>
9 
10 #include "wattcp.h"
11 #include "pcicmp.h"
12 #include "pcdbug.h"
13 #include "pcstat.h"
14 #include "language.h"
15 #include "strings.h"
16 #include "misc.h"
17 #include "ip6_in.h"
18 #include "chksum.h"
19 
29 WORD W32_CALL in_checksum (const void *ptr, unsigned len)
30 {
31  register long sum = 0;
32  register long slen = (long) len; /* must be signed */
33  register const WORD *wrd = (const WORD*) ptr;
34 
35  #if defined(WIN32) || defined(__DJGPP__)
36  // WATT_ASSERT (0); /* Why should we use this slow checksum routine? */
37  #endif
38 
39  while (slen > 1)
40  {
41  sum += *wrd++;
42  slen -= 2;
43  }
44  if (slen > 0)
45  sum += *(const BYTE*)wrd;
46 
47  /*@-shiftsigned@*/
48  while (sum >> 16)
49  sum = (sum & 0xFFFF) + (sum >> 16);
50 
51  return (WORD)sum;
52 }
53 
54 #if defined(USE_IPV6)
55 
58 WORD _ip6_checksum (const in6_Header *ip, WORD proto,
59  const void *payload, unsigned payloadlen)
60 {
62  DWORD chksum;
63 
64  memset (&ph, 0, sizeof(ph));
65  memcpy (&ph.src, &ip->source, sizeof(ph.src));
66  memcpy (&ph.dst, &ip->destination, sizeof(ph.dst));
67  ph.length = intel16 (payloadlen);
68  ph.next_hdr = (BYTE)proto;
69 
70  chksum = CHECKSUM (&ph, sizeof(ph));
71  chksum += CHECKSUM (payload, payloadlen);
72 
73  /* Wrap in the carries to reduce chksum to 16 bits.
74  */
75  chksum = (chksum >> 16) + (chksum & 0xFFFF);
76  chksum += (chksum >> 16);
77 
78  /* Take ones-complement and replace 0 with 0xFFFF.
79  */
80  chksum = (WORD)~chksum;
81  if (chksum == 0UL)
82  chksum = 0xFFFFUL;
83 
84  return (WORD)chksum;
85 }
86 
90 int _ip6_tcp_checksum (const in6_Header *ip, const tcp_Header *tcp, unsigned len)
91 {
92  if (_ip6_checksum(ip, IP6_NEXT_TCP, tcp, len) != 0xFFFF)
93  {
94  STAT (tcpstats.tcps_rcvbadsum++);
95  if (debug_on)
96  outsnl (_LANG("bad IPv6/TCP checksum"));
97  return (0);
98  }
99  return (1);
100 }
101 
105 int _ip6_udp_checksum (const in6_Header *ip, const udp_Header *udp, unsigned len)
106 {
107  if (_ip6_checksum(ip, IP6_NEXT_UDP, udp, len) != 0xFFFF)
108  {
109  STAT (udpstats.udps_badsum++);
110  if (debug_on)
111  outsnl (_LANG("bad IPv6/UDP checksum"));
112  return (0);
113  }
114  return (1);
115 }
116 
117 /*
118  * Check ICMP header checksum of an IPv6 packet.
119  * Caller upcates stats.
120  */
121 int _ip6_icmp_checksum (const in6_Header *ip, const void *icmp, unsigned len)
122 {
123  return (_ip6_checksum(ip, IP6_NEXT_ICMP, icmp, len) == 0xFFFF);
124 }
125 #endif /* USE_IPV6 */
126 
127 
128 #if defined(WIN32) && 0
129 
132 int ndis_in_checksum_offload (const void *ptr, unsigned len)
133 {
134 }
135 #endif /* WIN32 */
136 
137 #if defined(NOT_USED)
138 
139 #define CKSUM_CARRY(x) (x = (x >> 16) + (x & 0xffff), \
140  (~(x + (x >> 16)) & 0xffff) )
141 
142 #ifndef IP_PROTO
143 #define IP_PROTO 0 /* dummy for IP */
144 #endif
145 
146 /*
147  * Set header checksum on outgoing packets.
148  * Dug Song came up with this very cool checksuming implementation
149  * eliminating the need for explicit psuedoheader use. Check it out.
150  *
151  * Ripped from libnet 1.0.1
152  */
153 int do_checksum (const BYTE *buf, BYTE protocol, unsigned len)
154 {
155  struct in_Header *ip = (struct in_Header*) buf;
156  struct tcp_Header *tcp;
157  struct udp_Header *udp;
158  struct IGMPv1_packet *igmp;
159  union icmp_pkt *icmp;
160  WORD sum = 0;
161 
162  unsigned ip_hlen = in_GetHdrLen (ip);
163 
164  switch (protocol)
165  {
166  case TCP_PROTO:
167  tcp = (struct tcp_Header*) (buf + ip_hlen);
168  tcp->checksum = 0;
169  sum = CHECKSUM (&ip->source, 8);
170  sum += intel16 (TCP_PROTO + len);
171  sum += CHECKSUM (tcp, len);
172  tcp->checksum = CKSUM_CARRY (sum);
173  break;
174 
175  case UDP_PROTO:
176  udp = (struct udp_Header*) (buf + ip_hlen);
177  udp->checksum = 0;
178  sum = CHECKSUM (&ip->source, 8);
179  sum += intel16 (UDP_PROTO + len);
180  sum += CHECKSUM (udp, len);
181  udp->checksum = CKSUM_CARRY (sum);
182  break;
183 
184  case ICMP_PROTO:
185  icmp = (union icmp_pkt*) (buf + ip_hlen);
186  icmp->unused.checksum = 0;
187  sum = CHECKSUM (icmp, len);
188  icmp->unused.checksum = CKSUM_CARRY (sum);
189  break;
190 
191  case IGMP_PROTO:
192  igmp = (struct IGMPv1_packet*) (buf + ip_hlen);
193  igmp->checksum = 0;
194  sum += CHECKSUM (igmp, len);
195  igmp->checksum = CKSUM_CARRY (sum);
196  break;
197 
198  case IP_PROTO:
199  ip->checksum = 0;
200  sum = CHECKSUM (ip, len);
201  ip->checksum = CKSUM_CARRY (sum);
202  break;
203 
204  default:
205  TCP_CONSOLE_MSG (2, ("do_checksum: unknown protocol %d\n", protocol));
206  return (-1);
207  }
208  return (1);
209 }
210 #endif /* NOT_USED */
211 
int ndis_in_checksum_offload(const void *ptr, unsigned len)
Do the IP checksum in NIC hardware.
Definition: chksum.c:132
int _ip6_udp_checksum(const in6_Header *ip, const udp_Header *udp, unsigned len)
Check udp header checksum of an IPv6 packet.
Definition: chksum.c:105
Core definitions.
Definition: ip_icmp.h:62
Definition: igmp.h:62
Definition: ip.h:67
WORD W32_CALL in_checksum(const void *ptr, unsigned len)
This checksum routine is only used by 16-bit targets (and files outside the library).
Definition: chksum.c:29
WORD _ip6_checksum(const in6_Header *ip, WORD proto, const void *payload, unsigned payloadlen)
Generic IPv6 checksum function.
Definition: chksum.c:58
int _ip6_tcp_checksum(const in6_Header *ip, const tcp_Header *tcp, unsigned len)
Check tcp header checksum of an IPv6 packet.
Definition: chksum.c:90