Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/scapy/layers/dot11.py: 66%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

581 statements  

1# SPDX-License-Identifier: GPL-2.0-only 

2# This file is part of Scapy 

3# See https://scapy.net/ for more information 

4# Copyright (C) Philippe Biondi <phil@secdev.org> 

5 

6""" 

7Wireless LAN according to IEEE 802.11. 

8 

9This file contains bindings for 802.11 layers and some usual linklayers: 

10 - PRISM 

11 - RadioTap 

12""" 

13 

14import re 

15import struct 

16from zlib import crc32 

17 

18from scapy.config import conf, crypto_validator 

19from scapy.data import ETHER_ANY, DLT_IEEE802_11, DLT_PRISM_HEADER, \ 

20 DLT_IEEE802_11_RADIO 

21from scapy.compat import raw, plain_str, orb, chb 

22from scapy.packet import Packet, bind_layers, bind_top_down, NoPayload 

23from scapy.fields import ( 

24 BitEnumField, 

25 BitField, 

26 BitMultiEnumField, 

27 ByteEnumField, 

28 ByteField, 

29 ConditionalField, 

30 FCSField, 

31 FieldLenField, 

32 FieldListField, 

33 FlagsField, 

34 IntField, 

35 LEFieldLenField, 

36 LEIntField, 

37 LELongField, 

38 LEShortEnumField, 

39 LEShortField, 

40 LESignedIntField, 

41 MayEnd, 

42 MultipleTypeField, 

43 OUIField, 

44 PacketField, 

45 PacketListField, 

46 ReversePadField, 

47 ScalingField, 

48 ShortField, 

49 StrField, 

50 StrFixedLenField, 

51 StrLenField, 

52 XByteField, 

53 XStrFixedLenField, 

54) 

55from scapy.ansmachine import AnsweringMachine 

56from scapy.plist import PacketList 

57from scapy.layers.l2 import Ether, LLC, MACField 

58from scapy.layers.inet import IP, TCP 

59from scapy.error import warning, log_loading 

60from scapy.sendrecv import sniff, sendp 

61 

62 

63if conf.crypto_valid: 

64 from cryptography.hazmat.backends import default_backend 

65 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms 

66else: 

67 default_backend = Ciphers = algorithms = None 

68 log_loading.info("Can't import python-cryptography v1.7+. Disabled WEP decryption/encryption. (Dot11)") # noqa: E501 

69 

70 

71######### 

72# Prism # 

73######### 

74 

75# http://www.martin.cc/linux/prism 

76 

77class PrismHeader(Packet): 

78 """ iwpriv wlan0 monitor 3 """ 

79 name = "Prism header" 

80 fields_desc = [LEIntField("msgcode", 68), 

81 LEIntField("len", 144), 

82 StrFixedLenField("dev", "", 16), 

83 LEIntField("hosttime_did", 0), 

84 LEShortField("hosttime_status", 0), 

85 LEShortField("hosttime_len", 0), 

86 LEIntField("hosttime", 0), 

87 LEIntField("mactime_did", 0), 

88 LEShortField("mactime_status", 0), 

89 LEShortField("mactime_len", 0), 

90 LEIntField("mactime", 0), 

91 LEIntField("channel_did", 0), 

92 LEShortField("channel_status", 0), 

93 LEShortField("channel_len", 0), 

94 LEIntField("channel", 0), 

95 LEIntField("rssi_did", 0), 

96 LEShortField("rssi_status", 0), 

97 LEShortField("rssi_len", 0), 

98 LEIntField("rssi", 0), 

99 LEIntField("sq_did", 0), 

100 LEShortField("sq_status", 0), 

101 LEShortField("sq_len", 0), 

102 LEIntField("sq", 0), 

103 LEIntField("signal_did", 0), 

104 LEShortField("signal_status", 0), 

105 LEShortField("signal_len", 0), 

106 LESignedIntField("signal", 0), 

107 LEIntField("noise_did", 0), 

108 LEShortField("noise_status", 0), 

109 LEShortField("noise_len", 0), 

110 LEIntField("noise", 0), 

111 LEIntField("rate_did", 0), 

112 LEShortField("rate_status", 0), 

113 LEShortField("rate_len", 0), 

114 LEIntField("rate", 0), 

115 LEIntField("istx_did", 0), 

116 LEShortField("istx_status", 0), 

117 LEShortField("istx_len", 0), 

118 LEIntField("istx", 0), 

119 LEIntField("frmlen_did", 0), 

120 LEShortField("frmlen_status", 0), 

121 LEShortField("frmlen_len", 0), 

122 LEIntField("frmlen", 0), 

123 ] 

124 

125 def answers(self, other): 

126 if isinstance(other, PrismHeader): 

127 return self.payload.answers(other.payload) 

128 else: 

129 return self.payload.answers(other) 

130 

131############ 

132# RadioTap # 

133############ 

134 

135# https://www.radiotap.org/ 

136 

137# Note: Radiotap alignment is crazy. See the doc: 

138# https://www.radiotap.org/#alignment-in-radiotap 

139 

140# RadioTap constants 

141 

142 

143_rt_present = ['TSFT', 'Flags', 'Rate', 'Channel', 'FHSS', 'dBm_AntSignal', 

144 'dBm_AntNoise', 'Lock_Quality', 'TX_Attenuation', 

145 'dB_TX_Attenuation', 'dBm_TX_Power', 'Antenna', 

146 'dB_AntSignal', 'dB_AntNoise', 'RXFlags', 'TXFlags', 

147 'b17', 'b18', 'ChannelPlus', 'MCS', 'A_MPDU', 

148 'VHT', 'timestamp', 'HE', 'HE_MU', 'HE_MU_other_user', 

149 'zero_length_psdu', 'L_SIG', 'TLV', 

150 'RadiotapNS', 'VendorNS', 'Ext'] 

151 

152# Note: Inconsistencies with wireshark 

153# Wireshark ignores the suggested fields, whereas we implement some of them 

154# (some are well-used even though not accepted) 

155# However, flags that conflicts with Wireshark are not and MUST NOT be 

156# implemented -> b17, b18 

157 

158_rt_flags = ['CFP', 'ShortPreamble', 'wep', 'fragment', 'FCS', 'pad', 

159 'badFCS', 'ShortGI'] 

160 

161_rt_channelflags = ['res1', 'res2', 'res3', 'res4', 'Turbo', 'CCK', 

162 'OFDM', '2GHz', '5GHz', 'Passive', 'Dynamic_CCK_OFDM', 

163 'GFSK', 'GSM', 'StaticTurbo', '10MHz', '5MHz'] 

164 

165_rt_rxflags = ["res1", "BAD_PLCP", "res2"] 

166 

167_rt_txflags = ["TX_FAIL", "CTS", "RTS", "NOACK", "NOSEQ", "ORDER"] 

168 

169_rt_channelflags2 = ['res1', 'res2', 'res3', 'res4', 'Turbo', 'CCK', 

170 'OFDM', '2GHz', '5GHz', 'Passive', 'Dynamic_CCK_OFDM', 

171 'GFSK', 'GSM', 'StaticTurbo', '10MHz', '5MHz', 

172 '20MHz', '40MHz_ext_channel_above', 

173 '40MHz_ext_channel_below', 

174 'res5', 'res6', 'res7', 'res8', 'res9'] 

175 

176_rt_tsflags = ['32-bit_counter', 'Accuracy', 'res1', 'res2', 'res3', 

177 'res4', 'res5', 'res6'] 

178 

179_rt_knownmcs = ['MCS_bandwidth', 'MCS_index', 'guard_interval', 'HT_format', 

180 'FEC_type', 'STBC_streams', 'Ness', 'Ness_MSB'] 

181 

182_rt_bandwidth = {0: "20MHz", 1: "40MHz", 2: "ht40Mhz-", 3: "ht40MHz+"} 

183 

184_rt_a_mpdu_flags = ['Report0Subframe', 'Is0Subframe', 'KnownLastSubframe', 

185 'LastSubframe', 'CRCerror', 'EOFsubframe', 'KnownEOF', 

186 'res1', 'res2', 'res3', 'res4', 'res5', 'res6', 'res7', 

187 'res8'] 

188 

189_rt_vhtbandwidth = { 

190 0: "20MHz", 1: "40MHz", 2: "40MHz", 3: "40MHz", 4: "80MHz", 5: "80MHz", 

191 6: "80MHz", 7: "80MHz", 8: "80MHz", 9: "80MHz", 10: "80MHz", 11: "160MHz", 

192 12: "160MHz", 13: "160MHz", 14: "160MHz", 15: "160MHz", 16: "160MHz", 

193 17: "160MHz", 18: "160MHz", 19: "160MHz", 20: "160MHz", 21: "160MHz", 

194 22: "160MHz", 23: "160MHz", 24: "160MHz", 25: "160MHz" 

195} 

196 

197_rt_knownvht = ['STBC', 'TXOP_PS_NOT_ALLOWED', 'GuardInterval', 'SGINsysmDis', 

198 'LDPCextraOFDM', 'Beamformed', 'Bandwidth', 'GroupID', 

199 'PartialAID', 

200 'res1', 'res2', 'res3', 'res4', 'res5', 'res6', 'res7'] 

201 

202_rt_presentvht = ['STBC', 'TXOP_PS_NOT_ALLOWED', 'GuardInterval', 

203 'SGINsysmDis', 'LDPCextraOFDM', 'Beamformed', 

204 'res1', 'res2'] 

205 

206_rt_hemuother_per_user_known = [ 

207 'user field position', 

208 'STA-ID', 

209 'NSTS', 

210 'Tx Beamforming', 

211 'Spatial Configuration', 

212 'MCS', 

213 'DCM', 

214 'Coding', 

215] 

216 

217 

218# Radiotap utils 

219 

220# Note: extended presence masks are dissected pretty dumbly by 

221# Wireshark. 

222 

223def _next_radiotap_extpm(pkt, lst, cur, s): 

224 """Generates the next RadioTapExtendedPresenceMask""" 

225 if cur is None or (cur.present and cur.present.Ext): 

226 st = len(lst) + (cur is not None) 

227 return lambda *args: RadioTapExtendedPresenceMask(*args, index=st) 

228 return None 

229 

230 

231class RadioTapExtendedPresenceMask(Packet): 

232 """RadioTapExtendedPresenceMask should be instantiated by passing an 

233 `index=` kwarg, stating which place the item has in the list. 

234 

235 Passing index will update the b[x] fields accordingly to the index. 

236 e.g. 

237 >>> a = RadioTapExtendedPresenceMask(present="b0+b12+b29+Ext") 

238 >>> b = RadioTapExtendedPresenceMask(index=1, present="b33+b45+b59+b62") 

239 >>> pkt = RadioTap(present="Ext", Ext=[a, b]) 

240 """ 

241 name = "RadioTap Extended presence mask" 

242 fields_desc = [FlagsField('present', None, -32, 

243 ["b%s" % i for i in range(0, 31)] + ["Ext"])] 

244 

245 def __init__(self, _pkt=None, index=0, **kwargs): 

246 self._restart_indentation(index) 

247 Packet.__init__(self, _pkt, **kwargs) 

248 

249 def _restart_indentation(self, index): 

250 st = index * 32 

251 self.fields_desc[0].names = ["b%s" % (i + st) for i in range(0, 31)] + ["Ext"] # noqa: E501 

252 

253 def guess_payload_class(self, pay): 

254 return conf.padding_layer 

255 

256 

257# This is still unimplemented in Wireshark 

258# https://www.radiotap.org/fields/TLV.html 

259class RadioTapTLV(Packet): 

260 fields_desc = [ 

261 LEShortEnumField("type", 0, _rt_present), 

262 LEShortField("length", None), 

263 ConditionalField( 

264 OUIField("oui", 0), 

265 lambda pkt: pkt.type == 30 # VendorNS 

266 ), 

267 ConditionalField( 

268 ByteField("subtype", 0), 

269 lambda pkt: pkt.type == 30 

270 ), 

271 ConditionalField( 

272 LEShortField("presence_type", 0), 

273 lambda pkt: pkt.type == 30 

274 ), 

275 ConditionalField( 

276 LEShortField("reserved", 0), 

277 lambda pkt: pkt.type == 30 

278 ), 

279 StrLenField("data", b"", 

280 length_from=lambda pkt: pkt.length), 

281 StrLenField("pad", None, length_from=lambda pkt: -pkt.length % 4) 

282 ] 

283 

284 def post_build(self, pkt, pay): 

285 if self.length is None: 

286 pkt = pkt[:2] + struct.pack("<H", len(self.data)) + pkt[4:] 

287 if self.pad is None: 

288 pkt += b"\x00" * (-len(self.data) % 4) 

289 return pkt + pay 

290 

291 def extract_padding(self, s): 

292 return "", s 

293 

294 

295# RADIOTAP 

296 

297class RadioTap(Packet): 

298 name = "RadioTap" 

299 deprecated_fields = { 

300 "Channel": ("ChannelFrequency", "2.4.3"), 

301 "ChannelFlags2": ("ChannelPlusFlags", "2.4.3"), 

302 "ChannelNumber": ("ChannelPlusNumber", "2.4.3"), 

303 } 

304 fields_desc = [ 

305 ByteField('version', 0), 

306 ByteField('pad', 0), 

307 LEShortField('len', None), 

308 FlagsField('present', None, -32, _rt_present), # noqa: E501 

309 # Extended presence mask 

310 ConditionalField(PacketListField("Ext", [], next_cls_cb=_next_radiotap_extpm), lambda pkt: pkt.present and pkt.present.Ext), # noqa: E501 

311 # RadioTap fields - each starts with a ReversePadField 

312 # to handle padding 

313 

314 # TSFT 

315 ConditionalField( 

316 ReversePadField( 

317 LELongField("mac_timestamp", 0), 

318 8 

319 ), 

320 lambda pkt: pkt.present and pkt.present.TSFT), 

321 # Flags 

322 ConditionalField( 

323 FlagsField("Flags", None, -8, _rt_flags), 

324 lambda pkt: pkt.present and pkt.present.Flags), 

325 # Rate 

326 ConditionalField( 

327 ScalingField("Rate", 0, scaling=0.5, 

328 unit="Mbps", fmt="B"), 

329 lambda pkt: pkt.present and pkt.present.Rate), 

330 # Channel 

331 ConditionalField( 

332 ReversePadField( 

333 LEShortField("ChannelFrequency", 0), 

334 2 

335 ), 

336 lambda pkt: pkt.present and pkt.present.Channel), 

337 ConditionalField( 

338 FlagsField("ChannelFlags", None, -16, _rt_channelflags), 

339 lambda pkt: pkt.present and pkt.present.Channel), 

340 # dBm_AntSignal 

341 ConditionalField( 

342 ScalingField("dBm_AntSignal", 0, 

343 unit="dBm", fmt="b"), 

344 lambda pkt: pkt.present and pkt.present.dBm_AntSignal), 

345 # dBm_AntNoise 

346 ConditionalField( 

347 ScalingField("dBm_AntNoise", 0, 

348 unit="dBm", fmt="b"), 

349 lambda pkt: pkt.present and pkt.present.dBm_AntNoise), 

350 # Lock_Quality 

351 ConditionalField( 

352 ReversePadField( 

353 LEShortField("Lock_Quality", 0), 

354 2 

355 ), 

356 lambda pkt: pkt.present and pkt.present.Lock_Quality), 

357 # Antenna 

358 ConditionalField( 

359 ByteField("Antenna", 0), 

360 lambda pkt: pkt.present and pkt.present.Antenna), 

361 # RX Flags 

362 ConditionalField( 

363 ReversePadField( 

364 FlagsField("RXFlags", None, -16, _rt_rxflags), 

365 2 

366 ), 

367 lambda pkt: pkt.present and pkt.present.RXFlags), 

368 # TX Flags 

369 ConditionalField( 

370 ReversePadField( 

371 FlagsField("TXFlags", None, -16, _rt_txflags), 

372 2 

373 ), 

374 lambda pkt: pkt.present and pkt.present.TXFlags), 

375 # ChannelPlus 

376 ConditionalField( 

377 ReversePadField( 

378 FlagsField("ChannelPlusFlags", None, -32, _rt_channelflags2), 

379 4 

380 ), 

381 lambda pkt: pkt.present and pkt.present.ChannelPlus), 

382 ConditionalField( 

383 LEShortField("ChannelPlusFrequency", 0), 

384 lambda pkt: pkt.present and pkt.present.ChannelPlus), 

385 ConditionalField( 

386 ByteField("ChannelPlusNumber", 0), 

387 lambda pkt: pkt.present and pkt.present.ChannelPlus), 

388 # MCS 

389 ConditionalField( 

390 ReversePadField( 

391 FlagsField("knownMCS", None, -8, _rt_knownmcs), 

392 2 

393 ), 

394 lambda pkt: pkt.present and pkt.present.MCS), 

395 ConditionalField( 

396 BitField("Ness_LSB", 0, 1), 

397 lambda pkt: pkt.present and pkt.present.MCS), 

398 ConditionalField( 

399 BitField("STBC_streams", 0, 2), 

400 lambda pkt: pkt.present and pkt.present.MCS), 

401 ConditionalField( 

402 BitEnumField("FEC_type", 0, 1, {0: "BCC", 1: "LDPC"}), 

403 lambda pkt: pkt.present and pkt.present.MCS), 

404 ConditionalField( 

405 BitEnumField("HT_format", 0, 1, {0: "mixed", 1: "greenfield"}), 

406 lambda pkt: pkt.present and pkt.present.MCS), 

407 ConditionalField( 

408 BitEnumField("guard_interval", 0, 1, {0: "Long_GI", 1: "Short_GI"}), # noqa: E501 

409 lambda pkt: pkt.present and pkt.present.MCS), 

410 ConditionalField( 

411 BitEnumField("MCS_bandwidth", 0, 2, _rt_bandwidth), 

412 lambda pkt: pkt.present and pkt.present.MCS), 

413 ConditionalField( 

414 ByteField("MCS_index", 0), 

415 lambda pkt: pkt.present and pkt.present.MCS), 

416 # A_MPDU 

417 ConditionalField( 

418 ReversePadField( 

419 LEIntField("A_MPDU_ref", 0), 

420 4 

421 ), 

422 lambda pkt: pkt.present and pkt.present.A_MPDU), 

423 ConditionalField( 

424 FlagsField("A_MPDU_flags", None, -32, _rt_a_mpdu_flags), 

425 lambda pkt: pkt.present and pkt.present.A_MPDU), 

426 # VHT 

427 ConditionalField( 

428 ReversePadField( 

429 FlagsField("KnownVHT", None, -16, _rt_knownvht), 

430 2 

431 ), 

432 lambda pkt: pkt.present and pkt.present.VHT), 

433 ConditionalField( 

434 FlagsField("PresentVHT", None, -8, _rt_presentvht), 

435 lambda pkt: pkt.present and pkt.present.VHT), 

436 ConditionalField( 

437 ByteEnumField("VHT_bandwidth", 0, _rt_vhtbandwidth), 

438 lambda pkt: pkt.present and pkt.present.VHT), 

439 ConditionalField( 

440 StrFixedLenField("mcs_nss", 0, length=5), 

441 lambda pkt: pkt.present and pkt.present.VHT), 

442 ConditionalField( 

443 ByteField("GroupID", 0), 

444 lambda pkt: pkt.present and pkt.present.VHT), 

445 ConditionalField( 

446 ShortField("PartialAID", 0), 

447 lambda pkt: pkt.present and pkt.present.VHT), 

448 # timestamp 

449 ConditionalField( 

450 ReversePadField( 

451 LELongField("timestamp", 0), 

452 8 

453 ), 

454 lambda pkt: pkt.present and pkt.present.timestamp), 

455 ConditionalField( 

456 LEShortField("ts_accuracy", 0), 

457 lambda pkt: pkt.present and pkt.present.timestamp), 

458 ConditionalField( 

459 BitEnumField("ts_unit", 0, 4, { 

460 0: 'milliseconds', 

461 1: 'microseconds', 

462 2: 'nanoseconds'}), 

463 lambda pkt: pkt.present and pkt.present.timestamp), 

464 ConditionalField( 

465 BitField("ts_position", 0, 4), 

466 lambda pkt: pkt.present and pkt.present.timestamp), 

467 ConditionalField( 

468 FlagsField("ts_flags", None, 8, _rt_tsflags), 

469 lambda pkt: pkt.present and pkt.present.timestamp), 

470 # HE - XXX not complete 

471 ConditionalField( 

472 ReversePadField( 

473 LEShortField("he_data1", 0), 

474 2 

475 ), 

476 lambda pkt: pkt.present and pkt.present.HE), 

477 ConditionalField( 

478 LEShortField("he_data2", 0), 

479 lambda pkt: pkt.present and pkt.present.HE), 

480 ConditionalField( 

481 LEShortField("he_data3", 0), 

482 lambda pkt: pkt.present and pkt.present.HE), 

483 ConditionalField( 

484 LEShortField("he_data4", 0), 

485 lambda pkt: pkt.present and pkt.present.HE), 

486 ConditionalField( 

487 LEShortField("he_data5", 0), 

488 lambda pkt: pkt.present and pkt.present.HE), 

489 ConditionalField( 

490 LEShortField("he_data6", 0), 

491 lambda pkt: pkt.present and pkt.present.HE), 

492 # HE_MU 

493 ConditionalField( 

494 ReversePadField( 

495 LEShortField("hemu_flags1", 0), 

496 2 

497 ), 

498 lambda pkt: pkt.present and pkt.present.HE_MU), 

499 ConditionalField( 

500 LEShortField("hemu_flags2", 0), 

501 lambda pkt: pkt.present and pkt.present.HE_MU), 

502 ConditionalField( 

503 FieldListField("RU_channel1", [], ByteField('', 0), 

504 length_from=lambda x: 4), 

505 lambda pkt: pkt.present and pkt.present.HE_MU), 

506 ConditionalField( 

507 FieldListField("RU_channel2", [], ByteField('', 0), 

508 length_from=lambda x: 4), 

509 lambda pkt: pkt.present and pkt.present.HE_MU), 

510 # HE_MU_other_user 

511 ConditionalField( 

512 ReversePadField( 

513 LEShortField("hemuou_per_user_1", 0x7fff), 

514 2 

515 ), 

516 lambda pkt: pkt.present and pkt.present.HE_MU_other_user), 

517 ConditionalField( 

518 LEShortField("hemuou_per_user_2", 0x003f), 

519 lambda pkt: pkt.present and pkt.present.HE_MU_other_user), 

520 ConditionalField( 

521 ByteField("hemuou_per_user_position", 0), 

522 lambda pkt: pkt.present and pkt.present.HE_MU_other_user), 

523 ConditionalField( 

524 FlagsField("hemuou_per_user_known", 0, -16, 

525 _rt_hemuother_per_user_known), 

526 lambda pkt: pkt.present and pkt.present.HE_MU_other_user), 

527 # L_SIG 

528 ConditionalField( 

529 ReversePadField( 

530 FlagsField("lsig_data1", 0, -16, ["rate", "length"]), 

531 2 

532 ), 

533 lambda pkt: pkt.present and pkt.present.L_SIG), 

534 ConditionalField( 

535 BitField("lsig_length", 0, 12, tot_size=-2), 

536 lambda pkt: pkt.present and pkt.present.L_SIG), 

537 ConditionalField( 

538 BitField("lsig_rate", 0, 4, end_tot_size=-2), 

539 lambda pkt: pkt.present and pkt.present.L_SIG), 

540 # TLV fields 

541 ConditionalField( 

542 ReversePadField( 

543 PacketListField("tlvs", [], RadioTapTLV), 

544 4 

545 ), 

546 lambda pkt: pkt.present and pkt.present.TLV, 

547 ), 

548 # Remaining 

549 StrLenField('notdecoded', "", length_from=lambda pkt: 0) 

550 ] 

551 

552 def guess_payload_class(self, payload): 

553 if self.present and self.present.Flags and self.Flags.FCS: 

554 return Dot11FCS 

555 return Dot11 

556 

557 def post_dissect(self, s): 

558 length = max(self.len - len(self.original) + len(s), 0) 

559 self.notdecoded = s[:length] 

560 return s[length:] 

561 

562 def post_build(self, p, pay): 

563 if self.len is None: 

564 p = p[:2] + struct.pack("!H", len(p))[::-1] + p[4:] 

565 return p + pay 

566 

567 

568########## 

569# 802.11 # 

570########## 

571 

572# Note: 

573# 802.11-2016 includes the spec for 

574# 802.11abdghijekrywnpzvus,ae,aa,ad,ac,af 

575 

576# 802.11-2016 9.2 

577 

578# 802.11-2016 9.2.4.1.3 

579_dot11_subtypes = { 

580 0: { # Management 

581 0: "Association Request", 

582 1: "Association Response", 

583 2: "Reassociation Request", 

584 3: "Reassociation Response", 

585 4: "Probe Request", 

586 5: "Probe Response", 

587 6: "Timing Advertisement", 

588 8: "Beacon", 

589 9: "ATIM", 

590 10: "Disassociation", 

591 11: "Authentication", 

592 12: "Deauthentication", 

593 13: "Action", 

594 14: "Action No Ack", 

595 }, 

596 1: { # Control 

597 2: "Trigger", 

598 3: "TACK", 

599 4: "Beamforming Report Poll", 

600 5: "VHT/HE NDP Announcement", 

601 6: "Control Frame Extension", 

602 7: "Control Wrapper", 

603 8: "Block Ack Request", 

604 9: "Block Ack", 

605 10: "PS-Poll", 

606 11: "RTS", 

607 12: "CTS", 

608 13: "Ack", 

609 14: "CF-End", 

610 15: "CF-End+CF-Ack", 

611 }, 

612 2: { # Data 

613 0: "Data", 

614 1: "Data+CF-Ack", 

615 2: "Data+CF-Poll", 

616 3: "Data+CF-Ack+CF-Poll", 

617 4: "Null (no data)", 

618 5: "CF-Ack (no data)", 

619 6: "CF-Poll (no data)", 

620 7: "CF-Ack+CF-Poll (no data)", 

621 8: "QoS Data", 

622 9: "QoS Data+CF-Ack", 

623 10: "QoS Data+CF-Poll", 

624 11: "QoS Data+CF-Ack+CF-Poll", 

625 12: "QoS Null (no data)", 

626 14: "QoS CF-Poll (no data)", 

627 15: "QoS CF-Ack+CF-Poll (no data)" 

628 }, 

629 3: { # Extension 

630 0: "DMG Beacon", 

631 1: "S1G Beacon" 

632 } 

633} 

634 

635_dot11_cfe = { 

636 2: "Poll", 

637 3: "SPR", 

638 4: "Grant", 

639 5: "DMG CTS", 

640 6: "DMG DTS", 

641 7: "Grant Ack", 

642 8: "SSW", 

643 9: "SSW-Feedback", 

644 10: "SSW-Ack", 

645} 

646 

647 

648_dot11_addr_meaning = [ 

649 [ # Management: 802.11-2016 9.3.3.2 

650 "RA=DA", "TA=SA", "BSSID/STA", None, 

651 ], 

652 [ # Control 

653 "RA", "TA", None, None 

654 ], 

655 [ # Data: 802.11-2016 9.3.2.1: Table 9-26 

656 [["RA=DA", "RA=DA"], ["RA=BSSID", "RA"]], 

657 [["TA=SA", "TA=BSSID"], ["TA=SA", "TA"]], 

658 [["BSSID", "SA"], ["DA", "DA"]], 

659 [[None, None], ["SA", "BSSID"]], 

660 ], 

661 [ # Extension 

662 "BSSID", None, None, None 

663 ], 

664] 

665 

666 

667class _Dot11MacField(MACField): 

668 """ 

669 A MACField that displays the address type depending on the 

670 802.11 flags 

671 """ 

672 __slots__ = ["index"] 

673 

674 def __init__(self, name, default, index): 

675 self.index = index 

676 super(_Dot11MacField, self).__init__(name, default) 

677 

678 def i2repr(self, pkt, val): 

679 s = super(_Dot11MacField, self).i2repr(pkt, val) 

680 meaning = pkt.address_meaning(self.index) 

681 if meaning: 

682 return "%s (%s)" % (s, meaning) 

683 return s 

684 

685 

686# 802.11-2016 9.2.4.1.1 

687class Dot11(Packet): 

688 name = "802.11" 

689 fields_desc = [ 

690 BitMultiEnumField("subtype", 0, 4, _dot11_subtypes, 

691 lambda pkt: pkt.type), 

692 BitEnumField("type", 0, 2, ["Management", "Control", "Data", 

693 "Extension"]), 

694 BitField("proto", 0, 2), 

695 ConditionalField( 

696 BitEnumField("cfe", 0, 4, _dot11_cfe), 

697 lambda pkt: (pkt.type, pkt.subtype) == (1, 6) 

698 ), 

699 MultipleTypeField( 

700 [ 

701 ( 

702 FlagsField("FCfield", 0, 4, 

703 ["pw-mgt", "MD", "protected", "order"]), 

704 lambda pkt: (pkt.type, pkt.subtype) == (1, 6) 

705 ) 

706 ], 

707 FlagsField("FCfield", 0, 8, 

708 ["to-DS", "from-DS", "MF", "retry", 

709 "pw-mgt", "MD", "protected", "order"]) 

710 ), 

711 ShortField("ID", 0), 

712 _Dot11MacField("addr1", ETHER_ANY, 1), 

713 ConditionalField( 

714 _Dot11MacField("addr2", ETHER_ANY, 2), 

715 lambda pkt: (pkt.type != 1 or 

716 pkt.subtype in [0x4, 0x5, 0x6, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf]), 

717 ), 

718 ConditionalField( 

719 _Dot11MacField("addr3", ETHER_ANY, 3), 

720 lambda pkt: (pkt.type in [0, 2] or 

721 ((pkt.type, pkt.subtype) == (1, 6) and pkt.cfe == 6)), 

722 ), 

723 ConditionalField(LEShortField("SC", 0), lambda pkt: pkt.type != 1), 

724 ConditionalField( 

725 _Dot11MacField("addr4", ETHER_ANY, 4), 

726 lambda pkt: (pkt.type == 2 and 

727 pkt.FCfield & 3 == 3), # from-DS+to-DS 

728 ) 

729 ] 

730 

731 def mysummary(self): 

732 # Supports both Dot11 and Dot11FCS 

733 return self.sprintf("802.11 %%%s.type%% %%%s.subtype%% %%%s.addr2%% > %%%s.addr1%%" % ((self.__class__.__name__,) * 4)) # noqa: E501 

734 

735 def guess_payload_class(self, payload): 

736 if self.type == 0x02 and ( 

737 0x08 <= self.subtype <= 0xF and self.subtype != 0xD): 

738 return Dot11QoS 

739 elif self.FCfield.protected: 

740 # When a frame is handled by encryption, the Protected Frame bit 

741 # (previously called WEP bit) is set to 1, and the Frame Body 

742 # begins with the appropriate cryptographic header. 

743 return Dot11Encrypted 

744 else: 

745 return Packet.guess_payload_class(self, payload) 

746 

747 def answers(self, other): 

748 if isinstance(other, Dot11): 

749 if self.type == 0: # management 

750 if self.addr1.lower() != other.addr2.lower(): # check resp DA w/ req SA # noqa: E501 

751 return 0 

752 if (other.subtype, self.subtype) in [(0, 1), (2, 3), (4, 5)]: 

753 return 1 

754 if self.subtype == other.subtype == 11: # auth 

755 return self.payload.answers(other.payload) 

756 elif self.type == 1: # control 

757 return 0 

758 elif self.type == 2: # data 

759 return self.payload.answers(other.payload) 

760 elif self.type == 3: # reserved 

761 return 0 

762 return 0 

763 

764 def address_meaning(self, index): 

765 """ 

766 Return the meaning of the address[index] considering the context 

767 """ 

768 if index not in [1, 2, 3, 4]: 

769 raise ValueError("Wrong index: should be [1, 2, 3, 4]") 

770 index = index - 1 

771 if self.type == 0: # Management 

772 return _dot11_addr_meaning[0][index] 

773 elif self.type == 1: # Control 

774 if (self.type, self.subtype) == (1, 6) and self.cfe == 6: 

775 return ["RA", "NAV-SA", "NAV-DA"][index] 

776 return _dot11_addr_meaning[1][index] 

777 elif self.type == 2: # Data 

778 meaning = _dot11_addr_meaning[2][index][ 

779 self.FCfield.to_DS 

780 ][self.FCfield.from_DS] 

781 if meaning and index in [2, 3]: # Address 3-4 

782 if isinstance(self.payload, Dot11QoS): 

783 # MSDU and Short A-MSDU 

784 if self.payload.A_MSDU_Present: 

785 meaning = "BSSID" 

786 return meaning 

787 elif self.type == 3: # Extension 

788 return _dot11_addr_meaning[3][index] 

789 return None 

790 

791 def unwep(self, key=None, warn=1): 

792 if self.FCfield & 0x40 == 0: 

793 if warn: 

794 warning("No WEP to remove") 

795 return 

796 if isinstance(self.payload.payload, NoPayload): 

797 if key or conf.wepkey: 

798 self.payload.decrypt(key) 

799 if isinstance(self.payload.payload, NoPayload): 

800 if warn: 

801 warning("Dot11 can't be decrypted. Check conf.wepkey.") 

802 return 

803 self.FCfield &= ~0x40 

804 self.payload = self.payload.payload 

805 

806 

807class Dot11FCS(Dot11): 

808 name = "802.11-FCS" 

809 match_subclass = True 

810 fields_desc = Dot11.fields_desc + [FCSField("fcs", None, fmt="<I")] 

811 

812 def compute_fcs(self, s): 

813 return struct.pack("!I", crc32(s) & 0xffffffff)[::-1] 

814 

815 def post_build(self, p, pay): 

816 p += pay 

817 if self.fcs is None: 

818 p = p[:-4] + self.compute_fcs(p[:-4]) 

819 return p 

820 

821 

822class Dot11QoS(Packet): 

823 name = "802.11 QoS" 

824 fields_desc = [BitField("A_MSDU_Present", 0, 1), 

825 BitField("Ack_Policy", 0, 2), 

826 BitField("EOSP", 0, 1), 

827 BitField("TID", 0, 4), 

828 ByteField("TXOP", 0)] 

829 

830 def guess_payload_class(self, payload): 

831 if isinstance(self.underlayer, Dot11): 

832 if self.underlayer.FCfield.protected: 

833 return Dot11Encrypted 

834 return Packet.guess_payload_class(self, payload) 

835 

836 

837capability_list = ["res8", "res9", "short-slot", "res11", 

838 "res12", "DSSS-OFDM", "res14", "res15", 

839 "ESS", "IBSS", "CFP", "CFP-req", 

840 "privacy", "short-preamble", "PBCC", "agility"] 

841 

842reason_code = {0: "reserved", 1: "unspec", 2: "auth-expired", 

843 3: "deauth-ST-leaving", 

844 4: "inactivity", 5: "AP-full", 6: "class2-from-nonauth", 

845 7: "class3-from-nonass", 8: "disas-ST-leaving", 

846 9: "ST-not-auth"} 

847 

848status_code = {0: "success", 1: "failure", 10: "cannot-support-all-cap", 

849 11: "inexist-asso", 12: "asso-denied", 13: "algo-unsupported", 

850 14: "bad-seq-num", 15: "challenge-failure", 

851 16: "timeout", 17: "AP-full", 18: "rate-unsupported"} 

852 

853 

854class _Dot11EltUtils(Packet): 

855 """ 

856 Contains utils for classes that have Dot11Elt as payloads 

857 """ 

858 def network_stats(self): 

859 """Return a dictionary containing a summary of the Dot11 

860 elements fields 

861 """ 

862 summary = {} 

863 crypto = set() 

864 p = self.payload 

865 while isinstance(p, Dot11Elt): 

866 # Avoid overriding already-set SSID values because it is not part 

867 # of the standard and it protects from parsing bugs, 

868 # see https://github.com/secdev/scapy/issues/2683 

869 if p.ID == 0 and "ssid" not in summary: 

870 summary["ssid"] = plain_str(p.info) 

871 elif p.ID == 3: 

872 summary["channel"] = ord(p.info) 

873 elif isinstance(p, Dot11EltCountry): 

874 summary["country"] = plain_str(p.country_string[:2]) 

875 country_descriptor_types = { 

876 b"I": "Indoor", 

877 b"O": "Outdoor", 

878 b"X": "Non-country", 

879 b"\xff": "Ignored" 

880 } 

881 summary["country_desc_type"] = country_descriptor_types.get( 

882 p.country_string[-1:] 

883 ) 

884 elif isinstance(p, Dot11EltRates): 

885 rates = [(x & 0x7f) / 2. for x in p.rates] 

886 if "rates" in summary: 

887 summary["rates"].extend(rates) 

888 else: 

889 summary["rates"] = rates 

890 elif isinstance(p, Dot11EltRSN): 

891 wpa_version = "WPA2" 

892 # WPA3-only: 

893 # - AP shall at least enable AKM suite selector 00-0F-AC:8 

894 # - AP shall not enable AKM suite selector 00-0F-AC:2 and 

895 # 00-0F-AC:6 

896 # - AP shall set MFPC and MFPR to 1 

897 # - AP shall not enable WEP and TKIP 

898 # WPA3-transition: 

899 # - AP shall at least enable AKM suite selector 00-0F-AC:2 

900 # and 00-0F-AC:8 

901 # - AP shall set MFPC to 1 and MFPR to 0 

902 if any(x.suite == 8 for x in p.akm_suites) and \ 

903 all(x.suite not in [2, 6] for x in p.akm_suites) and \ 

904 p.mfp_capable and p.mfp_required and \ 

905 all(x.cipher not in [1, 2, 5] 

906 for x in p.pairwise_cipher_suites): 

907 # WPA3 only mode 

908 wpa_version = "WPA3" 

909 elif any(x.suite == 8 for x in p.akm_suites) and \ 

910 any(x.suite == 2 for x in p.akm_suites) and \ 

911 p.mfp_capable and not p.mfp_required: 

912 # WPA3 transition mode 

913 wpa_version = "WPA3-transition" 

914 # Append suite 

915 if p.akm_suites: 

916 auth = p.akm_suites[0].sprintf("%suite%") 

917 crypto.add(wpa_version + "/%s" % auth) 

918 else: 

919 crypto.add(wpa_version) 

920 elif p.ID == 221: 

921 if isinstance(p, Dot11EltMicrosoftWPA): 

922 if p.akm_suites: 

923 auth = p.akm_suites[0].sprintf("%suite%") 

924 crypto.add("WPA/%s" % auth) 

925 else: 

926 crypto.add("WPA") 

927 p = p.payload 

928 if not crypto and hasattr(self, "cap"): 

929 if self.cap.privacy: 

930 crypto.add("WEP") 

931 else: 

932 crypto.add("OPN") 

933 if crypto: 

934 summary["crypto"] = crypto 

935 return summary 

936 

937 

938############# 

939# 802.11 IE # 

940############# 

941 

942# 802.11-2016 - 9.4.2 

943 

944_dot11_info_elts_ids = { 

945 0: "SSID", 

946 1: "Supported Rates", 

947 2: "FHset", 

948 3: "DSSS Set", 

949 4: "CF Set", 

950 5: "TIM", 

951 6: "IBSS Set", 

952 7: "Country", 

953 10: "Request", 

954 11: "BSS Load", 

955 12: "EDCA Set", 

956 13: "TSPEC", 

957 14: "TCLAS", 

958 15: "Schedule", 

959 16: "Challenge text", 

960 32: "Power Constraint", 

961 33: "Power Capability", 

962 36: "Supported Channels", 

963 37: "Channel Switch Announcement", 

964 42: "ERP", 

965 45: "HT Capabilities", 

966 46: "QoS Capability", 

967 48: "RSN", 

968 50: "Extended Supported Rates", 

969 52: "Neighbor Report", 

970 61: "HT Operation", 

971 74: "Overlapping BSS Scan Parameters", 

972 107: "Interworking", 

973 127: "Extended Capabilities", 

974 191: "VHT Capabilities", 

975 192: "VHT Operation", 

976 221: "Vendor Specific" 

977} 

978 

979# Backward compatibility 

980_dot11_elt_deprecated_names = { 

981 "Rates": 1, 

982 "DSset": 3, 

983 "CFset": 4, 

984 "IBSSset": 6, 

985 "challenge": 16, 

986 "PowerCapability": 33, 

987 "Channels": 36, 

988 "ERPinfo": 42, 

989 "HTinfo": 45, 

990 "RSNinfo": 48, 

991 "ESRates": 50, 

992 "ExtendendCapatibilities": 127, 

993 "VHTCapabilities": 191, 

994 "Vendor": 221, 

995} 

996 

997_dot11_info_elts_ids_rev = {v: k for k, v in _dot11_info_elts_ids.items()} 

998_dot11_info_elts_ids_rev.update(_dot11_elt_deprecated_names) 

999_dot11_id_enum = ( 

1000 lambda x: _dot11_info_elts_ids.get(x, x), 

1001 lambda x: _dot11_info_elts_ids_rev.get(x, x) 

1002) 

1003 

1004 

1005# 802.11-2020 9.4.2.1 

1006 

1007class Dot11Elt(Packet): 

1008 """ 

1009 A Generic 802.11 Element 

1010 """ 

1011 __slots__ = ["info"] 

1012 name = "802.11 Information Element" 

1013 fields_desc = [ByteEnumField("ID", 0, _dot11_id_enum), 

1014 FieldLenField("len", None, "info", "B"), 

1015 StrLenField("info", "", length_from=lambda x: x.len, 

1016 max_length=255)] 

1017 show_indent = 0 

1018 

1019 def __setattr__(self, attr, val): 

1020 if attr == "info": 

1021 # Will be caught by __slots__: we need an extra call 

1022 try: 

1023 self.setfieldval(attr, val) 

1024 except AttributeError: 

1025 pass 

1026 super(Dot11Elt, self).__setattr__(attr, val) 

1027 

1028 def mysummary(self): 

1029 if self.ID == 0: 

1030 ssid = plain_str(self.info) 

1031 return "SSID='%s'" % ssid, [Dot11] 

1032 else: 

1033 return "" 

1034 

1035 registered_ies = {} 

1036 

1037 @classmethod 

1038 def register_variant(cls, id=None): 

1039 id = id or cls.ID.default 

1040 if id not in cls.registered_ies: 

1041 cls.registered_ies[id] = cls 

1042 

1043 @classmethod 

1044 def dispatch_hook(cls, _pkt=None, *args, **kargs): 

1045 if _pkt: 

1046 _id = ord(_pkt[:1]) 

1047 idcls = cls.registered_ies.get(_id, cls) 

1048 if idcls.dispatch_hook != cls.dispatch_hook: 

1049 # Vendor has its own dispatch_hook 

1050 return idcls.dispatch_hook(_pkt=_pkt, *args, **kargs) 

1051 cls = idcls 

1052 return cls 

1053 

1054 def pre_dissect(self, s): 

1055 # Backward compatibility: add info to all elements 

1056 # This allows to introduce new Dot11Elt classes without breaking 

1057 # previous code 

1058 if len(s) >= 3: 

1059 length = orb(s[1]) 

1060 if length > 0 and length <= 255: 

1061 self.info = s[2:2 + length] 

1062 return s 

1063 

1064 def post_build(self, p, pay): 

1065 if self.len is None: 

1066 p = p[:1] + chb(len(p) - 2) + p[2:] 

1067 return p + pay 

1068 

1069 

1070# 802.11-2020 9.4.2.4 

1071 

1072class Dot11EltDSSSet(Dot11Elt): 

1073 name = "802.11 DSSS Parameter Set" 

1074 match_subclass = True 

1075 fields_desc = [ 

1076 ByteEnumField("ID", 3, _dot11_id_enum), 

1077 ByteField("len", 1), 

1078 ByteField("channel", 0), 

1079 ] 

1080 

1081 

1082# 802.11-2020 9.4.2.11 

1083 

1084class Dot11EltERP(Dot11Elt): 

1085 name = "802.11 ERP" 

1086 match_subclass = True 

1087 fields_desc = [ 

1088 ByteEnumField("ID", 42, _dot11_id_enum), 

1089 ByteField("len", 1), 

1090 BitField("NonERP_Present", 0, 1), 

1091 BitField("Use_Protection", 0, 1), 

1092 BitField("Barker_Preamble_Mode", 0, 1), 

1093 BitField("res", 0, 5), 

1094 ] 

1095 

1096 

1097# 802.11-2020 9.4.2.24.2 

1098 

1099class RSNCipherSuite(Packet): 

1100 name = "Cipher suite" 

1101 fields_desc = [ 

1102 OUIField("oui", 0x000fac), 

1103 ByteEnumField("cipher", 0x04, { 

1104 0x00: "Use group cipher suite", 

1105 0x01: "WEP-40", 

1106 0x02: "TKIP", 

1107 0x03: "OCB", 

1108 0x04: "CCMP-128", 

1109 0x05: "WEP-104", 

1110 0x06: "BIP-CMAC-128", 

1111 0x07: "Group addressed traffic not allowed", 

1112 0x08: "GCMP-128", 

1113 0x09: "GCMP-256", 

1114 0x0A: "CCMP-256", 

1115 0x0B: "BIP-GMAC-128", 

1116 0x0C: "BIP-GMAC-256", 

1117 0x0D: "BIP-CMAC-256" 

1118 }) 

1119 ] 

1120 

1121 def extract_padding(self, s): 

1122 return "", s 

1123 

1124 

1125# 802.11-2020 9.4.2.24.3 

1126 

1127class AKMSuite(Packet): 

1128 name = "AKM suite" 

1129 fields_desc = [ 

1130 OUIField("oui", 0x000fac), 

1131 ByteEnumField("suite", 0x01, { 

1132 0x00: "Reserved", 

1133 0x01: "802.1X", 

1134 0x02: "PSK", 

1135 0x03: "FT-802.1X", 

1136 0x04: "FT-PSK", 

1137 0x05: "WPA-SHA256", 

1138 0x06: "PSK-SHA256", 

1139 0x07: "TDLS", 

1140 0x08: "SAE", 

1141 0x09: "FT-SAE", 

1142 0x0A: "AP-PEER-KEY", 

1143 0x0B: "WPA-SHA256-SUITE-B", 

1144 0x0C: "WPA-SHA384-SUITE-B", 

1145 0x0D: "FT-802.1X-SHA384", 

1146 0x0E: "FILS-SHA256", 

1147 0x0F: "FILS-SHA384", 

1148 0x10: "FT-FILS-SHA256", 

1149 0x11: "FT-FILS-SHA384", 

1150 0x12: "OWE" 

1151 }) 

1152 ] 

1153 

1154 def extract_padding(self, s): 

1155 return "", s 

1156 

1157 

1158# 802.11-2020 9.4.2.24.5 

1159 

1160class PMKIDListPacket(Packet): 

1161 name = "PMKIDs" 

1162 fields_desc = [ 

1163 LEFieldLenField("nb_pmkids", None, count_of="pmkid_list"), 

1164 FieldListField( 

1165 "pmkid_list", 

1166 None, 

1167 XStrFixedLenField("", "", length=16), 

1168 count_from=lambda pkt: pkt.nb_pmkids 

1169 ) 

1170 ] 

1171 

1172 def extract_padding(self, s): 

1173 return "", s 

1174 

1175 

1176# 802.11-2020 9.4.2.24.1 

1177 

1178class Dot11EltRSN(Dot11Elt): 

1179 name = "802.11 RSN information" 

1180 match_subclass = True 

1181 fields_desc = [ 

1182 ByteEnumField("ID", 48, _dot11_id_enum), 

1183 ByteField("len", None), 

1184 LEShortField("version", 1), 

1185 PacketField("group_cipher_suite", RSNCipherSuite(), RSNCipherSuite), 

1186 LEFieldLenField( 

1187 "nb_pairwise_cipher_suites", 

1188 None, 

1189 count_of="pairwise_cipher_suites" 

1190 ), 

1191 PacketListField( 

1192 "pairwise_cipher_suites", 

1193 [RSNCipherSuite()], 

1194 RSNCipherSuite, 

1195 count_from=lambda p: p.nb_pairwise_cipher_suites 

1196 ), 

1197 LEFieldLenField( 

1198 "nb_akm_suites", 

1199 None, 

1200 count_of="akm_suites" 

1201 ), 

1202 PacketListField( 

1203 "akm_suites", 

1204 [AKMSuite()], 

1205 AKMSuite, 

1206 count_from=lambda p: p.nb_akm_suites 

1207 ), 

1208 # RSN Capabilities 

1209 # 802.11-2020 9.4.2.24.4 

1210 BitField("mfp_capable", 1, 1), 

1211 BitField("mfp_required", 1, 1), 

1212 BitField("gtksa_replay_counter", 0, 2), 

1213 BitField("ptksa_replay_counter", 0, 2), 

1214 BitField("no_pairwise", 0, 1), 

1215 BitField("pre_auth", 0, 1), 

1216 BitField("reserved", 0, 1), 

1217 BitField("ocvc", 0, 1), 

1218 BitField("extended_key_id", 0, 1), 

1219 BitField("pbac", 0, 1), 

1220 BitField("spp_a_msdu_required", 0, 1), 

1221 BitField("spp_a_msdu_capable", 0, 1), 

1222 BitField("peer_key_enabled", 0, 1), 

1223 BitField("joint_multiband_rsna", 0, 1), 

1224 # Theoretically we could use mfp_capable/mfp_required to know if those 

1225 # fields are present, but some implementations poorly implement it. 

1226 # In practice, do as wireshark: guess using offset. 

1227 ConditionalField( 

1228 PacketField("pmkids", PMKIDListPacket(), PMKIDListPacket), 

1229 lambda pkt: ( 

1230 True if pkt.len is None else 

1231 pkt.len - ( 

1232 12 + 

1233 (pkt.nb_pairwise_cipher_suites or 0) * 4 + 

1234 (pkt.nb_akm_suites or 0) * 4 

1235 ) >= 2 

1236 ) 

1237 ), 

1238 ConditionalField( 

1239 PacketField("group_management_cipher_suite", 

1240 RSNCipherSuite(cipher=0x6), RSNCipherSuite), 

1241 lambda pkt: ( 

1242 True if pkt.len is None else 

1243 pkt.len - ( 

1244 12 + 

1245 (pkt.nb_pairwise_cipher_suites or 0) * 4 + 

1246 (pkt.nb_akm_suites or 0) * 4 + 

1247 (2 if pkt.pmkids else 0) + 

1248 (pkt.pmkids and pkt.pmkids.nb_pmkids or 0) * 16 

1249 ) >= 4 

1250 ) 

1251 ) 

1252 ] 

1253 

1254 

1255class Dot11EltCountryConstraintTriplet(Packet): 

1256 name = "802.11 Country Constraint Triplet" 

1257 fields_desc = [ 

1258 ByteField("first_channel_number", 1), 

1259 ByteField("num_channels", 24), 

1260 ByteField("mtp", 0) 

1261 ] 

1262 

1263 def extract_padding(self, s): 

1264 return b"", s 

1265 

1266 

1267class Dot11EltCountry(Dot11Elt): 

1268 name = "802.11 Country" 

1269 match_subclass = True 

1270 fields_desc = [ 

1271 ByteEnumField("ID", 7, _dot11_id_enum), 

1272 ByteField("len", None), 

1273 StrFixedLenField("country_string", b"\0\0\0", length=3), 

1274 MayEnd(PacketListField( 

1275 "descriptors", 

1276 [], 

1277 Dot11EltCountryConstraintTriplet, 

1278 length_from=lambda pkt: ( 

1279 pkt.len - 3 - (pkt.len % 3) 

1280 ) 

1281 )), 

1282 # When this extension is last, padding appears to be omitted 

1283 ConditionalField( 

1284 ByteField("pad", 0), 

1285 # The length should be 3 bytes per each triplet, and 3 bytes for the 

1286 # country_string field. The standard dictates that the element length 

1287 # must be even, so if the result is odd, add a padding byte. 

1288 # Some transmitters don't comply with the standard, so instead of assuming 

1289 # the length, we test whether there is a padding byte. 

1290 # Some edge cases are still not covered, for example, if the tag length 

1291 # (pkt.len) is an arbitrary number. 

1292 lambda pkt: ((len(pkt.descriptors) + 1) % 2) if pkt.len is None else (pkt.len % 3) # noqa: E501 

1293 ) 

1294 ] 

1295 

1296 

1297class _RateField(ByteField): 

1298 def i2repr(self, pkt, val): 

1299 if val is None: 

1300 return "" 

1301 s = str((val & 0x7f) / 2.) 

1302 if val & 0x80: 

1303 s += "(B)" 

1304 return s + " Mbps" 

1305 

1306 

1307class Dot11EltRates(Dot11Elt): 

1308 name = "802.11 Rates" 

1309 match_subclass = True 

1310 fields_desc = [ 

1311 ByteEnumField("ID", 1, _dot11_id_enum), 

1312 ByteField("len", None), 

1313 FieldListField( 

1314 "rates", 

1315 [0x82], 

1316 _RateField("", 0), 

1317 length_from=lambda p: p.len 

1318 ) 

1319 ] 

1320 

1321 

1322Dot11EltRates.register_variant(50) # Extended rates 

1323 

1324 

1325class Dot11EltHTCapabilities(Dot11Elt): 

1326 name = "802.11 HT Capabilities" 

1327 match_subclass = True 

1328 fields_desc = [ 

1329 ByteEnumField("ID", 45, _dot11_id_enum), 

1330 ByteField("len", None), 

1331 # HT Capabilities Info: 2B 

1332 BitField("L_SIG_TXOP_Protection", 0, 1, tot_size=-2), 

1333 BitField("Forty_Mhz_Intolerant", 0, 1), 

1334 BitField("PSMP", 0, 1), 

1335 BitField("DSSS_CCK", 0, 1), 

1336 BitEnumField("Max_A_MSDU", 0, 1, {0: "3839 o", 1: "7935 o"}), 

1337 BitField("Delayed_BlockAck", 0, 1), 

1338 BitField("Rx_STBC", 0, 2), 

1339 BitField("Tx_STBC", 0, 1), 

1340 BitField("Short_GI_40Mhz", 0, 1), 

1341 BitField("Short_GI_20Mhz", 0, 1), 

1342 BitField("Green_Field", 0, 1), 

1343 BitEnumField("SM_Power_Save", 0, 2, 

1344 {0: "static SM", 1: "dynamic SM", 3: "disabled"}), 

1345 BitEnumField("Supported_Channel_Width", 0, 1, 

1346 {0: "20Mhz", 1: "20Mhz+40Mhz"}), 

1347 BitField("LDPC_Coding_Capability", 0, 1, end_tot_size=-2), 

1348 # A-MPDU Parameters: 1B 

1349 BitField("res1", 0, 3, tot_size=-1), 

1350 BitField("Min_MPDCU_Start_Spacing", 8, 3), 

1351 BitField("Max_A_MPDU_Length_Exponent", 3, 2, end_tot_size=-1), 

1352 # Supported MCS set: 16B 

1353 BitField("res2", 0, 27, tot_size=-16), 

1354 BitField("TX_Unequal_Modulation", 0, 1), 

1355 BitField("TX_Max_Spatial_Streams", 0, 2), 

1356 BitField("TX_RX_MCS_Set_Not_Equal", 0, 1), 

1357 BitField("TX_MCS_Set_Defined", 0, 1), 

1358 BitField("res3", 0, 6), 

1359 BitField("RX_Highest_Supported_Data_Rate", 0, 10), 

1360 BitField("res4", 0, 3), 

1361 BitField("RX_MSC_Bitmask", 0, 77, end_tot_size=-16), 

1362 # HT Extended capabilities: 2B 

1363 BitField("res5", 0, 4, tot_size=-2), 

1364 BitField("RD_Responder", 0, 1), 

1365 BitField("HTC_HT_Support", 0, 1), 

1366 BitField("MCS_Feedback", 0, 2), 

1367 BitField("res6", 0, 5), 

1368 BitField("PCO_Transition_Time", 0, 2), 

1369 BitField("PCO", 0, 1, end_tot_size=-2), 

1370 # TX Beamforming Capabilities TxBF: 4B 

1371 BitField("res7", 0, 3, tot_size=-4), 

1372 BitField("Channel_Estimation_Capability", 0, 2), 

1373 BitField("CSI_max_n_Rows_Beamformer_Supported", 0, 2), 

1374 BitField("Compressed_Steering_n_Beamformer_Antennas_Supported", 0, 2), 

1375 BitField("Noncompressed_Steering_n_Beamformer_Antennas_Supported", 

1376 0, 2), 

1377 BitField("CSI_n_Beamformer_Antennas_Supported", 0, 2), 

1378 BitField("Minimal_Grouping", 0, 2), 

1379 BitField("Explicit_Compressed_Beamforming_Feedback", 0, 2), 

1380 BitField("Explicit_Noncompressed_Beamforming_Feedback", 0, 2), 

1381 BitField("Explicit_Transmit_Beamforming_CSI_Feedback", 0, 2), 

1382 BitField("Explicit_Compressed_Steering", 0, 1), 

1383 BitField("Explicit_Noncompressed_Steering", 0, 1), 

1384 BitField("Explicit_CSI_Transmit_Beamforming", 0, 1), 

1385 BitField("Calibration", 0, 2), 

1386 BitField("Implicit_Trasmit_Beamforming", 0, 1), 

1387 BitField("Transmit_NDP", 0, 1), 

1388 BitField("Receive_NDP", 0, 1), 

1389 BitField("Transmit_Staggered_Sounding", 0, 1), 

1390 BitField("Receive_Staggered_Sounding", 0, 1), 

1391 BitField("Implicit_Transmit_Beamforming_Receiving", 0, 1, 

1392 end_tot_size=-4), 

1393 # ASEL Capabilities: 1B 

1394 FlagsField("ASEL", 0, 8, [ 

1395 "res", 

1396 "Transmit_Sounding_PPDUs", 

1397 "Receive_ASEL", 

1398 "Antenna_Indices_Feedback", 

1399 "Explicit_CSI_Feedback", 

1400 "Explicit_CSI_Feedback_Based_Transmit_ASEL", 

1401 "Antenna_Selection", 

1402 ]) 

1403 ] 

1404 

1405 

1406class Dot11EltVendorSpecific(Dot11Elt): 

1407 name = "802.11 Vendor Specific" 

1408 match_subclass = True 

1409 fields_desc = [ 

1410 ByteEnumField("ID", 221, _dot11_id_enum), 

1411 ByteField("len", None), 

1412 OUIField("oui", 0x000000), 

1413 StrLenField("info", "", length_from=lambda x: x.len - 3) 

1414 ] 

1415 

1416 @classmethod 

1417 def dispatch_hook(cls, _pkt=None, *args, **kargs): 

1418 if _pkt: 

1419 oui = struct.unpack("!I", b"\x00" + _pkt[2:5])[0] 

1420 if oui == 0x0050f2: # Microsoft 

1421 type_ = orb(_pkt[5]) 

1422 if type_ == 0x01: 

1423 # MS WPA IE 

1424 return Dot11EltMicrosoftWPA 

1425 elif type_ == 0x02: 

1426 # MS WME IE TODO 

1427 # return Dot11EltMicrosoftWME 

1428 pass 

1429 elif type_ == 0x04: 

1430 # MS WPS IE TODO 

1431 # return Dot11EltWPS 

1432 pass 

1433 return Dot11EltVendorSpecific 

1434 return cls 

1435 

1436 

1437class Dot11EltMicrosoftWPA(Dot11EltVendorSpecific): 

1438 name = "802.11 Microsoft WPA" 

1439 match_subclass = True 

1440 ID = 221 

1441 oui = 0x0050f2 

1442 # It appears many WPA implementations ignore the fact 

1443 # that this IE should only have a single cipher and auth suite 

1444 fields_desc = Dot11EltVendorSpecific.fields_desc[:3] + [ 

1445 XByteField("type", 0x01) 

1446 ] + Dot11EltRSN.fields_desc[2:8] 

1447 

1448 

1449# 802.11-2016 9.4.2.19 

1450 

1451class Dot11EltCSA(Dot11Elt): 

1452 name = "802.11 CSA Element" 

1453 fields_desc = [ 

1454 ByteEnumField("ID", 37, _dot11_id_enum), 

1455 ByteField("len", 3), 

1456 ByteField("mode", 0), 

1457 ByteField("new_channel", 0), 

1458 ByteField("channel_switch_count", 0) 

1459 ] 

1460 

1461 

1462# 802.11-2016 9.4.2.59 

1463 

1464class Dot11EltOBSS(Dot11Elt): 

1465 name = "802.11 OBSS Scan Parameters Element" 

1466 fields_desc = [ 

1467 ByteEnumField("ID", 74, _dot11_id_enum), 

1468 ByteField("len", 14), 

1469 LEShortField("Passive_Dwell", 0), 

1470 LEShortField("Active_Dwell", 0), 

1471 LEShortField("Scan_Interval", 0), 

1472 LEShortField("Passive_Total_Per_Channel", 0), 

1473 LEShortField("Active_Total_Per_Channel", 0), 

1474 LEShortField("Delay", 0), 

1475 LEShortField("Activity_Threshold", 0), 

1476 ] 

1477 

1478 

1479# 802.11-2016 9.4.2.159 

1480 

1481class Dot11VHTOperationInfo(Packet): 

1482 name = "802.11 VHT Operation Information" 

1483 fields_desc = [ 

1484 ByteField("channel_width", 0), 

1485 ByteField("channel_center0", 36), 

1486 ByteField("channel_center1", 0), 

1487 ] 

1488 

1489 def extract_padding(self, s): 

1490 return "", s 

1491 

1492 

1493class Dot11EltVHTOperation(Dot11Elt): 

1494 name = "802.11 VHT Operation Element" 

1495 fields_desc = [ 

1496 ByteEnumField("ID", 192, _dot11_id_enum), 

1497 ByteField("len", 5), 

1498 PacketField( 

1499 "VHT_Operation_Info", 

1500 Dot11VHTOperationInfo(), 

1501 Dot11VHTOperationInfo 

1502 ), 

1503 FieldListField( 

1504 "mcs_set", 

1505 [0x00], 

1506 BitField('SS', 0x00, size=2), 

1507 count_from=lambda x: 8 

1508 ) 

1509 ] 

1510 

1511 

1512###################### 

1513# 802.11 Frame types # 

1514###################### 

1515 

1516# 802.11-2016 9.3 

1517 

1518class Dot11Beacon(_Dot11EltUtils): 

1519 name = "802.11 Beacon" 

1520 fields_desc = [LELongField("timestamp", 0), 

1521 LEShortField("beacon_interval", 0x0064), 

1522 FlagsField("cap", 0, 16, capability_list)] 

1523 

1524 

1525class Dot11ATIM(Packet): 

1526 name = "802.11 ATIM" 

1527 

1528 

1529class Dot11Disas(Packet): 

1530 name = "802.11 Disassociation" 

1531 fields_desc = [LEShortEnumField("reason", 1, reason_code)] 

1532 

1533 

1534class Dot11AssoReq(_Dot11EltUtils): 

1535 name = "802.11 Association Request" 

1536 fields_desc = [FlagsField("cap", 0, 16, capability_list), 

1537 LEShortField("listen_interval", 0x00c8)] 

1538 

1539 

1540class Dot11AssoResp(_Dot11EltUtils): 

1541 name = "802.11 Association Response" 

1542 fields_desc = [FlagsField("cap", 0, 16, capability_list), 

1543 LEShortField("status", 0), 

1544 LEShortField("AID", 0)] 

1545 

1546 

1547class Dot11ReassoReq(_Dot11EltUtils): 

1548 name = "802.11 Reassociation Request" 

1549 fields_desc = [FlagsField("cap", 0, 16, capability_list), 

1550 LEShortField("listen_interval", 0x00c8), 

1551 MACField("current_AP", ETHER_ANY)] 

1552 

1553 

1554class Dot11ReassoResp(Dot11AssoResp): 

1555 name = "802.11 Reassociation Response" 

1556 

1557 

1558class Dot11ProbeReq(_Dot11EltUtils): 

1559 name = "802.11 Probe Request" 

1560 

1561 

1562class Dot11ProbeResp(_Dot11EltUtils): 

1563 name = "802.11 Probe Response" 

1564 fields_desc = [LELongField("timestamp", 0), 

1565 LEShortField("beacon_interval", 0x0064), 

1566 FlagsField("cap", 0, 16, capability_list)] 

1567 

1568 

1569class Dot11Auth(_Dot11EltUtils): 

1570 name = "802.11 Authentication" 

1571 fields_desc = [LEShortEnumField("algo", 0, ["open", "sharedkey"]), 

1572 LEShortField("seqnum", 0), 

1573 LEShortEnumField("status", 0, status_code)] 

1574 

1575 def answers(self, other): 

1576 if self.algo != other.algo: 

1577 return 0 

1578 

1579 if ( 

1580 self.seqnum == other.seqnum + 1 or 

1581 (self.algo == 3 and self.seqnum == other.seqnum) 

1582 ): 

1583 return 1 

1584 return 0 

1585 

1586 

1587class Dot11Deauth(Packet): 

1588 name = "802.11 Deauthentication" 

1589 fields_desc = [LEShortEnumField("reason", 1, reason_code)] 

1590 

1591 

1592class Dot11Ack(Packet): 

1593 name = "802.11 Ack packet" 

1594 

1595 

1596# 802.11-2016 9.4.1.11 

1597 

1598class Dot11Action(Packet): 

1599 name = "802.11 Action" 

1600 fields_desc = [ 

1601 ByteEnumField("category", 0x00, { 

1602 0x00: "Spectrum Management", 

1603 0x01: "QoS", 

1604 0x02: "DLS", 

1605 0x03: "Block", 

1606 0x04: "Public", 

1607 0x05: "Radio Measurement", 

1608 0x06: "Fast BSS Transition", 

1609 0x07: "HT", 

1610 0x08: "SA Query", 

1611 0x09: "Protected Dual of Public Action", 

1612 0x0A: "WNM", 

1613 0x0B: "Unprotected WNM", 

1614 0x0C: "TDLS", 

1615 0x0D: "Mesh", 

1616 0x0E: "Multihop", 

1617 0x0F: "Self-protected", 

1618 0x10: "DMG", 

1619 0x11: "Reserved Wi-Fi Alliance", 

1620 0x12: "Fast Session Transfer", 

1621 0x13: "Robust AV Streaming", 

1622 0x14: "Unprotected DMG", 

1623 0x15: "VHT" 

1624 }) 

1625 ] 

1626 

1627 

1628# 802.11-2016 9.6.14.1 

1629 

1630class Dot11WNM(Packet): 

1631 name = "802.11 WNM Action" 

1632 fields_desc = [ 

1633 ByteEnumField("action", 0x00, { 

1634 0x00: "Event Request", 

1635 0x01: "Event Report", 

1636 0x02: "Diagnostic Request", 

1637 0x03: "Diagnostic Report", 

1638 0x04: "Location Configuration Request", 

1639 0x05: "Location Configuration Response", 

1640 0x06: "BSS Transition Management Query", 

1641 0x07: "BSS Transition Management Request", 

1642 0x08: "BSS Transition Management Response", 

1643 0x09: "FMS Request", 

1644 0x0A: "FMS Response", 

1645 0x0B: "Collocated Interference Request", 

1646 0x0C: "Collocated Interference Report", 

1647 0x0D: "TFS Request", 

1648 0x0E: "TFS Response", 

1649 0x0F: "TFS Notify", 

1650 0x10: "WNM Sleep Mode Request", 

1651 0x11: "WNM Sleep Mode Response", 

1652 0x12: "TIM Broadcast Request", 

1653 0x13: "TIM Broadcast Response", 

1654 0x14: "QoS Traffic Capability Update", 

1655 0x15: "Channel Usage Request", 

1656 0x16: "Channel Usage Response", 

1657 0x17: "DMS Request", 

1658 0x18: "DMS Response", 

1659 0x19: "Timing Measurement Request", 

1660 0x1A: "WNM Notification Request", 

1661 0x1B: "WNM Notification Response", 

1662 0x1C: "WNM-Notify Response" 

1663 }) 

1664 ] 

1665 

1666 

1667# 802.11-2016 9.4.2.37 

1668 

1669class SubelemTLV(Packet): 

1670 fields_desc = [ 

1671 ByteField("type", 0), 

1672 LEFieldLenField("len", None, fmt="B", length_of="value"), 

1673 FieldListField( 

1674 "value", 

1675 [], 

1676 ByteField('', 0), 

1677 length_from=lambda p: p.len 

1678 ) 

1679 ] 

1680 

1681 

1682class BSSTerminationDuration(Packet): 

1683 name = "BSS Termination Duration" 

1684 fields_desc = [ 

1685 ByteField("id", 4), 

1686 ByteField("len", 10), 

1687 LELongField("TSF", 0), 

1688 LEShortField("duration", 0) 

1689 ] 

1690 

1691 def extract_padding(self, s): 

1692 return "", s 

1693 

1694 

1695class NeighborReport(Packet): 

1696 name = "Neighbor Report" 

1697 fields_desc = [ 

1698 ByteField("type", 0), 

1699 ByteField("len", 13), 

1700 MACField("BSSID", ETHER_ANY), 

1701 # BSSID Information 

1702 BitField("AP_reach", 0, 2, tot_size=-4), 

1703 BitField("security", 0, 1), 

1704 BitField("key_scope", 0, 1), 

1705 BitField("capabilities", 0, 6), 

1706 BitField("mobility", 0, 1), 

1707 BitField("HT", 0, 1), 

1708 BitField("VHT", 0, 1), 

1709 BitField("FTM", 0, 1), 

1710 BitField("reserved", 0, 18, end_tot_size=-4), 

1711 # BSSID Information end 

1712 ByteField("op_class", 0), 

1713 ByteField("channel", 0), 

1714 ByteField("phy_type", 0), 

1715 ConditionalField( 

1716 PacketListField( 

1717 "subelems", 

1718 SubelemTLV(), 

1719 SubelemTLV, 

1720 length_from=lambda p: p.len - 13 

1721 ), 

1722 lambda p: p.len > 13 

1723 ) 

1724 ] 

1725 

1726 

1727# 802.11-2016 9.6.14.9 

1728 

1729btm_request_mode = [ 

1730 "Preferred_Candidate_List_Included", 

1731 "Abridged", 

1732 "Disassociation_Imminent", 

1733 "BSS_Termination_Included", 

1734 "ESS_Disassociation_Imminent" 

1735] 

1736 

1737 

1738class Dot11BSSTMRequest(Packet): 

1739 name = "BSS Transition Management Request" 

1740 fields_desc = [ 

1741 ByteField("token", 0), 

1742 FlagsField("mode", 0, 8, btm_request_mode), 

1743 LEShortField("disassociation_timer", 0), 

1744 ByteField("validity_interval", 0), 

1745 ConditionalField( 

1746 PacketField( 

1747 "termination_duration", 

1748 BSSTerminationDuration(), 

1749 BSSTerminationDuration 

1750 ), 

1751 lambda p: p.mode and p.mode.BSS_Termination_Included 

1752 ), 

1753 ConditionalField( 

1754 ByteField("url_len", 0), 

1755 lambda p: p.mode and p.mode.ESS_Disassociation_Imminent 

1756 ), 

1757 ConditionalField( 

1758 StrLenField("url", "", length_from=lambda p: p.url_len), 

1759 lambda p: p.mode and p.mode.ESS_Disassociation_Imminent != 0 

1760 ), 

1761 ConditionalField( 

1762 PacketListField( 

1763 "neighbor_report", 

1764 NeighborReport(), 

1765 NeighborReport 

1766 ), 

1767 lambda p: p.mode and p.mode.Preferred_Candidate_List_Included 

1768 ) 

1769 ] 

1770 

1771 

1772# 802.11-2016 9.6.14.10 

1773 

1774btm_status_code = [ 

1775 "Accept", 

1776 "Reject-Unspecified_reject_reason", 

1777 "Reject-Insufficient_Beacon_or_Probe_Response_frames", 

1778 "Reject-Insufficient_available_capacity_from_all_candidates", 

1779 "Reject-BSS_termination_undesired", 

1780 "Reject-BSS_termination_delay_requested", 

1781 "Reject-STA_BSS_Transition_Candidate_List_provided", 

1782 "Reject-No_suitable_BSS_transition_candidates", 

1783 "Reject-Leaving_ESS" 

1784] 

1785 

1786 

1787class Dot11BSSTMResponse(Packet): 

1788 name = "BSS Transition Management Response" 

1789 fields_desc = [ 

1790 ByteField("token", 0), 

1791 ByteEnumField("status", 0, btm_status_code), 

1792 ByteField("termination_delay", 0), 

1793 ConditionalField( 

1794 MACField("target", ETHER_ANY), 

1795 lambda p: p.status == 0 

1796 ), 

1797 ConditionalField( 

1798 PacketListField( 

1799 "neighbor_report", 

1800 NeighborReport(), 

1801 NeighborReport 

1802 ), 

1803 lambda p: p.status == 6 

1804 ) 

1805 ] 

1806 

1807 

1808# 802.11-2016 9.6.2.1 

1809 

1810class Dot11SpectrumManagement(Packet): 

1811 name = "802.11 Spectrum Management Action" 

1812 fields_desc = [ 

1813 ByteEnumField("action", 0x00, { 

1814 0x00: "Measurement Request", 

1815 0x01: "Measurement Report", 

1816 0x02: "TPC Request", 

1817 0x03: "TPC Report", 

1818 0x04: "Channel Switch Announcement", 

1819 }) 

1820 ] 

1821 

1822 

1823# 802.11-2016 9.6.2.6 

1824 

1825class Dot11CSA(Packet): 

1826 name = "Channel Switch Announcement Frame" 

1827 fields_desc = [ 

1828 PacketField("CSA", Dot11EltCSA(), Dot11EltCSA), 

1829 ] 

1830 

1831 

1832################### 

1833# 802.11 Security # 

1834################### 

1835 

1836# 802.11-2016 12 

1837 

1838class Dot11Encrypted(Packet): 

1839 name = "802.11 Encrypted (unknown algorithm)" 

1840 fields_desc = [StrField("data", None)] 

1841 

1842 @classmethod 

1843 def dispatch_hook(cls, _pkt=None, *args, **kargs): 

1844 # Extracted from 

1845 # https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-ieee80211.c # noqa: E501 

1846 KEY_EXTIV = 0x20 

1847 EXTIV_LEN = 8 

1848 if _pkt and len(_pkt) >= 3: 

1849 if (orb(_pkt[3]) & KEY_EXTIV) and (len(_pkt) >= EXTIV_LEN): 

1850 if orb(_pkt[1]) == ((orb(_pkt[0]) | 0x20) & 0x7f): # IS_TKIP 

1851 return Dot11TKIP 

1852 elif orb(_pkt[2]) == 0: # IS_CCMP 

1853 return Dot11CCMP 

1854 else: 

1855 # Unknown encryption algorithm 

1856 return Dot11Encrypted 

1857 else: 

1858 return Dot11WEP 

1859 return conf.raw_layer 

1860 

1861 

1862# 802.11-2016 12.3.2 

1863 

1864class Dot11WEP(Dot11Encrypted): 

1865 name = "802.11 WEP packet" 

1866 fields_desc = [StrFixedLenField("iv", b"\0\0\0", 3), 

1867 ByteField("keyid", 0), 

1868 StrField("wepdata", None, remain=4), 

1869 IntField("icv", None)] 

1870 

1871 def decrypt(self, key=None): 

1872 if key is None: 

1873 key = conf.wepkey 

1874 if key and conf.crypto_valid: 

1875 d = Cipher( 

1876 algorithms.ARC4(self.iv + key.encode("utf8")), 

1877 None, 

1878 default_backend(), 

1879 ).decryptor() 

1880 self.add_payload(LLC(d.update(self.wepdata) + d.finalize())) 

1881 

1882 def post_dissect(self, s): 

1883 self.decrypt() 

1884 

1885 def build_payload(self): 

1886 if self.wepdata is None: 

1887 return Packet.build_payload(self) 

1888 return b"" 

1889 

1890 @crypto_validator 

1891 def encrypt(self, p, pay, key=None): 

1892 if key is None: 

1893 key = conf.wepkey 

1894 if key: 

1895 if self.icv is None: 

1896 pay += struct.pack("<I", crc32(pay) & 0xffffffff) 

1897 icv = b"" 

1898 else: 

1899 icv = p[4:8] 

1900 e = Cipher( 

1901 algorithms.ARC4(self.iv + key.encode("utf8")), 

1902 None, 

1903 default_backend(), 

1904 ).encryptor() 

1905 return p[:4] + e.update(pay) + e.finalize() + icv 

1906 else: 

1907 warning("No WEP key set (conf.wepkey).. strange results expected..") # noqa: E501 

1908 return b"" 

1909 

1910 def post_build(self, p, pay): 

1911 if self.wepdata is None: 

1912 p = self.encrypt(p, raw(pay)) 

1913 return p 

1914 

1915# we can't dissect ICV / MIC here: they are encrypted 

1916 

1917# 802.11-2016 12.5.2.2 

1918 

1919 

1920class Dot11TKIP(Dot11Encrypted): 

1921 name = "802.11 TKIP packet" 

1922 fields_desc = [ 

1923 # iv - 4 bytes 

1924 ByteField("TSC1", 0), 

1925 ByteField("WEPSeed", 0), 

1926 ByteField("TSC0", 0), 

1927 BitField("key_id", 0, 2), # 

1928 BitField("ext_iv", 0, 1), # => LE = reversed order 

1929 BitField("res", 0, 5), # 

1930 # ext_iv - 4 bytes 

1931 ConditionalField(ByteField("TSC2", 0), lambda pkt: pkt.ext_iv), 

1932 ConditionalField(ByteField("TSC3", 0), lambda pkt: pkt.ext_iv), 

1933 ConditionalField(ByteField("TSC4", 0), lambda pkt: pkt.ext_iv), 

1934 ConditionalField(ByteField("TSC5", 0), lambda pkt: pkt.ext_iv), 

1935 # data 

1936 StrField("data", None), 

1937 ] 

1938 

1939# 802.11-2016 12.5.3.2 

1940 

1941 

1942class Dot11CCMP(Dot11Encrypted): 

1943 name = "802.11 CCMP packet" 

1944 fields_desc = [ 

1945 # iv - 8 bytes 

1946 ByteField("PN0", 0), 

1947 ByteField("PN1", 0), 

1948 ByteField("res0", 0), 

1949 BitField("key_id", 0, 2), # 

1950 BitField("ext_iv", 0, 1), # => LE = reversed order 

1951 BitField("res1", 0, 5), # 

1952 ByteField("PN2", 0), 

1953 ByteField("PN3", 0), 

1954 ByteField("PN4", 0), 

1955 ByteField("PN5", 0), 

1956 # data 

1957 StrField("data", None), 

1958 ] 

1959 

1960 

1961############ 

1962# Bindings # 

1963############ 

1964 

1965 

1966bind_top_down(RadioTap, Dot11FCS, present=2, Flags=16) 

1967bind_top_down(Dot11, Dot11QoS, type=2, subtype=0xc) 

1968 

1969bind_layers(PrismHeader, Dot11,) 

1970bind_layers(Dot11, LLC, type=2) 

1971bind_layers(Dot11QoS, LLC,) 

1972 

1973# 802.11-2016 9.2.4.1.3 Type and Subtype subfields 

1974bind_layers(Dot11, Dot11AssoReq, subtype=0, type=0) 

1975bind_layers(Dot11, Dot11AssoResp, subtype=1, type=0) 

1976bind_layers(Dot11, Dot11ReassoReq, subtype=2, type=0) 

1977bind_layers(Dot11, Dot11ReassoResp, subtype=3, type=0) 

1978bind_layers(Dot11, Dot11ProbeReq, subtype=4, type=0) 

1979bind_layers(Dot11, Dot11ProbeResp, subtype=5, type=0) 

1980bind_layers(Dot11, Dot11Beacon, subtype=8, type=0) 

1981bind_layers(Dot11, Dot11ATIM, subtype=9, type=0) 

1982bind_layers(Dot11, Dot11Disas, subtype=10, type=0) 

1983bind_layers(Dot11, Dot11Auth, subtype=11, type=0) 

1984bind_layers(Dot11, Dot11Deauth, subtype=12, type=0) 

1985bind_layers(Dot11, Dot11Action, subtype=13, type=0) 

1986bind_layers(Dot11, Dot11Ack, subtype=13, type=1) 

1987bind_layers(Dot11Beacon, Dot11Elt,) 

1988bind_layers(Dot11AssoReq, Dot11Elt,) 

1989bind_layers(Dot11AssoResp, Dot11Elt,) 

1990bind_layers(Dot11ReassoReq, Dot11Elt,) 

1991bind_layers(Dot11ReassoResp, Dot11Elt,) 

1992bind_layers(Dot11ProbeReq, Dot11Elt,) 

1993bind_layers(Dot11ProbeResp, Dot11Elt,) 

1994bind_layers(Dot11Auth, Dot11Elt,) 

1995bind_layers(Dot11Elt, Dot11Elt,) 

1996bind_layers(Dot11TKIP, conf.raw_layer) 

1997bind_layers(Dot11CCMP, conf.raw_layer) 

1998bind_layers(Dot11Action, Dot11SpectrumManagement, category=0x00) 

1999bind_layers(Dot11SpectrumManagement, Dot11CSA, action=4) 

2000bind_layers(Dot11Action, Dot11WNM, category=0x0A) 

2001bind_layers(Dot11WNM, Dot11BSSTMRequest, action=7) 

2002bind_layers(Dot11WNM, Dot11BSSTMResponse, action=8) 

2003 

2004 

2005conf.l2types.register(DLT_IEEE802_11, Dot11) 

2006conf.l2types.register_num2layer(801, Dot11) 

2007conf.l2types.register(DLT_PRISM_HEADER, PrismHeader) 

2008conf.l2types.register_num2layer(802, PrismHeader) 

2009conf.l2types.register(DLT_IEEE802_11_RADIO, RadioTap) 

2010conf.l2types.register_num2layer(803, RadioTap) 

2011 

2012#################### 

2013# Other WiFi utils # 

2014#################### 

2015 

2016 

2017class WiFi_am(AnsweringMachine): 

2018 """Before using this, initialize "iffrom" and "ifto" interfaces: 

2019iwconfig iffrom mode monitor 

2020iwpriv orig_ifto hostapd 1 

2021ifconfig ifto up 

2022note: if ifto=wlan0ap then orig_ifto=wlan0 

2023note: ifto and iffrom must be set on the same channel 

2024ex: 

2025ifconfig eth1 up 

2026iwconfig eth1 mode monitor 

2027iwconfig eth1 channel 11 

2028iwpriv wlan0 hostapd 1 

2029ifconfig wlan0ap up 

2030iwconfig wlan0 channel 11 

2031iwconfig wlan0 essid dontexist 

2032iwconfig wlan0 mode managed 

2033""" 

2034 function_name = "airpwn" 

2035 filter = None 

2036 

2037 def parse_options(self, iffrom=conf.iface, ifto=conf.iface, replace="", 

2038 pattern="", ignorepattern=""): 

2039 self.iffrom = iffrom 

2040 self.ifto = ifto 

2041 self.ptrn = re.compile(pattern.encode()) 

2042 self.iptrn = re.compile(ignorepattern.encode()) 

2043 self.replace = replace 

2044 

2045 def is_request(self, pkt): 

2046 if not isinstance(pkt, Dot11): 

2047 return 0 

2048 if not pkt.FCfield & 1: 

2049 return 0 

2050 if not pkt.haslayer(TCP): 

2051 return 0 

2052 tcp = pkt.getlayer(TCP) 

2053 pay = raw(tcp.payload) 

2054 if not self.ptrn.match(pay): 

2055 return 0 

2056 if self.iptrn.match(pay) is True: 

2057 return 0 

2058 return True 

2059 

2060 def make_reply(self, p): 

2061 ip = p.getlayer(IP) 

2062 tcp = p.getlayer(TCP) 

2063 pay = raw(tcp.payload) 

2064 p[IP].underlayer.remove_payload() 

2065 p.FCfield = "from-DS" 

2066 p.addr1, p.addr2 = p.addr2, p.addr1 

2067 p /= IP(src=ip.dst, dst=ip.src) 

2068 p /= TCP(sport=tcp.dport, dport=tcp.sport, 

2069 seq=tcp.ack, ack=tcp.seq + len(pay), 

2070 flags="PA") 

2071 q = p.copy() 

2072 p /= self.replace 

2073 q.ID += 1 

2074 q.getlayer(TCP).flags = "RA" 

2075 q.getlayer(TCP).seq += len(self.replace) 

2076 return [p, q] 

2077 

2078 def print_reply(self, query, *reply): 

2079 p = reply[0][0] 

2080 print(p.sprintf("Sent %IP.src%:%IP.sport% > %IP.dst%:%TCP.dport%")) 

2081 

2082 def send_reply(self, reply): 

2083 sendp(reply, iface=self.ifto, **self.optsend) 

2084 

2085 def sniff(self): 

2086 sniff(iface=self.iffrom, **self.optsniff) 

2087 

2088 

2089conf.stats_dot11_protocols += [Dot11WEP, Dot11Beacon, ] 

2090 

2091 

2092class Dot11PacketList(PacketList): 

2093 def __init__(self, res=None, name="Dot11List", stats=None): 

2094 if stats is None: 

2095 stats = conf.stats_dot11_protocols 

2096 

2097 PacketList.__init__(self, res, name, stats) 

2098 

2099 def toEthernet(self): 

2100 data = [x[Dot11] for x in self.res if Dot11 in x and x.type == 2] 

2101 r2 = [] 

2102 for p in data: 

2103 q = p.copy() 

2104 q.unwep() 

2105 r2.append(Ether() / q.payload.payload.payload) # Dot11/LLC/SNAP/IP 

2106 return PacketList(r2, name="Ether from %s" % self.listname)