diff options
author | James Crayne <jim.crayne@gmail.com> | 2019-09-28 13:43:29 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2020-01-01 19:27:53 -0500 |
commit | 11987749fc6e6d3e53ea737d46d5ab13a16faeb8 (patch) | |
tree | 5716463275c2d3e902889db619908ded2a73971c /dht/WifiHeader.hs | |
parent | add2c76bced51fde5e9917e7449ef52be70faf87 (diff) |
Factor out some new libraries
word64-map:
Data.Word64Map
network-addr:
Network.Address
tox-crypto:
Crypto.Tox
lifted-concurrent:
Control.Concurrent.Lifted.Instrument
Control.Concurrent.Async.Lifted.Instrument
psq-wrap:
Data.Wrapper.PSQInt
Data.Wrapper.PSQ
minmax-psq:
Data.MinMaxPSQ
tasks:
Control.Concurrent.Tasks
kad:
Network.Kademlia
Network.Kademlia.Bootstrap
Network.Kademlia.Routing
Network.Kademlia.CommonAPI
Network.Kademlia.Persistence
Network.Kademlia.Search
Diffstat (limited to 'dht/WifiHeader.hs')
-rw-r--r-- | dht/WifiHeader.hs | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/dht/WifiHeader.hs b/dht/WifiHeader.hs new file mode 100644 index 00000000..90e77003 --- /dev/null +++ b/dht/WifiHeader.hs | |||
@@ -0,0 +1,335 @@ | |||
1 | {-# LANGUAGE FlexibleInstances #-} | ||
2 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||
3 | {-# LANGUAGE PatternSynonyms #-} | ||
4 | module WifiHeader where | ||
5 | |||
6 | import Data.Bits | ||
7 | import Data.Word | ||
8 | |||
9 | import Net.Ethernet as Mac (Addr(..)) | ||
10 | import Net.Packet | ||
11 | import Net.PacketParsing | ||
12 | |||
13 | import LLCSNAP | ||
14 | |||
15 | -- 802.11 Mac header | ||
16 | -- | ||
17 | -- 23 bytes | ||
18 | |||
19 | -- Wikipedia: | ||
20 | -- | ||
21 | -- Frames are divided into very specific and standardized sections. Each frame | ||
22 | -- consists of a MAC header, payload, and frame check sequence (FCS). | ||
23 | -- | ||
24 | -- Data frames carry packets from web pages, files, etc. within the body.[51] | ||
25 | -- The body begins with an IEEE 802.2 header, with the Destination Service | ||
26 | -- Access Point (DSAP) specifying the protocol; however, if the DSAP is hex AA, | ||
27 | -- the 802.2 header is followed by a Subnetwork Access Protocol (SNAP) header, | ||
28 | -- with the Organizationally Unique Identifier (OUI) and protocol ID (PID) | ||
29 | -- fields specifying the protocol. If the OUI is all zeroes, the protocol ID | ||
30 | -- field is an EtherType value.[52] Almost all 802.11 data frames use 802.2 and | ||
31 | -- SNAP headers, and most use an OUI of 00:00:00 and an EtherType value. | ||
32 | -- | ||
33 | -- [51] http://www.wi-fiplanet.com/tutorials/article.php/1447501 | ||
34 | |||
35 | -- The first two bytes of the MAC header form a frame control field... | ||
36 | -- | ||
37 | -- The next two bytes are reserved for the Duration ID field | ||
38 | -- | ||
39 | -- An 802.11 frame can have up to four address fields. Each field can carry a | ||
40 | -- MAC address. The first 4 bits are used for the fragmentation number, and | ||
41 | -- the last 12 bits are the sequence number. | ||
42 | -- | ||
43 | -- The Sequence Control field is a two-byte section used for identifying | ||
44 | -- message order as well as eliminating duplicate frames. | ||
45 | -- | ||
46 | -- An optional two-byte Quality of Service control field that was added with | ||
47 | -- 802.11e. | ||
48 | -- | ||
49 | -- The payload or frame body field is variable in size, from 0 to 2304 bytes | ||
50 | -- plus any overhead from security encapsulation, and contains information from | ||
51 | -- higher layers | ||
52 | -- | ||
53 | -- The Frame Check Sequence (FCS) is the last four bytes in the standard 802.11 | ||
54 | -- frame. Often referred to as the Cyclic Redundancy Check (CRC), it allows for | ||
55 | -- integrity check of retrieved frames. | ||
56 | |||
57 | -- 2 bits | ||
58 | data Type = Management | ||
59 | | Control | ||
60 | | Data | ||
61 | | Reserved | ||
62 | deriving (Eq,Ord,Enum,Read,Show) | ||
63 | |||
64 | -- 4 bits | ||
65 | data SubType = AssociationRequest | ||
66 | | SubType1 | ||
67 | | SubType2 | ||
68 | | SubType3 | ||
69 | | ProbeRequest | ||
70 | | SubType5 | ||
71 | | SubType6 | ||
72 | | SubType7 | ||
73 | |||
74 | -- Any of the following used with type 'Data' means the optional | ||
75 | -- QoS field is present. | ||
76 | | Beacon | ||
77 | | SubType9 | ||
78 | | Disassociation | ||
79 | | SubTypeB | ||
80 | | SubTypeC | ||
81 | | SubTypeD | ||
82 | | SubTypeE | ||
83 | | SubTypeF | ||
84 | deriving (Eq,Ord,Enum,Read,Show) | ||
85 | |||
86 | -- Byte 0 (Frame Control Field 1) | ||
87 | wifiTypeBits :: Word8 -> Maybe (Type,SubType) | ||
88 | wifiTypeBits b | ||
89 | | version/=0 = Nothing | ||
90 | | otherwise = Just (typ,subtyp) | ||
91 | where | ||
92 | version = b .&. 0x03 | ||
93 | typ = toEnum $ fromIntegral $ 0x03 .&. shiftR b 2 | ||
94 | subtyp = toEnum $ fromIntegral $ 0x0F .&. shiftR b 4 | ||
95 | |||
96 | |||
97 | |||
98 | -- Byte 1 (Frame Control Field 2) | ||
99 | newtype Flags = Flags Word8 | ||
100 | deriving (Eq,Ord,Bits,Read,Show) | ||
101 | |||
102 | pattern ToDS = Flags 0x01 | ||
103 | pattern FromDS = Flags 0x02 | ||
104 | pattern MoreFragments = Flags 0x04 | ||
105 | pattern Retry = Flags 0x08 | ||
106 | pattern PowerManagement = Flags 0x10 | ||
107 | pattern MoreData = Flags 0x20 | ||
108 | pattern Protected = Flags 0x40 | ||
109 | pattern Order = Flags 0x80 | ||
110 | |||
111 | flagNames :: [(Flags, String)] | ||
112 | flagNames = | ||
113 | [( ToDS, "ToDS" ) | ||
114 | ,( FromDS, "FromDS" ) | ||
115 | ,( MoreFragments, "MoreFragments" ) | ||
116 | ,( Retry, "Retry" ) | ||
117 | ,( PowerManagement, "PowerManagement" ) | ||
118 | ,( MoreData, "MoreData" ) | ||
119 | ,( Protected, "Protected" ) | ||
120 | ,( Order, "Order" )] | ||
121 | |||
122 | -- Bytes 2,3 | ||
123 | -- Duration/ID field | ||
124 | -- | ||
125 | -- This field is of size 16 bits. It carries following fields. | ||
126 | -- | ||
127 | -- • In control type frames of subtype Power Save (PS)-Poll, the Duration/ID | ||
128 | -- field carries the association identity (AID) of the station that transmitted | ||
129 | -- the frame in the 14 least significant bits (LSB), with the 2 most | ||
130 | -- significant bits (MSB) both set to 1. AID value varies between values from 1 | ||
131 | -- to 2007. | ||
132 | -- | ||
133 | -- • In all the other frames, this field contains duration value as specified | ||
134 | -- for each of the frame. For all the frames transmitted during the CFP | ||
135 | -- (contention free time period) this field is set to 32,768. If the content of | ||
136 | -- this field is less than 32768, it is used to update NAV (Network Allocation | ||
137 | -- Vector). | ||
138 | newtype DurationID = DurationID Word16 | ||
139 | deriving (Eq,Ord,Read,Show) | ||
140 | |||
141 | instance Parse DurationID where parse = DurationID <$> parse -- (big endian) | ||
142 | |||
143 | |||
144 | |||
145 | -- Bytes 4-(21/27) (+18 or +24 bytes long) | ||
146 | -- | ||
147 | -- Wikipedia claimed: Address 1 is the receiver, Address 2 is the transmitter, | ||
148 | -- Address 3 is used for filtering purposes by the receiver.[dubious – discuss] | ||
149 | -- | ||
150 | -- But http://www.rfwireless-world.com/Articles/WLAN-MAC-layer-protocol.html | ||
151 | -- says: | ||
152 | -- | ||
153 | -- ToDS FromDS addr1 addr2 addr3 addr4 | ||
154 | -- ---- ------ ----- ----- ----- ----- | ||
155 | -- 0 0 DA SA BSSID - | ||
156 | -- 0 1 DA BSSID SA - | ||
157 | -- 1 0 BSSID SA DA - | ||
158 | -- 1 1 RA TA DA SA | ||
159 | -- | ||
160 | -- DataFrames: | ||
161 | -- | ||
162 | -- http://www.rfwireless-world.com/images/WLAN-MAC-Data-Frame.jpg | ||
163 | -- | ||
164 | -- Note 1: The address-1 always holds the RA(Receiver Address) of the intended | ||
165 | -- receiver or receivers(e.g. in multicast operation). Note 2 : The address-2 | ||
166 | -- always holds the address of STA which is transmitting the MAC frame. | ||
167 | |||
168 | data Addresses = Addresses | ||
169 | { bssid :: Maybe Mac.Addr -- BSSID | ||
170 | , srcAddr :: Mac.Addr -- SA | ||
171 | , dstAddr :: Mac.Addr -- DA | ||
172 | , txAddr :: Maybe Mac.Addr -- TA | ||
173 | , rxAddr :: Maybe Mac.Addr -- RA | ||
174 | } | ||
175 | deriving (Eq,Ord,Show) | ||
176 | |||
177 | parseAddresses :: Flags -> PacketParser Addresses | ||
178 | parseAddresses fc = case fc .&. (ToDS .|. FromDS) of | ||
179 | Flags 0 -> do | ||
180 | -- 0 0 DA SA BSSID - | ||
181 | _da <- parse | ||
182 | _sa <- parse | ||
183 | _bssid <- parse | ||
184 | return Addresses | ||
185 | { bssid = Just _bssid | ||
186 | , srcAddr = _sa | ||
187 | , dstAddr = _da | ||
188 | , txAddr = Nothing | ||
189 | , rxAddr = Nothing | ||
190 | } | ||
191 | FromDS -> do | ||
192 | -- 0 1 DA BSSID SA - | ||
193 | _da <- parse | ||
194 | _bssid <- parse | ||
195 | _sa <- parse | ||
196 | return Addresses | ||
197 | { bssid = Just _bssid | ||
198 | , srcAddr = _sa | ||
199 | , dstAddr = _da | ||
200 | , txAddr = Nothing | ||
201 | , rxAddr = Nothing | ||
202 | } | ||
203 | ToDS -> do | ||
204 | -- 1 0 BSSID SA DA - | ||
205 | _bssid <- parse | ||
206 | _sa <- parse | ||
207 | _da <- parse | ||
208 | return Addresses | ||
209 | { bssid = Just _bssid | ||
210 | , srcAddr = _sa | ||
211 | , dstAddr = _da | ||
212 | , txAddr = Nothing | ||
213 | , rxAddr = Nothing | ||
214 | } | ||
215 | Flags 0x03 -> do | ||
216 | -- 1 1 RA TA DA SA | ||
217 | _ra <- parse | ||
218 | _ta <- parse | ||
219 | _da <- parse | ||
220 | -- http://www.rfwireless-world.com/Articles/WLAN-MAC-layer-protocol-p2.html | ||
221 | -- indicates that there is a SequenceControl field here. | ||
222 | _sa <- parse | ||
223 | return Addresses | ||
224 | { bssid = Nothing | ||
225 | , srcAddr = _sa | ||
226 | , dstAddr = _da | ||
227 | , txAddr = Just _ta | ||
228 | , rxAddr = Just _ra | ||
229 | } | ||
230 | |||
231 | -- Bytes 22/28-23/29 (2 bytes) | ||
232 | -- | ||
233 | -- The Sequence Control field. | ||
234 | -- | ||
235 | -- A two-byte section used for identifying message order as well as eliminating | ||
236 | -- duplicate frames. The first 4 bits are used for the fragmentation number, | ||
237 | -- and the last 12 bits are the sequence number. | ||
238 | newtype SequenceControl = SequenceControl Word16 | ||
239 | deriving (Eq,Ord,Read,Show) | ||
240 | |||
241 | instance Parse SequenceControl where parse = SequenceControl <$> parse -- (big endian) | ||
242 | |||
243 | -- Optional: Bytes 24/30 - 25/31 | ||
244 | -- | ||
245 | -- An optional two-byte Quality of Service control field that was added with 802.11e. | ||
246 | newtype QoS = QoS Word16 | ||
247 | deriving (Eq,Ord,Read,Show) | ||
248 | |||
249 | -- Bytes 24/30 (802.11e maybe 26/32) - ? variable length | ||
250 | -- | ||
251 | -- Frame Body | ||
252 | |||
253 | -- Last 4 bytes. | ||
254 | -- | ||
255 | -- FCS | ||
256 | -- | ||
257 | -- Wikipedia cites https://wayback.archive.org/web/20090124151617/http://wifi.cs.st-andrews.ac.uk/wififrame.html | ||
258 | -- | ||
259 | -- From http://www.rfwireless-world.com/Articles/WLAN-MAC-layer-protocol.html | ||
260 | -- | ||
261 | -- The WLAN FCS field is a 32-bit field containing a 32-bit CRC. The FCS is | ||
262 | -- calculated over all the fields of the MAC header and the Frame Body field. | ||
263 | -- These are referred to as the calculation fields. | ||
264 | -- | ||
265 | -- The FCS is calculated using the following standard generator polynomial of | ||
266 | -- degree 32: G(x) = x³² + x²⁶ + x²³ + x²² + x¹⁶ + x¹² + x¹¹ + x¹⁰ + x⁸ + x⁷ + | ||
267 | -- x⁵ + x⁴ + x² + x + 1 | ||
268 | -- | ||
269 | -- The FCS is the 1's complement of the sum (modulo 2) of the following: | ||
270 | -- | ||
271 | -- • The remainder of xk * (x³¹+x³⁰+x²⁹+...+x² + x + 1) divided (modulo 2) by | ||
272 | -- G(x), where k is the number of bits in the calculation fields. | ||
273 | -- | ||
274 | -- • The remainder after multiplication of the contents (treated as a | ||
275 | -- polynomial) of the calculation fields by x³² and then division by G(x) | ||
276 | newtype FCS = FCS Word32 | ||
277 | deriving (Eq,Ord,Read,Show) | ||
278 | |||
279 | data Packet a = Packet | ||
280 | { wifiType :: Type | ||
281 | , subtype :: SubType | ||
282 | , flags :: Flags | ||
283 | , duration :: DurationID | ||
284 | , addresses :: Addresses | ||
285 | , sequenceControl :: SequenceControl | ||
286 | , qos :: Maybe QoS | ||
287 | , llcsnap :: Maybe LLCSNAP | ||
288 | , content :: a | ||
289 | , fcs :: Maybe FCS | ||
290 | } | ||
291 | deriving (Eq,Ord,Show) | ||
292 | |||
293 | -- Hardcoded flag to disable parsing FCS checksum. | ||
294 | hasFCS :: Bool | ||
295 | hasFCS = False -- DLT_IEEE802_11 has no trailing 4-byte FCS checksum | ||
296 | -- | ||
297 | -- Other link types might include this: | ||
298 | -- See: DLT_IEEE802_11_RADIO | ||
299 | -- or DLT_IEEE802_11_RADIO_AVS | ||
300 | |||
301 | instance Parse (Packet InPacket) where | ||
302 | parse = do | ||
303 | Just (typ,subtyp) <- wifiTypeBits <$> word8 | ||
304 | flgs <- Flags <$> word8 | ||
305 | durid <- DurationID <$> word16 | ||
306 | addrs <- parseAddresses flgs | ||
307 | sc <- SequenceControl <$> word16 -- TODO: Sometimes this precedes the 4th address. | ||
308 | qos <- if typ == Data && subtyp > SubType7 | ||
309 | then Just . QoS <$> parse | ||
310 | else return Nothing | ||
311 | llcsnap <- case typ of | ||
312 | Data -> Just <$> parse | ||
313 | _ -> return Nothing | ||
314 | rst <- therest | ||
315 | let (payload,fcs) = if hasFCS | ||
316 | then | ||
317 | let payload = takeInPack (len rst - 4) rst | ||
318 | fcshi = rst `wordAt` (len rst - 4) | ||
319 | fcslo = rst `wordAt` (len rst - 2) | ||
320 | fcs = FCS $ fromIntegral fcshi * 65536 | ||
321 | + fromIntegral fcslo | ||
322 | in (payload,Just fcs) | ||
323 | else (rst,Nothing) | ||
324 | return Packet | ||
325 | { wifiType = typ | ||
326 | , subtype = subtyp | ||
327 | , flags = flgs | ||
328 | , duration = durid | ||
329 | , addresses = addrs | ||
330 | , sequenceControl = sc | ||
331 | , qos = qos | ||
332 | , llcsnap = llcsnap | ||
333 | , content = payload | ||
334 | , fcs = fcs | ||
335 | } | ||