#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[236] =
{
[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,
};
|