/* Process SLIP line input */ void slip_rx( struct iface *iface) { int c; struct mbuf *bp; register struct slip *sp; int cdev; uint8 *cp; uint8 buf[4096]; int cnt; int xdev; xdev = iface->xdev; sp = &Slip[xdev]; cdev = sp->iface->dev; cnt = (*sp->get)(cdev,cp=buf,sizeof(buf)); while(--cnt >= 0){ if((bp = slip_decode(sp,*cp++)) == NULL) continue; /* More to come */ if (sp->iface->trace & IF_TRACE_RAW) raw_dump(sp->iface,IF_TRACE_IN,bp); if(sp->slcomp){ if ((c = bp->data[0]) & SL_TYPE_COMPRESSED_TCP) { if ( slhc_uncompress(sp->slcomp, &bp) <= 0 ) { free_p(&bp); sp->errors++; continue; } } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) { bp->data[0] &= 0x4f; if ( slhc_remember(sp->slcomp, &bp) <= 0 ) { free_p(&bp); sp->errors++; continue; } } } net_route( sp->iface, &bp); /* Especially on slow machines, serial I/O can be quite * compute intensive, so release the machine before we * do the next packet. This will allow this packet to * go on toward its ultimate destination. [Karn] */ kwait(NULL); } }
static int ipip_send(struct mbuf **bpp, struct iface *ifp, int32 gateway, uint8 tos) { char buf[MAX_FRAME]; int l; struct edv_t *edv; struct sockaddr_in addr; dump(ifp, IF_TRACE_OUT, *bpp); ifp->rawsndcnt++; ifp->lastsent = secclock(); if (ifp->trace & IF_TRACE_RAW) raw_dump(ifp, -1, *bpp); l = pullup(bpp, buf, sizeof(buf)); if (l <= 0 || *bpp) { free_p(bpp); return -1; } edv = (struct edv_t *) ifp->edv; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(gateway); addr.sin_port = htons(edv->port); sendto(edv->fd, buf, l, 0, (struct sockaddr *) &addr, sizeof(addr)); return l; }
void set_stack_frame_size(cell frame_size) { FACTOR_ASSERT(size() < 0xFFFFFF); FACTOR_ASSERT(!free_p()); FACTOR_ASSERT(frame_size % 16 == 0); FACTOR_ASSERT(frame_size <= 0xFF0); header = (header & 0xFFFFFF) | (frame_size << 20); }
/* Delete a fragment, return next one on queue */ static void freefrag( struct frag *fp ){ free_p(&fp->buf); free(fp); }
/* Free all resources associated with a reassembly descriptor */ static void free_reasm( struct reasm *r ){ register struct reasm *rp; struct reasm *rplast = NULL; register struct frag *fp; for(rp = Reasmq;rp != NULL;rplast = rp,rp=rp->next) if(r == rp) break; if(rp == NULL) return; /* Not on list */ stop_timer(&rp->timer); /* Remove from list of reassembly descriptors */ if(rplast != NULL) rplast->next = rp->next; else Reasmq = rp->next; /* Free any fragments on list, starting at beginning */ while((fp = rp->fraglist) != NULL){ rp->fraglist = fp->next; free_p(&fp->buf); free(fp); } free(rp); }
static int ethertap_send(struct mbuf **bpp, struct iface *ifp, int32 gateway, uint8 tos) { int l; struct edv_t *edv; struct ethertap_packet ethertap_packet; static const unsigned char ethernet_header[16] = { 0x00, 0x00, /* ??? */ 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, /* Destination address (kernel ethertap module) */ 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, /* Source address (WAMPES ethertap module) */ 0x08, 0x00 /* Protocol (IP) */ }; edv = (struct edv_t *) ifp->edv; dump(ifp, IF_TRACE_OUT, *bpp); ifp->rawsndcnt++; ifp->lastsent = secclock(); if (ifp->trace & IF_TRACE_RAW) { raw_dump(ifp, -1, *bpp); } l = pullup(bpp, ethertap_packet.data, sizeof(ethertap_packet.data)); if (l <= 0 || *bpp) { free_p(bpp); return -1; } memcpy(ethertap_packet.ethernet_header, (const char *) ethernet_header, sizeof(ethernet_header)); write(edv->fd, ðertap_packet, l + sizeof(ethertap_packet.ethernet_header)); return l; }
/* Decrement the IP TTL field in each packet on the send queue. If * a TTL goes to zero, discard the packet. */ void ttldec( struct iface *ifp ){ struct mbuf *bp,*bpprev,*bpnext; struct qhdr qhdr; struct ip ip; bpprev = NULL; for(bp = ifp->outq; bp != NULL;bpprev = bp,bp = bpnext){ bpnext = bp->anext; pullup(&bp,&qhdr,sizeof(qhdr)); ntohip(&ip,&bp); if(--ip.ttl == 0){ /* Drop packet */ icmp_output(&ip,bp,ICMP_TIME_EXCEED,0,NULL); if(bpprev == NULL) /* First on queue */ ifp->outq = bpnext; else bpprev->anext = bpnext; free_p(&bp); bp = bpprev; continue; } /* Put IP and queue headers back, restore to queue */ htonip(&ip,&bp,0); pushdown(&bp,&qhdr,sizeof(qhdr)); if(bpprev == NULL) /* First on queue */ ifp->outq = bp; else bpprev->anext = bp; bp->anext = bpnext; } }
int so_tcp_send(struct usock *up,struct mbuf **bpp,struct sockaddr *to) { struct tcb *tcb; long cnt; if((tcb = up->cb.tcb) == NULL){ free_p(bpp); errno = ENOTCONN; return -1; } cnt = send_tcp(tcb,bpp); while((tcb = up->cb.tcb) != NULL && tcb->sndcnt > tcb->window){ /* Send queue is full */ if(up->noblock){ errno = EWOULDBLOCK; return -1; } else if((errno = kwait(up)) != 0){ return -1; } } if(tcb == NULL){ errno = ENOTCONN; return -1; } return cnt; }
/* TCP discard server */ static void disc_server( struct tcb *tcb, int32 cnt) { struct mbuf *bp; if (recv_tcp(tcb, &bp, 0) > 0) free_p(&bp); }
void refiq() { register struct mbuf *bp; char i_state; #ifdef PI /* Temp hack to satisfy PI DMA requirements */ int32 dma_abs; /* TEMP */ int16 dma_page; /* TEMP */ #endif /* Empty the garbage */ if(Garbq != NULLBUF){ i_state = dirps(); bp = Garbq; Garbq = NULLBUF; restore(i_state); free_p(bp); } /* Replenish interrupt buffer pool */ /* G1EMM and HB9RWM fix */ while((Intqlen < Nibufs) && (Memthresh < availmem()) ){ #ifdef notdef while(Intqlen < Nibufs){ #endif if((bp = alloc_mbuf(Ibufsize)) == NULLBUF) break; #ifdef PI /* Temp hack to satisfy PI DMA requirements */ dma_abs = ((long)FP_SEG(bp->data) << 4) + (long)FP_OFF(bp->data); dma_page = dma_abs >> 16; if(((dma_abs+Ibufsize) >> 16) != dma_page){ i_state = dirps(); bp->next = Garbq; Garbq = bp; restore(i_state); continue; } #endif i_state = dirps(); bp->next = Intq; Intq = bp; Intqlen++; restore(i_state); } if(Iminfree == -1) Iminfree = Intqlen; } void iqstat() { tprintf("Intqlen %u Ibufsize %u Iminfree %u Ibuffail %lu Imaxrq %u\n", Intqlen,Ibufsize,Iminfree,Ibuffail,Ibuf_max_rq); /* g8fsl */ }
/* Perform device control on KISS TNC by sending control messages */ int32 kiss_ioctl( struct iface *iface, int cmd, int set, int32 val ){ struct mbuf *hbp; uint8 *cp; int rval = 0; /* At present, only certain parameters are supported by * stock KISS TNCs. As additional params are implemented, * this will have to be edited */ switch(cmd){ case PARAM_RETURN: set = 1; /* Note fall-thru */ case PARAM_TXDELAY: case PARAM_PERSIST: case PARAM_SLOTTIME: case PARAM_TXTAIL: case PARAM_FULLDUP: case PARAM_HW: if(!set){ rval = -1; /* Can't read back */ break; } /* Allocate space for cmd and arg */ if((hbp = alloc_mbuf(2)) == NULL){ free_p(&hbp); rval = -1; break; } cp = hbp->data; *cp++ = cmd; *cp = val; hbp->cnt = 2; slip_raw(iface,&hbp); /* Even more "raw" than kiss_raw */ rval = val; /* per Jay Maynard -- mce */ break; case PARAM_SPEED: /* These go to the local asy driver */ case PARAM_DTR: case PARAM_RTS: rval = asy_ioctl(iface,cmd,set,val); break; default: /* Not implemented */ rval = -1; break; } return rval; }
/* Send routine for point-to-point slip, no VJ header compression */ int slip_send( struct mbuf **bpp, /* Buffer to send */ struct iface *iface, /* Pointer to interface control block */ int32 gateway, /* Ignored (SLIP is point-to-point) */ uint8 tos ){ if(iface == NULL){ free_p(bpp); return -1; } return (*iface->raw)(iface,bpp); }
/* Low level send routine; user supplies mbuf for transmission. More * efficient than send() or sendto(), the higher level interfaces. * The "to" and "tolen" parameters are ignored on connection-oriented * sockets. * * In case of error, bp is freed so the caller doesn't have to worry about it. */ int send_mbuf( int s, /* Socket index */ struct mbuf **bpp, /* Buffer to send */ int flags, /* not currently used */ struct sockaddr *to, /* Destination, only for datagrams */ int tolen /* Length of destination */ ){ register struct usock *up; int cnt; struct socklink *sp; if((up = itop(s)) == NULL){ free_p(bpp); errno = EBADF; return -1; } sp = up->sp; /* Fail if send routine isn't present (shouldn't happen) */ if(sp->send == NULL){ free_p(bpp); return -1; } /* If remote address is supplied, check it */ if(to != NULL && (sp->check != NULL) && (*sp->check)(to,tolen) == -1){ free_p(bpp); errno = EAFNOSUPPORT; return -1; } /* The proto send routine is expected to free the buffer * we pass it even if the send fails */ if((cnt = (*sp->send)(up,bpp,to)) == -1){ errno = EOPNOTSUPP; return -1; } return cnt; }
/* Execute random quench algorithm on an interface's output queue */ void rquench( struct iface *ifp, int drop ){ struct mbuf *bp,*bplast; int i; struct qhdr qhdr; struct ip ip; struct mbuf *bpdup; if((i = len_q(ifp->outq)) == 0) return; /* Queue is empty */ i = urandom(i); /* Select a victim */ /* Search for i-th message on queue */ bplast = NULL; for(bp = ifp->outq;bp != NULL && i>0;i--,bplast=bp,bp=bp->anext) ; if(bp == NULL) return; /* "Can't happen" */ /* Send a source quench */ dup_p(&bpdup,bp,0,len_p(bp)); pullup(&bpdup,&qhdr,sizeof(qhdr)); ntohip(&ip,&bpdup); icmp_output(&ip,bpdup,ICMP_QUENCH,0,NULL); free_p(&bpdup); if(!drop) return; /* All done */ /* Drop the packet */ if(bplast != NULL) bplast->anext = bp->anext; else ifp->outq = bp->anext; /* First on list */ free_p(&bp); }
static void tcp_receive(struct tcb *tcb, int32 cnt) { char buffer[1024]; struct mbuf *bp; if (tcb->user > 0) { recv_tcp(tcb, &bp, 0); while ((cnt = pullup(&bp, buffer, sizeof(buffer))) > 0) if (write(tcb->user, buffer, (unsigned) cnt) != cnt) { free_p(&bp); close_tcp(tcb); return; } } }
/* Process incoming KISS TNC frame */ void kiss_recv( struct iface *iface, struct mbuf **bpp ){ char kisstype; kisstype = PULLCHAR(bpp); switch(kisstype & 0xf){ case PARAM_DATA: ax_recv(iface,bpp); break; default: free_p(bpp); break; } }
/* Create a fragment */ static struct frag * newfrag( uint16 offset, uint16 last, struct mbuf **bpp ){ struct frag *fp; if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULL){ /* Drop fragment */ free_p(bpp); return NULL; } fp->buf = *bpp; *bpp = NULL; fp->offset = offset; fp->last = last; return fp; }
/* Send routine for point-to-point slip, with VJ header compression */ int vjslip_send( struct mbuf **bpp, /* Buffer to send */ struct iface *iface, /* Pointer to interface control block */ int32 gateway, /* Ignored (SLIP is point-to-point) */ uint8 tos ){ register struct slip *sp; int type; if(iface == NULL){ free_p(bpp); return -1; } sp = &Slip[iface->xdev]; /* Attempt IP/ICP header compression */ type = slhc_compress(sp->slcomp,bpp,TRUE); (*bpp)->data[0] |= type; return (*iface->raw)(iface,bpp); }
/* Encode a packet in SLIP format */ static struct mbuf * slip_encode(struct mbuf **bpp) { struct mbuf *lbp; /* Mbuf containing line-ready packet */ register uint8 *cp; int c; /* Allocate output mbuf that's twice as long as the packet. * This is a worst-case guess (consider a packet full of FR_ENDs!) */ lbp = alloc_mbuf(2*len_p(*bpp) + 2); if(lbp == NULL){ /* No space; drop */ free_p(bpp); return NULL; } cp = lbp->data; /* Flush out any line garbage */ *cp++ = FR_END; /* Copy input to output, escaping special characters */ while((c = PULLCHAR(bpp)) != -1){ switch(c){ case FR_ESC: *cp++ = FR_ESC; *cp++ = T_FR_ESC; break; case FR_END: *cp++ = FR_ESC; *cp++ = T_FR_END; break; default: *cp++ = c; } } *cp++ = FR_END; lbp->cnt = cp - lbp->data; return lbp; }
/* Dump packet bytes, no interpretation */ void raw_dump( struct iface *ifp, int direction, struct mbuf *bp) { struct mbuf *tbp; FILE *fp; if((fp = ifp->trfp) == NULL) return; fprintf(fp,"\n******* raw packet dump (%s)\n", ((direction & IF_TRACE_OUT) ? "send" : "recv")); dup_p(&tbp,bp,0,len_p(bp)); if(tbp != NULL) hex_dump(fp,&tbp); else fprintf(fp,nospace); fprintf(fp,"*******\n"); free_p(&tbp); }
static void tcp_send(struct tcb *tcb) { int cnt; struct mbuf *bp; if ((cnt = space_tcp(tcb)) <= 0) { off_read(tcb->user); return; } if (!(bp = alloc_mbuf(cnt))) return; cnt = read(tcb->user, bp->data, (unsigned) cnt); if (cnt <= 0) { free_p(&bp); off_read(tcb->user); close_tcp(tcb); return; } bp->cnt = cnt; send_tcp(tcb, &bp); }
/* Size of the object pointed to by an untagged pointer */ template <typename Fixup> cell object::size(Fixup fixup) const { if (free_p()) return ((free_heap_block*)this)->size(); switch (type()) { case ARRAY_TYPE: return align(array_size((array*)this), data_alignment); case BIGNUM_TYPE: return align(array_size((bignum*)this), data_alignment); case BYTE_ARRAY_TYPE: return align(array_size((byte_array*)this), data_alignment); case STRING_TYPE: return align(string_size(string_capacity((string*)this)), data_alignment); case TUPLE_TYPE: { tuple_layout* layout = (tuple_layout*)fixup.translate_data( untag<object>(((tuple*)this)->layout)); return align(tuple_size(layout), data_alignment); } case QUOTATION_TYPE: return align(sizeof(quotation), data_alignment); case WORD_TYPE: return align(sizeof(word), data_alignment); case FLOAT_TYPE: return align(sizeof(boxed_float), data_alignment); case DLL_TYPE: return align(sizeof(dll), data_alignment); case ALIEN_TYPE: return align(sizeof(alien), data_alignment); case WRAPPER_TYPE: return align(sizeof(wrapper), data_alignment); case CALLSTACK_TYPE: return align( callstack_object_size(untag_fixnum(((callstack*)this)->length)), data_alignment); default: critical_error("Invalid header in size", (cell)this); return 0; /* can't happen */ } }
cell object::binary_payload_start(Fixup fixup) const { if(free_p()) return 0; switch(type()) { /* these objects do not refer to other objects at all */ case FLOAT_TYPE: case BYTE_ARRAY_TYPE: case BIGNUM_TYPE: case CALLSTACK_TYPE: return 0; /* these objects have some binary data at the end */ case WORD_TYPE: return sizeof(word) - sizeof(cell) * 3; case ALIEN_TYPE: return sizeof(cell) * 3; case DLL_TYPE: return sizeof(cell) * 2; case QUOTATION_TYPE: return sizeof(quotation) - sizeof(cell) * 2; case STRING_TYPE: return sizeof(string); /* everything else consists entirely of pointers */ case ARRAY_TYPE: return array_size<array>(array_capacity((array*)this)); case TUPLE_TYPE: { tuple_layout *layout = (tuple_layout *)fixup.translate_data(untag<object>(((tuple *)this)->layout)); return tuple_size(layout); } case WRAPPER_TYPE: return sizeof(wrapper); default: critical_error("Invalid header in binary_payload_start",(cell)this); return 0; /* can't happen */ } }
/* TCP garbage collection - called by storage allocator when free space * runs low. The send and receive queues are crunched. If the situation * is red, the resequencing queue is discarded; otherwise it is * also crunched. */ void tcp_garbage( int red) { struct tcb *tcb; struct reseq *rp,*rp1; for(tcb = Tcbs;tcb != NULL;tcb = tcb->next){ mbuf_crunch(&tcb->rcvq); mbuf_crunch(&tcb->sndq); for(rp = tcb->reseq;rp != NULL;rp = rp1){ rp1 = rp->next; if(red){ free_p(&rp->bp); free(rp); } else { mbuf_crunch(&rp->bp); } } if(red) tcb->reseq = NULL; } }
/* Close our TCB */ void close_self( struct tcb *tcb, int reason) { struct reseq *rp1; struct reseq *rp; if(tcb == NULL) return; stop_timer(&tcb->timer); tcb->reason = reason; /* Flush reassembly queue; nothing more can arrive */ for(rp = tcb->reseq;rp != NULL;rp = rp1){ rp1 = rp->next; free_p(&rp->bp); free(rp); } tcb->reseq = NULL; settcpstate(tcb,TCP_CLOSED); }
/* Process remote command */ static void uremote( struct iface *iface, struct udp_cb *up, int cnt) { struct mbuf *bp; struct socket fsock; char command; int32 addr; recv_udp(up,&fsock,&bp); command = PULLCHAR(&bp); switch(command & 0xff) { case SYS__EXIT: if(chkrpass(bp) == 0) { logmsg(NULL,"%s - Remote exit PASSWORD FAIL", pinet_udp(&fsock)); } else { logmsg(NULL,"%s - Remote exit PASSWORD OK", pinet_udp(&fsock)); main_exit = 1; } break; case KICK__ME: if(len_p(bp) >= sizeof(int32)) addr = pull32(&bp); else addr = fsock.address; kick(addr); /*** smtptick((void *)addr); ***/ break; } free_p(&bp); }
/* Process incoming bytes in SLIP format * When a buffer is complete, return it; otherwise NULL */ static struct mbuf * slip_decode( register struct slip *sp, uint8 c) /* Incoming character */ { struct mbuf *bp; switch(c){ case FR_END: bp = sp->rbp_head; sp->rbp_head = NULL; if(sp->escaped){ /* Treat this as an abort - discard frame */ free_p(&bp); bp = NULL; } sp->escaped &= ~SLIP_FLAG; return bp; /* Will be NULL if empty frame */ case FR_ESC: sp->escaped |= SLIP_FLAG; return NULL; } if(sp->escaped & SLIP_FLAG){ /* Translate 2-char escape sequence back to original char */ sp->escaped &= ~SLIP_FLAG; switch(c){ case T_FR_ESC: c = FR_ESC; break; case T_FR_END: c = FR_END; break; default: sp->errors++; break; } } /* We reach here with a character for the buffer; * make sure there's space for it */ if(sp->rbp_head == NULL){ /* Allocate first mbuf for new packet */ if((sp->rbp_tail = sp->rbp_head = alloc_mbuf(SLIP_ALLOC)) == NULL) return NULL; /* No memory, drop */ sp->rcp = sp->rbp_head->data; } else if(sp->rbp_tail->cnt == SLIP_ALLOC){ /* Current mbuf is full; link in another */ if((sp->rbp_tail->next = alloc_mbuf(SLIP_ALLOC)) == NULL){ /* No memory, drop whole thing */ free_p(&sp->rbp_head); sp->rbp_head = NULL; return NULL; } sp->rbp_tail = sp->rbp_tail->next; sp->rcp = sp->rbp_tail->data; } /* Store the character, increment fragment and total * byte counts */ *sp->rcp++ = c; sp->rbp_tail->cnt++; return NULL; }
cell stack_frame_size() const { if (free_p()) return 0; return (header >> 20) & 0xFF0; }
/* Reassemble incoming IP fragments and dispatch completed datagrams * to the proper transport module */ void ip_recv( struct iface *iface, /* Incoming interface */ struct ip *ip, /* Extracted IP header */ struct mbuf **bpp, /* Data portion */ int rxbroadcast, /* True if received on subnet broadcast address */ int32 spi /* Security association, if any */ ){ /* Function to call with completed datagram */ register struct raw_ip *rp; struct mbuf *bp1; int rxcnt = 0; register struct iplink *ipp; /* If we have a complete packet, call the next layer * to handle the result. Note that fraghandle passes back * a length field that does NOT include the IP header */ if(bpp == NULL || fraghandle(ip,bpp) == -1) return; /* Not done yet */ /* Trim data segment if necessary. */ trim_mbuf(bpp,ip->length - (IPLEN + ip->optlen)); ipInDelivers++; if(Ip_trace) dumpip(iface,ip,*bpp,spi); for(rp = Raw_ip;rp != NULL;rp = rp->next){ if(rp->protocol != ip->protocol) continue; rxcnt++; /* Duplicate the data portion, and put the header back on */ dup_p(&bp1,*bpp,0,len_p(*bpp)); if(bp1 != NULL){ htonip(ip,&bp1,IP_CS_OLD); enqueue(&rp->rcvq,&bp1); if(rp->r_upcall != NULL) (*rp->r_upcall)(rp); } else { free_p(&bp1); } } /* Look it up in the transport protocol table */ for(ipp = Iplink;ipp->funct != NULL;ipp++){ if(ipp->proto == ip->protocol) break; } if(ipp->funct != NULL){ /* Found, call transport protocol */ (*ipp->funct)(iface,ip,bpp,rxbroadcast,spi); } else { /* Not found */ if(rxcnt == 0){ /* Send an ICMP Protocol Unknown response... */ ipInUnknownProtos++; /* ...unless it's a broadcast */ if(!rxbroadcast){ icmp_output(ip,*bpp,ICMP_DEST_UNREACH, ICMP_PROT_UNREACH,NULL); } } free_p(bpp); } }
/* Process IP datagram fragments * If datagram is complete, return its length (MINUS header); * otherwise return -1 */ static int fraghandle( struct ip *ip, /* IP header, host byte order */ struct mbuf **bpp /* The fragment itself */ ){ register struct reasm *rp; /* Pointer to reassembly descriptor */ struct frag *lastfrag,*nextfrag,*tfp; struct mbuf *tbp; uint16 i; uint16 last; /* Index of first byte beyond fragment */ last = ip->offset + ip->length - (IPLEN + ip->optlen); rp = lookup_reasm(ip); if(ip->offset == 0 && !ip->flags.mf){ /* Complete datagram received. Discard any earlier fragments */ if(rp != NULL){ free_reasm(rp); ipReasmOKs++; } return ip->length; } ipReasmReqds++; if(rp == NULL){ /* First fragment; create new reassembly descriptor */ if((rp = creat_reasm(ip)) == NULL){ /* No space for descriptor, drop fragment */ ipReasmFails++; free_p(bpp); return -1; } } /* Keep restarting timer as long as we keep getting fragments */ stop_timer(&rp->timer); start_timer(&rp->timer); /* If this is the last fragment, we now know how long the * entire datagram is; record it */ if(!ip->flags.mf) rp->length = last; /* Set nextfrag to the first fragment which begins after us, * and lastfrag to the last fragment which begins before us */ lastfrag = NULL; for(nextfrag = rp->fraglist;nextfrag != NULL;nextfrag = nextfrag->next){ if(nextfrag->offset > ip->offset) break; lastfrag = nextfrag; } /* Check for overlap with preceeding fragment */ if(lastfrag != NULL && ip->offset < lastfrag->last){ /* Strip overlap from new fragment */ i = lastfrag->last - ip->offset; pullup(bpp,NULL,i); if(*bpp == NULL) return -1; /* Nothing left */ ip->offset += i; } /* Look for overlap with succeeding segments */ for(; nextfrag != NULL; nextfrag = tfp){ tfp = nextfrag->next; /* save in case we delete fp */ if(nextfrag->offset >= last) break; /* Past our end */ /* Trim the front of this entry; if nothing is * left, remove it. */ i = last - nextfrag->offset; pullup(&nextfrag->buf,NULL,i); if(nextfrag->buf == NULL){ /* superseded; delete from list */ if(nextfrag->prev != NULL) nextfrag->prev->next = nextfrag->next; else rp->fraglist = nextfrag->next; if(tfp->next != NULL) nextfrag->next->prev = nextfrag->prev; freefrag(nextfrag); } else nextfrag->offset = last; } /* Lastfrag now points, as before, to the fragment before us; * nextfrag points at the next fragment. Check to see if we can * join to either or both fragments. */ i = INSERT; if(lastfrag != NULL && lastfrag->last == ip->offset) i |= APPEND; if(nextfrag != NULL && nextfrag->offset == last) i |= PREPEND; switch(i){ case INSERT: /* Insert new desc between lastfrag and nextfrag */ tfp = newfrag(ip->offset,last,bpp); tfp->prev = lastfrag; tfp->next = nextfrag; if(lastfrag != NULL) lastfrag->next = tfp; /* Middle of list */ else rp->fraglist = tfp; /* First on list */ if(nextfrag != NULL) nextfrag->prev = tfp; break; case APPEND: /* Append to lastfrag */ append(&lastfrag->buf,bpp); lastfrag->last = last; /* Extend forward */ break; case PREPEND: /* Prepend to nextfrag */ tbp = nextfrag->buf; nextfrag->buf = *bpp; bpp = NULL; append(&nextfrag->buf,&tbp); nextfrag->offset = ip->offset; /* Extend backward */ break; case (APPEND|PREPEND): /* Consolidate by appending this fragment and nextfrag * to lastfrag and removing the nextfrag descriptor */ append(&lastfrag->buf,bpp); append(&lastfrag->buf,&nextfrag->buf); nextfrag->buf = NULL; lastfrag->last = nextfrag->last; /* Finally unlink and delete the now unneeded nextfrag */ lastfrag->next = nextfrag->next; if(nextfrag->next != NULL) nextfrag->next->prev = lastfrag; freefrag(nextfrag); break; } if(rp->fraglist->offset == 0 && rp->fraglist->next == NULL && rp->length != 0){ /* We've gotten a complete datagram, so extract it from the * reassembly buffer and pass it on. */ *bpp = rp->fraglist->buf; rp->fraglist->buf = NULL; /* Tell IP the entire length */ ip->length = rp->length + (IPLEN + ip->optlen); free_reasm(rp); ipReasmOKs++; ip->offset = 0; ip->flags.mf = 0; return ip->length; } else return -1; }