Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | /* * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket * interface as the means of communication with the user level. * * Checksumming functions for IP, TCP, UDP and so on * * Authors: Jorge Cwik, <jorge@laser.satlink.net> * Arnt Gulbrandsen, <agulbra@nvg.unit.no> * Borrows very liberally from tcp.c and ip.c, see those * files for more names. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ /* * Fixes: * * Ralf Baechle : generic ipv6 checksum * <ralf@waldorf-gmbh.de> */ #ifndef _CHECKSUM_H #define _CHECKSUM_H #include <asm/types.h> #include <asm/byteorder.h> #include <net/ip.h> #include <linux/in6.h> #include <asm/uaccess.h> #include <asm/checksum.h> #ifndef _HAVE_ARCH_IPV6_CSUM static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr, __u16 len, unsigned short proto, unsigned int csum) { int carry; __u32 ulen; __u32 uproto; csum += saddr->s6_addr32[0]; carry = (csum < saddr->s6_addr32[0]); csum += carry; csum += saddr->s6_addr32[1]; carry = (csum < saddr->s6_addr32[1]); csum += carry; csum += saddr->s6_addr32[2]; carry = (csum < saddr->s6_addr32[2]); csum += carry; csum += saddr->s6_addr32[3]; carry = (csum < saddr->s6_addr32[3]); csum += carry; csum += daddr->s6_addr32[0]; carry = (csum < daddr->s6_addr32[0]); csum += carry; csum += daddr->s6_addr32[1]; carry = (csum < daddr->s6_addr32[1]); csum += carry; csum += daddr->s6_addr32[2]; carry = (csum < daddr->s6_addr32[2]); csum += carry; csum += daddr->s6_addr32[3]; carry = (csum < daddr->s6_addr32[3]); csum += carry; ulen = htonl((__u32) len); csum += ulen; carry = (csum < ulen); csum += carry; uproto = htonl(proto); csum += uproto; carry = (csum < uproto); csum += carry; return csum_fold(csum); } #endif #ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER static inline unsigned int csum_and_copy_from_user (const char *src, char *dst, int len, int sum, int *err_ptr) { if (verify_area(VERIFY_READ, src, len) == 0) return csum_partial_copy_from_user(src, dst, len, sum, err_ptr); if (len) *err_ptr = -EFAULT; return sum; } #endif #ifndef HAVE_CSUM_COPY_USER static __inline__ unsigned int csum_and_copy_to_user (const char *src, char *dst, int len, unsigned int sum, int *err_ptr) { sum = csum_partial(src, len, sum); if (access_ok(VERIFY_WRITE, dst, len)) { if (copy_to_user(dst, src, len) == 0) return sum; } if (len) *err_ptr = -EFAULT; return -1; /* invalid checksum */ } #endif static inline unsigned int csum_add(unsigned int csum, unsigned int addend) { csum += addend; return csum + (csum < addend); } static inline unsigned int csum_sub(unsigned int csum, unsigned int addend) { return csum_add(csum, ~addend); } static inline unsigned int csum_block_add(unsigned int csum, unsigned int csum2, int offset) { if (offset&1) csum2 = ((csum2&0xFF00FF)<<8)+((csum2>>8)&0xFF00FF); return csum_add(csum, csum2); } static inline unsigned int csum_block_sub(unsigned int csum, unsigned int csum2, int offset) { if (offset&1) csum2 = ((csum2&0xFF00FF)<<8)+((csum2>>8)&0xFF00FF); return csum_sub(csum, csum2); } #endif |