|  | /* | 
|  | * 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; | 
|  | } |