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.
6 * IP/TCP/UDP checksumming routines
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
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.
20 #include <net/checksum.h>
22 #undef PROFILE_CHECKSUM
24 #ifdef PROFILE_CHECKSUM
25 /* these are just for profiling the checksum code with an oscillioscope.. uh */
27 #define BITOFF *((unsigned char *)0xb0000030) = 0xff
28 #define BITON *((unsigned char *)0xb0000030) = 0x0
31 #define CBITON LED_ACTIVE_SET(1)
32 #define CBITOFF LED_ACTIVE_SET(0)
43 * computes a partial checksum, e.g. for TCP/UDP fragments
46 #include <asm/delay.h>
48 unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
51 * Experiments with ethernet and slip connections show that buff
52 * is aligned on either a 2-byte or 4-byte boundary.
54 const unsigned char *endMarker = buff + len;
55 const unsigned char *marker = endMarker - (len % 16);
58 printk("unaligned buff %p\n", buff);
59 __delay(900); /* extra delay of 90 us to test performance hit */
62 while (buff < marker) {
63 sum += *((unsigned short *)buff)++;
64 sum += *((unsigned short *)buff)++;
65 sum += *((unsigned short *)buff)++;
66 sum += *((unsigned short *)buff)++;
67 sum += *((unsigned short *)buff)++;
68 sum += *((unsigned short *)buff)++;
69 sum += *((unsigned short *)buff)++;
70 sum += *((unsigned short *)buff)++;
72 marker = endMarker - (len % 2);
73 while(buff < marker) {
74 sum += *((unsigned short *)buff)++;
76 if(endMarker - buff > 0) {
77 sum += *buff; /* add extra byte seperately */
86 * copy while checksumming, otherwise like csum_partial
89 unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
90 int len, unsigned int sum)
92 const unsigned char *endMarker;
93 const unsigned char *marker;
94 printk("csum_partial_copy len %d.\n", len);
97 printk("unaligned src %p\n", src);
99 printk("unaligned dst %p\n", dst);
100 __delay(1800); /* extra delay of 90 us to test performance hit */
102 endMarker = src + len;
103 marker = endMarker - (len % 16);
105 while(src < marker) {
106 sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
107 sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
108 sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
109 sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
110 sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
111 sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
112 sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
113 sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
115 marker = endMarker - (len % 2);
116 while(src < marker) {
117 sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
119 if(endMarker - src > 0) {
120 sum += (*dst = *src); /* add extra byte seperately */