1 /* 2 * Copyright (c) 1985, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ns_cksum.c 7.6 (Berkeley) 12/16/90 8 */ 9 10 #include "sys/param.h" 11 #include "sys/mbuf.h" 12 13 14 /* 15 * Checksum routine for Network Systems Protocol Packets (VAX Version). 16 * 17 * This routine is very heavily used in the network 18 * code and should be modified for each CPU to be as fast as possible. 19 */ 20 21 u_short 22 ns_cksum(m, len) 23 register struct mbuf *m; 24 register int len; 25 { 26 register u_short *w; /* on vax, known to be r9 */ 27 register int sum = 0; /* on vax, known to be r8 */ 28 register int low = 0; /* on vax, known to be r7 */ 29 register int mlen = low; /* want 0, shuts lint up about low */ 30 31 for (;;) { 32 /* 33 * Each trip around loop adds in 34 * word from one mbuf segment. 35 */ 36 w = mtod(m, u_short *); 37 if (mlen == -1) { 38 /* 39 * There is a byte left from the last segment; 40 * add it into the checksum. Don't have to worry 41 * about a carry-out here because we make sure 42 * that high part of (32 bit) sum is small below. 43 */ 44 sum += *(u_char *)w << 8; 45 sum += sum; 46 w = (u_short *)((char *)w + 1); 47 mlen = m->m_len - 1; 48 len--; 49 } else 50 mlen = m->m_len; 51 m = m->m_next; 52 if (len < mlen) 53 mlen = len; 54 len -= mlen; 55 /* 56 * Force to long boundary so we do longword aligned 57 * memory operations. It is too hard to do byte 58 * adjustment, do only word adjustment. 59 */ 60 if (((int)w&0x2) && mlen >= 2) { 61 sum += *w++; 62 sum += sum; 63 mlen -= 2; 64 } 65 /* 66 * 67 * We can do a 16 bit ones complement sum using 68 * 32 bit arithmetic registers for adding, 69 * with carries from the low added 70 * into the high (by normal carry-chaining) 71 * so long as we fold back before 16 carries have occured. 72 * 73 */ 74 while ((mlen -= 32) >= 0) { 75 /*asm("bicpsw $1"); clears carry */ 76 #undef ADD 77 #define ADD asm("movw (r9)+,r7")asm("addl2 r7,r8")asm("addl2 r8,r8") 78 #define FOLD { asm("ashl $-16,r8,r0")asm(" addw2 r0,r8"); \ 79 asm("adwc $0,r8")asm(" movzwl r8,r8"); } 80 FOLD; 81 ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD; 82 FOLD; 83 ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD; 84 } 85 mlen += 32; 86 while ((mlen -= 8) >= 0) { 87 /*asm("bicpsw $1"); clears carry */ 88 FOLD; 89 ADD; ADD; ADD; ADD; 90 } 91 mlen += 8; 92 /* 93 * Now eliminate the possibility of carry-out's by 94 * folding back to a 16 bit number (adding high and 95 * low parts together.) Then mop up trailing words 96 * and maybe an odd byte. 97 */ 98 FOLD; 99 while ((mlen -= 2) >= 0) { 100 ADD; 101 } 102 if (mlen == -1) { 103 sum += *(u_char *)w; 104 } 105 if (len == 0) 106 break; 107 /* 108 * Locate the next block with some data. 109 * If there is a word split across a boundary we 110 * will wrap to the top with mlen == -1 and 111 * then add it in shifted appropriately. 112 */ 113 for (;;) { 114 if (m == 0) { 115 printf("idpcksum: out of data\n"); 116 goto done; 117 } 118 if (m->m_len) 119 break; 120 m = m->m_next; 121 } 122 } 123 done: 124 /* 125 * Add together high and low parts of sum 126 * and carry to get cksum. 127 * Have to be careful to not drop the last 128 * carry here. 129 */ 130 FOLD; 131 132 if(sum==0xffff) sum = 0; 133 return (sum); 134 } 135