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#if 0 28#define BITOFF *((unsigned char *)0xb0000030) = 0xff 29#define BITON *((unsigned char *)0xb0000030) = 0x0 30#endif 31#include <asm/io.h> 32#define CBITON LED_ACTIVE_SET(1) 33#define CBITOFF LED_ACTIVE_SET(0) 34#define BITOFF 35#define BITON 36#else 37#define BITOFF 38#define BITON 39#define CBITOFF 40#define CBITON 41#endif 42 43/* 44 * computes a partial checksum, e.g. for TCP/UDP fragments 45 */ 46 47#include <asm/delay.h> 48 49__wsum csum_partial(const void *p, int len, __wsum __sum) 50{ 51 u32 sum = (__force u32)__sum; 52 const u16 *buff = p; 53 /* 54 * Experiments with ethernet and slip connections show that buff 55 * is aligned on either a 2-byte or 4-byte boundary. 56 */ 57 const void *endMarker = p + len; 58 const void *marker = endMarker - (len % 16); 59#if 0 60 if((int)buff & 0x3) 61 printk("unaligned buff %p\n", buff); 62 __delay(900); /* extra delay of 90 us to test performance hit */ 63#endif 64 BITON; 65 while (buff < marker) { 66 sum += *buff++; 67 sum += *buff++; 68 sum += *buff++; 69 sum += *buff++; 70 sum += *buff++; 71 sum += *buff++; 72 sum += *buff++; 73 sum += *buff++; 74 } 75 marker = endMarker - (len % 2); 76 while (buff < marker) 77 sum += *buff++; 78 79 if (endMarker > buff) 80 sum += *(const u8 *)buff; /* add extra byte separately */ 81 82 BITOFF; 83 return (__force __wsum)sum; 84} 85 86EXPORT_SYMBOL(csum_partial); 87