radiotap.c (1693B)
1 /* 2 * Radio tap as exported by BSD and Linux. 3 * The wireless ethernet devices return this format on Linux 4 * when running in monitor mode. 5 * 6 * TODO: Automatically determine whether the ethernet 7 * device is radio or ether, so that -h is not needed. 8 */ 9 10 #include <u.h> 11 #include <libc.h> 12 #include <ip.h> 13 #include "dat.h" 14 #include "protos.h" 15 16 static Mux p_mux[] = 17 { 18 { "802.11", 0 }, 19 { 0 } 20 }; 21 22 typedef struct Hdr Hdr; 23 struct Hdr 24 { 25 uchar vers; 26 uchar pad; 27 ushort len; 28 ulong present; 29 }; 30 31 static int 32 unpackhdr(uchar *p, uchar *ep, Hdr *h) 33 { 34 if(p+sizeof(Hdr) > ep) 35 return -1; 36 h->vers = p[0]; 37 h->pad = p[1]; 38 h->len = LittleS(p+2); 39 h->present = LittleL(p+4); 40 // can be more present fields if 0x80000000 is set in each along the chain. 41 if(p+h->len > ep) 42 return -1; 43 return 0; 44 } 45 46 enum 47 { 48 Ot, 49 }; 50 51 static Field p_fields[] = 52 { 53 { 0 } 54 }; 55 56 static void 57 p_compile(Filter *f) 58 { 59 Mux *m; 60 61 if(f->op == '='){ 62 compile_cmp(radiotap.name, f, p_fields); 63 return; 64 } 65 for(m = p_mux; m->name != nil; m++){ 66 if(strcmp(f->s, m->name) == 0){ 67 f->pr = m->pr; 68 f->ulv = m->val; 69 f->subop = Ot; 70 return; 71 } 72 } 73 sysfatal("unknown radiotap field or protocol: %s", f->s); 74 } 75 76 static int 77 p_filter(Filter *f, Msg *m) 78 { 79 Hdr h; 80 81 memset(&h, 0, sizeof h); 82 if(unpackhdr(m->ps, m->pe, &h) < 0) 83 return 0; 84 m->ps += h.len; 85 switch(f->subop){ 86 case Ot: 87 return 1; 88 } 89 return 0; 90 } 91 92 static int 93 p_seprint(Msg *m) 94 { 95 Hdr h; 96 97 memset(&h, 0, sizeof h); 98 if(unpackhdr(m->ps, m->pe, &h) < 0) 99 return -1; 100 101 m->p = seprint(m->p, m->e, "%.*H", h.len, m->ps); 102 m->ps += h.len; 103 m->pr = &p80211; 104 return 0; 105 } 106 107 Proto radiotap = 108 { 109 "radiotap", 110 p_compile, 111 p_filter, 112 p_seprint, 113 p_mux, 114 nil, 115 nil, 116 defaultframer 117 };