lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [lwip-users] lwip_standard_chksum()


From: Curt McDowell
Subject: RE: [lwip-users] lwip_standard_chksum()
Date: Thu, 8 Dec 2005 16:41:31 -0800

Timmy Brolin wrote:
> Yes, I think I might have a better idea.
> This solution would even improve performance on machines
> which support unaligned memory accesses [...]

Tim, I've done what you've suggested before.

I'd like to contribute the following two masterpieces for inclusion in lwip
:-)  They handle arbitrary alignment and are "reasonably" fast.  While I've
done quite a bit of testing, of course there is no warranty on this code
express or implied -- use at your own risk.

Regards,
Curt McDowell
Broadcom Corp.
address@hidden

/*
 * IP checksum two bytes at a time with support for
 * unaligned buffer.
 * Works for len up to and including 0x20000.
 * by Curt McDowell, Broadcom Corp. 12/08/2005
 */

static u16_t
lwip_standard_chksum2(void *dataptr, int len)
{
  u8_t *pb = dataptr;
  u16_t *ps, t = 0;
  u32_t sum = 0;
  int odd = ((u32_t)pb & 1);

  /* Get aligned to u16_t */
  if (odd && len > 0) {
    ((u8_t *)&t)[1] = *pb++;
    len--;
  }

  /* Add the bulk of the data */
  ps = (u16_t *)pb;
  while (len > 1) {
    sum += *ps++;
    len -= 2;
  }

  /* Consume left-over byte, if any */
  if (len > 0)
    ((u8_t *)&t)[0] = *(u8_t *)ps;;

  /* Add end bytes */
  sum += t;

  /*  Fold 32-bit sum to 16 bits */
  while (sum >> 16)
    sum = (sum & 0xffff) + (sum >> 16);

  /* Swap if alignment was odd */
  if (odd)
    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);

  return sum;
}

/*
 * IP checksum four bytes at a time with support for
 * unaligned buffer.  Works for any length.
 * by Curt McDowell, Broadcom Corp. 12/08/2005
 */

static u16_t
lwip_standard_chksum4(u8_t *pb, int len)
{
  u16_t *ps, t = 0;
  u32_t *pl;
  u32_t sum = 0, tmp;
  int odd = ((u32_t)pb & 1);

  if (odd && len > 0) {
    ((u8_t *)&t)[1] = *pb++;
    len--;
  }

  ps = (u16_t *)pb;

  if (((u32_t)ps & 3) && len > 1) {
    sum += *ps++;
    len -= 2;
  }

  pl = (u32_t *)ps;

  while (len > 7)  {
    tmp = sum + *pl++;          /* ping */
    if (tmp < sum)
      tmp++;                    /* add back carry */

    sum = tmp + *pl++;          /* pong */
    if (sum < tmp)
      sum++;                    /* add back carry */

    len -= 8;
  }

  /* make room in upper bits */
  sum = (sum >> 16) + (sum & 0xffff);

  ps = (u16_t *)pl;

  while (len > 1) {             /* add 0-3 shorts */
    sum += *ps++;
    len -= 2;
  }

  if (len > 0)                  /* include odd byte */
    ((u8_t *)&t)[0] = *(u8_t *)ps;

  sum += t;                     /* add end bytes */

  while (sum >> 16)             /* combine halves */
    sum = (sum >> 16) + (sum & 0xffff);

  if (odd)
    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);

  return sum;
}







reply via email to

[Prev in Thread] Current Thread [Next in Thread]