Move values from IEEE80211 headers into a separate module
[wifihood] / wifiscanner / wiviz.py
1 #!/usr/bin/python
2
3 import pcapy
4 import struct
5
6 iface = 'wlan0'
7
8 max_bytes = 1024
9 promiscuous = False
10 read_timeout = 100 # in milliseconds
11 pc = pcapy.open_live(iface, max_bytes, promiscuous, read_timeout)
12
13 import ieee80211
14
15 import time
16
17 max_time = 1
18 tstamp = time.time()
19 discovered = []
20
21 def dealWithPacket ( hdr , data ) :
22
23     if hdr.getlen() != hdr.getcaplen() :
24         print "Error in header : %d vs. %d" % ( hdr.getlen() , hdr.getcaplen() )
25         return
26     if len(data) != hdr.getlen() :
27         print "Data lenght does not match"
28         return
29
30     it_version , it_len , it_present = struct.unpack("<Bxhl",data[:8])
31     if it_version != 0 :
32         print "Bad version (%s), it is probably not radiotap header" % it_version
33         return
34     if it_len <= 0 :
35         print "Bad length on radiotap header"
36         return
37
38     radiotap = data[:it_len]
39     payload = data[it_len:]
40
41     format , padstr = "<" , ""
42     fields = []
43     for name,bit,fmt,pad in ratiotap_header_bits :
44 # What about  'it_present & ( 0x1 << bit )' ??
45         if it_present & pow(2,bit) == pow(2,bit) :
46             if not fmt :
47                 print "Unknown bit %s (%d) set" % ( name , bit )
48                 return
49             fields.append( name )
50             if fmt == "hh" :
51                 fields.append( "CHANNEL_BITMAP" )
52             if pad :
53                 padstr += "x"
54             format += fmt
55     values = struct.unpack(format+padstr,radiotap[8:])
56
57     flags = []
58     for name,value in radiotap_flags :
59         if values[1] & value == value :
60             flags.append( name )
61
62     channel = []
63     for name,value in channel_flags :
64         if values[4] & value == value :
65             channel.append( name )
66
67     pointer = 0
68     pcktlen = len(payload)
69
70     frame_ctl , frame_subtype , duration_id = struct.unpack("BBh",payload[:4])
71     pointer += 4
72     pcktlen -= 4
73
74     for name,value in frame_type :
75         if frame_ctl & 0x0c == value :
76             type = name
77             break
78     else :
79         print "Unknown frame type %s" % ( frame_ctl & 0x0c , )
80         return
81
82     if type == "MGT" :
83         for name,value in management_subtypes :
84             if frame_ctl & 0xf0 == value :
85                 subtype = name
86                 break
87         else :
88             print "Unknown MGT subtype %s" % ( frame_ctl & 0xf0 , )
89             return
90
91     elif type == "CTL" :
92         for name,value in control_subtypes :
93             if frame_ctl & 0xf0 == value :
94                 subtype = name
95                 break
96         else :
97             print "Unknown CTL subtype %s" % ( frame_ctl & 0xf0 , )
98             return
99
100     elif type == "DATA" :
101         _subtype = []
102         for name,value in data_subtypes :
103             if frame_ctl & 0xf0 == value :
104                 _subtype.append( name )
105         subtype = "-".join( _subtype )
106
107     for name,value in directions :
108         if frame_subtype & 0x03 == value :
109             direction = name
110             break
111     else :
112         print "Unknown direction %s" % ( frame_subtype & 0x03 , )
113         return
114
115
116     mac_str = "BBBBBB" # is leading '<' required
117     mac_fmt = "%02X:%02X:%02X:%02X:%02X:%02X"
118
119     maclist = []
120     for i in range(3) :
121         maclist.append( mac_fmt % struct.unpack( mac_str , payload[pointer:pointer+6] ) )
122         pointer += 6
123         pcktlen -= 6
124         # FIXME : only CTL/ACK have single address ???
125         # FIXME : Is this the same than pcktlen == 2
126         if pcktlen < 6 :
127             break
128
129     sequence = struct.unpack("BB",payload[pointer:pointer+2])
130     pointer += 2
131     pcktlen -= 2
132
133 #    print fields
134 #    print values
135 #    print "Radiotap flags : %s" % " ".join(flags)
136 #    print "Channel %d (%s)" % ( values[3] , " ".join(channel) )
137 ##    print "Control info",frame_ctl,frame_subtype,duration_id,"seq",sequence
138 #    print type,":",maclist,"->",pcktlen
139 #    print
140
141     global tstamp,max_time,discovered
142     for mac in maclist :
143         if not mac in discovered :
144             tstamp = time.time()
145             discovered.append( mac )
146     if time.time()-tstamp > max_time :
147         fd = open( "discovered.list" , "a" )
148         for mac in discovered :
149             fd.write( "%s\n" % mac )
150         fd.close()
151         raise Exception( "Neighborhoud scan completed" )
152
153     print "%4s %13s %6s %4d %4d from %4d" % (type,subtype,direction,values[3],pcktlen,len(payload))," ; %4d %4d "%sequence,":"+" %s"*len(maclist) % tuple(maclist)
154
155 packet_limit = -1 # infinite
156 pc.loop( packet_limit , dealWithPacket )
157