/home/tomh/openhip/hip-0.5/src/include/win32/checksum.h

Go to the documentation of this file.
00001 /*
00002  * This file contains a combination of:
00003  * linux/include/asm-i386/checksum.h and
00004  * linux/include/net/checksum.h from the Linux 2.6.8.1 kernel,
00005  * plus HIP checksum modifications.
00006  * 
00007  */
00008 
00009 /*
00010  * INET         An implementation of the TCP/IP protocol suite for the LINUX
00011  *              operating system.  INET is implemented using the  BSD Socket
00012  *              interface as the means of communication with the user level.
00013  *
00014  *              Checksumming functions for IP, TCP, UDP and so on
00015  *
00016  * Authors:     Jorge Cwik, <jorge@laser.satlink.net>
00017  *              Arnt Gulbrandsen, <agulbra@nvg.unit.no>
00018  *              Borrows very liberally from tcp.c and ip.c, see those
00019  *              files for more names.
00020  *
00021  *              This program is free software; you can redistribute it and/or
00022  *              modify it under the terms of the GNU General Public License
00023  *              as published by the Free Software Foundation; either version
00024  *              2 of the License, or (at your option) any later version.
00025  */
00026 
00027 #ifndef _CHECKSUM_H
00028 #define _CHECKSUM_H
00029 
00030 #ifndef __WIN32__
00031 #include <asm/types.h>
00032 #include <endian.h>
00033 #include <netinet/in.h>
00034 #else
00035 #include <win32/types.h>
00036 #include <ws2tcpip.h>
00037 #endif /* __WIN32__ */
00038 
00039 #ifdef __WIN32__
00040 /* Windows' ws2tcpip.h has struct in6_addr with __u8 and __u16 members,
00041  * but no __u32 as we need here for accumulation.
00042  */
00043 struct my_in6_addr {
00044         __u32 s6_addr32[4];
00045 };
00046 #endif
00047 
00048 /*
00049  * the following inlines are from linux/include/asm-i386/checksum.h
00050  */
00051 
00052 /*
00053  *      This is a version of ip_compute_csum() optimized for IP headers,
00054  *      which always checksum on 4 octet boundaries.
00055  *
00056  *      By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
00057  *      Arnt Gulbrandsen.
00058  */
00059 #ifdef __WIN32__
00060 /* This isn't the 'fast' checksum, since the GCC inline ASM version is not 
00061  * available in Windows; this is the same code from hip_util.c */
00062 static __inline unsigned short ip_fast_csum(unsigned char * iph,
00063                                           unsigned int ihl)
00064 {
00065         __u16 checksum;
00066         unsigned long sum = 0;
00067         int count = ihl*4;
00068         unsigned short *p = (unsigned short *)iph;
00069 
00070         /* 
00071          * this checksum algorithm can be found 
00072          * in RFC 1071 section 4.1
00073          */
00074 
00075         /* one's complement sum 16-bit words of data */
00076         while (count > 1)  {
00077                 sum += *p++;
00078                 count -= 2;
00079         }
00080         /* add left-over byte, if any */
00081         if (count > 0)
00082                 sum += (unsigned char)*p;
00083  
00084         /*  Fold 32-bit sum to 16 bits */
00085         while (sum>>16)
00086                 sum = (sum & 0xffff) + (sum >> 16);
00087         /* take the one's complement of the sum */ 
00088         checksum = (__u16)(~sum);
00089     
00090         return(checksum);
00091 }
00092 #else
00093 static inline unsigned short ip_fast_csum(unsigned char * iph,
00094                                           unsigned int ihl)
00095 {
00096         unsigned int sum;
00097 
00098         __asm__ __volatile__(
00099             "movl (%1), %0      ;\n"
00100             "subl $4, %2        ;\n"
00101             "jbe 2f             ;\n"
00102             "addl 4(%1), %0     ;\n"
00103             "adcl 8(%1), %0     ;\n"
00104             "adcl 12(%1), %0    ;\n"
00105 "1:         adcl 16(%1), %0     ;\n"
00106             "lea 4(%1), %1      ;\n"
00107             "decl %2            ;\n"
00108             "jne 1b             ;\n"
00109             "adcl $0, %0        ;\n"
00110             "movl %0, %2        ;\n"
00111             "shrl $16, %0       ;\n"
00112             "addw %w2, %w0      ;\n"
00113             "adcl $0, %0        ;\n"
00114             "notl %0            ;\n"
00115 "2:                             ;\n"
00116         /* Since the input registers which are loaded with iph and ipl
00117            are modified, we must also specify them as outputs, or gcc
00118            will assume they contain their original values. */
00119         : "=r" (sum), "=r" (iph), "=r" (ihl)
00120         : "1" (iph), "2" (ihl)
00121         : "memory");
00122         return(sum);
00123 }
00124 #endif
00125 
00126 /*
00127  *      Fold a partial checksum
00128  */
00129 
00130 #ifdef __WIN32__
00131 static __inline unsigned int csum_fold(unsigned int sum)
00132 {
00133         /* this is from hip_util.c - checksum_packet() */
00134         /*  Fold 32-bit sum to 16 bits */
00135         while (sum>>16)
00136                 sum = (sum & 0xffff) + (sum >> 16);
00137         /* take the one's complement of the sum */ 
00138         return((__u16)~sum);
00139 }
00140 #else
00141 
00142 static inline unsigned int csum_fold(unsigned int sum)
00143 {
00144         __asm__(
00145                 "addl %1, %0            ;\n"
00146                 "adcl $0xffff, %0       ;\n"
00147                 : "=r" (sum)
00148                 : "r" (sum << 16), "0" (sum & 0xffff0000)
00149         );
00150         return (~sum) >> 16;
00151 }
00152 #endif
00153 
00154 #ifdef __WIN32__
00155 static __inline unsigned int csum_add(unsigned int csum, unsigned int addend);
00156 static __inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
00157                                                    unsigned long daddr,
00158                                                    unsigned short len,
00159                                                    unsigned short proto,
00160                                                    unsigned int sum)
00161 {
00162         sum = csum_add(sum, saddr);
00163         sum = csum_add(sum, daddr);
00164         sum = csum_add(sum, (__u32)len);
00165         sum = csum_add(sum, (__u32)proto);
00166         return(sum);    
00167 }
00168 #else
00169 
00170 static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
00171                                                    unsigned long daddr,
00172                                                    unsigned short len,
00173                                                    unsigned short proto,
00174                                                    unsigned int sum)
00175 {
00176     __asm__(
00177         "addl %1, %0    ;\n"
00178         "adcl %2, %0    ;\n"
00179         "adcl %3, %0    ;\n"
00180         "adcl $0, %0    ;\n"
00181         : "=r" (sum)
00182         : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
00183     return sum;
00184 }
00185 #endif
00186 
00187 /*
00188  * computes the checksum of the TCP/UDP pseudo-header
00189  * returns a 16-bit checksum, already complemented
00190  */
00191 #ifdef __WIN32__
00192 static __inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
00193                                                    unsigned long daddr,
00194                                                    unsigned short len,
00195                                                    unsigned short proto,
00196                                                    unsigned int sum)
00197 #else
00198 static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
00199                                                    unsigned long daddr,
00200                                                    unsigned short len,
00201                                                    unsigned short proto,
00202                                                    unsigned int sum)
00203 #endif
00204 {
00205         return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
00206 }
00207 
00208 #ifndef __WIN32__
00209 #define _HAVE_ARCH_IPV6_CSUM
00210 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
00211                                                      struct in6_addr *daddr,
00212                                                      __u32 len,
00213                                                      unsigned short proto,
00214                                                      unsigned int sum)
00215 {
00216         __asm__(
00217                 "addl 0(%1), %0         ;\n"
00218                 "adcl 4(%1), %0         ;\n"
00219                 "adcl 8(%1), %0         ;\n"
00220                 "adcl 12(%1), %0        ;\n"
00221                 "adcl 0(%2), %0         ;\n"
00222                 "adcl 4(%2), %0         ;\n"
00223                 "adcl 8(%2), %0         ;\n"
00224                 "adcl 12(%2), %0        ;\n"
00225                 "adcl %3, %0            ;\n"
00226                 "adcl %4, %0            ;\n"
00227                 "adcl $0, %0            ;\n"
00228                 : "=&r" (sum)
00229                 : "r" (saddr), "r" (daddr),
00230                   "r"(htonl(len)), "r"(htonl(proto)), "0"(sum));
00231 
00232         return csum_fold(sum);
00233 }
00234 #endif
00235 
00236 /*
00237  * the following inlines are from linux/include/net/checksum.h
00238  */
00239 
00240 #ifdef __WIN32__
00241 static __inline unsigned int csum_add(unsigned int csum, unsigned int addend)
00242 #else
00243 static inline unsigned int csum_add(unsigned int csum, unsigned int addend)
00244 #endif
00245 {
00246         csum += addend;
00247         return csum + (csum < addend);
00248 }
00249 
00250 #ifdef __WIN32__
00251 static __inline unsigned int csum_sub(unsigned int csum, unsigned int addend)
00252 #else
00253 static inline unsigned int csum_sub(unsigned int csum, unsigned int addend)
00254 #endif
00255 {
00256         return csum_add(csum, ~addend);
00257 }
00258 
00259 /* 
00260  * HIP checksum = tcp checksum + hitMagic - csum(saddr,daddr)
00261  */
00262 #ifdef __WIN32__
00263 static __inline unsigned short csum_tcpudp_hip_nofold(unsigned long saddr,
00264                                                    unsigned long daddr,
00265                                                    unsigned short sum,
00266                                                    unsigned short  hitMagic)
00267 #else
00268 static inline unsigned short csum_tcpudp_hip_nofold(unsigned long saddr,
00269                                                    unsigned long daddr,
00270                                                    unsigned short sum,
00271                                                    unsigned short  hitMagic)
00272 #endif
00273 {
00274         /* sum is assumed to be the folded complement, so get the sum back */
00275         unsigned short ret = ~sum;
00276 
00277         ret = ~csum_fold(csum_add(ret, hitMagic));
00278         ret = csum_fold(csum_sub(ret,~csum_fold(csum_add(saddr,daddr))));
00279 
00280         return ret;
00281 }
00282 
00283 #ifdef __WIN32__
00284 static __inline unsigned short csum_hip_revert(unsigned long saddr,
00285                                                    unsigned long daddr,
00286                                                    unsigned short sum,
00287                                                    unsigned short  hitMagic)
00288 #else
00289 static inline unsigned short csum_hip_revert(unsigned long saddr,
00290                                                    unsigned long daddr,
00291                                                    unsigned short sum,
00292                                                    unsigned short  hitMagic)
00293 #endif
00294 {
00295         /* sum is assumed to be the folded complement, so get the sum back */
00296         unsigned short ret = ~sum;
00297 
00298         ret = ~csum_fold(csum_sub(ret, hitMagic));
00299         ret = csum_fold(csum_add(ret,~csum_fold(csum_add(saddr,daddr))));
00300         return ret;
00301 }
00302 
00303 /* 
00304  * HIP checksum = tcp checksum + hitMagic - csum(saddr,daddr)
00305  */
00306 #ifdef __WIN32__
00307 static __inline unsigned short csum_tcpudp_hip_nofold6(struct in6_addr *saddr1,
00308                                                      struct in6_addr *daddr1,
00309                                                      unsigned short sum,
00310                                                      unsigned short  hitMagic)
00311 {
00312         int carry;
00313         unsigned int csum;
00314         /* sum is assumed to be the folded complement, so get the sum back */
00315         unsigned short ret = ~sum;
00316         
00317         /* Re-cast the struct since Windows has no 32-bit struct member. */
00318         struct my_in6_addr *saddr = (struct my_in6_addr*)saddr1;
00319         struct my_in6_addr *daddr = (struct my_in6_addr*)daddr1;
00320 
00321         /* First, sum saddr and daddr as done in csum_ipv6_magic() */
00322         csum = saddr->s6_addr32[0];
00323         carry = (csum < saddr->s6_addr32[0]);
00324         csum += carry;
00325 
00326         csum += saddr->s6_addr32[1];
00327         carry = (csum < saddr->s6_addr32[1]);
00328         csum += carry;
00329 
00330         csum += saddr->s6_addr32[2];
00331         carry = (csum < saddr->s6_addr32[2]);
00332         csum += carry;
00333 
00334         csum += saddr->s6_addr32[3];
00335         carry = (csum < saddr->s6_addr32[3]);
00336         csum += carry;
00337 
00338         csum += daddr->s6_addr32[0];
00339         carry = (csum < daddr->s6_addr32[0]);
00340         csum += carry;
00341 
00342         csum += daddr->s6_addr32[1];
00343         carry = (csum < daddr->s6_addr32[1]);
00344         csum += carry;
00345 
00346         csum += daddr->s6_addr32[2];
00347         carry = (csum < daddr->s6_addr32[2]);
00348         csum += carry;
00349 
00350         csum += daddr->s6_addr32[3];
00351         carry = (csum < daddr->s6_addr32[3]);
00352         csum += carry;
00353 
00354         /* Next, add in the hitMagic and subtract saddr+daddr */
00355         ret = ~csum_fold(csum_add(ret, hitMagic));
00356         ret = csum_fold(csum_sub(ret,~csum_fold(csum)));
00357 
00358         return ret;
00359 
00360 }
00361 #else
00362 
00363 static inline unsigned short csum_tcpudp_hip_nofold6(struct in6_addr *saddr,
00364                                                      struct in6_addr *daddr,
00365                                                      unsigned short sum,
00366                                                      unsigned short  hitMagic)
00367 {
00368         int carry;
00369         unsigned int csum;
00370         /* sum is assumed to be the folded complement, so get the sum back */
00371         unsigned short ret = ~sum;
00372         
00373         /* First, sum saddr and daddr as done in csum_ipv6_magic() */
00374 #ifdef __CYGWIN__
00375         csum = saddr->__u6_addr.__u6_addr32[0];
00376         carry = (csum < saddr->__u6_addr.__u6_addr32[0]);
00377         csum += carry;
00378 
00379         csum += saddr->__u6_addr.__u6_addr32[1];
00380         carry = (csum < saddr->__u6_addr.__u6_addr32[1]);
00381         csum += carry;
00382 
00383         csum += saddr->__u6_addr.__u6_addr32[2];
00384         carry = (csum < saddr->__u6_addr.__u6_addr32[2]);
00385         csum += carry;
00386 
00387         csum += saddr->__u6_addr.__u6_addr32[3];
00388         carry = (csum < saddr->__u6_addr.__u6_addr32[3]);
00389         csum += carry;
00390 
00391         csum += daddr->__u6_addr.__u6_addr32[0];
00392         carry = (csum < daddr->__u6_addr.__u6_addr32[0]);
00393         csum += carry;
00394 
00395         csum += daddr->__u6_addr.__u6_addr32[1];
00396         carry = (csum < daddr->__u6_addr.__u6_addr32[1]);
00397         csum += carry;
00398 
00399         csum += daddr->__u6_addr.__u6_addr32[2];
00400         carry = (csum < daddr->__u6_addr.__u6_addr32[2]);
00401         csum += carry;
00402 
00403         csum += daddr->__u6_addr.__u6_addr32[3];
00404         carry = (csum < daddr->__u6_addr.__u6_addr32[3]);
00405         csum += carry;
00406 #else
00407         csum = saddr->s6_addr32[0];
00408         carry = (csum < saddr->s6_addr32[0]);
00409         csum += carry;
00410 
00411         csum += saddr->s6_addr32[1];
00412         carry = (csum < saddr->s6_addr32[1]);
00413         csum += carry;
00414 
00415         csum += saddr->s6_addr32[2];
00416         carry = (csum < saddr->s6_addr32[2]);
00417         csum += carry;
00418 
00419         csum += saddr->s6_addr32[3];
00420         carry = (csum < saddr->s6_addr32[3]);
00421         csum += carry;
00422 
00423         csum += daddr->s6_addr32[0];
00424         carry = (csum < daddr->s6_addr32[0]);
00425         csum += carry;
00426 
00427         csum += daddr->s6_addr32[1];
00428         carry = (csum < daddr->s6_addr32[1]);
00429         csum += carry;
00430 
00431         csum += daddr->s6_addr32[2];
00432         carry = (csum < daddr->s6_addr32[2]);
00433         csum += carry;
00434 
00435         csum += daddr->s6_addr32[3];
00436         carry = (csum < daddr->s6_addr32[3]);
00437         csum += carry;
00438 #endif
00439 
00440         /* Next, add in the hitMagic and subtract saddr+daddr */
00441         ret = ~csum_fold(csum_add(ret, hitMagic));
00442         ret = csum_fold(csum_sub(ret,~csum_fold(csum)));
00443 
00444         return ret;
00445 }
00446 #endif
00447 
00448 #ifdef __WIN32__
00449 static __inline unsigned short csum_hip_revert6(struct in6_addr *saddr1,
00450                                                    struct in6_addr *daddr1,
00451                                                    unsigned short sum,
00452                                                    unsigned short  hitMagic)
00453 {
00454         int carry;
00455         unsigned int csum;
00456         /* sum is assumed to be the folded complement, so get the sum back */
00457         unsigned short ret = ~sum;
00458 
00459         /* Re-cast the struct since Windows has no 32-bit struct member. */
00460         struct my_in6_addr *saddr = (struct my_in6_addr*)saddr1;
00461         struct my_in6_addr *daddr = (struct my_in6_addr*)daddr1;
00462         
00463         /* First, sum saddr and daddr as done in csum_ipv6_magic() */
00464         csum = saddr->s6_addr32[0];
00465         carry = (csum < saddr->s6_addr32[0]);
00466         csum += carry;
00467 
00468         csum += saddr->s6_addr32[1];
00469         carry = (csum < saddr->s6_addr32[1]);
00470         csum += carry;
00471 
00472         csum += saddr->s6_addr32[2];
00473         carry = (csum < saddr->s6_addr32[2]);
00474         csum += carry;
00475 
00476         csum += saddr->s6_addr32[3];
00477         carry = (csum < saddr->s6_addr32[3]);
00478         csum += carry;
00479 
00480         csum += daddr->s6_addr32[0];
00481         carry = (csum < daddr->s6_addr32[0]);
00482         csum += carry;
00483 
00484         csum += daddr->s6_addr32[1];
00485         carry = (csum < daddr->s6_addr32[1]);
00486         csum += carry;
00487 
00488         csum += daddr->s6_addr32[2];
00489         carry = (csum < daddr->s6_addr32[2]);
00490         csum += carry;
00491 
00492         csum += daddr->s6_addr32[3];
00493         carry = (csum < daddr->s6_addr32[3]);
00494         csum += carry;
00495 
00496         /* Next, subtract hitMagic and add saddr+daddr */
00497         ret = ~csum_fold(csum_sub(ret, hitMagic));
00498         ret = csum_fold(csum_add(ret,~csum_fold(csum)));
00499         return ret;
00500 }
00501 
00502 #else
00503 static inline unsigned short csum_hip_revert6(struct in6_addr *saddr,
00504                                                    struct in6_addr *daddr,
00505                                                    unsigned short sum,
00506                                                    unsigned short  hitMagic)
00507 {
00508         int carry;
00509         unsigned int csum;
00510         /* sum is assumed to be the folded complement, so get the sum back */
00511         unsigned short ret = ~sum;
00512         
00513         /* First, sum saddr and daddr as done in csum_ipv6_magic() */
00514 #ifdef __CYGWIN__
00515         csum = saddr->__u6_addr.__u6_addr32[0];
00516         carry = (csum < saddr->__u6_addr.__u6_addr32[0]);
00517         csum += carry;
00518 
00519         csum += saddr->__u6_addr.__u6_addr32[1];
00520         carry = (csum < saddr->__u6_addr.__u6_addr32[1]);
00521         csum += carry;
00522 
00523         csum += saddr->__u6_addr.__u6_addr32[2];
00524         carry = (csum < saddr->__u6_addr.__u6_addr32[2]);
00525         csum += carry;
00526 
00527         csum += saddr->__u6_addr.__u6_addr32[3];
00528         carry = (csum < saddr->__u6_addr.__u6_addr32[3]);
00529         csum += carry;
00530 
00531         csum += daddr->__u6_addr.__u6_addr32[0];
00532         carry = (csum < daddr->__u6_addr.__u6_addr32[0]);
00533         csum += carry;
00534 
00535         csum += daddr->__u6_addr.__u6_addr32[1];
00536         carry = (csum < daddr->__u6_addr.__u6_addr32[1]);
00537         csum += carry;
00538 
00539         csum += daddr->__u6_addr.__u6_addr32[2];
00540         carry = (csum < daddr->__u6_addr.__u6_addr32[2]);
00541         csum += carry;
00542 
00543         csum += daddr->__u6_addr.__u6_addr32[3];
00544         carry = (csum < daddr->__u6_addr.__u6_addr32[3]);
00545         csum += carry;
00546 #else
00547         csum = saddr->s6_addr32[0];
00548         carry = (csum < saddr->s6_addr32[0]);
00549         csum += carry;
00550 
00551         csum += saddr->s6_addr32[1];
00552         carry = (csum < saddr->s6_addr32[1]);
00553         csum += carry;
00554 
00555         csum += saddr->s6_addr32[2];
00556         carry = (csum < saddr->s6_addr32[2]);
00557         csum += carry;
00558 
00559         csum += saddr->s6_addr32[3];
00560         carry = (csum < saddr->s6_addr32[3]);
00561         csum += carry;
00562 
00563         csum += daddr->s6_addr32[0];
00564         carry = (csum < daddr->s6_addr32[0]);
00565         csum += carry;
00566 
00567         csum += daddr->s6_addr32[1];
00568         carry = (csum < daddr->s6_addr32[1]);
00569         csum += carry;
00570 
00571         csum += daddr->s6_addr32[2];
00572         carry = (csum < daddr->s6_addr32[2]);
00573         csum += carry;
00574 
00575         csum += daddr->s6_addr32[3];
00576         carry = (csum < daddr->s6_addr32[3]);
00577         csum += carry;
00578 #endif
00579 
00580         /* Next, subtract hitMagic and add saddr+daddr */
00581         ret = ~csum_fold(csum_sub(ret, hitMagic));
00582         ret = csum_fold(csum_add(ret,~csum_fold(csum)));
00583         return ret;
00584 }
00585 #endif
00586 
00587 #endif

Generated on Mon Oct 22 11:43:43 2007 for OpenHIP by  doxygen 1.5.1