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 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* 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 1307dd7cddfSDavid du Colombier icmpstate(Conv *c, char *state, int n) 1317dd7cddfSDavid du Colombier { 1327dd7cddfSDavid du Colombier USED(c); 1337dd7cddfSDavid du Colombier return snprint(state, n, "%s", "Datagram"); 1347dd7cddfSDavid du Colombier } 1357dd7cddfSDavid du Colombier 1363ff48bf5SDavid du Colombier extern char* 1377dd7cddfSDavid du Colombier icmpannounce(Conv *c, char **argv, int argc) 1387dd7cddfSDavid du Colombier { 1397dd7cddfSDavid du Colombier char *e; 1407dd7cddfSDavid du Colombier 1417dd7cddfSDavid du Colombier e = Fsstdannounce(c, argv, argc); 1429a747e4fSDavid du Colombier if(e != nil) 1437dd7cddfSDavid du Colombier return e; 1447dd7cddfSDavid du Colombier Fsconnected(c, nil); 1457dd7cddfSDavid du Colombier 1467dd7cddfSDavid du Colombier return nil; 1477dd7cddfSDavid du Colombier } 1487dd7cddfSDavid du Colombier 1493ff48bf5SDavid du Colombier extern void 1507dd7cddfSDavid du Colombier icmpclose(Conv *c) 1517dd7cddfSDavid du Colombier { 1527dd7cddfSDavid du Colombier qclose(c->rq); 1537dd7cddfSDavid du Colombier qclose(c->wq); 1547dd7cddfSDavid du Colombier ipmove(c->laddr, IPnoaddr); 1557dd7cddfSDavid du Colombier ipmove(c->raddr, IPnoaddr); 1567dd7cddfSDavid du Colombier c->lport = 0; 1577dd7cddfSDavid du Colombier } 1587dd7cddfSDavid du Colombier 1597dd7cddfSDavid du Colombier static void 160e6c6b7f8SDavid du Colombier icmpkick(void *x, Block *bp) 1617dd7cddfSDavid du Colombier { 1623ff48bf5SDavid du Colombier Conv *c = x; 1637dd7cddfSDavid du Colombier Icmp *p; 1647dd7cddfSDavid du Colombier Icmppriv *ipriv; 1657dd7cddfSDavid du Colombier 1667dd7cddfSDavid du Colombier if(bp == nil) 1677dd7cddfSDavid du Colombier return; 1687dd7cddfSDavid du Colombier 1697dd7cddfSDavid du Colombier if(blocklen(bp) < ICMP_IPSIZE + ICMP_HDRSIZE){ 1707dd7cddfSDavid du Colombier freeblist(bp); 1717dd7cddfSDavid du Colombier return; 1727dd7cddfSDavid du Colombier } 1737dd7cddfSDavid du Colombier p = (Icmp *)(bp->rp); 1743ff48bf5SDavid du Colombier p->vihl = IP_VER4; 1757dd7cddfSDavid du Colombier ipriv = c->p->priv; 1767dd7cddfSDavid du Colombier if(p->type <= Maxtype) 1777dd7cddfSDavid du Colombier ipriv->out[p->type]++; 1787dd7cddfSDavid du Colombier 1797dd7cddfSDavid du Colombier v6tov4(p->dst, c->raddr); 1807dd7cddfSDavid du Colombier v6tov4(p->src, c->laddr); 1817dd7cddfSDavid du Colombier p->proto = IP_ICMPPROTO; 1827dd7cddfSDavid du Colombier hnputs(p->icmpid, c->lport); 1837dd7cddfSDavid du Colombier memset(p->cksum, 0, sizeof(p->cksum)); 1847dd7cddfSDavid du Colombier hnputs(p->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE)); 18559cc4ca5SDavid du Colombier ipriv->stats[OutMsgs]++; 186*a6a9e072SDavid du Colombier ipoput4(c->p->f, bp, 0, c->ttl, c->tos, nil); 1877dd7cddfSDavid du Colombier } 1887dd7cddfSDavid du Colombier 1897dd7cddfSDavid du Colombier extern void 1903ff48bf5SDavid du Colombier icmpttlexceeded(Fs *f, uchar *ia, Block *bp) 1917dd7cddfSDavid du Colombier { 1927dd7cddfSDavid du Colombier Block *nbp; 1937dd7cddfSDavid du Colombier Icmp *p, *np; 1947dd7cddfSDavid du Colombier 1957dd7cddfSDavid du Colombier p = (Icmp *)bp->rp; 1967dd7cddfSDavid du Colombier 1977dd7cddfSDavid du Colombier netlog(f, Logicmp, "sending icmpttlexceeded -> %V\n", p->src); 1987dd7cddfSDavid du Colombier nbp = allocb(ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8); 1997dd7cddfSDavid du Colombier nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8; 2007dd7cddfSDavid du Colombier np = (Icmp *)nbp->rp; 201d9306527SDavid du Colombier np->vihl = IP_VER4; 2027dd7cddfSDavid du Colombier memmove(np->dst, p->src, sizeof(np->dst)); 2033ff48bf5SDavid du Colombier v6tov4(np->src, ia); 2047dd7cddfSDavid du Colombier memmove(np->data, bp->rp, ICMP_IPSIZE + 8); 2057dd7cddfSDavid du Colombier np->type = TimeExceed; 2067dd7cddfSDavid du Colombier np->code = 0; 2077dd7cddfSDavid du Colombier np->proto = IP_ICMPPROTO; 2087dd7cddfSDavid du Colombier hnputs(np->icmpid, 0); 2097dd7cddfSDavid du Colombier hnputs(np->seq, 0); 2107dd7cddfSDavid du Colombier memset(np->cksum, 0, sizeof(np->cksum)); 2117dd7cddfSDavid du Colombier hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE)); 212*a6a9e072SDavid du Colombier ipoput4(f, nbp, 0, MAXTTL, DFLTTOS, nil); 2137dd7cddfSDavid du Colombier 2147dd7cddfSDavid du Colombier } 2157dd7cddfSDavid du Colombier 216d9306527SDavid du Colombier static void 217d9306527SDavid du Colombier icmpunreachable(Fs *f, Block *bp, int code, int seq) 2187dd7cddfSDavid du Colombier { 2197dd7cddfSDavid du Colombier Block *nbp; 2207dd7cddfSDavid du Colombier Icmp *p, *np; 2217dd7cddfSDavid du Colombier int i; 2227dd7cddfSDavid du Colombier uchar addr[IPaddrlen]; 2237dd7cddfSDavid du Colombier 2247dd7cddfSDavid du Colombier p = (Icmp *)bp->rp; 2257dd7cddfSDavid du Colombier 2267dd7cddfSDavid du Colombier /* only do this for unicast sources and destinations */ 2277dd7cddfSDavid du Colombier v4tov6(addr, p->dst); 2287dd7cddfSDavid du Colombier i = ipforme(f, addr); 2297dd7cddfSDavid du Colombier if((i&Runi) == 0) 2307dd7cddfSDavid du Colombier return; 2317dd7cddfSDavid du Colombier v4tov6(addr, p->src); 2327dd7cddfSDavid du Colombier i = ipforme(f, addr); 2337dd7cddfSDavid du Colombier if(i != 0 && (i&Runi) == 0) 2347dd7cddfSDavid du Colombier return; 2357dd7cddfSDavid du Colombier 2367dd7cddfSDavid du Colombier netlog(f, Logicmp, "sending icmpnoconv -> %V\n", p->src); 2377dd7cddfSDavid du Colombier nbp = allocb(ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8); 2387dd7cddfSDavid du Colombier nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8; 2397dd7cddfSDavid du Colombier np = (Icmp *)nbp->rp; 240d9306527SDavid du Colombier np->vihl = IP_VER4; 2417dd7cddfSDavid du Colombier memmove(np->dst, p->src, sizeof(np->dst)); 2427dd7cddfSDavid du Colombier memmove(np->src, p->dst, sizeof(np->src)); 2437dd7cddfSDavid du Colombier memmove(np->data, bp->rp, ICMP_IPSIZE + 8); 2447dd7cddfSDavid du Colombier np->type = Unreachable; 245d9306527SDavid du Colombier np->code = code; 2467dd7cddfSDavid du Colombier np->proto = IP_ICMPPROTO; 2477dd7cddfSDavid du Colombier hnputs(np->icmpid, 0); 248d9306527SDavid du Colombier hnputs(np->seq, seq); 2497dd7cddfSDavid du Colombier memset(np->cksum, 0, sizeof(np->cksum)); 2507dd7cddfSDavid du Colombier hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE)); 251*a6a9e072SDavid du Colombier ipoput4(f, nbp, 0, MAXTTL, DFLTTOS, nil); 2527dd7cddfSDavid du Colombier } 2537dd7cddfSDavid du Colombier 254d9306527SDavid du Colombier extern void 255d9306527SDavid du Colombier icmpnoconv(Fs *f, Block *bp) 256d9306527SDavid du Colombier { 257d9306527SDavid du Colombier icmpunreachable(f, bp, 3, 0); 258d9306527SDavid du Colombier } 259d9306527SDavid du Colombier 260d9306527SDavid du Colombier extern void 261d9306527SDavid du Colombier icmpcantfrag(Fs *f, Block *bp, int mtu) 262d9306527SDavid du Colombier { 263d9306527SDavid du Colombier icmpunreachable(f, bp, 4, mtu); 264d9306527SDavid du Colombier } 265d9306527SDavid du Colombier 2667dd7cddfSDavid du Colombier static void 2677dd7cddfSDavid du Colombier goticmpkt(Proto *icmp, Block *bp) 2687dd7cddfSDavid du Colombier { 2697dd7cddfSDavid du Colombier Conv **c, *s; 2707dd7cddfSDavid du Colombier Icmp *p; 2717dd7cddfSDavid du Colombier uchar dst[IPaddrlen]; 2727dd7cddfSDavid du Colombier ushort recid; 2737dd7cddfSDavid du Colombier 2747dd7cddfSDavid du Colombier p = (Icmp *) bp->rp; 2757dd7cddfSDavid du Colombier v4tov6(dst, p->src); 2767dd7cddfSDavid du Colombier recid = nhgets(p->icmpid); 2777dd7cddfSDavid du Colombier 2787dd7cddfSDavid du Colombier for(c = icmp->conv; *c; c++) { 2797dd7cddfSDavid du Colombier s = *c; 2807dd7cddfSDavid du Colombier if(s->lport == recid) 2817dd7cddfSDavid du Colombier if(ipcmp(s->raddr, dst) == 0){ 2827dd7cddfSDavid du Colombier bp = concatblock(bp); 2837dd7cddfSDavid du Colombier if(bp != nil) 2847dd7cddfSDavid du Colombier qpass(s->rq, bp); 2857dd7cddfSDavid du Colombier return; 2867dd7cddfSDavid du Colombier } 2877dd7cddfSDavid du Colombier } 2887dd7cddfSDavid du Colombier freeblist(bp); 2897dd7cddfSDavid du Colombier } 2907dd7cddfSDavid du Colombier 2917dd7cddfSDavid du Colombier static Block * 2927dd7cddfSDavid du Colombier mkechoreply(Block *bp) 2937dd7cddfSDavid du Colombier { 2947dd7cddfSDavid du Colombier Icmp *q; 2957dd7cddfSDavid du Colombier uchar ip[4]; 2967dd7cddfSDavid du Colombier 2977dd7cddfSDavid du Colombier q = (Icmp *)bp->rp; 2983ff48bf5SDavid du Colombier q->vihl = IP_VER4; 2997dd7cddfSDavid du Colombier memmove(ip, q->src, sizeof(q->dst)); 3007dd7cddfSDavid du Colombier memmove(q->src, q->dst, sizeof(q->src)); 3017dd7cddfSDavid du Colombier memmove(q->dst, ip, sizeof(q->dst)); 3027dd7cddfSDavid du Colombier q->type = EchoReply; 3037dd7cddfSDavid du Colombier memset(q->cksum, 0, sizeof(q->cksum)); 3047dd7cddfSDavid du Colombier hnputs(q->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE)); 3057dd7cddfSDavid du Colombier 3067dd7cddfSDavid du Colombier return bp; 3077dd7cddfSDavid du Colombier } 3087dd7cddfSDavid du Colombier 3097dd7cddfSDavid du Colombier static char *unreachcode[] = 3107dd7cddfSDavid du Colombier { 3117dd7cddfSDavid du Colombier [0] "net unreachable", 3127dd7cddfSDavid du Colombier [1] "host unreachable", 3137dd7cddfSDavid du Colombier [2] "protocol unreachable", 3147dd7cddfSDavid du Colombier [3] "port unreachable", 3153ff48bf5SDavid du Colombier [4] "fragmentation needed and DF set", 3167dd7cddfSDavid du Colombier [5] "source route failed", 3177dd7cddfSDavid du Colombier }; 3187dd7cddfSDavid du Colombier 3197dd7cddfSDavid du Colombier static void 3209a747e4fSDavid du Colombier icmpiput(Proto *icmp, Ipifc*, Block *bp) 3217dd7cddfSDavid du Colombier { 3227dd7cddfSDavid du Colombier int n, iplen; 3237dd7cddfSDavid du Colombier Icmp *p; 3247dd7cddfSDavid du Colombier Block *r; 3257dd7cddfSDavid du Colombier Proto *pr; 3267dd7cddfSDavid du Colombier char *msg; 3277dd7cddfSDavid du Colombier char m2[128]; 3287dd7cddfSDavid du Colombier Icmppriv *ipriv; 3297dd7cddfSDavid du Colombier 3307dd7cddfSDavid du Colombier ipriv = icmp->priv; 3317dd7cddfSDavid du Colombier 33259cc4ca5SDavid du Colombier ipriv->stats[InMsgs]++; 3337dd7cddfSDavid du Colombier 3347dd7cddfSDavid du Colombier p = (Icmp *)bp->rp; 3357dd7cddfSDavid du Colombier netlog(icmp->f, Logicmp, "icmpiput %d %d\n", p->type, p->code); 3367dd7cddfSDavid du Colombier n = blocklen(bp); 3377dd7cddfSDavid du Colombier if(n < ICMP_IPSIZE+ICMP_HDRSIZE){ 33859cc4ca5SDavid du Colombier ipriv->stats[InErrors]++; 33959cc4ca5SDavid du Colombier ipriv->stats[HlenErrs]++; 3407dd7cddfSDavid du Colombier netlog(icmp->f, Logicmp, "icmp hlen %d\n", n); 3417dd7cddfSDavid du Colombier goto raise; 3427dd7cddfSDavid du Colombier } 3437dd7cddfSDavid du Colombier iplen = nhgets(p->length); 3447dd7cddfSDavid du Colombier if(iplen > n || (iplen % 1)){ 34559cc4ca5SDavid du Colombier ipriv->stats[LenErrs]++; 34659cc4ca5SDavid du Colombier ipriv->stats[InErrors]++; 3477dd7cddfSDavid du Colombier netlog(icmp->f, Logicmp, "icmp length %d\n", iplen); 3487dd7cddfSDavid du Colombier goto raise; 3497dd7cddfSDavid du Colombier } 3507dd7cddfSDavid du Colombier if(ptclcsum(bp, ICMP_IPSIZE, iplen - ICMP_IPSIZE)){ 35159cc4ca5SDavid du Colombier ipriv->stats[InErrors]++; 35259cc4ca5SDavid du Colombier ipriv->stats[CsumErrs]++; 3537dd7cddfSDavid du Colombier netlog(icmp->f, Logicmp, "icmp checksum error\n"); 3547dd7cddfSDavid du Colombier goto raise; 3557dd7cddfSDavid du Colombier } 3567dd7cddfSDavid du Colombier if(p->type <= Maxtype) 3577dd7cddfSDavid du Colombier ipriv->in[p->type]++; 3587dd7cddfSDavid du Colombier 3597dd7cddfSDavid du Colombier switch(p->type) { 3607dd7cddfSDavid du Colombier case EchoRequest: 3613ff48bf5SDavid du Colombier if (iplen < n) 3623ff48bf5SDavid du Colombier bp = trimblock(bp, 0, iplen); 3637dd7cddfSDavid du Colombier r = mkechoreply(bp); 3647dd7cddfSDavid du Colombier ipriv->out[EchoReply]++; 365*a6a9e072SDavid du Colombier ipoput4(icmp->f, r, 0, MAXTTL, DFLTTOS, nil); 3667dd7cddfSDavid du Colombier break; 3677dd7cddfSDavid du Colombier case Unreachable: 3683ff48bf5SDavid du Colombier if(p->code > 5 || p->code < 0) 3697dd7cddfSDavid du Colombier msg = unreachcode[1]; 3703ff48bf5SDavid du Colombier else 3717dd7cddfSDavid du Colombier msg = unreachcode[p->code]; 3727dd7cddfSDavid du Colombier 3737dd7cddfSDavid du Colombier bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE; 3749a747e4fSDavid du Colombier if(blocklen(bp) < MinAdvise){ 37559cc4ca5SDavid du Colombier ipriv->stats[LenErrs]++; 3767dd7cddfSDavid du Colombier goto raise; 3777dd7cddfSDavid du Colombier } 3787dd7cddfSDavid du Colombier p = (Icmp *)bp->rp; 3797dd7cddfSDavid du Colombier pr = Fsrcvpcolx(icmp->f, p->proto); 3807dd7cddfSDavid du Colombier if(pr != nil && pr->advise != nil) { 3817dd7cddfSDavid du Colombier (*pr->advise)(pr, bp, msg); 3827dd7cddfSDavid du Colombier return; 3837dd7cddfSDavid du Colombier } 3847dd7cddfSDavid du Colombier 3857dd7cddfSDavid du Colombier bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE; 3867dd7cddfSDavid du Colombier goticmpkt(icmp, bp); 3877dd7cddfSDavid du Colombier break; 3887dd7cddfSDavid du Colombier case TimeExceed: 3897dd7cddfSDavid du Colombier if(p->code == 0){ 3907dd7cddfSDavid du Colombier sprint(m2, "ttl exceeded at %V", p->src); 3917dd7cddfSDavid du Colombier 3927dd7cddfSDavid du Colombier bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE; 3939a747e4fSDavid du Colombier if(blocklen(bp) < MinAdvise){ 39459cc4ca5SDavid du Colombier ipriv->stats[LenErrs]++; 3957dd7cddfSDavid du Colombier goto raise; 3967dd7cddfSDavid du Colombier } 3977dd7cddfSDavid du Colombier p = (Icmp *)bp->rp; 3987dd7cddfSDavid du Colombier pr = Fsrcvpcolx(icmp->f, p->proto); 3997dd7cddfSDavid du Colombier if(pr != nil && pr->advise != nil) { 4007dd7cddfSDavid du Colombier (*pr->advise)(pr, bp, m2); 4017dd7cddfSDavid du Colombier return; 4027dd7cddfSDavid du Colombier } 4039a747e4fSDavid du Colombier bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE; 4047dd7cddfSDavid du Colombier } 4057dd7cddfSDavid du Colombier 4067dd7cddfSDavid du Colombier goticmpkt(icmp, bp); 4077dd7cddfSDavid du Colombier break; 4087dd7cddfSDavid du Colombier default: 4097dd7cddfSDavid du Colombier goticmpkt(icmp, bp); 4107dd7cddfSDavid du Colombier break; 4117dd7cddfSDavid du Colombier } 4127dd7cddfSDavid du Colombier return; 4137dd7cddfSDavid du Colombier 4147dd7cddfSDavid du Colombier raise: 4157dd7cddfSDavid du Colombier freeblist(bp); 4167dd7cddfSDavid du Colombier } 4177dd7cddfSDavid du Colombier 4187dd7cddfSDavid du Colombier void 4197dd7cddfSDavid du Colombier icmpadvise(Proto *icmp, Block *bp, char *msg) 4207dd7cddfSDavid du Colombier { 4217dd7cddfSDavid du Colombier Conv **c, *s; 4227dd7cddfSDavid du Colombier Icmp *p; 4237dd7cddfSDavid du Colombier uchar dst[IPaddrlen]; 4247dd7cddfSDavid du Colombier ushort recid; 4257dd7cddfSDavid du Colombier 4267dd7cddfSDavid du Colombier p = (Icmp *) bp->rp; 4277dd7cddfSDavid du Colombier v4tov6(dst, p->dst); 4287dd7cddfSDavid du Colombier recid = nhgets(p->icmpid); 4297dd7cddfSDavid du Colombier 4307dd7cddfSDavid du Colombier for(c = icmp->conv; *c; c++) { 4317dd7cddfSDavid du Colombier s = *c; 4327dd7cddfSDavid du Colombier if(s->lport == recid) 4337dd7cddfSDavid du Colombier if(ipcmp(s->raddr, dst) == 0){ 4347dd7cddfSDavid du Colombier qhangup(s->rq, msg); 4357dd7cddfSDavid du Colombier qhangup(s->wq, msg); 4367dd7cddfSDavid du Colombier break; 4377dd7cddfSDavid du Colombier } 4387dd7cddfSDavid du Colombier } 4397dd7cddfSDavid du Colombier freeblist(bp); 4407dd7cddfSDavid du Colombier } 4417dd7cddfSDavid du Colombier 4427dd7cddfSDavid du Colombier int 4437dd7cddfSDavid du Colombier icmpstats(Proto *icmp, char *buf, int len) 4447dd7cddfSDavid du Colombier { 44559cc4ca5SDavid du Colombier Icmppriv *priv; 44659cc4ca5SDavid du Colombier char *p, *e; 44759cc4ca5SDavid du Colombier int i; 4487dd7cddfSDavid du Colombier 44959cc4ca5SDavid du Colombier priv = icmp->priv; 45059cc4ca5SDavid du Colombier p = buf; 45159cc4ca5SDavid du Colombier e = p+len; 45259cc4ca5SDavid du Colombier for(i = 0; i < Nstats; i++) 45359cc4ca5SDavid du Colombier p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]); 45459cc4ca5SDavid du Colombier for(i = 0; i <= Maxtype; i++){ 45559cc4ca5SDavid du Colombier if(icmpnames[i]) 45659cc4ca5SDavid du Colombier p = seprint(p, e, "%s: %lud %lud\n", icmpnames[i], priv->in[i], priv->out[i]); 45759cc4ca5SDavid du Colombier else 45859cc4ca5SDavid du Colombier p = seprint(p, e, "%d: %lud %lud\n", i, priv->in[i], priv->out[i]); 45959cc4ca5SDavid du Colombier } 46059cc4ca5SDavid du Colombier return p - buf; 4617dd7cddfSDavid du Colombier } 4627dd7cddfSDavid du Colombier 4637dd7cddfSDavid du Colombier void 4647dd7cddfSDavid du Colombier icmpinit(Fs *fs) 4657dd7cddfSDavid du Colombier { 4667dd7cddfSDavid du Colombier Proto *icmp; 4677dd7cddfSDavid du Colombier 4687dd7cddfSDavid du Colombier icmp = smalloc(sizeof(Proto)); 4697dd7cddfSDavid du Colombier icmp->priv = smalloc(sizeof(Icmppriv)); 4707dd7cddfSDavid du Colombier icmp->name = "icmp"; 4717dd7cddfSDavid du Colombier icmp->connect = icmpconnect; 4727dd7cddfSDavid du Colombier icmp->announce = icmpannounce; 4737dd7cddfSDavid du Colombier icmp->state = icmpstate; 4747dd7cddfSDavid du Colombier icmp->create = icmpcreate; 4757dd7cddfSDavid du Colombier icmp->close = icmpclose; 4767dd7cddfSDavid du Colombier icmp->rcv = icmpiput; 4777dd7cddfSDavid du Colombier icmp->stats = icmpstats; 4787dd7cddfSDavid du Colombier icmp->ctl = nil; 4797dd7cddfSDavid du Colombier icmp->advise = icmpadvise; 4807dd7cddfSDavid du Colombier icmp->gc = nil; 4817dd7cddfSDavid du Colombier icmp->ipproto = IP_ICMPPROTO; 4827dd7cddfSDavid du Colombier icmp->nc = 16; 4837dd7cddfSDavid du Colombier icmp->ptclsize = 0; 4847dd7cddfSDavid du Colombier 4857dd7cddfSDavid du Colombier Fsproto(fs, icmp); 4867dd7cddfSDavid du Colombier } 487