| /* |
| * This file is part of the UCB release of Plan 9. It is subject to the license |
| * terms in the LICENSE file found in the top-level directory of this |
| * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No |
| * part of the UCB release of Plan 9, including this file, may be copied, |
| * modified, propagated, or distributed except according to the terms contained |
| * in the LICENSE file. |
| */ |
| #include <stdlib.h> |
| |
| #include <iplib/iplib.h> |
| #include <parlib/parlib.h> |
| #include <signal.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| |
| static short endian = 1; |
| static uint8_t *aendian = (uint8_t *)&endian; |
| #define LITTLE *aendian |
| |
| /* "Returns the one's complement checksum used in IP protocols." That's from |
| * Plan 9's man page. This is not a usable, as is - you want to call |
| * ip_calc_xsum(). */ |
| uint16_t ptclbsum(uint8_t *addr, int len) |
| { |
| uint32_t losum, hisum, mdsum, x; |
| uint32_t t1, t2; |
| |
| losum = 0; |
| hisum = 0; |
| mdsum = 0; |
| |
| x = 0; |
| if ((uintptr_t)addr & 1) { |
| if (len) { |
| hisum += addr[0]; |
| len--; |
| addr++; |
| } |
| x = 1; |
| } |
| while(len >= 16) { |
| t1 = *(uint16_t*)(addr + 0); |
| t2 = *(uint16_t*)(addr + 2); mdsum += t1; |
| t1 = *(uint16_t*)(addr + 4); mdsum += t2; |
| t2 = *(uint16_t*)(addr + 6); mdsum += t1; |
| t1 = *(uint16_t*)(addr + 8); mdsum += t2; |
| t2 = *(uint16_t*)(addr + 10); mdsum += t1; |
| t1 = *(uint16_t*)(addr + 12); mdsum += t2; |
| t2 = *(uint16_t*)(addr + 14); mdsum += t1; |
| mdsum += t2; |
| len -= 16; |
| addr += 16; |
| } |
| while (len >= 2) { |
| mdsum += *(uint16_t *)addr; |
| len -= 2; |
| addr += 2; |
| } |
| if (x) { |
| if (len) |
| losum += addr[0]; |
| if (LITTLE) |
| losum += mdsum; |
| else |
| hisum += mdsum; |
| } else { |
| if (len) |
| hisum += addr[0]; |
| if (LITTLE) |
| hisum += mdsum; |
| else |
| losum += mdsum; |
| } |
| |
| losum += hisum >> 8; |
| losum += (hisum & 0xff) << 8; |
| while (hisum = losum >> 16) |
| losum = hisum + (losum & 0xffff); |
| |
| return losum & 0xffff; |
| } |
| |
| /* Calculates an IP checksum for [addr, addr + len), returning the xsum in host |
| * endian. */ |
| uint16_t ip_calc_xsum(uint8_t *addr, size_t len) |
| { |
| return ~ptclbsum(addr, len) & 0xffff; |
| } |