Code für IP-Checksum

Nach dem Verständnis von Einerkomplement-Arithmetik, geht es an die Entwicklung eines eigenen Prüfsummen-Codes. Dieser soll auf aktuellen 64bit Systemen in der natürlichen (32bit) Wortbreite von IP-Paketen Daten verarbeiten.

Zuerst einmal ein klassisches Headerfile, in dem auf aktuelle 64bit Architektur abgehoben wird. Diese gestattet es die Daten als 32bit Worte einzulesen, eine Größe in der die Header der IP-Protokollfamilie typischerweise gemessen werden. Bei Bedarf kann man hier auch auf 32/16bit zurückgehen.

#ifndef _IP_CHECKSUM_H
#define _IP_CHECKSUM_H

#include <stdint.h>

typedef uint32_t checksum_data_t;
typedef uint64_t checksum_intermediate_t;
#define CHECKSUM_ALIGNMENT_BITS 3
/* sizeof(checksum_intermediate_t) >= 2 * sizeof(checksum_data_t)  */
/* CHECKSUM_ALIGNMENT_BITS         == log(sizeof(checksum_data_t)) */

uint16_t checksum_finalize(checksum_intermediate_t partial_sum);
checksum_intermediate_t checksum_block(checksum_intermediate_t partial_sum,
                                       void const * data, uint16_t length);

#endif /* _IP_CHECKSUM_H */

Anschließend der richtige Code.

#include "ip-checksum.h"

uint16_t checksum_finalize(checksum_intermediate_t partial_sum) {
   checksum_intermediate_t carry, sum = partial_sum;

   for(carry = sum >> 16; carry; carry = sum >> 16) {
      sum = (sum & 0xffff) + carry;
   }

   return ~(uint16_t)sum;
}

checksum_intermediate_t checksum_block(checksum_intermediate_t partial_sum, void const * data, uint16_t length) {
   uint8_t const *         p = data;
   uint16_t                l = length;
   checksum_intermediate_t s = partial_sum;

   /* Handle unlikely misalignment */
   switch((int)p & CHECKSUM_ALIGNMENT_BITS) {
    case 0:
      break;
    default:
      l = sizeof(checksum_data_t) - ((int)p & CHECKSUM_ALIGNMENT_BITS);
      if(length > l)
        s = checksum_block(s, p + l, length - l);
      break;
   }

   /* Worker loop */
   while(l >= sizeof(checksum_data_t)) {
      s += *(checksum_data_t*)p;
      p += sizeof(checksum_data_t);
      l -= sizeof(checksum_data_t);
   }

   /* Handle trailing */
   while(l >= 2) {
      s += *(uint16_t*)p;
      p += sizeof(uint16_t);
      l -= sizeof(uint16_t);
   }
   if(l > 0) {
      s += htons(p[0]);
   }

   return s;
}

Mal sehen, wie sich der Code macht.

Post a comment