/* * Packet De-Fragmentaion 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. * * * Based on RFC815 */ #include #include #include "wattcp.h" #define MAXBUFS 5 /* maximum number of Ethernet buffers */ #define MAXFRAGS MAXBUFS-1 #define FRAGHOLDTIME 15 /* 15 secs to hold before discarding */ #define INFINITY 30000 #define IP_HEADER_SIZE 20 #define IP_MF 0x0020 // More fragment in INTEL form //#define IP_DF 0x2000 // Don't fragments typedef struct { longword source; // longword destination; // byte proto; My app only does TCP so don't care word identification; } fragkey; typedef struct hd { struct hd * next; int start; int end; } hole_descr; typedef struct { byte used; // this position in table in use fragkey key; hole_descr *hole_first; longword timer; in_Header *ip; byte *data_offset; } fraghdr; static fraghdr fraglist[MAXFRAGS] = {{0,{0,0},NULL,0,NULL}, {0,{0,0},NULL,0,NULL}, {0,{0,0},NULL,0,NULL}, {0,{0,0},NULL,0,NULL}}; int active_frags = 0; extern word _pktipofs; /* offset from header to start of pkt */ /* Fragment is called if the frag section of the IP header is not zero and DF bit not set */ byte * fragment(in_Header * ip) { //int fc; fraghdr *my_frag; hole_descr *hole = NULL; hole_descr *prev_hole = NULL; fragkey key; int found = 0; int got_hole = 0; int data_start; int data_end; int data_length; int temp,i; int more_frags; // Set to true if this is the last frag byte * buffer; // Should check that the packet is actually valid and do a checksum on it. // Assemble key //key.proto = ip->proto; key.source=ip->source; key.identification = ip->identification; // Check if we have a match for (i=0;ifo ) << 3; //* 8 data_length = intel16(ip->length)-in_GetHdrlenBytes(ip); data_end = data_start + data_length; more_frags = ip->frags & IP_MF; if (!found) { // Mark as used *((byte *)ip - (2 + _pktipofs)) = 2; // Find first empty slot for (i=0;i < MAXFRAGS && fraglist[i].used;i++); my_frag = &fraglist[i]; // mark as used my_frag->used = 1; // inc active frags counter active_frags++; // Setup frag header data, first packet memcpy(&my_frag->key,&key,sizeof(key)); my_frag->timer = set_timeout(max(FRAGHOLDTIME,ip->ttl)); my_frag->ip = ip; // Set pointers to beinging of IP packet data my_frag->data_offset = (byte *)my_frag->ip + in_GetHdrlenBytes(ip); // Setup initial hole table if (data_start) // i.e. not Zero { memcpy(my_frag->data_offset + data_start,(byte *)ip+in_GetHdrlenBytes(ip),data_length); // Bracket beginning of data hole = my_frag->hole_first = my_frag->data_offset; hole->start = 0; hole->end = data_start-1; if (more_frags) { hole->next = my_frag->data_offset + data_length + 1; hole = hole->next; } else { hole = my_frag->hole_first->next = NULL; // Adjust length ip->length = intel16(data_end + in_GetHdrlenBytes(ip)); } } else { // Setup hole = my_frag->hole_first = my_frag->data_offset + data_length + 1; } // Bracket end if (hole) { hole->start = data_length;// + 1; hole->end = INFINITY; hole->next = NULL; } return NULL; // Go back for more! } // End !found // Adjust length if (!more_frags) my_frag->ip->length = intel16(data_end + in_GetHdrlenBytes(ip)); // Hole handling hole = my_frag->hole_first; do { if (!(data_start > hole->end)) if (!(data_end < hole->start)) // We've found the spot { // Mark as got. got_hole =1; // Find where to insert // Check is there 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) my_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 = data_end + 1 + my_frag->data_offset; hole->start = data_end+1; hole->end = temp; // prev_hole = NULL if first if (!prev_hole) { hole->next = my_frag->hole_first; my_frag->hole_first = hole; } else { hole->next = prev_hole->next; prev_hole->next = hole; } } } prev_hole = hole; hole = hole->next; } while (!hole && !got_hole); // Until we got to the end or found // Thats all setup so copy in the data if (got_hole) memcpy(my_frag->data_offset + data_start,(byte *)ip+in_GetHdrlenBytes(ip),data_length); // And release the buffer; pkt_buf_release((byte *)ip); // Now do we have all the parts? if (!my_frag->hole_first) { my_frag->used = 0; active_frags--; // Redo checksum as we've changed the length in the header my_frag->ip->checksum = 0; // Zero my_frag->ip->checksum = ~ checksum( my_frag->ip, sizeof( in_Header )); return((byte *)my_frag->ip - _pktipofs); } return NULL; } void timeout_frags(void) { int i; for (i=0;i