Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / niu_ippktgen / C / libnet / src / libnet_checksum.c
CommitLineData
86530b38
AT
1/*
2 * $Id: libnet_checksum.c,v 1.1.1.1 2007/02/13 22:21:21 drp Exp $
3 *
4 * libnet
5 * libnet_checksum.c - checksum routines
6 *
7 * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 */
32
33#if (HAVE_CONFIG_H)
34#include "../include/config.h"
35#endif
36#if (!(_WIN32) || (__CYGWIN__))
37#include "../include/libnet.h"
38#else
39#include "../include/win32/libnet.h"
40#endif
41int
42libnet_in_cksum(u_int16_t *addr, int len)
43{
44 int sum;
45
46 sum = 0;
47
48 while (len > 1)
49 {
50 sum += *addr++;
51 len -= 2;
52 }
53 if (len == 1)
54 {
55 sum += *(u_int8_t *)addr << 8;
56 }
57
58 return (sum);
59}
60
61int
62libnet_toggle_checksum(libnet_t *l, libnet_ptag_t ptag, int mode)
63{
64 libnet_pblock_t *p;
65
66 p = libnet_pblock_find(l, ptag);
67 if (p == NULL)
68 {
69 /* err msg set in libnet_pblock_find() */
70 return (-1);
71 }
72 if (mode == LIBNET_ON)
73 {
74 if ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
75 {
76 return (1);
77 }
78 else
79 {
80 (p->flags) |= LIBNET_PBLOCK_DO_CHECKSUM;
81 return (1);
82 }
83 }
84 else
85 {
86 if ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
87 {
88 (p->flags) &= ~LIBNET_PBLOCK_DO_CHECKSUM;
89 return (1);
90 }
91 else
92 {
93 return (1);
94 }
95 }
96}
97
98
99int
100libnet_do_checksum(libnet_t *l, u_int8_t *buf, int protocol, int len)
101{
102 /* will need to update this for ipv6 at some point */
103 struct libnet_ipv4_hdr *iph_p;
104 struct libnet_ipv6_hdr *ip6h_p;
105 int is_ipv6;
106 int ip_hl;
107 int sum;
108
109 is_ipv6 = 0; /* default to not using IPv6 */
110 sum = 0;
111 iph_p = NULL;
112 ip6h_p = NULL;
113
114 if (len == 0)
115 {
116 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
117 "%s(): header length can't be zero\n", __func__);
118 return (-1);
119 }
120
121 /*
122 * Figure out which IP version we're dealing with. We'll assume v4
123 * and overlay a header structure to yank out the version.
124 */
125 iph_p = (struct libnet_ipv4_hdr *)buf;
126
127 if (iph_p && iph_p->ip_v == 6) {
128 ip6h_p = (struct libnet_ipv6_hdr *)buf;
129 is_ipv6 = 1;
130 ip_hl = 40;
131 } else {
132 is_ipv6 = 0;
133 ip_hl = iph_p->ip_hl << 2;
134 }
135
136 /*
137 * Dug Song came up with this very cool checksuming implementation
138 * eliminating the need for explicit psuedoheader use. Check it out.
139 */
140 switch (protocol)
141 {
142 case IPPROTO_SCTP:
143 {
144 struct libnet_sctp_hdr *sctph_p =
145 (struct libnet_sctp_hdr *)(buf + ip_hl);
146 sctph_p->checksum = 0;
147 sum = libnet_sctp_cksum((u_int8_t *)sctph_p, len);
148 sctph_p->checksum = sum;
149 break;
150 }
151
152 /*
153 * Style note: normally I don't advocate declaring variables inside
154 * blocks of control, but it makes good sense here. -- MDS
155 */
156 case IPPROTO_TCP:
157 {
158 struct libnet_tcp_hdr *tcph_p =
159 (struct libnet_tcp_hdr *)(buf + ip_hl);
160#if 0
161#if (STUPID_SOLARIS_CHECKSUM_BUG)
162 tcph_p->th_sum = tcph_p->th_off << 2;
163 return (1);
164#endif /* STUPID_SOLARIS_CHECKSUM_BUG */
165#endif
166#if (HAVE_HPUX11)
167 if (l->injection_type != LIBNET_LINK)
168 {
169 /*
170 * Similiar to the Solaris Checksum bug - but need to add
171 * the size of the TCP payload (only for raw sockets).
172 */
173 tcph_p->th_sum = (tcph_p->th_off << 2) +
174 (len - (tcph_p->th_off << 2));
175 return (1);
176 }
177#endif
178 tcph_p->th_sum = 0;
179 if (is_ipv6)
180 {
181 sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
182 }
183 else
184 {
185 sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);
186 }
187 sum += ntohs(IPPROTO_TCP + len);
188 sum += libnet_in_cksum((u_int16_t *)tcph_p, len);
189 tcph_p->th_sum = LIBNET_CKSUM_CARRY(sum);
190 break;
191 }
192 case IPPROTO_UDP:
193 {
194 struct libnet_udp_hdr *udph_p =
195 (struct libnet_udp_hdr *)(buf + ip_hl);
196 udph_p->uh_sum = 0;
197 if (is_ipv6)
198 {
199 sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
200 }
201 else
202 {
203 sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);
204 }
205 sum += ntohs(IPPROTO_UDP + len);
206 sum += libnet_in_cksum((u_int16_t *)udph_p, len);
207 udph_p->uh_sum = LIBNET_CKSUM_CARRY(sum);
208 break;
209 }
210 case IPPROTO_ICMP:
211 {
212 struct libnet_icmpv4_hdr *icmph_p =
213 (struct libnet_icmpv4_hdr *)(buf + ip_hl);
214
215 icmph_p->icmp_sum = 0;
216 if (is_ipv6)
217 {
218 sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
219 sum += ntohs(IPPROTO_ICMP6 + len);
220 }
221 sum += libnet_in_cksum((u_int16_t *)icmph_p, len);
222 icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum);
223 break;
224 }
225 case IPPROTO_IGMP:
226 {
227 struct libnet_igmp_hdr *igmph_p =
228 (struct libnet_igmp_hdr *)(buf + ip_hl);
229
230 igmph_p->igmp_sum = 0;
231 sum = libnet_in_cksum((u_int16_t *)igmph_p, len);
232 igmph_p->igmp_sum = LIBNET_CKSUM_CARRY(sum);
233 break;
234 }
235 case IPPROTO_RSVP:
236 {
237 struct libnet_rsvp_hdr *rsvph_p =
238 (struct libnet_rsvp_hdr *)(buf + ip_hl);
239
240 rsvph_p->checksum = 0;
241 sum = libnet_in_cksum((u_int16_t *)rsvph_p, len);
242 rsvph_p->checksum = LIBNET_CKSUM_CARRY(sum);
243 break;
244 }
245 case IPPROTO_PIM:
246 {
247 struct libnet_pim_hdr *pim_p =
248 (struct libnet_pim_hdr *)(buf + ip_hl);
249
250 pim_p->pim_sum = 0;
251 if ((pim_p->pim_ver_type & 0x0f) == PIM_REGISTER) {
252 sum = libnet_in_cksum((u_int16_t *)pim_p, LIBNET_PIM_H);
253 } else {
254 sum = libnet_in_cksum((u_int16_t *)pim_p, len);
255 }
256 pim_p->pim_sum = LIBNET_CKSUM_CARRY(sum);
257 break;
258 }
259 case IPPROTO_GRE:
260 {
261 /* checksum is always at the same place in GRE header
262 * in the multiple RFC version of the protocol ... ouf !!!
263 */
264 struct libnet_gre_hdr *greh_p =
265 (struct libnet_gre_hdr *)(buf + ip_hl);
266 u_int16_t fv = ntohs(greh_p->flags_ver);
267 if (!(fv & (GRE_CSUM|GRE_ROUTING | GRE_VERSION_0)) ||
268 !(fv & (GRE_CSUM|GRE_VERSION_1)))
269 {
270 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
271 "%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n", __func__, fv);
272 return (-1);
273 }
274 sum = libnet_in_cksum((u_int16_t *)greh_p, len);
275 greh_p->gre_sum = LIBNET_CKSUM_CARRY(sum);
276 break;
277 }
278 case IPPROTO_OSPF:
279 {
280 struct libnet_ospf_hdr *oh_p =
281 (struct libnet_ospf_hdr *)(buf + ip_hl);
282
283 oh_p->ospf_sum = 0;
284 sum += libnet_in_cksum((u_int16_t *)oh_p, len);
285 oh_p->ospf_sum = LIBNET_CKSUM_CARRY(sum);
286 break;
287 }
288 case IPPROTO_OSPF_LSA:
289 {
290 struct libnet_ospf_hdr *oh_p =
291 (struct libnet_ospf_hdr *)(buf + ip_hl);
292 struct libnet_lsa_hdr *lsa_p =
293 (struct libnet_lsa_hdr *)(buf +
294 ip_hl + oh_p->ospf_len);
295
296 lsa_p->lsa_sum = 0;
297 sum += libnet_in_cksum((u_int16_t *)lsa_p, len);
298 lsa_p->lsa_sum = LIBNET_CKSUM_CARRY(sum);
299 break;
300#if 0
301 /*
302 * Reworked fletcher checksum taken from RFC 1008.
303 */
304 int c0, c1;
305 struct libnet_lsa_hdr *lsa_p = (struct libnet_lsa_hdr *)buf;
306 u_int8_t *p, *p1, *p2, *p3;
307
308 c0 = 0;
309 c1 = 0;
310
311 lsa_p->lsa_cksum = 0;
312
313 p = buf;
314 p1 = buf;
315 p3 = buf + len; /* beginning and end of buf */
316
317 while (p1 < p3)
318 {
319 p2 = p1 + LIBNET_MODX;
320 if (p2 > p3)
321 {
322 p2 = p3;
323 }
324
325 for (p = p1; p < p2; p++)
326 {
327 c0 += (*p);
328 c1 += c0;
329 }
330
331 c0 %= 255;
332 c1 %= 255; /* modular 255 */
333
334 p1 = p2;
335 }
336
337#if AWR_PLEASE_REWORK_THIS
338 lsa_p->lsa_cksum[0] = (((len - 17) * c0 - c1) % 255);
339 if (lsa_p->lsa_cksum[0] <= 0)
340 {
341 lsa_p->lsa_cksum[0] += 255;
342 }
343
344 lsa_p->lsa_cksum[1] = (510 - c0 - lsa_p->lsa_cksum[0]);
345 if (lsa_p->lsa_cksum[1] > 255)
346 {
347 lsa_p->lsa_cksum[1] -= 255;
348 }
349#endif
350 break;
351#endif
352 }
353 case IPPROTO_IP:
354 {
355 iph_p->ip_sum = 0;
356 sum = libnet_in_cksum((u_int16_t *)iph_p, ip_hl);
357 iph_p->ip_sum = LIBNET_CKSUM_CARRY(sum);
358 break;
359 }
360 case IPPROTO_VRRP:
361 {
362 struct libnet_vrrp_hdr *vrrph_p =
363 (struct libnet_vrrp_hdr *)(buf + ip_hl);
364
365 vrrph_p->vrrp_sum = 0;
366 sum = libnet_in_cksum((u_int16_t *)vrrph_p, len);
367 vrrph_p->vrrp_sum = LIBNET_CKSUM_CARRY(sum);
368 break;
369 }
370 case LIBNET_PROTO_CDP:
371 { /* XXX - Broken: how can we easily get the entire packet size? */
372 struct libnet_cdp_hdr *cdph_p =
373 (struct libnet_cdp_hdr *)buf;
374
375 cdph_p->cdp_sum = 0;
376 sum = libnet_in_cksum((u_int16_t *)cdph_p, len);
377 cdph_p->cdp_sum = LIBNET_CKSUM_CARRY(sum);
378 break;
379 }
380 case LIBNET_PROTO_ISL:
381 {
382 // struct libnet_isl_hdr *islh_p =
383 // (struct libnet_isl_hdr *)buf;
384 /*
385 * Need to compute 4 byte CRC for the ethernet frame and for
386 * the ISL frame itself. Use the libnet_crc function.
387 */
388 }
389 default:
390 {
391 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
392 "%s(): unsuported protocol %d\n", __func__, protocol);
393 return (-1);
394 }
395 }
396 return (1);
397}
398
399
400u_int16_t
401libnet_ip_check(u_int16_t *addr, int len)
402{
403 int sum;
404
405 sum = libnet_in_cksum(addr, len);
406 return (LIBNET_CKSUM_CARRY(sum));
407}
408
409/* EOF */