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