akaros/user/iplib/ptclbsum.c
<<
>>
Prefs
   1/*
   2 * This file is part of the UCB release of Plan 9. It is subject to the license
   3 * terms in the LICENSE file found in the top-level directory of this
   4 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
   5 * part of the UCB release of Plan 9, including this file, may be copied,
   6 * modified, propagated, or distributed except according to the terms contained
   7 * in the LICENSE file.
   8 */
   9#include <stdlib.h>
  10
  11#include <iplib/iplib.h>
  12#include <parlib/parlib.h>
  13#include <signal.h>
  14#include <stdio.h>
  15#include <unistd.h>
  16
  17static short endian = 1;
  18static uint8_t *aendian = (uint8_t *)&endian;
  19#define LITTLE *aendian
  20
  21/* "Returns the one's complement checksum used in IP protocols."  That's from
  22 * Plan 9's man page.  This is not a usable, as is - you want to call
  23 * ip_calc_xsum(). */
  24uint16_t ptclbsum(uint8_t *addr, int len)
  25{
  26        uint32_t losum, hisum, mdsum, x;
  27        uint32_t t1, t2;
  28
  29        losum = 0;
  30        hisum = 0;
  31        mdsum = 0;
  32
  33        x = 0;
  34        if ((uintptr_t)addr & 1) {
  35                if (len) {
  36                        hisum += addr[0];
  37                        len--;
  38                        addr++;
  39                }
  40                x = 1;
  41        }
  42        while(len >= 16) {
  43                t1 = *(uint16_t*)(addr + 0);
  44                t2 = *(uint16_t*)(addr + 2);    mdsum += t1;
  45                t1 = *(uint16_t*)(addr + 4);    mdsum += t2;
  46                t2 = *(uint16_t*)(addr + 6);    mdsum += t1;
  47                t1 = *(uint16_t*)(addr + 8);    mdsum += t2;
  48                t2 = *(uint16_t*)(addr + 10);   mdsum += t1;
  49                t1 = *(uint16_t*)(addr + 12);   mdsum += t2;
  50                t2 = *(uint16_t*)(addr + 14);   mdsum += t1;
  51                mdsum += t2;
  52                len -= 16;
  53                addr += 16;
  54        }
  55        while (len >= 2) {
  56                mdsum += *(uint16_t *)addr;
  57                len -= 2;
  58                addr += 2;
  59        }
  60        if (x) {
  61                if (len)
  62                        losum += addr[0];
  63                if (LITTLE)
  64                        losum += mdsum;
  65                else
  66                        hisum += mdsum;
  67        } else {
  68                if (len)
  69                        hisum += addr[0];
  70                if (LITTLE)
  71                        hisum += mdsum;
  72                else
  73                        losum += mdsum;
  74        }
  75
  76        losum += hisum >> 8;
  77        losum += (hisum & 0xff) << 8;
  78        while (hisum = losum >> 16)
  79                losum = hisum + (losum & 0xffff);
  80
  81        return losum & 0xffff;
  82}
  83
  84/* Calculates an IP checksum for [addr, addr + len), returning the xsum in host
  85 * endian. */
  86uint16_t ip_calc_xsum(uint8_t *addr, size_t len)
  87{
  88        return ~ptclbsum(addr, len) & 0xffff;
  89}
  90