Jesper Nilsson | 5712e4d | 2008-01-21 11:11:25 +0100 | [diff] [blame] | 1 | /* |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Al Viro | 3532010 | 2006-11-14 21:15:19 -0800 | [diff] [blame] | 49 | __wsum csum_partial(const void *p, int len, __wsum __sum) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 50 | { |
Al Viro | 3532010 | 2006-11-14 21:15:19 -0800 | [diff] [blame] | 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); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 59 | #if 0 |
Al Viro | 3532010 | 2006-11-14 21:15:19 -0800 | [diff] [blame] | 60 | if((int)buff & 0x3) |
| 61 | printk("unaligned buff %p\n", buff); |
| 62 | __delay(900); /* extra delay of 90 us to test performance hit */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 | #endif |
Al Viro | 3532010 | 2006-11-14 21:15:19 -0800 | [diff] [blame] | 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 seperately */ |
| 81 | |
| 82 | BITOFF; |
| 83 | return (__force __wsum)sum; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | EXPORT_SYMBOL(csum_partial); |