Goto sanos source index

//
// inet.c
//
// Functions common to all TCP/IP modules, such as the Internet checksum and the
// byte order functions.
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
// Portions Copyright (C) 2001, Swedish Institute of Computer Science.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.  
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
// SUCH DAMAGE.
// 

#include <net/net.h>

//
// chksum
//
// Sums up all 16 bit words in a memory portion. Also includes any odd byte.
// This function is used by the other checksum functions.
//
// For now, this is not optimized. Must be optimized for the particular processor
// arcitecture on which it is to run. Preferebly coded in assembler.
//

static unsigned long chksum(void *dataptr, int len) {
  unsigned long acc;
    
  for (acc = 0; len > 1; len -= 2) acc += *((unsigned short *) dataptr)++;

  // Add up any odd byte
  if (len == 1) acc += *(unsigned char *) dataptr;

  acc = (acc >> 16) + (acc & 0xFFFF);
  if ((acc & 0xFFFF0000) != 0) acc = (acc >> 16) + (acc & 0xFFFF);

  return acc;
}

//
// inet_chksum_pseudo
//
// Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
//

unsigned short inet_chksum_pseudo(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, 
                                  unsigned char proto, unsigned short proto_len) {
  unsigned long acc;
  struct pbuf *q;
  int swapped;

  acc = 0;
  swapped = 0;
  for (q = p; q != NULL; q = q->next) {
    acc += chksum(q->payload, q->len);
    while (acc >> 16) acc = (acc & 0xFFFF) + (acc >> 16);

    if (q->len % 2 != 0) {
      swapped = 1 - swapped;
      acc = ((acc & 0xFF) << 8) | ((acc & 0xFF00) >> 8);
    }
  }

  if (swapped) acc = ((acc & 0xFF) << 8) | ((acc & 0xFF00) >> 8);

  acc += (src->addr & 0xFFFF);
  acc += ((src->addr >> 16) & 0xFFFF);
  acc += (dest->addr & 0xFFFF);
  acc += ((dest->addr >> 16) & 0xFFFF);
  acc += (unsigned long) htons((unsigned short) proto);
  acc += (unsigned long) htons(proto_len);  
  
  while (acc >> 16) acc = (acc & 0xFFFF) + (acc >> 16);

  return (unsigned short) ~(acc & 0xFFFF);
}

//
// inet_chksum
//
// Calculates the Internet checksum over a portion of memory. Used primarely for IP
// and ICMP.
//

unsigned short inet_chksum(void *dataptr, int len) {
  unsigned long acc;

  acc = chksum(dataptr, len);
  while (acc >> 16) acc = (acc & 0xFFFF) + (acc >> 16);

  return (unsigned short) ~(acc & 0xFFFF);
}

unsigned short inet_chksum_pbuf(struct pbuf *p) {
  unsigned long acc;
  struct pbuf *q;
  int swapped;
  
  acc = 0;
  swapped = 0;
  for (q = p; q != NULL; q = q->next) {
    acc += chksum(q->payload, q->len);
    while (acc >> 16) acc = (acc & 0xFFFF) + (acc >> 16);

    if (q->len % 2 != 0) {
      swapped = 1 - swapped;
      acc = ((acc & 0xFF) << 8) | ((acc & 0xFF00) >> 8);
    }
  }
 
  if (swapped) acc = ((acc & 0xFF) << 8) | ((acc & 0xFF00) >> 8);

  return (unsigned short) ~(acc & 0xFFFF);
}