/home/tomh/openhip/hip-0.5/src/include/mac/checksum_mac.h

Go to the documentation of this file.
00001 #include <sys/types.h>
00002 #include <netinet/in.h>
00003 
00004 #ifdef __BIG_ENDIAN__
00005 static inline unsigned short csum_tcpudp_hip_nofold(unsigned long,
00006                                                    unsigned long,
00007                                                    unsigned short,
00008                                                    unsigned short);
00009 
00010 static inline unsigned int csum_fold(unsigned int sum)
00011 {
00012         unsigned int tmp;
00013 
00014         /* swap the two 16-bit halves of sum */
00015         __asm__("rlwinm %0,%1,16,0,31" : "=r" (tmp) : "r" (sum));
00016         /* if there is a carry from adding the two 16-bit halves,
00017            it will carry from the lower half into the upper half,
00018            giving us the correct sum in the upper half. */
00019         sum = ~(sum + tmp) >> 16;
00020         return sum;
00021 }
00022 
00023 static inline unsigned int csum_add(unsigned int csum, unsigned int addend)
00024 {
00025         csum += addend;
00026         return csum + (csum < addend);
00027 }
00028 
00029 static inline unsigned int csum_sub(unsigned int csum, unsigned int addend)
00030 {
00031         return csum_add(csum, ~addend);
00032 }
00033 
00034 ushort checksum16(unsigned char* data, int len)
00035 {
00036     uint sum = 0;
00037     if ((len & 1) == 0)
00038         len = len >> 1;
00039     else
00040         len = (len >> 1) + 1;
00041     while (len > 0) {
00042         sum += *((ushort*)data);
00043         data += sizeof(ushort);
00044         len--;
00045     }
00046     sum = (sum >> 16) + (sum & 0xffff);
00047     sum += (sum >> 16);
00048     return(~sum);
00049 }
00050 
00051 
00052 
00053 static inline unsigned short csum_tcpudp_hip_nofold(unsigned long saddr,
00054                                                    unsigned long daddr,
00055                                                    unsigned short sum,
00056                                                    unsigned short  hitMagic)
00057 {
00058         /* sum is assumed to be the folded complement, so get the sum back */
00059         unsigned short ret = ~sum;
00060 
00061         ret = ~csum_fold(csum_add(ret, hitMagic));
00062         ret = csum_fold(csum_sub(ret,~csum_fold(csum_add(saddr,daddr))));
00063 
00064         return ret;
00065 }
00066 
00067 static inline unsigned short ip_fast_csum(unsigned char * iph,
00068                                           unsigned int ihl)
00069 {
00070 return checksum16(iph,ihl);
00071 }
00072 
00073 
00074 static inline unsigned short csum_hip_revert(unsigned long saddr,
00075                                                    unsigned long daddr,
00076                                                    unsigned short sum,
00077                                                    unsigned short  hitMagic)
00078 {
00079         /* sum is assumed to be the folded complement, so get the sum back */
00080         unsigned short ret = ~sum;
00081 
00082         ret = ~csum_fold(csum_sub(ret, hitMagic));
00083         ret = csum_fold(csum_add(ret,~csum_fold(csum_add(saddr,daddr))));
00084         return ret;
00085 }
00086 #ifdef XXX_OBSOLETE?
00087 /*
00088  * computes the checksum of the TCP/UDP pseudo-header
00089  * returns a 16-bit checksum, already complemented
00090  */
00091 static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
00092                                                    unsigned long daddr,
00093                                                    unsigned short len,
00094                                                    unsigned short proto,
00095                                                    unsigned int sum)
00096 {
00097         return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
00098 }
00099 #endif
00100 #elif defined(__LITTLE_ENDIAN__)
00101 /*
00102  * This file contains a combination of:
00103  * linux/include/asm-i386/checksum.h and
00104  * linux/include/net/checksum.h from the Linux 2.6.8.1 kernel,
00105  * plus HIP checksum modifications.
00106  * 
00107  */
00108 
00109 /*
00110  * INET         An implementation of the TCP/IP protocol suite for the LINUX
00111  *              operating system.  INET is implemented using the  BSD Socket
00112  *              interface as the means of communication with the user level.
00113  *
00114  *              Checksumming functions for IP, TCP, UDP and so on
00115  *
00116  * Authors:     Jorge Cwik, <jorge@laser.satlink.net>
00117  *              Arnt Gulbrandsen, <agulbra@nvg.unit.no>
00118  *              Borrows very liberally from tcp.c and ip.c, see those
00119  *              files for more names.
00120  *
00121  *              This program is free software; you can redistribute it and/or
00122  *              modify it under the terms of the GNU General Public License
00123  *              as published by the Free Software Foundation; either version
00124  *              2 of the License, or (at your option) any later version.
00125  */
00126 
00127 #ifndef _CHECKSUM_H
00128 #define _CHECKSUM_H
00129 
00130 /*
00131  * the following inlines are from linux/include/asm-i386/checksum.h
00132  */
00133 
00134 /*
00135  *      This is a version of ip_compute_csum() optimized for IP headers,
00136  *      which always checksum on 4 octet boundaries.
00137  *
00138  *      By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
00139  *      Arnt Gulbrandsen.
00140  */
00141 
00142 static inline unsigned short ip_fast_csum(unsigned char * iph,
00143                                           unsigned int ihl)
00144 {
00145         unsigned int sum;
00146 
00147         __asm__ __volatile__(
00148             "movl (%1), %0      ;\n"
00149             "subl $4, %2        ;\n"
00150             "jbe 2f             ;\n"
00151             "addl 4(%1), %0     ;\n"
00152             "adcl 8(%1), %0     ;\n"
00153             "adcl 12(%1), %0    ;\n"
00154 "1:         adcl 16(%1), %0     ;\n"
00155             "lea 4(%1), %1      ;\n"
00156             "decl %2            ;\n"
00157             "jne 1b             ;\n"
00158             "adcl $0, %0        ;\n"
00159             "movl %0, %2        ;\n"
00160             "shrl $16, %0       ;\n"
00161             "addw %w2, %w0      ;\n"
00162             "adcl $0, %0        ;\n"
00163             "notl %0            ;\n"
00164 "2:                             ;\n"
00165         /* Since the input registers which are loaded with iph and ipl
00166            are modified, we must also specify them as outputs, or gcc
00167            will assume they contain their original values. */
00168         : "=r" (sum), "=r" (iph), "=r" (ihl)
00169         : "1" (iph), "2" (ihl)
00170         : "memory");
00171         return(sum);
00172 }
00173 
00174 /*
00175  *      Fold a partial checksum
00176  */
00177 
00178 static inline unsigned int csum_fold(unsigned int sum)
00179 {
00180         __asm__(
00181                 "addl %1, %0            ;\n"
00182                 "adcl $0xffff, %0       ;\n"
00183                 : "=r" (sum)
00184                 : "r" (sum << 16), "0" (sum & 0xffff0000)
00185         );
00186         return (~sum) >> 16;
00187 }
00188 
00189 static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
00190                                                    unsigned long daddr,
00191                                                    unsigned short len,
00192                                                    unsigned short proto,
00193                                                    unsigned int sum)
00194 {
00195     __asm__(
00196         "addl %1, %0    ;\n"
00197         "adcl %2, %0    ;\n"
00198         "adcl %3, %0    ;\n"
00199         "adcl $0, %0    ;\n"
00200         : "=r" (sum)
00201         : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
00202     return sum;
00203 }
00204 
00205 /*
00206  * computes the checksum of the TCP/UDP pseudo-header
00207  * returns a 16-bit checksum, already complemented
00208  */
00209 static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
00210                                                    unsigned long daddr,
00211                                                    unsigned short len,
00212                                                    unsigned short proto,
00213                                                    unsigned int sum)
00214 {
00215         return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
00216 }
00217 
00218 #define _HAVE_ARCH_IPV6_CSUM
00219 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
00220                                                      struct in6_addr *daddr,
00221                                                      __u32 len,
00222                                                      unsigned short proto,
00223                                                      unsigned int sum)
00224 {
00225         __asm__(
00226                 "addl 0(%1), %0         ;\n"
00227                 "adcl 4(%1), %0         ;\n"
00228                 "adcl 8(%1), %0         ;\n"
00229                 "adcl 12(%1), %0        ;\n"
00230                 "adcl 0(%2), %0         ;\n"
00231                 "adcl 4(%2), %0         ;\n"
00232                 "adcl 8(%2), %0         ;\n"
00233                 "adcl 12(%2), %0        ;\n"
00234                 "adcl %3, %0            ;\n"
00235                 "adcl %4, %0            ;\n"
00236                 "adcl $0, %0            ;\n"
00237                 : "=&r" (sum)
00238                 : "r" (saddr), "r" (daddr),
00239                   "r"(htonl(len)), "r"(htonl(proto)), "0"(sum));
00240 
00241         return csum_fold(sum);
00242 }
00243 #endif
00244 
00245 /*
00246  * the following inlines are from linux/include/net/checksum.h
00247  */
00248 
00249 static inline unsigned int csum_add(unsigned int csum, unsigned int addend)
00250 {
00251         csum += addend;
00252         return csum + (csum < addend);
00253 }
00254 
00255 static inline unsigned int csum_sub(unsigned int csum, unsigned int addend)
00256 {
00257         return csum_add(csum, ~addend);
00258 }
00259 
00260 /* 
00261  * HIP checksum = tcp checksum + hitMagic - csum(saddr,daddr)
00262  */
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 {
00268         /* sum is assumed to be the folded complement, so get the sum back */
00269         unsigned short ret = ~sum;
00270 
00271         ret = ~csum_fold(csum_add(ret, hitMagic));
00272         ret = csum_fold(csum_sub(ret,~csum_fold(csum_add(saddr,daddr))));
00273 
00274         return ret;
00275 }
00276 
00277 static inline unsigned short csum_hip_revert(unsigned long saddr,
00278                                                    unsigned long daddr,
00279                                                    unsigned short sum,
00280                                                    unsigned short  hitMagic)
00281 {
00282         /* sum is assumed to be the folded complement, so get the sum back */
00283         unsigned short ret = ~sum;
00284 
00285         ret = ~csum_fold(csum_sub(ret, hitMagic));
00286         ret = csum_fold(csum_add(ret,~csum_fold(csum_add(saddr,daddr))));
00287         return ret;
00288 }
00289 
00290 /* 
00291  * HIP checksum = tcp checksum + hitMagic - csum(saddr,daddr)
00292  */
00293 static inline unsigned short csum_tcpudp_hip_nofold6(struct in6_addr *saddr,
00294                                                      struct in6_addr *daddr,
00295                                                      unsigned short sum,
00296                                                      unsigned short  hitMagic)
00297 {
00298         int carry;
00299         unsigned int csum;
00300         /* sum is assumed to be the folded complement, so get the sum back */
00301         unsigned short ret = ~sum;
00302         
00303         /* First, sum saddr and daddr as done in csum_ipv6_magic() */
00304 
00305         csum = saddr->__u6_addr.__u6_addr32[0];
00306         carry = (csum < saddr->__u6_addr.__u6_addr32[0]);
00307         csum += carry;
00308 
00309         csum += saddr->__u6_addr.__u6_addr32[1];
00310         carry = (csum < saddr->__u6_addr.__u6_addr32[1]);
00311         csum += carry;
00312 
00313         csum += saddr->__u6_addr.__u6_addr32[2];
00314         carry = (csum < saddr->__u6_addr.__u6_addr32[2]);
00315         csum += carry;
00316 
00317         csum += saddr->__u6_addr.__u6_addr32[3];
00318         carry = (csum < saddr->__u6_addr.__u6_addr32[3]);
00319         csum += carry;
00320 
00321         csum += daddr->__u6_addr.__u6_addr32[0];
00322         carry = (csum < daddr->__u6_addr.__u6_addr32[0]);
00323         csum += carry;
00324 
00325         csum += daddr->__u6_addr.__u6_addr32[1];
00326         carry = (csum < daddr->__u6_addr.__u6_addr32[1]);
00327         csum += carry;
00328 
00329         csum += daddr->__u6_addr.__u6_addr32[2];
00330         carry = (csum < daddr->__u6_addr.__u6_addr32[2]);
00331         csum += carry;
00332 
00333         csum += daddr->__u6_addr.__u6_addr32[3];
00334         carry = (csum < daddr->__u6_addr.__u6_addr32[3]);
00335         csum += carry;
00336 
00337         /* Next, add in the hitMagic and subtract saddr+daddr */
00338         ret = ~csum_fold(csum_add(ret, hitMagic));
00339         ret = csum_fold(csum_sub(ret,~csum_fold(csum)));
00340 
00341         return ret;
00342 }
00343 
00344 static inline unsigned short csum_hip_revert6(struct in6_addr *saddr,
00345                                                    struct in6_addr *daddr,
00346                                                    unsigned short sum,
00347                                                    unsigned short  hitMagic)
00348 {
00349         int carry;
00350         unsigned int csum;
00351         /* sum is assumed to be the folded complement, so get the sum back */
00352         unsigned short ret = ~sum;
00353         
00354         /* First, sum saddr and daddr as done in csum_ipv6_magic() */
00355         csum = saddr->__u6_addr.__u6_addr32[0];
00356         carry = (csum < saddr->__u6_addr.__u6_addr32[0]);
00357         csum += carry;
00358 
00359         csum += saddr->__u6_addr.__u6_addr32[1];
00360         carry = (csum < saddr->__u6_addr.__u6_addr32[1]);
00361         csum += carry;
00362 
00363         csum += saddr->__u6_addr.__u6_addr32[2];
00364         carry = (csum < saddr->__u6_addr.__u6_addr32[2]);
00365         csum += carry;
00366 
00367         csum += saddr->__u6_addr.__u6_addr32[3];
00368         carry = (csum < saddr->__u6_addr.__u6_addr32[3]);
00369         csum += carry;
00370 
00371         csum += daddr->__u6_addr.__u6_addr32[0];
00372         carry = (csum < daddr->__u6_addr.__u6_addr32[0]);
00373         csum += carry;
00374 
00375         csum += daddr->__u6_addr.__u6_addr32[1];
00376         carry = (csum < daddr->__u6_addr.__u6_addr32[1]);
00377         csum += carry;
00378 
00379         csum += daddr->__u6_addr.__u6_addr32[2];
00380         carry = (csum < daddr->__u6_addr.__u6_addr32[2]);
00381         csum += carry;
00382 
00383         csum += daddr->__u6_addr.__u6_addr32[3];
00384         carry = (csum < daddr->__u6_addr.__u6_addr32[3]);
00385         csum += carry;
00386 
00387         /* Next, subtract hitMagic and add saddr+daddr */
00388         ret = ~csum_fold(csum_sub(ret, hitMagic));
00389         ret = csum_fold(csum_add(ret,~csum_fold(csum)));
00390         return ret;
00391 }
00392 #endif

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