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 + -
显示快捷键?