converted to git
[tridge/junkcode.git] / csum.c
1 #define __KERNEL__
2
3 #include <linux/config.h>
4 #include <asm/segment.h>
5 #include <asm/system.h>
6 #include <linux/types.h>
7 #include <linux/kernel.h>
8 #include <linux/sched.h>
9 #include <linux/string.h>
10 #include <linux/errno.h>
11 #include <linux/config.h>
12
13 #include <linux/socket.h>
14 #include <linux/sockios.h>
15 #include <linux/in.h>
16 #include <linux/inet.h>
17 #include <linux/netdevice.h>
18 #include <linux/icmp.h>
19 #include <linux/udp.h>
20 #include <net/ip.h>
21 #include <net/protocol.h>
22 #include <net/route.h>
23 #include <net/tcp.h>
24 #include <net/udp.h>
25 #include <linux/skbuff.h>
26 #include <net/sock.h>
27 #include <net/icmp.h>
28 #include <linux/firewall.h>
29 #include <linux/ip_fw.h>
30 #include <net/checksum.h>
31 #include <linux/proc_fs.h>
32 #include <linux/stat.h>
33 #include <net/checksum.h>
34
35 /*
36  * computes a partial checksum, e.g. for TCP/UDP fragments
37  */
38
39 unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) {
40           /*
41            * Experiments with ethernet and slip connections show that buff
42            * is aligned on either a 2-byte or 4-byte boundary.  We get at
43            * least a 2x speedup on 486 and Pentium if it is 4-byte aligned.
44            * Fortunately, it is easy to convert 2-byte alignment to 4-byte
45            * alignment for the unrolled loop.
46            */
47         __asm__("
48             testl $2, %%esi             # Check alignment.
49             jz 2f                       # Jump if alignment is ok.
50             subl $2, %%ecx              # Alignment uses up two bytes.
51             jae 1f                      # Jump if we had at least two bytes.
52             addl $2, %%ecx              # ecx was < 2.  Deal with it.
53             jmp 4f
54 1:          movw (%%esi), %%bx
55             addl $2, %%esi
56             addw %%bx, %%ax
57             adcl $0, %%eax
58 2:
59             movl %%ecx, %%edx
60             shrl $5, %%ecx
61             jz 2f
62             testl %%esi, %%esi
63 1:          movl (%%esi), %%ebx
64             adcl %%ebx, %%eax
65             movl 4(%%esi), %%ebx
66             adcl %%ebx, %%eax
67             movl 8(%%esi), %%ebx
68             adcl %%ebx, %%eax
69             movl 12(%%esi), %%ebx
70             adcl %%ebx, %%eax
71             movl 16(%%esi), %%ebx
72             adcl %%ebx, %%eax
73             movl 20(%%esi), %%ebx
74             adcl %%ebx, %%eax
75             movl 24(%%esi), %%ebx
76             adcl %%ebx, %%eax
77             movl 28(%%esi), %%ebx
78             adcl %%ebx, %%eax
79             lea 32(%%esi), %%esi
80             dec %%ecx
81             jne 1b
82             adcl $0, %%eax
83 2:          movl %%edx, %%ecx
84             andl $0x1c, %%edx
85             je 4f
86             shrl $2, %%edx
87             testl %%esi, %%esi
88 3:          adcl (%%esi), %%eax
89             lea 4(%%esi), %%esi
90             dec %%edx
91             jne 3b
92             adcl $0, %%eax
93 4:          andl $3, %%ecx
94             jz 7f
95             cmpl $2, %%ecx
96             jb 5f
97             movw (%%esi),%%cx
98             leal 2(%%esi),%%esi
99             je 6f
100             shll $16,%%ecx
101 5:          movb (%%esi),%%cl
102 6:          addl %%ecx,%%eax
103             adcl $0, %%eax
104 7:          "
105         : "=a"(sum)
106         : "0"(sum), "c"(len), "S"(buff)
107         : "bx", "cx", "dx", "si");
108         return(sum);
109 }
110
111 /* 32 bits version of the checksum routines written for the Alpha by Linus */
112 static unsigned short from32to16(unsigned long x)
113 {
114         /* add up 16-bit and 17-bit words for 17+c bits */
115         x = (x & 0xffff) + (x >> 16);
116         /* add up 16-bit and 2-bit for 16+c bit */
117         x = (x & 0xffff) + (x >> 16);
118         /* add up carry.. */
119         x = (x & 0xffff) + (x >> 16);
120         return x;
121 }
122
123
124 main(int argc,char *argv[])
125 {
126   unsigned long sum1,sum2,sum3,sum4,sum5;
127   int i;
128   __u32 saddr=0x32456787,daddr=0x89764512;
129   int len=512,proto=7;
130   char data1[512];
131   int seed = time(0);
132
133   if (argc > 1) seed = atoi(argv[1]);
134
135   while (1) {
136     srandom(seed);
137     for (i=0; i<512 ; i++) {
138       data1[i] = random();
139     }
140
141   sum1 = csum_tcpudp_magic(saddr,daddr,len,proto,csum_partial(data1,512,0));
142
143   sum2 = csum_tcpudp_magic(saddr,daddr,len,proto,csum_partial(data1,256,0));
144   
145   data1[4]++;
146   daddr ^= 0x765432FE;
147
148   sum3 = csum_tcpudp_magic(saddr,daddr,len,proto,csum_partial(data1,256,0));
149   
150   sum4 = ~sum3 + (~sum1 - ~sum2);
151   if (!(sum4>>16)) sum4++;
152   sum4 = 0xFFFF & (~from32to16(sum4));
153
154   sum5 = csum_tcpudp_magic(saddr,daddr,len,proto,csum_partial(data1,512,0));
155
156   if (sum4 != sum5) {
157     printf("Failed with seed=%d\n",seed);
158     exit(1);
159   }
160   seed++;
161   if (!(seed & 0xFFF))
162     printf("seed=0x%X\n",seed);
163   }
164
165   printf("%X %X\n",~sum3,~sum3 + (~sum1 - ~sum2));
166   printf("sum1=%X\n",(unsigned int)sum1 & 0xFFFF);
167   printf("sum2=%X\n",(unsigned int)sum2 & 0xFFFF);
168   printf("sum3=%X\n",(unsigned int)sum3 & 0xFFFF);
169   printf("sum4=%X\n",(unsigned int)sum4 & 0xFFFF);
170   printf("sum5=%X\n",(unsigned int)sum5 & 0xFFFF);
171 }