?? ip.c
字號:
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;
}
/* Arrange for receipt of raw IP datagrams */
struct raw_ip *
raw_ip(
int protocol,
void (*r_upcall)()
){
register struct raw_ip *rp;
rp = (struct raw_ip *)callocw(1,sizeof(struct raw_ip));
rp->protocol = protocol;
rp->r_upcall = r_upcall;
rp->next = Raw_ip;
Raw_ip = rp;
return rp;
}
/* Free a raw IP descriptor */
void
del_ip(
struct raw_ip *rpp
){
struct raw_ip *rplast = NULL;
register struct raw_ip *rp;
/* Do sanity check on arg */
for(rp = Raw_ip;rp != NULL;rplast=rp,rp = rp->next)
if(rp == rpp)
break;
if(rp == NULL)
return; /* Doesn't exist */
/* Unlink */
if(rplast != NULL)
rplast->next = rp->next;
else
Raw_ip = rp->next;
/* Free resources */
free_q(&rp->rcvq);
free(rp);
}
static struct reasm *
lookup_reasm(
struct ip *ip
){
register struct reasm *rp;
struct reasm *rplast = NULL;
for(rp = Reasmq;rp != NULL;rplast=rp,rp = rp->next){
if(ip->id == rp->id && ip->source == rp->source
&& ip->dest == rp->dest && ip->protocol == rp->protocol){
if(rplast != NULL){
/* Move to top of list for speed */
rplast->next = rp->next;
rp->next = Reasmq;
Reasmq = rp;
}
return rp;
}
}
return NULL;
}
/* Create a reassembly descriptor,
* put at head of reassembly list
*/
static struct reasm *
creat_reasm(
struct ip *ip
){
register struct reasm *rp;
if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULL)
return rp; /* No space for descriptor */
rp->source = ip->source;
rp->dest = ip->dest;
rp->id = ip->id;
rp->protocol = ip->protocol;
set_timer(&rp->timer,ipReasmTimeout * 1000L);
rp->timer.func = ip_timeout;
rp->timer.arg = rp;
rp->next = Reasmq;
Reasmq = rp;
return rp;
}
/* 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);
}
/* Handle reassembly timeouts by deleting all reassembly resources */
static void
ip_timeout(
void *arg
){
free_reasm((struct reasm *)arg);
ipReasmFails++;
}
/* 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;
}
/* Delete a fragment, return next one on queue */
static void
freefrag(
struct frag *fp
){
free_p(&fp->buf);
free(fp);
}
/* In red alert mode, blow away the whole reassembly queue. Otherwise crunch
* each fragment on each reassembly descriptor
*/
void
ip_garbage(
int red
){
struct reasm *rp,*rp1;
struct frag *fp;
struct raw_ip *rwp;
struct iface *ifp;
/* Run through the reassembly queue */
for(rp = Reasmq;rp != NULL;rp = rp1){
rp1 = rp->next;
if(red){
free_reasm(rp);
} else {
for(fp = rp->fraglist;fp != NULL;fp = fp->next){
mbuf_crunch(&fp->buf);
}
}
}
/* Run through the raw IP queue */
for(rwp = Raw_ip;rwp != NULL;rwp = rwp->next)
mbuf_crunch(&rwp->rcvq);
/* Walk through interface output queues and decrement IP TTLs.
* Discard and return ICMP TTL exceeded messages for any that
* go to zero. (Some argue that this ought to be done all the
* time, but it would probably break a lot of machines with
* small IP TTL settings using amateur packet radio paths.)
*
* Also send an ICMP source quench message to one
* randomly chosen packet on each queue. If in red mode,
* also drop the packet.
*/
for(ifp=Ifaces;ifp != NULL;ifp = ifp->next){
ttldec(ifp);
rquench(ifp,red);
}
}
/* 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;
}
}
/* 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);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -