Blob


1 /*
2 * IEEE 802.11.
3 */
5 #include <u.h>
6 #include <libc.h>
7 #include <ip.h>
8 #include "dat.h"
9 #include "protos.h"
11 enum
12 {
13 Tmgmt = 0,
14 Tctl,
15 Tdata,
17 CtlPoll = 0xA,
18 CtlRts,
19 CtlCts,
20 CtlAck,
21 CtlCfEnd,
22 CtlCfEndAck,
24 Data = 0,
25 DataCfAck,
26 DataCfPoll,
27 DataCfAckPoll,
28 Nodata,
29 NodataCfAck,
30 NodataCfPoll,
31 NodataCfAckPoll,
33 FlagTods = 0x1,
34 FlagFromds = 0x2,
35 FlagMoreflag = 0x4,
36 FlagRetry = 0x8,
37 FlagPowerMgmt = 0x10,
38 FlagMoreData = 0x20,
39 FlagWep = 0x40,
40 FlagOrder = 0x80,
42 ProtoNone = 0,
43 ProtoLlc,
44 };
46 static Mux p_mux[] =
47 {
48 { "llc", ProtoLlc },
49 { 0 }
50 };
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 };
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;
86 if(h->vers != 0)
87 return 0;
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;
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;
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;
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;
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;
145 break;
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?
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;
180 p += h->hdrlen;
181 h->proto = ProtoNone;
182 if(!(h->flags&FlagWep))
183 h->proto = ProtoLlc;
184 break;
186 return 0;
189 enum
191 Os,
192 Od,
193 Ot,
194 Or,
195 Obssid,
196 Oa,
197 Opr,
198 };
200 static Field p_fields[] =
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 };
212 static void
213 p_compile(Filter *f)
215 Mux *m;
217 if(f->op == '='){
218 compile_cmp(p80211.name, f, p_fields);
219 return;
221 if(strcmp(f->s, "mgmt") == 0){
222 f->pr = &p80211;
223 f->ulv = Tmgmt;
224 f->subop = Ot;
225 return;
227 if(strcmp(f->s, "ctl") == 0){
228 f->pr = &p80211;
229 f->ulv = Tctl;
230 f->subop = Ot;
231 return;
233 if(strcmp(f->s, "data") == 0){
234 f->pr = &p80211;
235 f->ulv = Tdata;
236 f->subop = Ot;
237 return;
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;
247 sysfatal("unknown 802.11 field or protocol: %s", f->s);
250 static int
251 p_filter(Filter *f, Msg *m)
253 Hdr h;
255 memset(&h, 0, sizeof h);
256 if(unpackhdr(m->ps, m->pe, &h) < 0)
257 return 0;
258 m->ps += h.hdrlen;
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;
280 return 0;
283 static int
284 p_seprint(Msg *m)
286 Hdr h;
288 memset(&h, 0, sizeof h);
289 if(unpackhdr(m->ps, m->pe, &h) < 0)
290 return -1;
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;
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;
349 if(!(h.flags&FlagWep))
350 m->pr = &llc;
351 break;
353 m->ps += h.hdrlen;
354 return 0;
357 Proto p80211 =
359 "802.11",
360 p_compile,
361 p_filter,
362 p_seprint,
363 p_mux,
364 nil,
365 nil,
366 defaultframer
367 };