diff options
author | Russ Cox <rsc@swtch.com> | 2008-07-24 08:04:02 -0700 |
---|---|---|
committer | Russ Cox <rsc@swtch.com> | 2008-07-24 08:04:02 -0700 |
commit | 17b19538a48c036dbdc8817d233c0086f327485c (patch) | |
tree | 5c6260c0dda237cad964fb4fd809c89d09f2629d /src/cmd/ip/snoopy/p80211.c | |
parent | 7e36b43bba16df64a08c13358ba2a70ae9001770 (diff) | |
download | plan9port-17b19538a48c036dbdc8817d233c0086f327485c.tar.gz plan9port-17b19538a48c036dbdc8817d233c0086f327485c.tar.bz2 plan9port-17b19538a48c036dbdc8817d233c0086f327485c.zip |
snoopy: add support for wireless monitor mode packets
Diffstat (limited to 'src/cmd/ip/snoopy/p80211.c')
-rw-r--r-- | src/cmd/ip/snoopy/p80211.c | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/src/cmd/ip/snoopy/p80211.c b/src/cmd/ip/snoopy/p80211.c new file mode 100644 index 00000000..92ed8aba --- /dev/null +++ b/src/cmd/ip/snoopy/p80211.c @@ -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 +}; |