1/* 2 * INET An implementation of the TCP/IP protocol suite for the LINUX 3 * operating system. INET is implemented using the BSD Socket 4 * interface as the means of communication with the user level. 5 * 6 * IP/TCP/UDP checksumming routines 7 * 8 * Authors: Jorge Cwik, <jorge@laser.satlink.net> 9 * Arnt Gulbrandsen, <agulbra@nvg.unit.no> 10 * Tom May, <ftom@netcom.com> 11 * Lots of code moved from tcp.c and ip.c; see those files 12 * for more names. 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License 16 * as published by the Free Software Foundation; either version 17 * 2 of the License, or (at your option) any later version. 18 */ 19 20#include <net/checksum.h> 21#include <net/module.h> 22 23#undef PROFILE_CHECKSUM 24 25#ifdef PROFILE_CHECKSUM 26/* these are just for profiling the checksum code with an oscillioscope.. uh */ 27#include <asm/io.h> 28#define CBITON LED_ACTIVE_SET(1) 29#define CBITOFF LED_ACTIVE_SET(0) 30#define BITOFF 31#define BITON 32#else 33#define BITOFF 34#define BITON 35#define CBITOFF 36#define CBITON 37#endif 38 39/* 40 * computes a partial checksum, e.g. for TCP/UDP fragments 41 */ 42 43#include <asm/delay.h> 44 45__wsum csum_partial(const void *p, int len, __wsum __sum) 46{ 47 u32 sum = (__force u32)__sum; 48 const u16 *buff = p; 49 /* 50 * Experiments with ethernet and slip connections show that buff 51 * is aligned on either a 2-byte or 4-byte boundary. 52 */ 53 const void *endMarker = p + len; 54 const void *marker = endMarker - (len % 16); 55 BITON; 56 while (buff < marker) { 57 sum += *buff++; 58 sum += *buff++; 59 sum += *buff++; 60 sum += *buff++; 61 sum += *buff++; 62 sum += *buff++; 63 sum += *buff++; 64 sum += *buff++; 65 } 66 marker = endMarker - (len % 2); 67 while (buff < marker) 68 sum += *buff++; 69 70 if (endMarker > buff) 71 sum += *(const u8 *)buff; /* add extra byte separately */ 72 73 BITOFF; 74 return (__force __wsum)sum; 75} 76 77EXPORT_SYMBOL(csum_partial); 78