URI: 
       tsnoopy: add support for wireless monitor mode packets - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 17b19538a48c036dbdc8817d233c0086f327485c
   DIR parent 7e36b43bba16df64a08c13358ba2a70ae9001770
  HTML Author: Russ Cox <rsc@swtch.com>
       Date:   Thu, 24 Jul 2008 08:04:02 -0700
       
       snoopy: add support for wireless monitor mode packets
       
       Diffstat:
         M src/cmd/ip/snoopy/dat.h             |       5 ++++-
         A src/cmd/ip/snoopy/llc.c             |     173 +++++++++++++++++++++++++++++++
         M src/cmd/ip/snoopy/mkfile            |       5 +++++
         A src/cmd/ip/snoopy/p80211.c          |     367 ++++++++++++++++++++++++++++++
         M src/cmd/ip/snoopy/protos.c          |       5 +++++
         M src/cmd/ip/snoopy/protos.h          |       5 +++++
         A src/cmd/ip/snoopy/radiotap.c        |     117 +++++++++++++++++++++++++++++++
         A src/cmd/ip/snoopy/snap.c            |     112 +++++++++++++++++++++++++++++++
         M src/cmd/ip/snoopy/udp.c             |       1 +
       
       9 files changed, 789 insertions(+), 1 deletion(-)
       ---
   DIR diff --git a/src/cmd/ip/snoopy/dat.h b/src/cmd/ip/snoopy/dat.h
       t@@ -6,7 +6,10 @@ typedef struct Proto Proto;
        
        #define NetS(x) ((((uchar*)x)[0]<<8) | ((uchar*)x)[1])
        #define Net3(x) ((((uchar*)x)[0]<<16) | (((uchar*)x)[1]<<8) | ((uchar*)x)[2])
       -#define NetL(x) ((((uchar*)x)[0]<<24) | (((uchar*)x)[1]<<16) | (((uchar*)x)[2]<<8) | ((uchar*)x)[3])
       +#define NetL(x) (((ulong)((((uchar*)x)[0]<<24) | (((uchar*)x)[1]<<16) | (((uchar*)x)[2]<<8) | ((uchar*)x)[3]))&0xFFFFFFFFU)
       +
       +#define LittleS(x) ((((uchar*)x)[1]<<8) | ((uchar*)x)[0])
       +#define LittleL(x) (((ulong)((((uchar*)x)[3]<<24) | (((uchar*)x)[2]<<16) | (((uchar*)x)[1]<<8) | ((uchar*)x)[0]))&0xFFFFFFFFU)
        
        /*
         *  one per protocol module
   DIR diff --git a/src/cmd/ip/snoopy/llc.c b/src/cmd/ip/snoopy/llc.c
       t@@ -0,0 +1,173 @@
       +/* 
       + * LLC.  Only enough to dispatch to SNAP and IP.
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +#include "dat.h"
       +#include "protos.h"
       +
       +enum
       +{
       +        UFmt = 3,
       +        Gsap = 1,
       +        IG = 1,
       +        SFmt = 1,
       +        UPoll = 0x10,
       +        IsPoll = 0x100,
       +        XidFi = 0x81,
       +        
       +        SapNull = 0,
       +        SapGlobal = 0xff,
       +        Sap8021BI = 0x02,
       +        Sap8021BG = 0x03,
       +        SapSNA = 0x04,
       +        SapIP = 0x06,
       +        SapProwayNM = 0x0e,
       +        Sap8021D = 0x42,
       +        SapRS511 = 0x4e,
       +        SapISO8208 = 0x7e,
       +        SapProway = 0x8e,
       +        SapSnap = 0xaa,
       +        SapIpx = 0xe0,
       +        SapNetbeui = 0xf0,
       +        SapIsons = 0xfe,
       +};
       +
       +static Mux p_mux[] =
       +{
       +// Linux gives llc -> snap not llc -> ip.
       +// If we don't tell snoopy about llc -> ip, then the default patterns
       +// like snoopy -h radiotap -f dns work better.
       +//        { "ip", SapIP },        
       +        { "snap", SapSnap },
       +        { 0 }
       +};
       +
       +typedef struct Hdr Hdr;
       +struct Hdr
       +{
       +        uchar dsap;
       +        uchar ssap;
       +        uchar dsapf;
       +        uchar ssapf;
       +        ushort ctl;
       +        uchar isu;
       +        int hdrlen;
       +};
       +
       +static int
       +unpackhdr(uchar *p, uchar *ep, Hdr *h)
       +{
       +        if(p+3 > ep)
       +                return -1;
       +        h->dsapf = p[0];
       +        h->dsap = h->dsapf & ~IG;
       +        h->ssapf = p[1];
       +        h->ssap = h->ssapf & ~Gsap;
       +        h->ctl = p[2];
       +        h->hdrlen = 3;
       +        if((h->ctl&UFmt) == UFmt)
       +                h->isu = 1;
       +        else{
       +                if(p+4 > ep)
       +                        return -1;
       +                h->hdrlen = 4;
       +                h->ctl = LittleS(p+2);
       +        }
       +        return 0;
       +}
       +
       +enum
       +{
       +        Ossap,
       +        Odsap,
       +        Ot,
       +};
       +
       +static Field p_fields[] =
       +{
       +        { "ssap",        Fnum,        Ossap,        "ssap" },
       +        { "dsap",        Fnum,        Odsap,        "dsap" },
       +        { 0 }
       +};
       +
       +static void
       +p_compile(Filter *f)
       +{
       +        Mux *m;
       +
       +        if(f->op == '='){
       +                compile_cmp(llc.name, f, p_fields);
       +                return;
       +        }
       +        for(m = p_mux; m->name != nil; m++){
       +                if(strcmp(f->s, m->name) == 0){
       +                        f->pr = m->pr;
       +                        f->ulv = m->val;
       +                        f->subop = Ot;
       +                        return;
       +                }
       +        }
       +        sysfatal("unknown llc field or protocol: %s", f->s);
       +}
       +
       +static int
       +p_filter(Filter *f, Msg *m)
       +{
       +        Hdr h;
       +
       +        memset(&h, 0, sizeof h);
       +        if(unpackhdr(m->ps, m->pe, &h) < 0)
       +                return 0;
       +        m->ps += h.hdrlen;
       +
       +        switch(f->subop){
       +        case Ossap:
       +                return f->ulv == h.ssap;
       +        case Odsap:
       +                return f->ulv == h.dsap;
       +        case Ot:
       +                return f->ulv == h.ssap && f->ulv == h.dsap;
       +        }
       +        return 0;
       +}
       +
       +static int
       +p_seprint(Msg *m)
       +{
       +        Hdr h;
       +        
       +        memset(&h, 0, sizeof h);
       +        if(unpackhdr(m->ps, m->pe, &h) < 0)
       +                return -1;
       +
       +        m->pr = &dump;
       +        m->p = seprint(m->p, m->e, "ssap=%02x dsap=%02x ctl=%04x", h.ssap, h.dsap, h.ctl);
       +        m->ps += h.hdrlen;
       +        m->pr = &dump;
       +        if(h.ssap == h.dsap){
       +                switch(h.ssap){
       +                case SapIP:
       +                        m->pr = &ip;
       +                        break;
       +                case SapSnap:
       +                        m->pr = &snap;
       +                        break;
       +                }
       +        }        
       +        return 0;
       +}
       +
       +Proto llc =
       +{
       +        "llc",
       +        p_compile,
       +        p_filter,
       +        p_seprint,
       +        p_mux,
       +        nil,
       +        nil,
       +        defaultframer
       +};
   DIR diff --git a/src/cmd/ip/snoopy/mkfile b/src/cmd/ip/snoopy/mkfile
       t@@ -27,6 +27,11 @@ PROTOS=\
                ppp_ipcp\
                pppoe_sess\
                pppoe_disc\
       +        dns\
       +        p80211\
       +        llc\
       +        radiotap\
       +        snap\
        
        POBJS=${PROTOS:%=%.$O}
        
   DIR diff --git a/src/cmd/ip/snoopy/p80211.c b/src/cmd/ip/snoopy/p80211.c
       t@@ -0,0 +1,367 @@
       +/* 
       + * IEEE 802.11.
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +#include "dat.h"
       +#include "protos.h"
       +
       +enum
       +{
       +        Tmgmt = 0,
       +        Tctl,
       +        Tdata,
       +
       +        CtlPoll = 0xA,
       +        CtlRts,
       +        CtlCts,
       +        CtlAck,
       +        CtlCfEnd,
       +        CtlCfEndAck,
       +
       +        Data = 0,
       +        DataCfAck,
       +        DataCfPoll,
       +        DataCfAckPoll,
       +        Nodata,
       +        NodataCfAck,
       +        NodataCfPoll,
       +        NodataCfAckPoll,
       +        
       +        FlagTods = 0x1,
       +        FlagFromds = 0x2,
       +        FlagMoreflag = 0x4,
       +        FlagRetry = 0x8,
       +        FlagPowerMgmt = 0x10,
       +        FlagMoreData = 0x20,
       +        FlagWep = 0x40,
       +        FlagOrder = 0x80,
       +        
       +        ProtoNone = 0,
       +        ProtoLlc,
       +};
       +
       +static Mux p_mux[] =
       +{
       +        { "llc", ProtoLlc },
       +        { 0 }
       +};
       +
       +typedef struct Hdr Hdr;
       +struct Hdr
       +{
       +        uchar vers;
       +        uchar type;
       +        uchar subtype;
       +        uchar flags;
       +        ushort dur;
       +        uchar aid;
       +        uchar ra[6];
       +        uchar ta[6];
       +        uchar bssid[6];
       +        uchar sa[6];
       +        uchar da[6];
       +        ushort seq;
       +        int proto;
       +        int hdrlen;
       +};
       +
       +static int
       +unpackhdr(uchar *p, uchar *ep, Hdr *h)
       +{
       +        if(p+2 > ep)
       +                return -1;
       +        h->vers = p[0]&3;
       +        if(h->vers != 0){
       +                h->hdrlen = 2;
       +                return -1;
       +        }
       +        h->type = (p[0]>>2)&3;
       +        h->subtype = (p[0]>>4)&15;
       +        h->flags = p[1];
       +        h->hdrlen = 2;
       +
       +        if(h->vers != 0)
       +                return 0;
       +        
       +        switch(h->type){
       +        case Tmgmt:
       +                // fc dur da sa bssid seq
       +                if(p+2+2+6+6+6+2 > ep)
       +                        return -1;
       +                h->hdrlen = 24;
       +                h->dur = LittleS(p+2);
       +                memmove(h->da, p+4, 6);
       +                memmove(h->sa, p+10, 6);
       +                memmove(h->bssid, p+16, 6);
       +                h->seq = LittleS(p+22);
       +                break;
       +        
       +        case Tctl:
       +                switch(h->subtype){
       +                case CtlPoll:
       +                        // fc aid bssid ta
       +                        if(p+2+2+6+6 > ep)
       +                                return -1;
       +                        h->hdrlen = 16;
       +                        h->aid = LittleS(p+2);
       +                        memmove(h->bssid, p+4, 6);
       +                        memmove(h->ta, p+10, 6);
       +                        break;
       +                
       +                case CtlRts:
       +                        // fc dur ra ta
       +                        if(p+2+2+6+6 > ep)
       +                                return -1;
       +                        h->hdrlen = 16;
       +                        h->dur = LittleS(p+2);
       +                        memmove(h->ra, p+4, 6);
       +                        memmove(h->ta, p+10, 6);
       +                        break;
       +                
       +                case CtlCts:
       +                case CtlAck:
       +                        // fc dur ra
       +                        if(p+2+2+6 > ep)
       +                                return -1;
       +                        h->hdrlen = 10;
       +                        h->dur = LittleS(p+2);
       +                        memmove(h->ra, p+4, 6);
       +                        break;
       +                
       +                case CtlCfEnd:
       +                case CtlCfEndAck:
       +                        // fc dur ra bssid
       +                        if(p+2+2+6+6 > ep)
       +                                return -1;
       +                        h->hdrlen = 16;
       +                        h->dur = LittleS(p+2);
       +                        memmove(h->ra, p+4, 6);
       +                        memmove(h->bssid, p+10, 6);
       +                        break;
       +                }
       +                break;
       +        
       +        case Tdata:
       +                if(p+24 > ep)
       +                        return -1;
       +                h->hdrlen = 24;
       +                h->dur = LittleS(p+2);        // ??? maybe
       +                // Also, what is at p+22?
       +
       +                switch(h->flags&(FlagFromds|FlagTods)){
       +                case 0:
       +                        memmove(h->da, p+4, 6);
       +                        memmove(h->sa, p+10, 6);
       +                        memmove(h->bssid, p+16, 6);
       +                        break;
       +                case FlagFromds:
       +                        memmove(h->da, p+4, 6);
       +                        memmove(h->bssid, p+10, 6);
       +                        memmove(h->sa, p+16, 6);
       +                        break;
       +                case FlagTods:
       +                        memmove(h->bssid, p+4, 6);
       +                        memmove(h->sa, p+10, 6);
       +                        memmove(h->da, p+16, 6);
       +                        break;
       +                case FlagFromds|FlagTods:
       +                        if(p+30 > ep)
       +                                return -1;
       +                        h->hdrlen = 30;
       +                        memmove(h->ra, p+4, 6);
       +                        memmove(h->ta, p+10, 6);
       +                        memmove(h->da, p+16, 6);
       +                        memmove(h->sa, p+24, 6);        // 24 sic
       +                        break;
       +                }
       +                p += h->hdrlen;
       +                h->proto = ProtoNone;
       +                if(!(h->flags&FlagWep))
       +                        h->proto = ProtoLlc;
       +                break;
       +        }
       +        return 0;        
       +}
       +
       +enum
       +{
       +        Os,
       +        Od,
       +        Ot,
       +        Or,
       +        Obssid,
       +        Oa,
       +        Opr,
       +};
       +
       +static Field p_fields[] =
       +{
       +        { "s",        Fether,        Os,        "source address" },
       +        { "d",        Fether,        Od,        "destination address" },
       +        { "t",        Fether,        Ot,        "transmit address" },
       +        { "r",        Fether,        Or,        "receive address" },
       +        { "bssid", Fether,        Obssid, "bssid address" },
       +        { "a",        Fether,        Oa,        "any address" },
       +        { "sd",        Fether,        Oa,        "source|destination address" },
       +        { 0 }
       +};
       +
       +static void
       +p_compile(Filter *f)
       +{
       +        Mux *m;
       +
       +        if(f->op == '='){
       +                compile_cmp(p80211.name, f, p_fields);
       +                return;
       +        }
       +        if(strcmp(f->s, "mgmt") == 0){
       +                f->pr = &p80211;
       +                f->ulv = Tmgmt;
       +                f->subop = Ot;
       +                return;
       +        }
       +        if(strcmp(f->s, "ctl") == 0){
       +                f->pr = &p80211;
       +                f->ulv = Tctl;
       +                f->subop = Ot;
       +                return;
       +        }
       +        if(strcmp(f->s, "data") == 0){
       +                f->pr = &p80211;
       +                f->ulv = Tdata;
       +                f->subop = Ot;
       +                return;
       +        }
       +        for(m = p_mux; m->name != nil; m++){
       +                if(strcmp(f->s, m->name) == 0){
       +                        f->pr = m->pr;
       +                        f->ulv = m->val;
       +                        f->subop = Opr;
       +                        return;
       +                }
       +        }
       +        sysfatal("unknown 802.11 field or protocol: %s", f->s);
       +}
       +
       +static int
       +p_filter(Filter *f, Msg *m)
       +{
       +        Hdr h;
       +
       +        memset(&h, 0, sizeof h);
       +        if(unpackhdr(m->ps, m->pe, &h) < 0)
       +                return 0;
       +        m->ps += h.hdrlen;
       +
       +        switch(f->subop){
       +        case Os:
       +                return memcmp(h.sa, f->a, 6) == 0;
       +        case Od:
       +                return memcmp(h.da, f->a, 6) == 0;
       +        case Ot:
       +                return memcmp(h.ta, f->a, 6) == 0;
       +        case Or:
       +                return memcmp(h.ra, f->a, 6) == 0;
       +        case Obssid:
       +                return memcmp(h.bssid, f->a, 6) == 0;
       +        case Oa:
       +                return memcmp(h.sa, f->a, 6) == 0
       +                        || memcmp(h.da, f->a, 6) == 0
       +                        || memcmp(h.ta, f->a, 6) == 0
       +                        || memcmp(h.ra, f->a, 6) == 0
       +                        || memcmp(h.bssid, f->a, 6) == 0;
       +        case Opr:
       +                return h.proto == f->ulv;
       +        }
       +        return 0;
       +}
       +
       +static int
       +p_seprint(Msg *m)
       +{
       +        Hdr h;
       +        
       +        memset(&h, 0, sizeof h);
       +        if(unpackhdr(m->ps, m->pe, &h) < 0)
       +                return -1;
       +
       +        m->pr = &dump;
       +        m->p = seprint(m->p, m->e, "fc=%02x flags=%02x ", m->ps[0], m->ps[1]);
       +        switch(h.type){
       +        case Tmgmt:
       +                m->p = seprint(m->p, m->e, "mgmt dur=%d d=%E s=%E bssid=%E seq=%d",
       +                        h.dur, h.da, h.sa, h.bssid, h.seq);
       +                break;
       +        case Tctl:
       +                switch(h.subtype){
       +                case CtlPoll:
       +                        m->p = seprint(m->p, m->e, "ctl poll aid=%d bssid=%E t=%E",
       +                                h.aid, h.bssid, h.ta);
       +                        break;
       +                case CtlRts:
       +                        m->p = seprint(m->p, m->e, "ctl rts dur=%d r=%E t=%E",
       +                                h.dur, h.ra, h.ta);
       +                        break;
       +                case CtlCts:
       +                        m->p = seprint(m->p, m->e, "ctl cts dur=%d r=%E",
       +                                h.dur, h.ra);
       +                        break;
       +                case CtlAck:
       +                        m->p = seprint(m->p, m->e, "ctl ack dur=%d r=%E",
       +                                h.dur, h.ra);
       +                        break;
       +                case CtlCfEnd:
       +                        m->p = seprint(m->p, m->e, "ctl cf end dur=%d r=%E bssid=%E",
       +                                h.dur, h.ra, h.bssid);
       +                        break;
       +                case CtlCfEndAck:
       +                        m->p = seprint(m->p, m->e, "ctl cf end ack dur=%d r=%E bssid=%E",
       +                                h.dur, h.ra, h.bssid);
       +                        break;
       +                default:
       +                        m->p = seprint(m->p, m->e, "ctl %.*H", m->ps, h.hdrlen);
       +                        break;
       +                }
       +                break;
       +        case Tdata:
       +                switch(h.flags&(FlagFromds|FlagTods)){
       +                case 0:
       +                        m->p = seprint(m->p, m->e, "data d=%E s=%E bssid=%E",
       +                                h.da, h.sa, h.bssid);
       +                        break;
       +                case FlagFromds:
       +                        m->p = seprint(m->p, m->e, "data fds d=%E bssid=%E s=%E",
       +                                h.da, h.bssid, h.sa);
       +                        break;
       +                case FlagTods:
       +                        m->p = seprint(m->p, m->e, "data tds bssid=%E s=%E d=%E",
       +                                h.bssid, h.sa, h.da);
       +                        break;
       +                case FlagFromds|FlagTods:
       +                        m->p = seprint(m->p, m->e, "data fds tds r=%E t=%E d=%E s=%E",
       +                                h.ra, h.ta, h.da, h.sa);
       +                        break;
       +                }
       +                if(!(h.flags&FlagWep))
       +                        m->pr = &llc;
       +                break;
       +        }
       +        m->ps += h.hdrlen;
       +        return 0;
       +}
       +
       +Proto p80211 =
       +{
       +        "802.11",
       +        p_compile,
       +        p_filter,
       +        p_seprint,
       +        p_mux,
       +        nil,
       +        nil,
       +        defaultframer
       +};
   DIR diff --git a/src/cmd/ip/snoopy/protos.c b/src/cmd/ip/snoopy/protos.c
       t@@ -29,5 +29,10 @@ Proto *protos[] =
                &ppp_ipcp,
                &pppoe_sess,
                &pppoe_disc,
       +        &dns,
       +        &p80211,
       +        &llc,
       +        &radiotap,
       +        &snap,
                0
        };
   DIR diff --git a/src/cmd/ip/snoopy/protos.h b/src/cmd/ip/snoopy/protos.h
       t@@ -23,3 +23,8 @@ extern Proto ppp_chap;
        extern Proto ppp_ipcp;
        extern Proto pppoe_sess;
        extern Proto pppoe_disc;
       +extern Proto dns;
       +extern Proto p80211;
       +extern Proto llc;
       +extern Proto radiotap;
       +extern Proto snap;
   DIR diff --git a/src/cmd/ip/snoopy/radiotap.c b/src/cmd/ip/snoopy/radiotap.c
       t@@ -0,0 +1,117 @@
       +/*
       + * Radio tap as exported by BSD and Linux.
       + * The wireless ethernet devices return this format on Linux
       + * when running in monitor mode.
       + *
       + * TODO: Automatically determine whether the ethernet
       + * device is radio or ether, so that -h is not needed.
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +#include "dat.h"
       +#include "protos.h"
       +
       +static Mux p_mux[] =
       +{
       +        { "802.11", 0 },
       +        { 0 }
       +};
       +
       +typedef struct Hdr Hdr;
       +struct Hdr
       +{
       +        uchar vers;
       +        uchar pad;
       +        ushort        len;
       +        ulong        present;
       +};
       +
       +static int
       +unpackhdr(uchar *p, uchar *ep, Hdr *h)
       +{
       +        if(p+sizeof(Hdr) > ep)
       +                return -1;
       +        h->vers = p[0];
       +        h->pad = p[1];
       +        h->len = LittleS(p+2);
       +        h->present = LittleL(p+4);
       +        // can be more present fields if 0x80000000 is set in each along the chain.
       +        if(p+h->len > ep)
       +                return -1;
       +        return 0;
       +}
       +
       +enum
       +{
       +        Ot,
       +};
       +
       +static Field p_fields[] =
       +{
       +        { 0 }
       +};
       +
       +static void
       +p_compile(Filter *f)
       +{
       +        Mux *m;
       +
       +        if(f->op == '='){
       +                compile_cmp(radiotap.name, f, p_fields);
       +                return;
       +        }
       +        for(m = p_mux; m->name != nil; m++){
       +                if(strcmp(f->s, m->name) == 0){
       +                        f->pr = m->pr;
       +                        f->ulv = m->val;
       +                        f->subop = Ot;
       +                        return;
       +                }
       +        }
       +        sysfatal("unknown radiotap field or protocol: %s", f->s);
       +}
       +
       +static int
       +p_filter(Filter *f, Msg *m)
       +{
       +        Hdr h;
       +
       +        memset(&h, 0, sizeof h);
       +        if(unpackhdr(m->ps, m->pe, &h) < 0)
       +                return 0;
       +        m->ps += h.len;
       +        switch(f->subop){
       +        case Ot:
       +                return 1;
       +        }
       +        return 0;
       +}
       +
       +static int
       +p_seprint(Msg *m)
       +{
       +        Hdr h;
       +        
       +        memset(&h, 0, sizeof h);
       +        if(unpackhdr(m->ps, m->pe, &h) < 0)
       +                return -1;
       +
       +        m->p = seprint(m->p, m->e, "%.*H", h.len, m->ps);
       +        m->ps += h.len;
       +        m->pr = &p80211;
       +        return 0;
       +}
       +
       +Proto radiotap =
       +{
       +        "radiotap",
       +        p_compile,
       +        p_filter,
       +        p_seprint,
       +        p_mux,
       +        nil,
       +        nil,
       +        defaultframer
       +};
   DIR diff --git a/src/cmd/ip/snoopy/snap.c b/src/cmd/ip/snoopy/snap.c
       t@@ -0,0 +1,112 @@
       +/* 
       + * SNAP.
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +#include "dat.h"
       +#include "protos.h"
       +
       +enum
       +{
       +        Oorg,
       +        Oet,
       +        
       +        OuiEther = 0,
       +        OuiCisco = 0xc,
       +        OuiCisco90 = 0xf8,
       +        OuiRfc2684 = 0x80c2,
       +        OuiAppletalk = 0x80007,
       +};
       +
       +static Mux p_mux[] =
       +{
       +        {"ip",                0x0800,        } ,
       +        {"arp",                0x0806,        } ,
       +        {"rarp",        0x0806,        } ,
       +        {"ip6",         0x86dd, } ,
       +        {"pppoe_disc",        0x8863, },
       +        {"pppoe_sess",        0x8864, },
       +        {"eapol",        0x888e, },
       +        { 0 }
       +};
       +
       +typedef struct Hdr Hdr;
       +struct Hdr
       +{
       +        uchar org[3];
       +        uchar et[2];
       +};
       +
       +static Field p_fields[] =
       +{
       +        { "org",        Fnum,        Oorg,        "org" },
       +        { "et",        Fnum,        Oet,        "et" },
       +        { 0 }
       +};
       +
       +static void
       +p_compile(Filter *f)
       +{
       +        Mux *m;
       +
       +        if(f->op == '='){
       +                compile_cmp(snap.name, f, p_fields);
       +                return;
       +        }
       +        for(m = p_mux; m->name != nil; m++){
       +                if(strcmp(f->s, m->name) == 0){
       +                        f->pr = m->pr;
       +                        f->ulv = m->val;
       +                        f->subop = Oet;
       +                        return;
       +                }
       +        }
       +        sysfatal("unknown snap field or protocol: %s", f->s);
       +}
       +
       +static int
       +p_filter(Filter *f, Msg *m)
       +{
       +        Hdr *h;
       +
       +        if(m->pe - m->ps < sizeof(Hdr))
       +                return 0;
       +        h = (Hdr*)m->ps;
       +        m->ps += 5;
       +        switch(f->subop){
       +        case Oorg:
       +                return f->ulv == Net3(h->org);
       +        case Oet:
       +                return f->ulv == NetS(h->et);
       +        }
       +        return 0;
       +}
       +
       +static int
       +p_seprint(Msg *m)
       +{
       +        Hdr *h;
       +
       +        if(m->pe - m->ps < sizeof(Hdr))
       +                return 0;
       +        h = (Hdr*)m->ps;
       +        m->ps += 5;
       +        demux(p_mux, NetS(h->et), NetS(h->et), m, &dump);
       +
       +        m->p = seprint(m->p, m->e, "org=%06x et=%04x", Net3(h->org), NetS(h->et));
       +        return 0;
       +}
       +
       +Proto snap =
       +{
       +        "snap",
       +        p_compile,
       +        p_filter,
       +        p_seprint,
       +        p_mux,
       +        nil,
       +        nil,
       +        defaultframer
       +};
   DIR diff --git a/src/cmd/ip/snoopy/udp.c b/src/cmd/ip/snoopy/udp.c
       t@@ -41,6 +41,7 @@ static Mux p_mux[] =
        {
                {"bootp",        67, },
                {"ninep",        6346, },        /* tvs */
       +        {"dns", 53 },
                {"rtp",                ANYPORT, },
                {"rtcp",        ANYPORT, },
                {0}