/* 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); }
/* 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); }
/* 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); } }
void dump( struct iface *ifp, int direction, struct mbuf *bp ){ struct mbuf *tbp; uint size; time_t timer; char *cp; struct iftype *ift; FILE *fp; if(ifp == NULL || (ifp->trace & direction) == 0 || (fp = ifp->trfp) == NULL) return; /* Nothing to trace */ ift = ifp->iftype; switch(direction){ case IF_TRACE_IN: if((ifp->trace & IF_TRACE_NOBC) && ift != NULL && (ift->addrtest != NULL) && (*ift->addrtest)(ifp,bp) == 0) return; /* broadcasts are suppressed */ timer = (time_t) secclock(); cp = ctime(&timer); cp[24] = '\0'; fprintf(fp,"\n%s - %s recv:\n",cp,ifp->name); break; case IF_TRACE_OUT: timer = (time_t) secclock(); cp = ctime(&timer); cp[24] = '\0'; fprintf(fp,"\n%s - %s sent:\n",cp,ifp->name); break; } if(bp == NULL || (size = len_p(bp)) == 0){ fprintf(fp,"empty packet!!\n"); return; } dup_p(&tbp,bp,0,size); if(tbp == NULL){ fprintf(fp,nospace); return; } if(ift != NULL && ift->trace != NULL) (*ift->trace)(fp,&tbp,1); if(ifp->trace & IF_TRACE_ASCII){ /* Dump only data portion of packet in ascii */ ascii_dump(fp,&tbp); } else if(ifp->trace & IF_TRACE_HEX){ /* Dump entire packet in hex/ascii */ free_p(&tbp); dup_p(&tbp,bp,0,len_p(bp)); if(tbp != NULL) hex_dump(fp,&tbp); else fprintf(fp,nospace); } free_p(&tbp); }
/* Return an ICMP response to the sender of a datagram. * Unlike most routines, the callER frees the mbuf. */ int icmp_output( struct ip *ip, /* Header of offending datagram */ struct mbuf *data, /* Data portion of datagram - FREED BY CALLER */ uint8 type, /* Codes to send */ uint8 code, union icmp_args *args ){ struct mbuf *bp; struct icmp icmp; /* ICMP protocol header */ uint dlen; /* Length of data portion of offending pkt */ uint length; /* Total length of reply */ if(ip == NULL) return -1; if(ip->protocol == ICMP_PTCL){ /* Peek at type field of ICMP header to see if it's safe to * return an ICMP message */ switch(data->data[0]){ case ICMP_ECHO_REPLY: case ICMP_ECHO: case ICMP_TIMESTAMP: case ICMP_TIME_REPLY: case ICMP_INFO_RQST: case ICMP_INFO_REPLY: break; /* These are all safe */ default: /* Never send an ICMP error message about another * ICMP error message! */ return -1; } } /* Compute amount of original datagram to return. * We return the original IP header, and up to 8 bytes past that. */ dlen = min(8,len_p(data)); length = dlen + ICMPLEN + IPLEN + ip->optlen; /* Take excerpt from data portion */ if(data != NULL && dup_p(&bp,data,0,dlen) == 0) return -1; /* The caller will free data */ /* Recreate and tack on offending IP header */ htonip(ip,&bp,IP_CS_NEW); icmp.type = type; icmp.code = code; icmp.args.unused = 0; switch(icmp.type){ case ICMP_PARAM_PROB: icmpOutParmProbs++; icmp.args.pointer = args->pointer; break; case ICMP_REDIRECT: icmpOutRedirects++; icmp.args.address = args->address; break; case ICMP_ECHO: icmpOutEchos++; break; case ICMP_ECHO_REPLY: icmpOutEchoReps++; break; case ICMP_INFO_RQST: break; case ICMP_INFO_REPLY: break; case ICMP_TIMESTAMP: icmpOutTimestamps++; break; case ICMP_TIME_REPLY: icmpOutTimestampReps++; icmp.args.echo.id = args->echo.id; icmp.args.echo.seq = args->echo.seq; break; case ICMP_ADDR_MASK: icmpOutAddrMasks++; break; case ICMP_ADDR_MASK_REPLY: icmpOutAddrMaskReps++; break; case ICMP_DEST_UNREACH: if(icmp.code == ICMP_FRAG_NEEDED) icmp.args.mtu = args->mtu; icmpOutDestUnreachs++; break; case ICMP_TIME_EXCEED: icmpOutTimeExcds++; break; case ICMP_QUENCH: icmpOutSrcQuenchs++; break; } icmpOutMsgs++; /* Now stick on the ICMP header */ htonicmp(&icmp,&bp); return ip_send(INADDR_ANY,ip->source,ICMP_PTCL,ip->tos,0,&bp,length,0,0); }