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 };