summaryrefslogtreecommitdiff
path: root/dht/WifiHeader.hs
diff options
context:
space:
mode:
authorJames Crayne <jim.crayne@gmail.com>2019-09-28 13:43:29 -0400
committerJoe Crayne <joe@jerkface.net>2020-01-01 19:27:53 -0500
commit11987749fc6e6d3e53ea737d46d5ab13a16faeb8 (patch)
tree5716463275c2d3e902889db619908ded2a73971c /dht/WifiHeader.hs
parentadd2c76bced51fde5e9917e7449ef52be70faf87 (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.hs335
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 #-}
4module WifiHeader where
5
6import Data.Bits
7import Data.Word
8
9import Net.Ethernet as Mac (Addr(..))
10import Net.Packet
11import Net.PacketParsing
12
13import 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
58data Type = Management
59 | Control
60 | Data
61 | Reserved
62 deriving (Eq,Ord,Enum,Read,Show)
63
64-- 4 bits
65data 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)
87wifiTypeBits :: Word8 -> Maybe (Type,SubType)
88wifiTypeBits 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)
99newtype Flags = Flags Word8
100 deriving (Eq,Ord,Bits,Read,Show)
101
102pattern ToDS = Flags 0x01
103pattern FromDS = Flags 0x02
104pattern MoreFragments = Flags 0x04
105pattern Retry = Flags 0x08
106pattern PowerManagement = Flags 0x10
107pattern MoreData = Flags 0x20
108pattern Protected = Flags 0x40
109pattern Order = Flags 0x80
110
111flagNames :: [(Flags, String)]
112flagNames =
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).
138newtype DurationID = DurationID Word16
139 deriving (Eq,Ord,Read,Show)
140
141instance 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
168data 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
177parseAddresses :: Flags -> PacketParser Addresses
178parseAddresses 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.
238newtype SequenceControl = SequenceControl Word16
239 deriving (Eq,Ord,Read,Show)
240
241instance 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.
246newtype 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)
276newtype FCS = FCS Word32
277 deriving (Eq,Ord,Read,Show)
278
279data 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.
294hasFCS :: Bool
295hasFCS = 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
301instance 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 }