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