home *** CD-ROM | disk | FTP | other *** search
- /* Internet Control Message Protocol */
- #include "global.h"
- #include "mbuf.h"
- #include "misc.h"
- #include "internet.h"
- #include "timer.h"
- #include "iface.h"
- #include "ip.h"
- #include "netuser.h"
- #include "tcp.h"
- #include "icmp.h"
-
- struct icmp_errors icmp_errors;
- struct icmp_stats icmp_stats;
-
- /* Process an incoming ICMP packet */
- void icmp_input(struct mbuf *bp, char protocol, int32 source,
- int32 dest, char tos, int16 length, char rxbroadcast)
- {
- struct mbuf *tbp;
- struct icmp icmp; /* ICMP header */
- struct ip ip; /* Offending datagram header */
- int16 type; /* Type of ICMP message */
-
- protocol = protocol;
-
- 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;
- if(type < ICMP_TYPES)
- icmp_stats.input[type]++;
-
- switch(uchar(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(uchar(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.
- */
- icmp.type = ECHO_REPLY;
- if((tbp = htonicmp(&icmp,bp)) == NULLBUF){
- free_p(bp);
- return;
- }
- icmp_stats.output[ECHO_REPLY]++;
- ip_send(dest,source,ICMP_PTCL,tos,0,tbp,length,0,0);
- return;
- case REDIRECT: /* Redirect */
- case PARAM_PROB: /* Parameter Problem */
- break;
- case ECHO_REPLY: /* Echo Reply */
- echo_proc(source,dest,&icmp,bp);
- 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.
- * Unlike most routines, the callER frees the mbuf.
- */
- int icmp_output(struct ip *ip, struct mbuf *data, char type, char code,
- union icmp_args *args)
- {
- struct mbuf *bp;
- 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 -1;
- if(type < ICMP_TYPES)
- icmp_stats.output[type]++;
-
- if(uchar(ip->protocol) == ICMP_PTCL){
- /* Never send an ICMP message about another ICMP message */
- icmp_errors.noloop++;
- 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_mbuf(data));
- length = dlen + ICMPLEN + IPLEN + ip->optlen;
- /* Take excerpt from data portion */
- if(data != NULLBUF && (bp = copy_p(data,dlen)) == NULLBUF)
- return -1; /* The caller will free data */
-
- /* Recreate and tack on offending IP header */
- if((data = htonip(ip,bp)) == NULLBUF){
- free_p(bp);
- return -1;
- }
- icmp.type = type;
- icmp.code = code;
- switch(uchar(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;
- }
- /* Now stick on the ICMP header */
- if((bp = htonicmp(&icmp,data)) == NULLBUF){
- free_p(data);
- return -1;
- }
- return 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(struct icmp *icmp, struct mbuf *data)
- {
- struct mbuf *bp;
- register char *cp;
- int16 checksum;
-
- if((bp = pushdown(data,ICMPLEN)) == NULLBUF)
- return NULLBUF;
- cp = bp->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);
-
- /* Compute checksum, and stash result */
- checksum = cksum(NULLHEADER,bp,len_mbuf(bp));
- cp = &bp->data[2];
- cp = put16(cp,checksum);
-
- return bp;
- }
- /* Pull off ICMP header */
- int ntohicmp(struct icmp *icmp, struct mbuf **bpp)
- {
- if(icmp == (struct icmp *)NULL)
- return -1;
- 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);
- return 0;
- }
-