1 /* $Id$ */
2 /*
3 ** Copyright (C) 2000,2001 Christopher Cramer <cec@ee.duke.edu>
4 ** Snort is Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
5 **
6 ** Copyright (C) 2002-2009 Sourcefire, Inc.
7 ** Marc Norton <mnorton@sourcefire.com>
8 **
9 ** This program is free software; you can redistribute it and/or modify
10 ** it under the terms of the GNU General Public License Version 2 as
11 ** published by the Free Software Foundation. You may not use, modify or
12 ** distribute this program under any other version of the GNU General
13 ** Public License.
14 **
15 ** This program is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ** GNU General Public License for more details.
19 **
20 ** You should have received a copy of the GNU General Public License
21 ** along with this program; if not, write to the Free Software
22 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 **
24 **
25 ** 7/2002 Marc Norton - added inline/optimized checksum routines
26 ** these handle all hi/low endian issues
27 ** 8/2002 Marc Norton - removed old checksum code and prototype
28 **
29 */
30
31 #ifndef __CHECKSUM_H__
32 #define __CHECKSUM_H__
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "debug.h"
39 #include <sys/types.h>
40
41
42 /* define checksum error flags */
43 #define CSE_IP 0x01
44 #define CSE_TCP 0x02
45 #define CSE_UDP 0x04
46 #define CSE_ICMP 0x08
47 #define CSE_IGMP 0x10
48
49 /*
50 * checksum IP - header=20+ bytes
51 *
52 * w - short words of data
53 * blen - byte length
54 *
55 */
in_chksum_ip(unsigned short * w,int blen)56 static INLINE unsigned short in_chksum_ip( unsigned short * w, int blen )
57 {
58 unsigned int cksum;
59
60 /* IP must be >= 20 bytes */
61 cksum = w[0];
62 cksum += w[1];
63 cksum += w[2];
64 cksum += w[3];
65 cksum += w[4];
66 cksum += w[5];
67 cksum += w[6];
68 cksum += w[7];
69 cksum += w[8];
70 cksum += w[9];
71
72 blen -= 20;
73 w += 10;
74
75 while( blen ) /* IP-hdr must be an integral number of 4 byte words */
76 {
77 cksum += w[0];
78 cksum += w[1];
79 w += 2;
80 blen -= 4;
81 }
82
83 cksum = (cksum >> 16) + (cksum & 0x0000ffff);
84 cksum += (cksum >> 16);
85
86 return (unsigned short) (~cksum);
87 }
88
89 /*
90 * checksum tcp
91 *
92 * h - pseudo header - 12 bytes
93 * d - tcp hdr + payload
94 * dlen - length of tcp hdr + payload in bytes
95 *
96 */
in_chksum_tcp(unsigned short * h,unsigned short * d,int dlen)97 static INLINE unsigned short in_chksum_tcp( unsigned short *h, unsigned short * d, int dlen )
98 {
99 unsigned int cksum;
100 unsigned short answer=0;
101
102 /* PseudoHeader must have 12 bytes */
103 cksum = h[0];
104 cksum += h[1];
105 cksum += h[2];
106 cksum += h[3];
107 cksum += h[4];
108 cksum += h[5];
109
110 /* TCP hdr must have 20 hdr bytes */
111 cksum += d[0];
112 cksum += d[1];
113 cksum += d[2];
114 cksum += d[3];
115 cksum += d[4];
116 cksum += d[5];
117 cksum += d[6];
118 cksum += d[7];
119 cksum += d[8];
120 cksum += d[9];
121
122 dlen -= 20; /* bytes */
123 d += 10; /* short's */
124
125 while(dlen >=32)
126 {
127 cksum += d[0];
128 cksum += d[1];
129 cksum += d[2];
130 cksum += d[3];
131 cksum += d[4];
132 cksum += d[5];
133 cksum += d[6];
134 cksum += d[7];
135 cksum += d[8];
136 cksum += d[9];
137 cksum += d[10];
138 cksum += d[11];
139 cksum += d[12];
140 cksum += d[13];
141 cksum += d[14];
142 cksum += d[15];
143 d += 16;
144 dlen -= 32;
145 }
146
147 while(dlen >=8)
148 {
149 cksum += d[0];
150 cksum += d[1];
151 cksum += d[2];
152 cksum += d[3];
153 d += 4;
154 dlen -= 8;
155 }
156
157 while(dlen > 1)
158 {
159 cksum += *d++;
160 dlen -= 2;
161 }
162
163 if( dlen == 1 )
164 {
165 /* printf("new checksum odd byte-packet\n"); */
166 *(unsigned char*)(&answer) = (*(unsigned char*)d);
167
168 /* cksum += (uint16_t) (*(uint8_t*)d); */
169
170 cksum += answer;
171 }
172
173 cksum = (cksum >> 16) + (cksum & 0x0000ffff);
174 cksum += (cksum >> 16);
175
176 return (unsigned short)(~cksum);
177 }
178 /*
179 * checksum tcp for IPv6.
180 *
181 * h - pseudo header - 12 bytes
182 * d - tcp hdr + payload
183 * dlen - length of tcp hdr + payload in bytes
184 *
185 */
in_chksum_tcp6(unsigned short * h,unsigned short * d,int dlen)186 static INLINE unsigned short in_chksum_tcp6( unsigned short *h, unsigned short * d, int dlen )
187 {
188 unsigned int cksum;
189 unsigned short answer=0;
190
191 /* PseudoHeader must have 36 bytes */
192 cksum = h[0];
193 cksum += h[1];
194 cksum += h[2];
195 cksum += h[3];
196 cksum += h[4];
197 cksum += h[5];
198 cksum += h[6];
199 cksum += h[7];
200 cksum += h[8];
201 cksum += h[9];
202 cksum += h[10];
203 cksum += h[11];
204 cksum += h[12];
205 cksum += h[13];
206 cksum += h[14];
207 cksum += h[15];
208 cksum += h[16];
209 cksum += h[17];
210
211 /* TCP hdr must have 20 hdr bytes */
212 cksum += d[0];
213 cksum += d[1];
214 cksum += d[2];
215 cksum += d[3];
216 cksum += d[4];
217 cksum += d[5];
218 cksum += d[6];
219 cksum += d[7];
220 cksum += d[8];
221 cksum += d[9];
222
223 dlen -= 20; /* bytes */
224 d += 10; /* short's */
225
226 while(dlen >=32)
227 {
228 cksum += d[0];
229 cksum += d[1];
230 cksum += d[2];
231 cksum += d[3];
232 cksum += d[4];
233 cksum += d[5];
234 cksum += d[6];
235 cksum += d[7];
236 cksum += d[8];
237 cksum += d[9];
238 cksum += d[10];
239 cksum += d[11];
240 cksum += d[12];
241 cksum += d[13];
242 cksum += d[14];
243 cksum += d[15];
244 d += 16;
245 dlen -= 32;
246 }
247
248 while(dlen >=8)
249 {
250 cksum += d[0];
251 cksum += d[1];
252 cksum += d[2];
253 cksum += d[3];
254 d += 4;
255 dlen -= 8;
256 }
257
258 while(dlen > 1)
259 {
260 cksum += *d++;
261 dlen -= 2;
262 }
263
264 if( dlen == 1 )
265 {
266 /* printf("new checksum odd byte-packet\n"); */
267 *(unsigned char*)(&answer) = (*(unsigned char*)d);
268
269 /* cksum += (uint16_t) (*(uint8_t*)d); */
270
271 cksum += answer;
272 }
273
274 cksum = (cksum >> 16) + (cksum & 0x0000ffff);
275 cksum += (cksum >> 16);
276
277 return (unsigned short)(~cksum);
278 }
279
280 /*
281 * checksum udp
282 *
283 * h - pseudo header - 12 bytes
284 * d - udp hdr + payload
285 * dlen - length of payload in bytes
286 *
287 */
in_chksum_udp6(unsigned short * h,unsigned short * d,int dlen)288 static INLINE unsigned short in_chksum_udp6( unsigned short *h, unsigned short * d, int dlen )
289 {
290 unsigned int cksum;
291 unsigned short answer=0;
292
293 /* PseudoHeader must have 12 bytes */
294 cksum = h[0];
295 cksum += h[1];
296 cksum += h[2];
297 cksum += h[3];
298 cksum += h[4];
299 cksum += h[5];
300 cksum += h[6];
301 cksum += h[7];
302 cksum += h[8];
303 cksum += h[9];
304 cksum += h[10];
305 cksum += h[11];
306 cksum += h[12];
307 cksum += h[13];
308 cksum += h[14];
309 cksum += h[15];
310 cksum += h[16];
311 cksum += h[17];
312
313 /* UDP must have 8 hdr bytes */
314 cksum += d[0];
315 cksum += d[1];
316 cksum += d[2];
317 cksum += d[3];
318
319 dlen -= 8; /* bytes */
320 d += 4; /* short's */
321
322 while(dlen >=32)
323 {
324 cksum += d[0];
325 cksum += d[1];
326 cksum += d[2];
327 cksum += d[3];
328 cksum += d[4];
329 cksum += d[5];
330 cksum += d[6];
331 cksum += d[7];
332 cksum += d[8];
333 cksum += d[9];
334 cksum += d[10];
335 cksum += d[11];
336 cksum += d[12];
337 cksum += d[13];
338 cksum += d[14];
339 cksum += d[15];
340 d += 16;
341 dlen -= 32;
342 }
343
344 while(dlen >=8)
345 {
346 cksum += d[0];
347 cksum += d[1];
348 cksum += d[2];
349 cksum += d[3];
350 d += 4;
351 dlen -= 8;
352 }
353
354 while(dlen > 1)
355 {
356 cksum += *d++;
357 dlen -= 2;
358 }
359
360 if( dlen == 1 )
361 {
362 *(unsigned char*)(&answer) = (*(unsigned char*)d);
363 cksum += answer;
364 }
365
366 cksum = (cksum >> 16) + (cksum & 0x0000ffff);
367 cksum += (cksum >> 16);
368
369 return (unsigned short)(~cksum);
370 }
371
372
373
in_chksum_udp(unsigned short * h,unsigned short * d,int dlen)374 static INLINE unsigned short in_chksum_udp( unsigned short *h, unsigned short * d, int dlen )
375 {
376 unsigned int cksum;
377 unsigned short answer=0;
378
379 /* PseudoHeader must have 36 bytes */
380 cksum = h[0];
381 cksum += h[1];
382 cksum += h[2];
383 cksum += h[3];
384 cksum += h[4];
385 cksum += h[5];
386
387 /* UDP must have 8 hdr bytes */
388 cksum += d[0];
389 cksum += d[1];
390 cksum += d[2];
391 cksum += d[3];
392
393 dlen -= 8; /* bytes */
394 d += 4; /* short's */
395
396 while(dlen >=32)
397 {
398 cksum += d[0];
399 cksum += d[1];
400 cksum += d[2];
401 cksum += d[3];
402 cksum += d[4];
403 cksum += d[5];
404 cksum += d[6];
405 cksum += d[7];
406 cksum += d[8];
407 cksum += d[9];
408 cksum += d[10];
409 cksum += d[11];
410 cksum += d[12];
411 cksum += d[13];
412 cksum += d[14];
413 cksum += d[15];
414 d += 16;
415 dlen -= 32;
416 }
417
418 while(dlen >=8)
419 {
420 cksum += d[0];
421 cksum += d[1];
422 cksum += d[2];
423 cksum += d[3];
424 d += 4;
425 dlen -= 8;
426 }
427
428 while(dlen > 1)
429 {
430 cksum += *d++;
431 dlen -= 2;
432 }
433
434 if( dlen == 1 )
435 {
436 *(unsigned char*)(&answer) = (*(unsigned char*)d);
437 cksum += answer;
438 }
439
440 cksum = (cksum >> 16) + (cksum & 0x0000ffff);
441 cksum += (cksum >> 16);
442
443 return (unsigned short)(~cksum);
444 }
445
446 /*
447 * checksum icmp
448 */
in_chksum_icmp(unsigned short * w,int blen)449 static INLINE unsigned short in_chksum_icmp( unsigned short * w, int blen )
450 {
451 unsigned short answer=0;
452 unsigned int cksum = 0;
453
454 while(blen >=32)
455 {
456 cksum += w[0];
457 cksum += w[1];
458 cksum += w[2];
459 cksum += w[3];
460 cksum += w[4];
461 cksum += w[5];
462 cksum += w[6];
463 cksum += w[7];
464 cksum += w[8];
465 cksum += w[9];
466 cksum += w[10];
467 cksum += w[11];
468 cksum += w[12];
469 cksum += w[13];
470 cksum += w[14];
471 cksum += w[15];
472 w += 16;
473 blen -= 32;
474 }
475
476 while(blen >=8)
477 {
478 cksum += w[0];
479 cksum += w[1];
480 cksum += w[2];
481 cksum += w[3];
482 w += 4;
483 blen -= 8;
484 }
485
486 while(blen > 1)
487 {
488 cksum += *w++;
489 blen -= 2;
490 }
491
492 if( blen == 1 )
493 {
494 *(unsigned char*)(&answer) = (*(unsigned char*)w);
495 cksum += answer;
496 }
497
498 cksum = (cksum >> 16) + (cksum & 0x0000ffff);
499 cksum += (cksum >> 16);
500
501
502 return (unsigned short)(~cksum);
503 }
504
505 /*
506 * checksum icmp6
507 */
in_chksum_icmp6(unsigned short * w,int blen)508 static INLINE unsigned short in_chksum_icmp6( unsigned short * w, int blen )
509 {
510 // XXX ICMP6 CHECKSUM NOT YET IMPLEMENTED
511 return 0;
512 #if 0
513 unsigned short answer=0;
514 unsigned int cksum = 0;
515
516 while(blen >=32)
517 {
518 cksum += w[0];
519 cksum += w[1];
520 cksum += w[2];
521 cksum += w[3];
522 cksum += w[4];
523 cksum += w[5];
524 cksum += w[6];
525 cksum += w[7];
526 cksum += w[8];
527 cksum += w[9];
528 cksum += w[10];
529 cksum += w[11];
530 cksum += w[12];
531 cksum += w[13];
532 cksum += w[14];
533 cksum += w[15];
534 w += 16;
535 blen -= 32;
536 }
537
538 while(blen >=8)
539 {
540 cksum += w[0];
541 cksum += w[1];
542 cksum += w[2];
543 cksum += w[3];
544 w += 4;
545 blen -= 8;
546 }
547
548 while(blen > 1)
549 {
550 cksum += *w++;
551 blen -= 2;
552 }
553
554 if( blen == 1 )
555 {
556 *(unsigned char*)(&answer) = (*(unsigned char*)w);
557 cksum += answer;
558 }
559
560 cksum = (cksum >> 16) + (cksum & 0x0000ffff);
561 cksum += (cksum >> 16);
562
563
564 return (unsigned short)(~cksum);
565 #endif
566 }
567
568
569 #endif /* __CHECKSUM_H__ */
570