#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr
{
uchar hrd[2];
uchar pro[2];
uchar hln;
uchar pln;
uchar op[2];
uchar sha[6];
uchar spa[4];
uchar tha[6];
uchar tpa[4];
};
enum
{
ARPLEN= 28,
};
enum
{
Ospa,
Otpa,
Ostpa,
Osha,
Otha,
Ostha,
Opa,
};
static Field p_fields[] =
{
{"spa", Fv4ip, Ospa, "protocol source", } ,
{"tpa", Fv4ip, Otpa, "protocol target", } ,
{"a", Fv4ip, Ostpa, "protocol source/target", } ,
{"sha", Fba, Osha, "hardware source", } ,
{"tha", Fba, Otha, "hardware target", } ,
{"ah", Fba, Ostha, "hardware source/target", } ,
{0}
};
static void
p_compile(Filter *f)
{
if(f->op == '='){
compile_cmp(arp.name, f, p_fields);
return;
}
sysfatal("unknown arp field: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
if(m->pe - m->ps < ARPLEN)
return 0;
h = (Hdr*)m->ps;
m->ps += ARPLEN;
switch(f->subop){
case Ospa:
return h->pln == 4 && NetL(h->spa) == f->ulv;
case Otpa:
return h->pln == 4 && NetL(h->tpa) == f->ulv;
case Ostpa:
return h->pln == 4 && (NetL(h->tpa) == f->ulv ||
NetL(h->spa) == f->ulv);
case Osha:
return memcmp(h->sha, f->a, h->hln) == 0;
case Otha:
return memcmp(h->tha, f->a, h->hln) == 0;
case Ostha:
return memcmp(h->sha, f->a, h->hln)==0
||memcmp(h->tha, f->a, h->hln)==0;
}
return 0;
}
static int
p_seprint(Msg *m)
{
Hdr *h;
if(m->pe - m->ps < ARPLEN)
return -1;
h = (Hdr*)m->ps;
m->ps += ARPLEN;
/* no next protocol */
m->pr = nil;
m->p = seprint(m->p, m->e, "op=%1d len=%1d/%1d spa=%V sha=%E tpa=%V tha=%E",
NetS(h->op), h->pln, h->hln,
h->spa, h->sha, h->tpa, h->tha);
return 0;
}
Proto arp =
{
"arp",
p_compile,
p_filter,
p_seprint,
nil,
nil,
p_fields,
defaultframer,
};
Proto rarp =
{
"rarp",
p_compile,
p_filter,
p_seprint,
nil,
nil,
p_fields,
defaultframer,
};
|