fragment.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 747 行 · 第 1/2 页

C
747
字号

/*
 *  Packet De-Fragmentation code for WATTCP
 *  Written by and COPYRIGHT (c)1993 to Quentin Smart
 *                               smart@actrix.gen.nz
 *  all rights reserved.
 *
 *    This software is distributed in the hope that it will be useful,
 *    but without any warranty; without even the implied warranty of
 *    merchantability or fitness for a particular purpose.
 *
 *    You may freely distribute this source code, but if distributed for
 *    financial gain then only executables derived from the source may be
 *    sold.
 *
 *  Murf = Murf@perftech.com
 *  other fragfix = mdurkin@tsoft.net
 *
 *  Based on RFC815
 *
 *  Code used to use pktbuf[] as reassembly buffer. It now allocates
 *  a "bucket" dynamically. There are MAX_IP_FRAGS buckets to handle
 *  at the same time (currently 1).
 *
 *  G.Vanem 1998 <giva@bgnett.no>
 */

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#include "wattcp.h"
#include "strings.h"
#include "language.h"
#include "chksum.h"
#include "ip_out.h"
#include "misc.h"
#include "pcconfig.h"
#include "pcstat.h"
#include "pcqueue.h"
#include "pcsed.h"
#include "pcpkt.h"
#include "pcdbug.h"
#include "pcicmp.h"
#include "pcsed.h"
#include "pcbsd.h"
#include "pctcp.h"

#if defined(USE_FRAGMENTS)

/*@-nullderef@*/

#define MAX_IP_FRAGS    1      /* max # of fragmented IP-packets */
#define FRAGHOLDTIME    15     /* time to hold before discarding */

#define BUCKET_SIZE     (sizeof(HugeIP))  /* ~= 64k bytes */
#define BUCKET_MARKER   0xDEADBEEF

typedef struct huge_ip {
        in_Header hdr;
        BYTE      data [MAX_FRAG_SIZE];   /* 66600 for DOSX */
        DWORD     marker;
      } HugeIP;

typedef struct {
        DWORD  source;
        DWORD  destin;
        WORD   ident;
        BYTE   proto;
        BYTE   tos;
      } frag_key;

typedef struct {
        char        used;     /* this bucket is taken */
        int         active;   /* # of active fragments */
        mac_address mac_src;  /* remember for icmp_timexceed() */
        HugeIP     *ip;       /* malloced, size = (BUCKET_SIZE) */
      } frag_bucket;

typedef struct hd {
        struct hd *next;
        long       start;
        long       end;
      } hole_descr;

typedef struct {
        BYTE        used;     /* this position in table in use */
        frag_key    key;
        DWORD       timer;
        hole_descr *hole_first;
        in_Header  *ip;
        BYTE       *data_offset;
      } frag_hdr;


static frag_hdr    frag_list    [MAX_IP_FRAGS][MAX_FRAGMENTS];
static frag_bucket frag_buckets [MAX_IP_FRAGS];

static long        data_start;
static long        data_end;
static long        data_length;
static int         more_frags;

static int         check_data_start  (const in_Header *ip, DWORD ofs, DWORD len);
static void        setup_first_frag  (const in_Header *ip, int idx, frag_key *key);
static in_Header * alloc_frag_buffer (const in_Header *ip);

#ifdef TEST_PROG
#define MSG(x) printf x
#else
#define MSG(x) ((void)0)
#endif

int _ip_frag_reasm = FRAGHOLDTIME;  /* max time for reassembly */

/*
 * ip_defragment() is called if the frag section of the IP header
 * is non-zero and DF bit not set.
 */
in_Header * ip_defragment (const in_Header *ip, DWORD offset, WORD flags)
{
  frag_hdr   *frag      = NULL;
  hole_descr *hole      = NULL;
  hole_descr *prev_hole = NULL;

  frag_key key;
  int      found    = 0;
  int      got_hole = 0;
  int      i, j;   /* to-do: use j for handling MAX_IP_FRAGS simultaneously */

  STAT (ipstats.ips_fragments++);

#if 0
  MSG (("ip_defrag: src %s, dst %s, prot %d, id %04X\n",
        inet_ntoa (*(struct in_addr*)&ip->source),
        inet_ntoa (*(struct in_addr*)&ip->destination),
        ip->proto, ip->identification));
#endif

  /* Check IP version & header length/checksum
   * !!to-do: probably better to check ip-header after we found the
   *          key. Then we could empty the whole bucket on error.
   */
  if (!_chk_ip_header(ip))
  {
    MSG (("!_chk_ip_header()\r"));
    STAT (ipstats.ips_fragdropped++);
    return (NULL);
  }

  /* Calculate where data should go
   */
  data_start  = (long) offset;
  data_length = (long) intel16 (ip->length) - in_GetHdrLen(ip);
  data_end    = data_start + data_length;
  more_frags  = (flags & IP_MF);

  if (!check_data_start(ip,data_start,data_length))
  {
    DEBUG_RX (NULL, ip);
    STAT (ipstats.ips_fragdropped++);
    return (NULL);
  }

  /* Assemble a fragment match-key
   */
  memset (&key, 0, sizeof(key));
  key.proto  = ip->proto;
  key.source = ip->source;
  key.destin = ip->destination;
  key.ident  = ip->identification;
  key.tos    = ip->tos;

  /* Check if we have a match
   */
  for (i = j = 0; i < MAX_FRAGMENTS; i++)
  {
   /* to-do!! : scan `j' over all our buckets.
    */
    frag = &frag_list[j][i];
    if (frag->used && !memcmp(&frag->key,&key,sizeof(key)))
    {
      found = TRUE;
      break;
    }
  }

  MSG (("bucket %d, key %sfound, i=%d\n", j, found ? "" : "not ", i));

  if (!found)
  {
    /* Can't handle any new frags, biff packet
     */
    if (frag_buckets[j].active == MAX_FRAGMENTS)
    {
      DEBUG_RX (NULL, ip);
      STAT (ipstats.ips_fragdropped++);
    }
    else
    {
      /* Setup first fragment received
       */
      setup_first_frag (ip, j, &key);
    }
    return (NULL);
  }

  MSG (("found, more_frags %d\n", more_frags ? 1 : 0));

  if (!more_frags)           /* Adjust length  */
     frag->ip->length = intel16 ((WORD)(data_end + in_GetHdrLen(ip)));

  hole = frag->hole_first;   /* Hole handling */

  do
  {
    long temp;

    if (hole && (data_start <= hole->end) &&   /* We've found the spot */
        (data_end >= hole->start))
    {
      got_hole = 1;

      /* Find where to insert fragment.
       * Check if there's a hole before the new frag
       */
      temp = hole->end;    /* Pick up old hole end for later */

      if (data_start > hole->start)
      {
        hole->end = data_start - 1;
        prev_hole = hole;  /* We have a new prev */
      }
      else
      {
        /* No, delete current hole
         */
        if (!prev_hole)
             frag->hole_first = hole->next;
        else prev_hole->next  = hole->next;
      }

      /* Is there a hole after the current fragment
       * Only if we're not last and more to come
       */
      if (data_end < hole->end && more_frags)
      {
        hole = (hole_descr*) (data_end + 1 + frag->data_offset);
        hole->start = data_end + 1;
        hole->end   = temp;

        /* prev_hole = NULL if first
         */
        if (!prev_hole)
        {
          hole->next = frag->hole_first;
          frag->hole_first = hole;
        }
        else
        {
          hole->next = prev_hole->next;
          prev_hole->next = hole;
        }
      }
    }
    prev_hole = hole;
    hole = hole->next;
  }
  while (hole);          /* Until we got to the end or found */


  /* Thats all setup so copy in the data
   */
  if (got_hole)
     memcpy (frag->data_offset + data_start,
             (BYTE*)ip + in_GetHdrLen(ip), (size_t)data_length);

  MSG (("got_hole %d, frag->hole_first %lX\n",
        got_hole, (DWORD)frag->hole_first));

  if (!frag->hole_first)    /* Now we have all the parts */
  { 
    if (frag_buckets[j].active >= 1)
        frag_buckets[j].active--;
 
   /* Redo checksum as we've changed the length in the header
    */
    frag->ip->frag_ofs = 0;
    frag->ip->checksum = 0;
    frag->ip->checksum = ~checksum (frag->ip, sizeof(in_Header));

    STAT (ipstats.ips_reassembled++);
    return (frag->ip);       /* MAC-header is in front of IP */
  }
  return (NULL);
}


/*
 *  Prepare and setup for reassembly
 */
static void setup_first_frag (const in_Header *ip, int idx, frag_key *key)
{
  frag_hdr   *frag;
  in_Header  *bucket;
  hole_descr *hole;
  int  i;

  /* Allocate a fragment bucket. MAC-header is in front of bucket.
   */
  bucket = alloc_frag_buffer (ip);
  if (!bucket)
  {
    STAT (ipstats.ips_fragdropped++);
    return;
  }

  /* Find first empty slot
   */
  frag = &frag_list[idx][0];
  for (i = 0; i < MAX_FRAGMENTS; i++, frag++)
      if (!frag->used)
         break;

  frag->used = 1;               /* mark as used             */
  frag_buckets[idx].active++;   /* inc active frags counter */

  MSG (("bucket=%d, active=%u, i=%d\n", idx, frag_buckets[idx].active, i));

  /* Remember MAC source address
   */
  if (!_pktserial)
       memcpy (&frag_buckets[idx].mac_src, MAC_SRC(ip), sizeof(mac_address));
  else memset (&frag_buckets[idx].mac_src, 0, sizeof(mac_address));

  /* Setup frag header data, first packet
   */
  frag->key   = *key;
  frag->ip    = bucket;
  frag->timer = set_timeout (1000 * max(_ip_frag_reasm, ip->ttl));

  /* Set pointers to beginning of IP packet data
   */
  frag->data_offset = (BYTE*)bucket + in_GetHdrLen(ip);

  /* Setup initial hole table
   */
  if (data_start == 0)  /* 1st fragment sent is 1st fragment received */
  {
    WORD  ip_len = intel16 (ip->length);
    BYTE *dst    = (BYTE*)bucket;   

    memcpy (dst, ip, min(ip_len,mtu));
    hole = (hole_descr*) (dst + ip_len + 1);
    frag->hole_first = hole;
  }
  else
  {
    /* !!fix-me: assumes header length of this fragment is same as
     *           in reassembled IP packet (may have IP-options)
     */
    BYTE *dst = frag->data_offset + data_start;
    BYTE *src = (BYTE*)ip + in_GetHdrLen(ip);

    memcpy (dst, src, (size_t)data_length);

    /* Bracket beginning of data
     */
    hole        = frag->hole_first = (hole_descr*)frag->data_offset;
    hole->start = 0;
    hole->end   = data_start - 1;
    if (more_frags)
    {
      hole->next = (hole_descr*) (frag->data_offset + data_length + 1);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?