/* 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; } }
/* Send an IP datagram. Modeled after the example interface on p 32 of * RFC 791 */ int ip_send( int32 source, /* source address */ int32 dest, /* Destination address */ char protocol, /* Protocol */ char tos, /* Type of service */ char ttl, /* Time-to-live */ struct mbuf **bpp, /* Data portion of datagram */ uint16 length, /* Optional length of data portion */ uint16 id, /* Optional identification */ char df /* Don't-fragment flag */ ){ struct ip ip; /* IP header */ ipOutRequests++; if(bpp == NULL) return -1; if(source == INADDR_ANY) source = locaddr(dest); if(length == 0 && *bpp != NULL) length = len_p(*bpp); if(id == 0) id = Id_cntr++; if(ttl == 0) ttl = ipDefaultTTL; /* Fill in IP header */ ip.version = IPVERSION; ip.tos = tos; ip.length = IPLEN + length; ip.id = id; ip.offset = 0; ip.flags.mf = 0; ip.flags.df = df; ip.flags.congest = 0; ip.ttl = ttl; ip.protocol = protocol; ip.source = source; ip.dest = dest; ip.optlen = 0; if(Ip_trace) dumpip(NULL,&ip,*bpp,0); htonip(&ip,bpp,IP_CS_NEW); if(ismyaddr(ip.dest)){ /* Pretend it has been sent by the loopback interface before * it appears in the receive queue */ #ifdef SIM net_sim(bpp); #else net_route(&Loopback,bpp); #endif Loopback.ipsndcnt++; Loopback.rawsndcnt++; Loopback.lastsent = secclock(); } else net_route(NULL,bpp); return 0; }
/* Process an incoming ICMP packet */ void icmp_input( struct iface *iface, /* Incoming interface (ignored) */ struct ip *ip, /* Pointer to decoded IP header structure */ struct mbuf **bpp, /* Pointer to ICMP message */ int rxbroadcast, int32 said ){ struct icmplink *ipp; struct icmp icmp; /* ICMP header */ struct ip oip; /* Offending datagram header */ uint type; /* Type of ICMP message */ uint length; icmpInMsgs++; if(rxbroadcast){ /* Broadcast ICMP packets are to be IGNORED !! */ icmpInErrors++; free_p(bpp); return; } length = ip->length - IPLEN - ip->optlen; if(cksum(NULL,*bpp,length) != 0){ /* Bad ICMP checksum; discard */ icmpInErrors++; free_p(bpp); return; } ntohicmp(&icmp,bpp); /* Process the message. Some messages are passed up to the protocol * module for handling, others are handled here. */ type = icmp.type; switch(type){ case ICMP_TIME_EXCEED: /* Time-to-live Exceeded */ case ICMP_DEST_UNREACH: /* Destination Unreachable */ case ICMP_QUENCH: /* Source Quench */ case ICMP_IPSP: /* Bad security packet */ switch(type){ case ICMP_TIME_EXCEED: /* Time-to-live Exceeded */ icmpInTimeExcds++; break; case ICMP_DEST_UNREACH: /* Destination Unreachable */ icmpInDestUnreachs++; break; case ICMP_QUENCH: /* Source Quench */ icmpInSrcQuenchs++; break; } ntohip(&oip,bpp); /* Extract offending IP header */ if(Icmp_trace){ printf("ICMP from %s:",inet_ntoa(ip->source)); printf(" dest %s %s",inet_ntoa(oip.dest), smsg(Icmptypes,ICMP_TYPES,type)); switch(type){ case ICMP_TIME_EXCEED: printf(" %s\n", smsg(Exceed,NEXCEED,icmp.code)); break; case ICMP_DEST_UNREACH: printf(" %s\n", smsg(Unreach,NUNREACH,icmp.code)); break; case ICMP_IPSP: printf(" %s\n",smsg(Said_icmp,NIPSP,icmp.code)); break; default: printf(" %u\n",icmp.code); break; } } for(ipp = Icmplink;ipp->funct != NULL;ipp++) if(ipp->proto == oip.protocol) break; if(ipp->funct != NULL){ (*ipp->funct)(ip->source,oip.source,oip.dest,icmp.type, icmp.code,bpp); } break; case ICMP_ECHO: /* Echo Request */ /* Change type to ECHO_REPLY, recompute checksum, * and return datagram. */ icmpInEchos++; icmp.type = ICMP_ECHO_REPLY; htonicmp(&icmp,bpp); icmpOutEchoReps++; { int32 tmp = ip->source; ip->source = ip->dest; ip->dest = tmp; ip->ttl = (char) ipDefaultTTL; htonip(ip,bpp,IP_CS_NEW); icmpOutMsgs++; net_route(NULL,bpp); } return; case ICMP_REDIRECT: /* Redirect */ icmpInRedirects++; ntohip(&oip,bpp); /* Extract offending IP header */ if(Icmp_trace){ printf("ICMP from %s:",inet_ntoa(ip->source)); printf(" dest %s %s",inet_ntoa(oip.dest), smsg(Icmptypes,ICMP_TYPES,type)); printf(" new gateway %s\n",inet_ntoa(icmp.args.address)); } break; case ICMP_PARAM_PROB: /* Parameter Problem */ icmpInParmProbs++; break; case ICMP_ECHO_REPLY: /* Echo Reply */ icmpInEchoReps++; echo_proc(ip->source,ip->dest,&icmp,bpp); break; case ICMP_TIMESTAMP: /* Timestamp */ icmpInTimestamps++; { int32 tmp; uint8 buf[12]; struct timeval tv; if(pullup(bpp,buf,sizeof(buf)) != sizeof(buf)){ free_p(bpp); return; } gettimeofday(&tv,0); tmp = (tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000; put32(&buf[4],tmp); /* Receive Timestamp */ put32(&buf[8],tmp); /* Transmit Timestamp */ pushdown(bpp,buf,sizeof(buf)); icmp.type = ICMP_TIME_REPLY; htonicmp(&icmp,bpp); icmpOutTimestampReps++; tmp = ip->source; ip->source = ip->dest; ip->dest = tmp; ip->ttl = (char) ipDefaultTTL; htonip(ip,bpp,IP_CS_NEW); icmpOutMsgs++; net_route(NULL,bpp); return; } case ICMP_TIME_REPLY: /* Timestamp Reply */ icmpInTimestampReps++; break; case ICMP_INFO_RQST: /* Information Request */ break; case ICMP_INFO_REPLY: /* Information Reply */ break; } free_p(bpp); }
/* 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); } }
/* 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); }