/* Internet Control Message Protocol */ #include "global.h" #include "mbuf.h" #include "internet.h" #include "timer.h" #include "iface.h" #include "ip.h" #include "icmp.h" struct icmp_errors icmp_errors; struct icmp_stats icmp_stats; /* Process an incoming ICMP packet */ void icmp_input(bp,protocol,source,dest,tos,length,rxbroadcast) struct mbuf *bp; /* Pointer to ICMP message */ char protocol; /* Should always be ICMP_PTCL */ int32 source; /* Sender of ICMP message */ int32 dest; /* Us */ char tos; /* Type of Service */ int16 length; /* Length of ICMP message */ char rxbroadcast; { struct mbuf *htonicmp(); struct icmp icmp; /* ICMP header */ struct ip ip; /* Offending datagram header */ int16 type; /* Type of ICMP message */ extern int pingflag; /* DG2KK */ if(rxbroadcast){ /* Broadcast ICMP packets are to be IGNORED !! */ icmp_errors.bdcsts++; free_p(bp); return; } if(cksum(NULLHEADER,bp,length) != 0){ /* Bad ICMP checksum; discard */ icmp_errors.checksum++; free_p(bp); return; } ntohicmp(&icmp,&bp); /* Process the message. Some messages are passed up to the protocol * module for handling, others are handled here. */ type = icmp.type & 0xff; if(type < ICMP_TYPES) icmp_stats.input[type]++; switch(type){ case TIME_EXCEED: /* Time-to-live Exceeded */ case DEST_UNREACH: /* Destination Unreachable */ case QUENCH: /* Source Quench */ ntohip(&ip,&bp); /* Extract offending IP header */ switch(ip.protocol){ case TCP_PTCL: tcp_icmp(ip.source,ip.dest,icmp.type,icmp.code,&bp); break; } break; case ECHO: /* Echo Request */ /* Change type to ECHO_REPLY, recompute checksum, * and return datagram. */ /* DG2KK: don't send an ECHO_REPLY if pingflag is 'off' */ if(pingflag == 0) return; icmp.type = ECHO_REPLY; bp = htonicmp(&icmp,bp); icmp_stats.output[ECHO_REPLY]++; ip_send(dest,source,ICMP_PTCL,tos,0,bp,length,0,0); return; case REDIRECT: /* Redirect */ case PARAM_PROB: /* Parameter Problem */ break; case ECHO_REPLY: /* Echo Reply */ echo_proc(source,dest,&icmp); break; case TIMESTAMP: /* Timestamp */ case TIME_REPLY: /* Timestamp Reply */ case INFO_RQST: /* Information Request */ case INFO_REPLY: /* Information Reply */ break; } free_p(bp); } /* Return an ICMP response to the sender of a datagram */ icmp_output(ip,bp,type,code,args) struct ip *ip; /* Header of offending datagram */ struct mbuf *bp; /* Data portion of datagram */ char type,code; /* Codes to send */ union icmp_args *args; { struct mbuf *htonicmp(); struct mbuf *htonip(); struct icmp icmp; /* ICMP protocol header */ int16 dlen; /* Length of data portion of offending pkt */ int16 length; /* Total length of reply */ extern int32 ip_addr; /* Our IP address */ if(ip == NULLIP) return; if(type < ICMP_TYPES) icmp_stats.output[type]++; if(ip->protocol == ICMP_PTCL){ /* Never send an ICMP message about another ICMP message */ icmp_errors.noloop++; return; } /* Compute amount of original datagram to return. * We return the original IP header, and up to 8 bytes past that. */ dlen = min(8,len_mbuf(bp)); length = dlen + ICMPLEN + IPLEN + ip->optlen; if(bp != NULLBUF){ /* Take excerpt from data portion */ bp = copy_p(bp,dlen); } /* Recreate and tack on offending IP header */ bp = htonip(ip,bp); icmp.type = type; icmp.code = code; switch(icmp.type){ case PARAM_PROB: icmp.args.pointer = args->pointer; break; case REDIRECT: icmp.args.address = args->address; break; case ECHO: case ECHO_REPLY: case INFO_RQST: case INFO_REPLY: case TIMESTAMP: case TIME_REPLY: icmp.args.echo.id = args->echo.id; icmp.args.echo.seq = args->echo.seq; break; default: icmp.args.unused = 0; break; } bp = htonicmp(&icmp,bp); /* Now stick on the ICMP header */ ip_send(ip_addr,ip->source,ICMP_PTCL,ip->tos,0,bp,length,0,0); } /* Generate ICMP header in network byte order, link data, compute checksum */ struct mbuf * htonicmp(icmp,data) struct icmp *icmp; struct mbuf *data; { struct mbuf *rval; register char *cp; int16 checksum; rval = alloc_mbuf(ICMPLEN); rval->cnt = ICMPLEN; cp = rval->data; *cp++ = icmp->type; *cp++ = icmp->code; cp = put16(cp,0); /* Clear checksum */ cp = put16(cp,icmp->args.echo.id); cp = put16(cp,icmp->args.echo.seq); /* Link in data, compute checksum, and stash result */ rval->next = data; checksum = cksum(NULLHEADER,rval,len_mbuf(rval)); cp = &rval->data[2]; cp = put16(cp,checksum); return rval; } /* Pull off ICMP header */ ntohicmp(icmp,bpp) struct icmp *icmp; struct mbuf **bpp; { icmp->type = pullchar(bpp); icmp->code = pullchar(bpp); (void) pull16(bpp); /* Toss checksum */ icmp->args.echo.id = pull16(bpp); icmp->args.echo.seq = pull16(bpp); }