17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "../port/error.h"
77dd7cddfSDavid du Colombier
87dd7cddfSDavid du Colombier #include "ip.h"
97dd7cddfSDavid du Colombier
107dd7cddfSDavid du Colombier typedef struct Icmp {
117dd7cddfSDavid du Colombier uchar vihl; /* Version and header length */
127dd7cddfSDavid du Colombier uchar tos; /* Type of service */
137dd7cddfSDavid du Colombier uchar length[2]; /* packet length */
147dd7cddfSDavid du Colombier uchar id[2]; /* Identification */
157dd7cddfSDavid du Colombier uchar frag[2]; /* Fragment information */
167dd7cddfSDavid du Colombier uchar ttl; /* Time to live */
177dd7cddfSDavid du Colombier uchar proto; /* Protocol */
187dd7cddfSDavid du Colombier uchar ipcksum[2]; /* Header checksum */
197dd7cddfSDavid du Colombier uchar src[4]; /* Ip source */
207dd7cddfSDavid du Colombier uchar dst[4]; /* Ip destination */
217dd7cddfSDavid du Colombier uchar type;
227dd7cddfSDavid du Colombier uchar code;
237dd7cddfSDavid du Colombier uchar cksum[2];
247dd7cddfSDavid du Colombier uchar icmpid[2];
257dd7cddfSDavid du Colombier uchar seq[2];
267dd7cddfSDavid du Colombier uchar data[1];
277dd7cddfSDavid du Colombier } Icmp;
287dd7cddfSDavid du Colombier
297dd7cddfSDavid du Colombier enum { /* Packet Types */
307dd7cddfSDavid du Colombier EchoReply = 0,
317dd7cddfSDavid du Colombier Unreachable = 3,
327dd7cddfSDavid du Colombier SrcQuench = 4,
3359cc4ca5SDavid du Colombier Redirect = 5,
347dd7cddfSDavid du Colombier EchoRequest = 8,
357dd7cddfSDavid du Colombier TimeExceed = 11,
367dd7cddfSDavid du Colombier InParmProblem = 12,
377dd7cddfSDavid du Colombier Timestamp = 13,
387dd7cddfSDavid du Colombier TimestampReply = 14,
397dd7cddfSDavid du Colombier InfoRequest = 15,
407dd7cddfSDavid du Colombier InfoReply = 16,
417dd7cddfSDavid du Colombier AddrMaskRequest = 17,
427dd7cddfSDavid du Colombier AddrMaskReply = 18,
4359cc4ca5SDavid du Colombier
447dd7cddfSDavid du Colombier Maxtype = 18,
457dd7cddfSDavid du Colombier };
467dd7cddfSDavid du Colombier
479a747e4fSDavid du Colombier enum
489a747e4fSDavid du Colombier {
499a747e4fSDavid du Colombier MinAdvise = 24, /* minimum needed for us to advise another protocol */
509a747e4fSDavid du Colombier };
519a747e4fSDavid du Colombier
5259cc4ca5SDavid du Colombier char *icmpnames[Maxtype+1] =
5359cc4ca5SDavid du Colombier {
5459cc4ca5SDavid du Colombier [EchoReply] "EchoReply",
5559cc4ca5SDavid du Colombier [Unreachable] "Unreachable",
5659cc4ca5SDavid du Colombier [SrcQuench] "SrcQuench",
5759cc4ca5SDavid du Colombier [Redirect] "Redirect",
5859cc4ca5SDavid du Colombier [EchoRequest] "EchoRequest",
5959cc4ca5SDavid du Colombier [TimeExceed] "TimeExceed",
6059cc4ca5SDavid du Colombier [InParmProblem] "InParmProblem",
6159cc4ca5SDavid du Colombier [Timestamp] "Timestamp",
6259cc4ca5SDavid du Colombier [TimestampReply] "TimestampReply",
6359cc4ca5SDavid du Colombier [InfoRequest] "InfoRequest",
6459cc4ca5SDavid du Colombier [InfoReply] "InfoReply",
6559cc4ca5SDavid du Colombier [AddrMaskRequest] "AddrMaskRequest",
6659cc4ca5SDavid du Colombier [AddrMaskReply ] "AddrMaskReply ",
6759cc4ca5SDavid du Colombier };
6859cc4ca5SDavid du Colombier
697dd7cddfSDavid du Colombier enum {
707dd7cddfSDavid du Colombier IP_ICMPPROTO = 1,
717dd7cddfSDavid du Colombier ICMP_IPSIZE = 20,
727dd7cddfSDavid du Colombier ICMP_HDRSIZE = 8,
737dd7cddfSDavid du Colombier };
747dd7cddfSDavid du Colombier
7559cc4ca5SDavid du Colombier enum
767dd7cddfSDavid du Colombier {
7759cc4ca5SDavid du Colombier InMsgs,
7859cc4ca5SDavid du Colombier InErrors,
7959cc4ca5SDavid du Colombier OutMsgs,
8059cc4ca5SDavid du Colombier CsumErrs,
8159cc4ca5SDavid du Colombier LenErrs,
8259cc4ca5SDavid du Colombier HlenErrs,
8359cc4ca5SDavid du Colombier
8459cc4ca5SDavid du Colombier Nstats,
8559cc4ca5SDavid du Colombier };
8659cc4ca5SDavid du Colombier
8759cc4ca5SDavid du Colombier static char *statnames[Nstats] =
8859cc4ca5SDavid du Colombier {
8959cc4ca5SDavid du Colombier [InMsgs] "InMsgs",
9059cc4ca5SDavid du Colombier [InErrors] "InErrors",
9159cc4ca5SDavid du Colombier [OutMsgs] "OutMsgs",
9259cc4ca5SDavid du Colombier [CsumErrs] "CsumErrs",
9359cc4ca5SDavid du Colombier [LenErrs] "LenErrs",
9459cc4ca5SDavid du Colombier [HlenErrs] "HlenErrs",
957dd7cddfSDavid du Colombier };
967dd7cddfSDavid du Colombier
977dd7cddfSDavid du Colombier typedef struct Icmppriv Icmppriv;
987dd7cddfSDavid du Colombier struct Icmppriv
997dd7cddfSDavid du Colombier {
10059cc4ca5SDavid du Colombier ulong stats[Nstats];
1017dd7cddfSDavid du Colombier
10259cc4ca5SDavid du Colombier /* message counts */
1037dd7cddfSDavid du Colombier ulong in[Maxtype+1];
1047dd7cddfSDavid du Colombier ulong out[Maxtype+1];
1057dd7cddfSDavid du Colombier };
1067dd7cddfSDavid du Colombier
107e6c6b7f8SDavid du Colombier static void icmpkick(void *x, Block*);
1083ff48bf5SDavid du Colombier
1093ff48bf5SDavid du Colombier static void
icmpcreate(Conv * c)1103ff48bf5SDavid du Colombier icmpcreate(Conv *c)
1113ff48bf5SDavid du Colombier {
1123ff48bf5SDavid du Colombier c->rq = qopen(64*1024, Qmsg, 0, c);
113e6c6b7f8SDavid du Colombier c->wq = qbypass(icmpkick, c);
1143ff48bf5SDavid du Colombier }
1153ff48bf5SDavid du Colombier
1163ff48bf5SDavid du Colombier extern char*
icmpconnect(Conv * c,char ** argv,int argc)1177dd7cddfSDavid du Colombier icmpconnect(Conv *c, char **argv, int argc)
1187dd7cddfSDavid du Colombier {
1197dd7cddfSDavid du Colombier char *e;
1207dd7cddfSDavid du Colombier
1217dd7cddfSDavid du Colombier e = Fsstdconnect(c, argv, argc);
1223ff48bf5SDavid du Colombier if(e != nil)
1233ff48bf5SDavid du Colombier return e;
1247dd7cddfSDavid du Colombier Fsconnected(c, e);
1257dd7cddfSDavid du Colombier
1263ff48bf5SDavid du Colombier return nil;
1277dd7cddfSDavid du Colombier }
1287dd7cddfSDavid du Colombier
1293ff48bf5SDavid du Colombier extern int
icmpstate(Conv * c,char * state,int n)1307dd7cddfSDavid du Colombier icmpstate(Conv *c, char *state, int n)
1317dd7cddfSDavid du Colombier {
1327dd7cddfSDavid du Colombier USED(c);
13303a1fc68SDavid du Colombier return snprint(state, n, "%s qin %d qout %d\n",
1344fec87e5SDavid du Colombier "Datagram",
1354fec87e5SDavid du Colombier c->rq ? qlen(c->rq) : 0,
1364fec87e5SDavid du Colombier c->wq ? qlen(c->wq) : 0
1374fec87e5SDavid du Colombier );
1387dd7cddfSDavid du Colombier }
1397dd7cddfSDavid du Colombier
1403ff48bf5SDavid du Colombier extern char*
icmpannounce(Conv * c,char ** argv,int argc)1417dd7cddfSDavid du Colombier icmpannounce(Conv *c, char **argv, int argc)
1427dd7cddfSDavid du Colombier {
1437dd7cddfSDavid du Colombier char *e;
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier e = Fsstdannounce(c, argv, argc);
1469a747e4fSDavid du Colombier if(e != nil)
1477dd7cddfSDavid du Colombier return e;
1487dd7cddfSDavid du Colombier Fsconnected(c, nil);
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier return nil;
1517dd7cddfSDavid du Colombier }
1527dd7cddfSDavid du Colombier
1533ff48bf5SDavid du Colombier extern void
icmpclose(Conv * c)1547dd7cddfSDavid du Colombier icmpclose(Conv *c)
1557dd7cddfSDavid du Colombier {
1567dd7cddfSDavid du Colombier qclose(c->rq);
1577dd7cddfSDavid du Colombier qclose(c->wq);
1587dd7cddfSDavid du Colombier ipmove(c->laddr, IPnoaddr);
1597dd7cddfSDavid du Colombier ipmove(c->raddr, IPnoaddr);
1607dd7cddfSDavid du Colombier c->lport = 0;
1617dd7cddfSDavid du Colombier }
1627dd7cddfSDavid du Colombier
1637dd7cddfSDavid du Colombier static void
icmpkick(void * x,Block * bp)164e6c6b7f8SDavid du Colombier icmpkick(void *x, Block *bp)
1657dd7cddfSDavid du Colombier {
1663ff48bf5SDavid du Colombier Conv *c = x;
1677dd7cddfSDavid du Colombier Icmp *p;
1687dd7cddfSDavid du Colombier Icmppriv *ipriv;
1697dd7cddfSDavid du Colombier
1707dd7cddfSDavid du Colombier if(bp == nil)
1717dd7cddfSDavid du Colombier return;
1727dd7cddfSDavid du Colombier
1737dd7cddfSDavid du Colombier if(blocklen(bp) < ICMP_IPSIZE + ICMP_HDRSIZE){
1747dd7cddfSDavid du Colombier freeblist(bp);
1757dd7cddfSDavid du Colombier return;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier p = (Icmp *)(bp->rp);
1783ff48bf5SDavid du Colombier p->vihl = IP_VER4;
1797dd7cddfSDavid du Colombier ipriv = c->p->priv;
1807dd7cddfSDavid du Colombier if(p->type <= Maxtype)
1817dd7cddfSDavid du Colombier ipriv->out[p->type]++;
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier v6tov4(p->dst, c->raddr);
1847dd7cddfSDavid du Colombier v6tov4(p->src, c->laddr);
1857dd7cddfSDavid du Colombier p->proto = IP_ICMPPROTO;
1867dd7cddfSDavid du Colombier hnputs(p->icmpid, c->lport);
1877dd7cddfSDavid du Colombier memset(p->cksum, 0, sizeof(p->cksum));
1887dd7cddfSDavid du Colombier hnputs(p->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE));
18959cc4ca5SDavid du Colombier ipriv->stats[OutMsgs]++;
190a6a9e072SDavid du Colombier ipoput4(c->p->f, bp, 0, c->ttl, c->tos, nil);
1917dd7cddfSDavid du Colombier }
1927dd7cddfSDavid du Colombier
1937dd7cddfSDavid du Colombier extern void
icmpttlexceeded(Fs * f,uchar * ia,Block * bp)1943ff48bf5SDavid du Colombier icmpttlexceeded(Fs *f, uchar *ia, Block *bp)
1957dd7cddfSDavid du Colombier {
1967dd7cddfSDavid du Colombier Block *nbp;
1977dd7cddfSDavid du Colombier Icmp *p, *np;
1987dd7cddfSDavid du Colombier
1997dd7cddfSDavid du Colombier p = (Icmp *)bp->rp;
2007dd7cddfSDavid du Colombier
2017dd7cddfSDavid du Colombier netlog(f, Logicmp, "sending icmpttlexceeded -> %V\n", p->src);
2027dd7cddfSDavid du Colombier nbp = allocb(ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8);
2037dd7cddfSDavid du Colombier nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8;
2047dd7cddfSDavid du Colombier np = (Icmp *)nbp->rp;
205d9306527SDavid du Colombier np->vihl = IP_VER4;
2067dd7cddfSDavid du Colombier memmove(np->dst, p->src, sizeof(np->dst));
2073ff48bf5SDavid du Colombier v6tov4(np->src, ia);
2087dd7cddfSDavid du Colombier memmove(np->data, bp->rp, ICMP_IPSIZE + 8);
2097dd7cddfSDavid du Colombier np->type = TimeExceed;
2107dd7cddfSDavid du Colombier np->code = 0;
2117dd7cddfSDavid du Colombier np->proto = IP_ICMPPROTO;
2127dd7cddfSDavid du Colombier hnputs(np->icmpid, 0);
2137dd7cddfSDavid du Colombier hnputs(np->seq, 0);
2147dd7cddfSDavid du Colombier memset(np->cksum, 0, sizeof(np->cksum));
2157dd7cddfSDavid du Colombier hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE));
216a6a9e072SDavid du Colombier ipoput4(f, nbp, 0, MAXTTL, DFLTTOS, nil);
2177dd7cddfSDavid du Colombier
2187dd7cddfSDavid du Colombier }
2197dd7cddfSDavid du Colombier
220d9306527SDavid du Colombier static void
icmpunreachable(Fs * f,Block * bp,int code,int seq)221d9306527SDavid du Colombier icmpunreachable(Fs *f, Block *bp, int code, int seq)
2227dd7cddfSDavid du Colombier {
2237dd7cddfSDavid du Colombier Block *nbp;
2247dd7cddfSDavid du Colombier Icmp *p, *np;
2257dd7cddfSDavid du Colombier int i;
2267dd7cddfSDavid du Colombier uchar addr[IPaddrlen];
2277dd7cddfSDavid du Colombier
2287dd7cddfSDavid du Colombier p = (Icmp *)bp->rp;
2297dd7cddfSDavid du Colombier
2307dd7cddfSDavid du Colombier /* only do this for unicast sources and destinations */
2317dd7cddfSDavid du Colombier v4tov6(addr, p->dst);
2327dd7cddfSDavid du Colombier i = ipforme(f, addr);
2337dd7cddfSDavid du Colombier if((i&Runi) == 0)
2347dd7cddfSDavid du Colombier return;
2357dd7cddfSDavid du Colombier v4tov6(addr, p->src);
2367dd7cddfSDavid du Colombier i = ipforme(f, addr);
2377dd7cddfSDavid du Colombier if(i != 0 && (i&Runi) == 0)
2387dd7cddfSDavid du Colombier return;
2397dd7cddfSDavid du Colombier
2407dd7cddfSDavid du Colombier netlog(f, Logicmp, "sending icmpnoconv -> %V\n", p->src);
2417dd7cddfSDavid du Colombier nbp = allocb(ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8);
2427dd7cddfSDavid du Colombier nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8;
2437dd7cddfSDavid du Colombier np = (Icmp *)nbp->rp;
244d9306527SDavid du Colombier np->vihl = IP_VER4;
2457dd7cddfSDavid du Colombier memmove(np->dst, p->src, sizeof(np->dst));
2467dd7cddfSDavid du Colombier memmove(np->src, p->dst, sizeof(np->src));
2477dd7cddfSDavid du Colombier memmove(np->data, bp->rp, ICMP_IPSIZE + 8);
2487dd7cddfSDavid du Colombier np->type = Unreachable;
249d9306527SDavid du Colombier np->code = code;
2507dd7cddfSDavid du Colombier np->proto = IP_ICMPPROTO;
2517dd7cddfSDavid du Colombier hnputs(np->icmpid, 0);
252d9306527SDavid du Colombier hnputs(np->seq, seq);
2537dd7cddfSDavid du Colombier memset(np->cksum, 0, sizeof(np->cksum));
2547dd7cddfSDavid du Colombier hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE));
255a6a9e072SDavid du Colombier ipoput4(f, nbp, 0, MAXTTL, DFLTTOS, nil);
2567dd7cddfSDavid du Colombier }
2577dd7cddfSDavid du Colombier
258d9306527SDavid du Colombier extern void
icmpnoconv(Fs * f,Block * bp)259d9306527SDavid du Colombier icmpnoconv(Fs *f, Block *bp)
260d9306527SDavid du Colombier {
261d9306527SDavid du Colombier icmpunreachable(f, bp, 3, 0);
262d9306527SDavid du Colombier }
263d9306527SDavid du Colombier
264d9306527SDavid du Colombier extern void
icmpcantfrag(Fs * f,Block * bp,int mtu)265d9306527SDavid du Colombier icmpcantfrag(Fs *f, Block *bp, int mtu)
266d9306527SDavid du Colombier {
267d9306527SDavid du Colombier icmpunreachable(f, bp, 4, mtu);
268d9306527SDavid du Colombier }
269d9306527SDavid du Colombier
2707dd7cddfSDavid du Colombier static void
goticmpkt(Proto * icmp,Block * bp)2717dd7cddfSDavid du Colombier goticmpkt(Proto *icmp, Block *bp)
2727dd7cddfSDavid du Colombier {
2737dd7cddfSDavid du Colombier Conv **c, *s;
2747dd7cddfSDavid du Colombier Icmp *p;
2757dd7cddfSDavid du Colombier uchar dst[IPaddrlen];
2767dd7cddfSDavid du Colombier ushort recid;
2777dd7cddfSDavid du Colombier
2787dd7cddfSDavid du Colombier p = (Icmp *) bp->rp;
2797dd7cddfSDavid du Colombier v4tov6(dst, p->src);
2807dd7cddfSDavid du Colombier recid = nhgets(p->icmpid);
2817dd7cddfSDavid du Colombier
2827dd7cddfSDavid du Colombier for(c = icmp->conv; *c; c++) {
2837dd7cddfSDavid du Colombier s = *c;
2847dd7cddfSDavid du Colombier if(s->lport == recid)
2857dd7cddfSDavid du Colombier if(ipcmp(s->raddr, dst) == 0){
2867dd7cddfSDavid du Colombier bp = concatblock(bp);
2877dd7cddfSDavid du Colombier if(bp != nil)
2887dd7cddfSDavid du Colombier qpass(s->rq, bp);
2897dd7cddfSDavid du Colombier return;
2907dd7cddfSDavid du Colombier }
2917dd7cddfSDavid du Colombier }
2927dd7cddfSDavid du Colombier freeblist(bp);
2937dd7cddfSDavid du Colombier }
2947dd7cddfSDavid du Colombier
2957dd7cddfSDavid du Colombier static Block *
mkechoreply(Block * bp)2967dd7cddfSDavid du Colombier mkechoreply(Block *bp)
2977dd7cddfSDavid du Colombier {
2987dd7cddfSDavid du Colombier Icmp *q;
2997dd7cddfSDavid du Colombier uchar ip[4];
3007dd7cddfSDavid du Colombier
3017dd7cddfSDavid du Colombier q = (Icmp *)bp->rp;
3023ff48bf5SDavid du Colombier q->vihl = IP_VER4;
3037dd7cddfSDavid du Colombier memmove(ip, q->src, sizeof(q->dst));
3047dd7cddfSDavid du Colombier memmove(q->src, q->dst, sizeof(q->src));
3057dd7cddfSDavid du Colombier memmove(q->dst, ip, sizeof(q->dst));
3067dd7cddfSDavid du Colombier q->type = EchoReply;
3077dd7cddfSDavid du Colombier memset(q->cksum, 0, sizeof(q->cksum));
3087dd7cddfSDavid du Colombier hnputs(q->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE));
3097dd7cddfSDavid du Colombier
3107dd7cddfSDavid du Colombier return bp;
3117dd7cddfSDavid du Colombier }
3127dd7cddfSDavid du Colombier
3137dd7cddfSDavid du Colombier static char *unreachcode[] =
3147dd7cddfSDavid du Colombier {
3157dd7cddfSDavid du Colombier [0] "net unreachable",
3167dd7cddfSDavid du Colombier [1] "host unreachable",
3177dd7cddfSDavid du Colombier [2] "protocol unreachable",
3187dd7cddfSDavid du Colombier [3] "port unreachable",
3193ff48bf5SDavid du Colombier [4] "fragmentation needed and DF set",
3207dd7cddfSDavid du Colombier [5] "source route failed",
3217dd7cddfSDavid du Colombier };
3227dd7cddfSDavid du Colombier
3237dd7cddfSDavid du Colombier static void
icmpiput(Proto * icmp,Ipifc *,Block * bp)3249a747e4fSDavid du Colombier icmpiput(Proto *icmp, Ipifc*, Block *bp)
3257dd7cddfSDavid du Colombier {
3267dd7cddfSDavid du Colombier int n, iplen;
3277dd7cddfSDavid du Colombier Icmp *p;
3287dd7cddfSDavid du Colombier Block *r;
3297dd7cddfSDavid du Colombier Proto *pr;
3307dd7cddfSDavid du Colombier char *msg;
3317dd7cddfSDavid du Colombier char m2[128];
3327dd7cddfSDavid du Colombier Icmppriv *ipriv;
3337dd7cddfSDavid du Colombier
3347dd7cddfSDavid du Colombier ipriv = icmp->priv;
3357dd7cddfSDavid du Colombier
33659cc4ca5SDavid du Colombier ipriv->stats[InMsgs]++;
3377dd7cddfSDavid du Colombier
3387dd7cddfSDavid du Colombier p = (Icmp *)bp->rp;
339c6569576SDavid du Colombier netlog(icmp->f, Logicmp, "icmpiput %s (%d) %d\n",
340c6569576SDavid du Colombier (p->type < nelem(icmpnames)? icmpnames[p->type]: ""),
341c6569576SDavid du Colombier p->type, p->code);
3427dd7cddfSDavid du Colombier n = blocklen(bp);
3437dd7cddfSDavid du Colombier if(n < ICMP_IPSIZE+ICMP_HDRSIZE){
34459cc4ca5SDavid du Colombier ipriv->stats[InErrors]++;
34559cc4ca5SDavid du Colombier ipriv->stats[HlenErrs]++;
3467dd7cddfSDavid du Colombier netlog(icmp->f, Logicmp, "icmp hlen %d\n", n);
3477dd7cddfSDavid du Colombier goto raise;
3487dd7cddfSDavid du Colombier }
3497dd7cddfSDavid du Colombier iplen = nhgets(p->length);
3505acbe002SDavid du Colombier if(iplen > n){
35159cc4ca5SDavid du Colombier ipriv->stats[LenErrs]++;
35259cc4ca5SDavid du Colombier ipriv->stats[InErrors]++;
3537dd7cddfSDavid du Colombier netlog(icmp->f, Logicmp, "icmp length %d\n", iplen);
3547dd7cddfSDavid du Colombier goto raise;
3557dd7cddfSDavid du Colombier }
3567dd7cddfSDavid du Colombier if(ptclcsum(bp, ICMP_IPSIZE, iplen - ICMP_IPSIZE)){
35759cc4ca5SDavid du Colombier ipriv->stats[InErrors]++;
35859cc4ca5SDavid du Colombier ipriv->stats[CsumErrs]++;
3597dd7cddfSDavid du Colombier netlog(icmp->f, Logicmp, "icmp checksum error\n");
3607dd7cddfSDavid du Colombier goto raise;
3617dd7cddfSDavid du Colombier }
3627dd7cddfSDavid du Colombier if(p->type <= Maxtype)
3637dd7cddfSDavid du Colombier ipriv->in[p->type]++;
3647dd7cddfSDavid du Colombier
3657dd7cddfSDavid du Colombier switch(p->type) {
3667dd7cddfSDavid du Colombier case EchoRequest:
3673ff48bf5SDavid du Colombier if (iplen < n)
3683ff48bf5SDavid du Colombier bp = trimblock(bp, 0, iplen);
369*58da3067SDavid du Colombier r = mkechoreply(concatblock(bp));
3707dd7cddfSDavid du Colombier ipriv->out[EchoReply]++;
371a6a9e072SDavid du Colombier ipoput4(icmp->f, r, 0, MAXTTL, DFLTTOS, nil);
3727dd7cddfSDavid du Colombier break;
3737dd7cddfSDavid du Colombier case Unreachable:
374eb2d877eSDavid du Colombier if(p->code > 5)
3757dd7cddfSDavid du Colombier msg = unreachcode[1];
3763ff48bf5SDavid du Colombier else
3777dd7cddfSDavid du Colombier msg = unreachcode[p->code];
3787dd7cddfSDavid du Colombier
3797dd7cddfSDavid du Colombier bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
3809a747e4fSDavid du Colombier if(blocklen(bp) < MinAdvise){
38159cc4ca5SDavid du Colombier ipriv->stats[LenErrs]++;
3827dd7cddfSDavid du Colombier goto raise;
3837dd7cddfSDavid du Colombier }
3847dd7cddfSDavid du Colombier p = (Icmp *)bp->rp;
3857dd7cddfSDavid du Colombier pr = Fsrcvpcolx(icmp->f, p->proto);
3867dd7cddfSDavid du Colombier if(pr != nil && pr->advise != nil) {
3877dd7cddfSDavid du Colombier (*pr->advise)(pr, bp, msg);
3887dd7cddfSDavid du Colombier return;
3897dd7cddfSDavid du Colombier }
3907dd7cddfSDavid du Colombier
3917dd7cddfSDavid du Colombier bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE;
3927dd7cddfSDavid du Colombier goticmpkt(icmp, bp);
3937dd7cddfSDavid du Colombier break;
3947dd7cddfSDavid du Colombier case TimeExceed:
3957dd7cddfSDavid du Colombier if(p->code == 0){
3964e3613abSDavid du Colombier snprint(m2, sizeof m2, "ttl exceeded at %V", p->src);
3977dd7cddfSDavid du Colombier
3987dd7cddfSDavid du Colombier bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
3999a747e4fSDavid du Colombier if(blocklen(bp) < MinAdvise){
40059cc4ca5SDavid du Colombier ipriv->stats[LenErrs]++;
4017dd7cddfSDavid du Colombier goto raise;
4027dd7cddfSDavid du Colombier }
4037dd7cddfSDavid du Colombier p = (Icmp *)bp->rp;
4047dd7cddfSDavid du Colombier pr = Fsrcvpcolx(icmp->f, p->proto);
4057dd7cddfSDavid du Colombier if(pr != nil && pr->advise != nil) {
4067dd7cddfSDavid du Colombier (*pr->advise)(pr, bp, m2);
4077dd7cddfSDavid du Colombier return;
4087dd7cddfSDavid du Colombier }
4099a747e4fSDavid du Colombier bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE;
4107dd7cddfSDavid du Colombier }
4117dd7cddfSDavid du Colombier
4127dd7cddfSDavid du Colombier goticmpkt(icmp, bp);
4137dd7cddfSDavid du Colombier break;
4147dd7cddfSDavid du Colombier default:
4157dd7cddfSDavid du Colombier goticmpkt(icmp, bp);
4167dd7cddfSDavid du Colombier break;
4177dd7cddfSDavid du Colombier }
4187dd7cddfSDavid du Colombier return;
4197dd7cddfSDavid du Colombier
4207dd7cddfSDavid du Colombier raise:
4217dd7cddfSDavid du Colombier freeblist(bp);
4227dd7cddfSDavid du Colombier }
4237dd7cddfSDavid du Colombier
4247dd7cddfSDavid du Colombier void
icmpadvise(Proto * icmp,Block * bp,char * msg)4257dd7cddfSDavid du Colombier icmpadvise(Proto *icmp, Block *bp, char *msg)
4267dd7cddfSDavid du Colombier {
4277dd7cddfSDavid du Colombier Conv **c, *s;
4287dd7cddfSDavid du Colombier Icmp *p;
4297dd7cddfSDavid du Colombier uchar dst[IPaddrlen];
4307dd7cddfSDavid du Colombier ushort recid;
4317dd7cddfSDavid du Colombier
4327dd7cddfSDavid du Colombier p = (Icmp *) bp->rp;
4337dd7cddfSDavid du Colombier v4tov6(dst, p->dst);
4347dd7cddfSDavid du Colombier recid = nhgets(p->icmpid);
4357dd7cddfSDavid du Colombier
4367dd7cddfSDavid du Colombier for(c = icmp->conv; *c; c++) {
4377dd7cddfSDavid du Colombier s = *c;
4387dd7cddfSDavid du Colombier if(s->lport == recid)
4397dd7cddfSDavid du Colombier if(ipcmp(s->raddr, dst) == 0){
4407dd7cddfSDavid du Colombier qhangup(s->rq, msg);
4417dd7cddfSDavid du Colombier qhangup(s->wq, msg);
4427dd7cddfSDavid du Colombier break;
4437dd7cddfSDavid du Colombier }
4447dd7cddfSDavid du Colombier }
4457dd7cddfSDavid du Colombier freeblist(bp);
4467dd7cddfSDavid du Colombier }
4477dd7cddfSDavid du Colombier
4487dd7cddfSDavid du Colombier int
icmpstats(Proto * icmp,char * buf,int len)4497dd7cddfSDavid du Colombier icmpstats(Proto *icmp, char *buf, int len)
4507dd7cddfSDavid du Colombier {
45159cc4ca5SDavid du Colombier Icmppriv *priv;
45259cc4ca5SDavid du Colombier char *p, *e;
45359cc4ca5SDavid du Colombier int i;
4547dd7cddfSDavid du Colombier
45559cc4ca5SDavid du Colombier priv = icmp->priv;
45659cc4ca5SDavid du Colombier p = buf;
45759cc4ca5SDavid du Colombier e = p+len;
45859cc4ca5SDavid du Colombier for(i = 0; i < Nstats; i++)
45959cc4ca5SDavid du Colombier p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]);
46059cc4ca5SDavid du Colombier for(i = 0; i <= Maxtype; i++){
46159cc4ca5SDavid du Colombier if(icmpnames[i])
46259cc4ca5SDavid du Colombier p = seprint(p, e, "%s: %lud %lud\n", icmpnames[i], priv->in[i], priv->out[i]);
46359cc4ca5SDavid du Colombier else
46459cc4ca5SDavid du Colombier p = seprint(p, e, "%d: %lud %lud\n", i, priv->in[i], priv->out[i]);
46559cc4ca5SDavid du Colombier }
46659cc4ca5SDavid du Colombier return p - buf;
4677dd7cddfSDavid du Colombier }
4687dd7cddfSDavid du Colombier
4697dd7cddfSDavid du Colombier void
icmpinit(Fs * fs)4707dd7cddfSDavid du Colombier icmpinit(Fs *fs)
4717dd7cddfSDavid du Colombier {
4727dd7cddfSDavid du Colombier Proto *icmp;
4737dd7cddfSDavid du Colombier
4747dd7cddfSDavid du Colombier icmp = smalloc(sizeof(Proto));
4757dd7cddfSDavid du Colombier icmp->priv = smalloc(sizeof(Icmppriv));
4767dd7cddfSDavid du Colombier icmp->name = "icmp";
4777dd7cddfSDavid du Colombier icmp->connect = icmpconnect;
4787dd7cddfSDavid du Colombier icmp->announce = icmpannounce;
4797dd7cddfSDavid du Colombier icmp->state = icmpstate;
4807dd7cddfSDavid du Colombier icmp->create = icmpcreate;
4817dd7cddfSDavid du Colombier icmp->close = icmpclose;
4827dd7cddfSDavid du Colombier icmp->rcv = icmpiput;
4837dd7cddfSDavid du Colombier icmp->stats = icmpstats;
4847dd7cddfSDavid du Colombier icmp->ctl = nil;
4857dd7cddfSDavid du Colombier icmp->advise = icmpadvise;
4867dd7cddfSDavid du Colombier icmp->gc = nil;
4877dd7cddfSDavid du Colombier icmp->ipproto = IP_ICMPPROTO;
488ef53e415SDavid du Colombier icmp->nc = 128;
4897dd7cddfSDavid du Colombier icmp->ptclsize = 0;
4907dd7cddfSDavid du Colombier
4917dd7cddfSDavid du Colombier Fsproto(fs, icmp);
4927dd7cddfSDavid du Colombier }
493