/* * IEEE 802.11. */ #include #include #include #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 };