Annotation of embedaddon/libnet/src/libnet_checksum.c, revision 1.1.1.1
1.1 misho 1: /*
2: * $Id: libnet_checksum.c,v 1.13 2004/03/01 20:26:12 mike 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
41: int
42: libnet_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_int16_t *)addr;
56: }
57:
58: return (sum);
59: }
60:
61: int
62: libnet_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:
99: int
100: libnet_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: if (iph_p && iph_p->ip_v == 6)
127: {
128: ip6h_p = (struct libnet_ipv6_hdr *)buf;
129: is_ipv6 = 1;
130: ip_hl = 40;
131: }
132: else
133: {
134: is_ipv6 = 0;
135: ip_hl = iph_p->ip_hl << 2;
136: }
137:
138: /*
139: * Dug Song came up with this very cool checksuming implementation
140: * eliminating the need for explicit psuedoheader use. Check it out.
141: */
142: switch (protocol)
143: {
144: /*
145: * Style note: normally I don't advocate declaring variables inside
146: * blocks of control, but it makes good sense here. -- MDS
147: */
148: case IPPROTO_TCP:
149: {
150: struct libnet_tcp_hdr *tcph_p =
151: (struct libnet_tcp_hdr *)(buf + ip_hl);
152:
153: #if (STUPID_SOLARIS_CHECKSUM_BUG)
154: tcph_p->th_sum = tcph_p->th_off << 2;
155: return (1);
156: #endif /* STUPID_SOLARIS_CHECKSUM_BUG */
157: #if (HAVE_HPUX11)
158: if (l->injection_type != LIBNET_LINK)
159: {
160: /*
161: * Similiar to the Solaris Checksum bug - but need to add
162: * the size of the TCP payload (only for raw sockets).
163: */
164: tcph_p->th_sum = (tcph_p->th_off << 2) +
165: (len - (tcph_p->th_off << 2));
166: return (1);
167: }
168: #endif
169: tcph_p->th_sum = 0;
170: if (is_ipv6)
171: {
172: sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
173: }
174: else
175: {
176: sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);
177: }
178: sum += ntohs(IPPROTO_TCP + len);
179: sum += libnet_in_cksum((u_int16_t *)tcph_p, len);
180: tcph_p->th_sum = LIBNET_CKSUM_CARRY(sum);
181: break;
182: }
183: case IPPROTO_UDP:
184: {
185: struct libnet_udp_hdr *udph_p =
186: (struct libnet_udp_hdr *)(buf + ip_hl);
187: udph_p->uh_sum = 0;
188: if (is_ipv6)
189: {
190: sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
191: }
192: else
193: {
194: sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);
195: }
196: sum += ntohs(IPPROTO_UDP + len);
197: sum += libnet_in_cksum((u_int16_t *)udph_p, len);
198: udph_p->uh_sum = LIBNET_CKSUM_CARRY(sum);
199: break;
200: }
201: case IPPROTO_ICMP:
202: {
203: struct libnet_icmpv4_hdr *icmph_p =
204: (struct libnet_icmpv4_hdr *)(buf + ip_hl);
205:
206: icmph_p->icmp_sum = 0;
207: if (is_ipv6)
208: {
209: sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
210: sum += ntohs(IPPROTO_ICMP6 + len);
211: }
212: sum += libnet_in_cksum((u_int16_t *)icmph_p, len);
213: icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum);
214: break;
215: }
216: case IPPROTO_IGMP:
217: {
218: struct libnet_igmp_hdr *igmph_p =
219: (struct libnet_igmp_hdr *)(buf + ip_hl);
220:
221: igmph_p->igmp_sum = 0;
222: sum = libnet_in_cksum((u_int16_t *)igmph_p, len);
223: igmph_p->igmp_sum = LIBNET_CKSUM_CARRY(sum);
224: break;
225: }
226: case IPPROTO_GRE:
227: {
228: /* checksum is always at the same place in GRE header
229: * in the multiple RFC version of the protocol ... ouf !!!
230: */
231: struct libnet_gre_hdr *greh_p =
232: (struct libnet_gre_hdr *)(buf + ip_hl);
233: u_int16_t fv = ntohs(greh_p->flags_ver);
234: if (!(fv & (GRE_CSUM|GRE_ROUTING | GRE_VERSION_0)) ||
235: !(fv & (GRE_CSUM|GRE_VERSION_1)))
236: {
237: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
238: "%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n", __func__, fv);
239: return (-1);
240: }
241: sum = libnet_in_cksum((u_int16_t *)greh_p, len);
242: greh_p->gre_sum = LIBNET_CKSUM_CARRY(sum);
243: break;
244: }
245: case IPPROTO_OSPF:
246: {
247: struct libnet_ospf_hdr *oh_p =
248: (struct libnet_ospf_hdr *)(buf + ip_hl);
249:
250: oh_p->ospf_sum = 0;
251: sum += libnet_in_cksum((u_int16_t *)oh_p, len);
252: oh_p->ospf_sum = LIBNET_CKSUM_CARRY(sum);
253: break;
254: }
255: case IPPROTO_OSPF_LSA:
256: {
257: struct libnet_ospf_hdr *oh_p =
258: (struct libnet_ospf_hdr *)(buf + ip_hl);
259: struct libnet_lsa_hdr *lsa_p =
260: (struct libnet_lsa_hdr *)(buf +
261: ip_hl + oh_p->ospf_len);
262:
263: lsa_p->lsa_sum = 0;
264: sum += libnet_in_cksum((u_int16_t *)lsa_p, len);
265: lsa_p->lsa_sum = LIBNET_CKSUM_CARRY(sum);
266: break;
267: #if 0
268: /*
269: * Reworked fletcher checksum taken from RFC 1008.
270: */
271: int c0, c1;
272: struct libnet_lsa_hdr *lsa_p = (struct libnet_lsa_hdr *)buf;
273: u_int8_t *p, *p1, *p2, *p3;
274:
275: c0 = 0;
276: c1 = 0;
277:
278: lsa_p->lsa_cksum = 0;
279:
280: p = buf;
281: p1 = buf;
282: p3 = buf + len; /* beginning and end of buf */
283:
284: while (p1 < p3)
285: {
286: p2 = p1 + LIBNET_MODX;
287: if (p2 > p3)
288: {
289: p2 = p3;
290: }
291:
292: for (p = p1; p < p2; p++)
293: {
294: c0 += (*p);
295: c1 += c0;
296: }
297:
298: c0 %= 255;
299: c1 %= 255; /* modular 255 */
300:
301: p1 = p2;
302: }
303:
304: #if AWR_PLEASE_REWORK_THIS
305: lsa_p->lsa_cksum[0] = (((len - 17) * c0 - c1) % 255);
306: if (lsa_p->lsa_cksum[0] <= 0)
307: {
308: lsa_p->lsa_cksum[0] += 255;
309: }
310:
311: lsa_p->lsa_cksum[1] = (510 - c0 - lsa_p->lsa_cksum[0]);
312: if (lsa_p->lsa_cksum[1] > 255)
313: {
314: lsa_p->lsa_cksum[1] -= 255;
315: }
316: #endif
317: break;
318: #endif
319: }
320: case IPPROTO_IP:
321: {
322: iph_p->ip_sum = 0;
323: sum = libnet_in_cksum((u_int16_t *)iph_p, ip_hl);
324: iph_p->ip_sum = LIBNET_CKSUM_CARRY(sum);
325: break;
326: }
327: case IPPROTO_VRRP:
328: {
329: struct libnet_vrrp_hdr *vrrph_p =
330: (struct libnet_vrrp_hdr *)(buf + ip_hl);
331:
332: vrrph_p->vrrp_sum = 0;
333: sum = libnet_in_cksum((u_int16_t *)vrrph_p, len);
334: vrrph_p->vrrp_sum = LIBNET_CKSUM_CARRY(sum);
335: break;
336: }
337: case LIBNET_PROTO_CDP:
338: { /* XXX - Broken: how can we easily get the entire packet size? */
339: struct libnet_cdp_hdr *cdph_p =
340: (struct libnet_cdp_hdr *)buf;
341:
342: cdph_p->cdp_sum = 0;
343: sum = libnet_in_cksum((u_int16_t *)cdph_p, len);
344: cdph_p->cdp_sum = LIBNET_CKSUM_CARRY(sum);
345: break;
346: }
347: case LIBNET_PROTO_ISL:
348: {
349: // struct libnet_isl_hdr *islh_p =
350: // (struct libnet_isl_hdr *)buf;
351: /*
352: * Need to compute 4 byte CRC for the ethernet frame and for
353: * the ISL frame itself. Use the libnet_crc function.
354: */
355: }
356: default:
357: {
358: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
359: "%s(): unsuported protocol %d\n", __func__, protocol);
360: return (-1);
361: }
362: }
363: return (1);
364: }
365:
366:
367: u_int16_t
368: libnet_ip_check(u_int16_t *addr, int len)
369: {
370: int sum;
371:
372: sum = libnet_in_cksum(addr, len);
373: return (LIBNET_CKSUM_CARRY(sum));
374: }
375:
376: /* EOF */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>