Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"

typedef struct Hdr      Hdr;
struct Hdr
{       uchar   type;
        uchar   code;
        uchar   cksum[2];       /* Checksum */
        uchar   data[1];
};

enum
{
        ICMPLEN=        4,
};

enum
{
        Ot,     /* type */
        Op,     /* next protocol */
};

static Field p_fields[] = 
{
        {"t",           Fnum,   Ot,     "type", } ,
        {0}
};

enum
{
        EchoRep=        0,
        Unreachable=    3,
        SrcQuench=      4,
        Redirect=       5,
        EchoReq=        8,
        TimeExceed=     11,
        ParamProb=      12,
        TSreq=          13,
        TSrep=          14,
        InfoReq=        15,
        InfoRep=        16,
};

static Mux p_mux[] =
{
        {"ip",  Unreachable, },
        {"ip",  SrcQuench, },
        {"ip",  Redirect, },
        {"ip",  TimeExceed, },
        {"ip",  ParamProb, },
        {0},
};

char *icmpmsg[256] =
{
[EchoRep]       "EchoRep",
[Unreachable]   "Unreachable",
[SrcQuench]     "SrcQuench",
[Redirect]      "Redirect",
[EchoReq]       "EchoReq",
[TimeExceed]    "TimeExceed",
[ParamProb]     "ParamProb",
[TSreq]         "TSreq",
[TSrep]         "TSrep",
[InfoReq]       "InfoReq",
[InfoRep]       "InfoRep",
};

static void
p_compile(Filter *f)
{
        if(f->op == '='){
                compile_cmp(icmp.name, f, p_fields);
                return;
        }
        if(strcmp(f->s, "ip") == 0){
                f->pr = p_mux->pr;
                f->subop = Op;
                return;
        }
        sysfatal("unknown icmp field or protocol: %s", f->s);
}

static int
p_filter(Filter *f, Msg *m)
{
        Hdr *h;

        if(m->pe - m->ps < ICMPLEN)
                return 0;

        h = (Hdr*)m->ps;
        m->ps += ICMPLEN;

        switch(f->subop){
        case Ot:
                if(h->type == f->ulv)
                        return 1;
                break;
        case Op:
                switch(h->type){
                case Unreachable:
                case TimeExceed:
                case SrcQuench:
                case Redirect:
                case ParamProb:
                        m->ps += 4;
                        return 1;
                }
        }
        return 0;
}

static int
p_seprint(Msg *m)
{
        Hdr *h;
        char *tn;
        char *p = m->p;
        char *e = m->e;
        ushort cksum2, cksum;

        h = (Hdr*)m->ps;
        m->ps += ICMPLEN;
        m->pr = &dump;

        if(m->pe - m->ps < ICMPLEN)
                return -1;

        tn = icmpmsg[h->type];
        if(tn == nil)
                p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
                        h->code, (ushort)NetS(h->cksum));
        else
                p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
                        h->code, (ushort)NetS(h->cksum));
        if(Cflag){
                cksum = NetS(h->cksum);
                h->cksum[0] = 0;
                h->cksum[1] = 0;
                cksum2 = ~ptclbsum((uchar*)h, m->pe - m->ps + ICMPLEN) & 0xffff;
                if(cksum != cksum2)
                        p = seprint(p,e, " !ck=%4.4ux", cksum2);
        }
        switch(h->type){
        case EchoRep:
        case EchoReq:
                m->ps += 4;
                p = seprint(p, e, " id=%ux seq=%ux",
                        NetS(h->data), NetS(h->data+2));
                break;
        case TSreq:
        case TSrep:
                m->ps += 12;
                p = seprint(p, e, " orig=%ud rcv=%ux xmt=%ux",
                        NetL(h->data), NetL(h->data+4),
                        NetL(h->data+8));
                m->pr = nil;
                break;
        case InfoReq:
        case InfoRep:
                break;
        case Unreachable:
        case TimeExceed:
        case SrcQuench:
                m->ps += 4;
                m->pr = &ip;
                break;
        case Redirect:
                m->ps += 4;
                m->pr = &ip;
                p = seprint(p, e, "gw=%V", h->data);
                break;
        case ParamProb:
                m->ps += 4;
                m->pr = &ip;
                p = seprint(p, e, "ptr=%2.2ux", h->data[0]);
                break;
        }
        m->p = p;
        return 0;
}

Proto icmp =
{
        "icmp",
        p_compile,
        p_filter,
        p_seprint,
        p_mux,
        "%lud",
        p_fields,
        defaultframer,
};