plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

p80211.c (6470B)


      1 /*
      2  * IEEE 802.11.
      3  */
      4 
      5 #include <u.h>
      6 #include <libc.h>
      7 #include <ip.h>
      8 #include "dat.h"
      9 #include "protos.h"
     10 
     11 enum
     12 {
     13 	Tmgmt = 0,
     14 	Tctl,
     15 	Tdata,
     16 
     17 	CtlPoll = 0xA,
     18 	CtlRts,
     19 	CtlCts,
     20 	CtlAck,
     21 	CtlCfEnd,
     22 	CtlCfEndAck,
     23 
     24 	Data = 0,
     25 	DataCfAck,
     26 	DataCfPoll,
     27 	DataCfAckPoll,
     28 	Nodata,
     29 	NodataCfAck,
     30 	NodataCfPoll,
     31 	NodataCfAckPoll,
     32 
     33 	FlagTods = 0x1,
     34 	FlagFromds = 0x2,
     35 	FlagMoreflag = 0x4,
     36 	FlagRetry = 0x8,
     37 	FlagPowerMgmt = 0x10,
     38 	FlagMoreData = 0x20,
     39 	FlagWep = 0x40,
     40 	FlagOrder = 0x80,
     41 
     42 	ProtoNone = 0,
     43 	ProtoLlc,
     44 };
     45 
     46 static Mux p_mux[] =
     47 {
     48 	{ "llc", ProtoLlc },
     49 	{ 0 }
     50 };
     51 
     52 typedef struct Hdr Hdr;
     53 struct Hdr
     54 {
     55 	uchar vers;
     56 	uchar type;
     57 	uchar subtype;
     58 	uchar flags;
     59 	ushort dur;
     60 	uchar aid;
     61 	uchar ra[6];
     62 	uchar ta[6];
     63 	uchar bssid[6];
     64 	uchar sa[6];
     65 	uchar da[6];
     66 	ushort seq;
     67 	int proto;
     68 	int hdrlen;
     69 };
     70 
     71 static int
     72 unpackhdr(uchar *p, uchar *ep, Hdr *h)
     73 {
     74 	if(p+2 > ep)
     75 		return -1;
     76 	h->vers = p[0]&3;
     77 	if(h->vers != 0){
     78 		h->hdrlen = 2;
     79 		return -1;
     80 	}
     81 	h->type = (p[0]>>2)&3;
     82 	h->subtype = (p[0]>>4)&15;
     83 	h->flags = p[1];
     84 	h->hdrlen = 2;
     85 
     86 	if(h->vers != 0)
     87 		return 0;
     88 
     89 	switch(h->type){
     90 	case Tmgmt:
     91 		// fc dur da sa bssid seq
     92 		if(p+2+2+6+6+6+2 > ep)
     93 			return -1;
     94 		h->hdrlen = 24;
     95 		h->dur = LittleS(p+2);
     96 		memmove(h->da, p+4, 6);
     97 		memmove(h->sa, p+10, 6);
     98 		memmove(h->bssid, p+16, 6);
     99 		h->seq = LittleS(p+22);
    100 		break;
    101 
    102 	case Tctl:
    103 		switch(h->subtype){
    104 		case CtlPoll:
    105 			// fc aid bssid ta
    106 			if(p+2+2+6+6 > ep)
    107 				return -1;
    108 			h->hdrlen = 16;
    109 			h->aid = LittleS(p+2);
    110 			memmove(h->bssid, p+4, 6);
    111 			memmove(h->ta, p+10, 6);
    112 			break;
    113 
    114 		case CtlRts:
    115 			// fc dur ra ta
    116 			if(p+2+2+6+6 > ep)
    117 				return -1;
    118 			h->hdrlen = 16;
    119 			h->dur = LittleS(p+2);
    120 			memmove(h->ra, p+4, 6);
    121 			memmove(h->ta, p+10, 6);
    122 			break;
    123 
    124 		case CtlCts:
    125 		case CtlAck:
    126 			// fc dur ra
    127 			if(p+2+2+6 > ep)
    128 				return -1;
    129 			h->hdrlen = 10;
    130 			h->dur = LittleS(p+2);
    131 			memmove(h->ra, p+4, 6);
    132 			break;
    133 
    134 		case CtlCfEnd:
    135 		case CtlCfEndAck:
    136 			// fc dur ra bssid
    137 			if(p+2+2+6+6 > ep)
    138 				return -1;
    139 			h->hdrlen = 16;
    140 			h->dur = LittleS(p+2);
    141 			memmove(h->ra, p+4, 6);
    142 			memmove(h->bssid, p+10, 6);
    143 			break;
    144 		}
    145 		break;
    146 
    147 	case Tdata:
    148 		if(p+24 > ep)
    149 			return -1;
    150 		h->hdrlen = 24;
    151 		h->dur = LittleS(p+2);	// ??? maybe
    152 		// Also, what is at p+22?
    153 
    154 		switch(h->flags&(FlagFromds|FlagTods)){
    155 		case 0:
    156 			memmove(h->da, p+4, 6);
    157 			memmove(h->sa, p+10, 6);
    158 			memmove(h->bssid, p+16, 6);
    159 			break;
    160 		case FlagFromds:
    161 			memmove(h->da, p+4, 6);
    162 			memmove(h->bssid, p+10, 6);
    163 			memmove(h->sa, p+16, 6);
    164 			break;
    165 		case FlagTods:
    166 			memmove(h->bssid, p+4, 6);
    167 			memmove(h->sa, p+10, 6);
    168 			memmove(h->da, p+16, 6);
    169 			break;
    170 		case FlagFromds|FlagTods:
    171 			if(p+30 > ep)
    172 				return -1;
    173 			h->hdrlen = 30;
    174 			memmove(h->ra, p+4, 6);
    175 			memmove(h->ta, p+10, 6);
    176 			memmove(h->da, p+16, 6);
    177 			memmove(h->sa, p+24, 6);	// 24 sic
    178 			break;
    179 		}
    180 		p += h->hdrlen;
    181 		h->proto = ProtoNone;
    182 		if(!(h->flags&FlagWep))
    183 			h->proto = ProtoLlc;
    184 		break;
    185 	}
    186 	return 0;
    187 }
    188 
    189 enum
    190 {
    191 	Os,
    192 	Od,
    193 	Ot,
    194 	Or,
    195 	Obssid,
    196 	Oa,
    197 	Opr,
    198 };
    199 
    200 static Field p_fields[] =
    201 {
    202 	{ "s",	Fether,	Os,	"source address" },
    203 	{ "d",	Fether,	Od,	"destination address" },
    204 	{ "t",	Fether,	Ot,	"transmit address" },
    205 	{ "r",	Fether,	Or,	"receive address" },
    206 	{ "bssid", Fether,	Obssid, "bssid address" },
    207 	{ "a",	Fether,	Oa,	"any address" },
    208 	{ "sd",	Fether,	Oa,	"source|destination address" },
    209 	{ 0 }
    210 };
    211 
    212 static void
    213 p_compile(Filter *f)
    214 {
    215 	Mux *m;
    216 
    217 	if(f->op == '='){
    218 		compile_cmp(p80211.name, f, p_fields);
    219 		return;
    220 	}
    221 	if(strcmp(f->s, "mgmt") == 0){
    222 		f->pr = &p80211;
    223 		f->ulv = Tmgmt;
    224 		f->subop = Ot;
    225 		return;
    226 	}
    227 	if(strcmp(f->s, "ctl") == 0){
    228 		f->pr = &p80211;
    229 		f->ulv = Tctl;
    230 		f->subop = Ot;
    231 		return;
    232 	}
    233 	if(strcmp(f->s, "data") == 0){
    234 		f->pr = &p80211;
    235 		f->ulv = Tdata;
    236 		f->subop = Ot;
    237 		return;
    238 	}
    239 	for(m = p_mux; m->name != nil; m++){
    240 		if(strcmp(f->s, m->name) == 0){
    241 			f->pr = m->pr;
    242 			f->ulv = m->val;
    243 			f->subop = Opr;
    244 			return;
    245 		}
    246 	}
    247 	sysfatal("unknown 802.11 field or protocol: %s", f->s);
    248 }
    249 
    250 static int
    251 p_filter(Filter *f, Msg *m)
    252 {
    253 	Hdr h;
    254 
    255 	memset(&h, 0, sizeof h);
    256 	if(unpackhdr(m->ps, m->pe, &h) < 0)
    257 		return 0;
    258 	m->ps += h.hdrlen;
    259 
    260 	switch(f->subop){
    261 	case Os:
    262 		return memcmp(h.sa, f->a, 6) == 0;
    263 	case Od:
    264 		return memcmp(h.da, f->a, 6) == 0;
    265 	case Ot:
    266 		return memcmp(h.ta, f->a, 6) == 0;
    267 	case Or:
    268 		return memcmp(h.ra, f->a, 6) == 0;
    269 	case Obssid:
    270 		return memcmp(h.bssid, f->a, 6) == 0;
    271 	case Oa:
    272 		return memcmp(h.sa, f->a, 6) == 0
    273 			|| memcmp(h.da, f->a, 6) == 0
    274 			|| memcmp(h.ta, f->a, 6) == 0
    275 			|| memcmp(h.ra, f->a, 6) == 0
    276 			|| memcmp(h.bssid, f->a, 6) == 0;
    277 	case Opr:
    278 		return h.proto == f->ulv;
    279 	}
    280 	return 0;
    281 }
    282 
    283 static int
    284 p_seprint(Msg *m)
    285 {
    286 	Hdr h;
    287 
    288 	memset(&h, 0, sizeof h);
    289 	if(unpackhdr(m->ps, m->pe, &h) < 0)
    290 		return -1;
    291 
    292 	m->pr = &dump;
    293 	m->p = seprint(m->p, m->e, "fc=%02x flags=%02x ", m->ps[0], m->ps[1]);
    294 	switch(h.type){
    295 	case Tmgmt:
    296 		m->p = seprint(m->p, m->e, "mgmt dur=%d d=%E s=%E bssid=%E seq=%d",
    297 			h.dur, h.da, h.sa, h.bssid, h.seq);
    298 		break;
    299 	case Tctl:
    300 		switch(h.subtype){
    301 		case CtlPoll:
    302 			m->p = seprint(m->p, m->e, "ctl poll aid=%d bssid=%E t=%E",
    303 				h.aid, h.bssid, h.ta);
    304 			break;
    305 		case CtlRts:
    306 			m->p = seprint(m->p, m->e, "ctl rts dur=%d r=%E t=%E",
    307 				h.dur, h.ra, h.ta);
    308 			break;
    309 		case CtlCts:
    310 			m->p = seprint(m->p, m->e, "ctl cts dur=%d r=%E",
    311 				h.dur, h.ra);
    312 			break;
    313 		case CtlAck:
    314 			m->p = seprint(m->p, m->e, "ctl ack dur=%d r=%E",
    315 				h.dur, h.ra);
    316 			break;
    317 		case CtlCfEnd:
    318 			m->p = seprint(m->p, m->e, "ctl cf end dur=%d r=%E bssid=%E",
    319 				h.dur, h.ra, h.bssid);
    320 			break;
    321 		case CtlCfEndAck:
    322 			m->p = seprint(m->p, m->e, "ctl cf end ack dur=%d r=%E bssid=%E",
    323 				h.dur, h.ra, h.bssid);
    324 			break;
    325 		default:
    326 			m->p = seprint(m->p, m->e, "ctl %.*H", m->ps, h.hdrlen);
    327 			break;
    328 		}
    329 		break;
    330 	case Tdata:
    331 		switch(h.flags&(FlagFromds|FlagTods)){
    332 		case 0:
    333 			m->p = seprint(m->p, m->e, "data d=%E s=%E bssid=%E",
    334 				h.da, h.sa, h.bssid);
    335 			break;
    336 		case FlagFromds:
    337 			m->p = seprint(m->p, m->e, "data fds d=%E bssid=%E s=%E",
    338 				h.da, h.bssid, h.sa);
    339 			break;
    340 		case FlagTods:
    341 			m->p = seprint(m->p, m->e, "data tds bssid=%E s=%E d=%E",
    342 				h.bssid, h.sa, h.da);
    343 			break;
    344 		case FlagFromds|FlagTods:
    345 			m->p = seprint(m->p, m->e, "data fds tds r=%E t=%E d=%E s=%E",
    346 				h.ra, h.ta, h.da, h.sa);
    347 			break;
    348 		}
    349 		if(!(h.flags&FlagWep))
    350 			m->pr = &llc;
    351 		break;
    352 	}
    353 	m->ps += h.hdrlen;
    354 	return 0;
    355 }
    356 
    357 Proto p80211 =
    358 {
    359 	"802.11",
    360 	p_compile,
    361 	p_filter,
    362 	p_seprint,
    363 	p_mux,
    364 	nil,
    365 	nil,
    366 	defaultframer
    367 };