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