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
00015 __asm__("rlwinm %0,%1,16,0,31" : "=r" (tmp) : "r" (sum));
00016
00017
00018
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
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
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
00089
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
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 #ifndef _CHECKSUM_H
00128 #define _CHECKSUM_H
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
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
00166
00167
00168 : "=r" (sum), "=r" (iph), "=r" (ihl)
00169 : "1" (iph), "2" (ihl)
00170 : "memory");
00171 return(sum);
00172 }
00173
00174
00175
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
00207
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
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
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
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
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
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
00301 unsigned short ret = ~sum;
00302
00303
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
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
00352 unsigned short ret = ~sum;
00353
00354
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
00388 ret = ~csum_fold(csum_sub(ret, hitMagic));
00389 ret = csum_fold(csum_add(ret,~csum_fold(csum)));
00390 return ret;
00391 }
00392 #endif