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

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

610 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 

66 

67 try: 

68 # cryptography > 43.0 

69 from cryptography.hazmat.decrepit.ciphers import ( 

70 algorithms as decrepit_algorithms, 

71 ) 

72 except ImportError: 

73 decrepit_algorithms = algorithms 

74else: 

75 default_backend = Ciphers = algorithms = decrepit_algorithms = None 

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

77 

78 

79######### 

80# Prism # 

81######### 

82 

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

84 

85class PrismHeader(Packet): 

86 """ iwpriv wlan0 monitor 3 """ 

87 name = "Prism header" 

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

89 LEIntField("len", 144), 

90 StrFixedLenField("dev", "", 16), 

91 LEIntField("hosttime_did", 0), 

92 LEShortField("hosttime_status", 0), 

93 LEShortField("hosttime_len", 0), 

94 LEIntField("hosttime", 0), 

95 LEIntField("mactime_did", 0), 

96 LEShortField("mactime_status", 0), 

97 LEShortField("mactime_len", 0), 

98 LEIntField("mactime", 0), 

99 LEIntField("channel_did", 0), 

100 LEShortField("channel_status", 0), 

101 LEShortField("channel_len", 0), 

102 LEIntField("channel", 0), 

103 LEIntField("rssi_did", 0), 

104 LEShortField("rssi_status", 0), 

105 LEShortField("rssi_len", 0), 

106 LEIntField("rssi", 0), 

107 LEIntField("sq_did", 0), 

108 LEShortField("sq_status", 0), 

109 LEShortField("sq_len", 0), 

110 LEIntField("sq", 0), 

111 LEIntField("signal_did", 0), 

112 LEShortField("signal_status", 0), 

113 LEShortField("signal_len", 0), 

114 LESignedIntField("signal", 0), 

115 LEIntField("noise_did", 0), 

116 LEShortField("noise_status", 0), 

117 LEShortField("noise_len", 0), 

118 LEIntField("noise", 0), 

119 LEIntField("rate_did", 0), 

120 LEShortField("rate_status", 0), 

121 LEShortField("rate_len", 0), 

122 LEIntField("rate", 0), 

123 LEIntField("istx_did", 0), 

124 LEShortField("istx_status", 0), 

125 LEShortField("istx_len", 0), 

126 LEIntField("istx", 0), 

127 LEIntField("frmlen_did", 0), 

128 LEShortField("frmlen_status", 0), 

129 LEShortField("frmlen_len", 0), 

130 LEIntField("frmlen", 0), 

131 ] 

132 

133 def answers(self, other): 

134 if isinstance(other, PrismHeader): 

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

136 else: 

137 return self.payload.answers(other) 

138 

139############ 

140# RadioTap # 

141############ 

142 

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

144 

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

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

147 

148# RadioTap constants 

149 

150 

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

152 'dBm_AntNoise', 'Lock_Quality', 'TX_Attenuation', 

153 'dB_TX_Attenuation', 'dBm_TX_Power', 'Antenna', 

154 'dB_AntSignal', 'dB_AntNoise', 'RXFlags', 'TXFlags', 

155 'b17', 'b18', 'ChannelPlus', 'MCS', 'A_MPDU', 

156 'VHT', 'timestamp', 'HE', 'HE_MU', 'HE_MU_other_user', 

157 'zero_length_psdu', 'L_SIG', 'TLV', 

158 'RadiotapNS', 'VendorNS', 'Ext'] 

159 

160# Note: Inconsistencies with wireshark 

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

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

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

164# implemented -> b17, b18 

165 

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

167 'badFCS', 'ShortGI'] 

168 

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

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

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

172 

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

174 

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

176 

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

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

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

180 '20MHz', '40MHz_ext_channel_above', 

181 '40MHz_ext_channel_below', 

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

183 

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

185 'res4', 'res5', 'res6'] 

186 

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

188 'FEC_type', 'STBC_streams', 'Ness', 'Ness_MSB'] 

189 

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

191 

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

193 'LastSubframe', 'CRCerror', 'EOFsubframe', 'KnownEOF', 

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

195 'res8'] 

196 

197_rt_vhtbandwidth = { 

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

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

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

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

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

203} 

204 

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

206 'LDPCextraOFDM', 'Beamformed', 'Bandwidth', 'GroupID', 

207 'PartialAID', 

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

209 

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

211 'SGINsysmDis', 'LDPCextraOFDM', 'Beamformed', 

212 'res1', 'res2'] 

213 

214_rt_hemuother_per_user_known = [ 

215 'user field position', 

216 'STA-ID', 

217 'NSTS', 

218 'Tx Beamforming', 

219 'Spatial Configuration', 

220 'MCS', 

221 'DCM', 

222 'Coding', 

223] 

224 

225 

226# Radiotap utils 

227 

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

229# Wireshark. 

230 

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

232 """Generates the next RadioTapExtendedPresenceMask""" 

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

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

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

236 return None 

237 

238 

239class RadioTapExtendedPresenceMask(Packet): 

240 """RadioTapExtendedPresenceMask should be instantiated by passing an 

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

242 

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

244 e.g. 

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

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

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

248 """ 

249 name = "RadioTap Extended presence mask" 

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

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

252 

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

254 self._restart_indentation(index) 

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

256 

257 def _restart_indentation(self, index): 

258 st = index * 32 

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

260 

261 def guess_payload_class(self, pay): 

262 return conf.padding_layer 

263 

264 

265# This is still unimplemented in Wireshark 

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

267class RadioTapTLV(Packet): 

268 fields_desc = [ 

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

270 LEShortField("length", None), 

271 ConditionalField( 

272 OUIField("oui", 0), 

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

274 ), 

275 ConditionalField( 

276 ByteField("subtype", 0), 

277 lambda pkt: pkt.type == 30 

278 ), 

279 ConditionalField( 

280 LEShortField("presence_type", 0), 

281 lambda pkt: pkt.type == 30 

282 ), 

283 ConditionalField( 

284 LEShortField("reserved", 0), 

285 lambda pkt: pkt.type == 30 

286 ), 

287 StrLenField("data", b"", 

288 length_from=lambda pkt: pkt.length), 

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

290 ] 

291 

292 def post_build(self, pkt, pay): 

293 if self.length is None: 

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

295 if self.pad is None: 

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

297 return pkt + pay 

298 

299 def extract_padding(self, s): 

300 return "", s 

301 

302 

303# RADIOTAP 

304 

305class RadioTap(Packet): 

306 name = "RadioTap" 

307 deprecated_fields = { 

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

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

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

311 } 

312 fields_desc = [ 

313 ByteField('version', 0), 

314 ByteField('pad', 0), 

315 LEShortField('len', None), 

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

317 # Extended presence mask 

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

319 # RadioTap fields - each starts with a ReversePadField 

320 # to handle padding 

321 

322 # TSFT 

323 ConditionalField( 

324 ReversePadField( 

325 LELongField("mac_timestamp", 0), 

326 8 

327 ), 

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

329 # Flags 

330 ConditionalField( 

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

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

333 # Rate 

334 ConditionalField( 

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

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

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

338 # Channel 

339 ConditionalField( 

340 ReversePadField( 

341 LEShortField("ChannelFrequency", 0), 

342 2 

343 ), 

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

345 ConditionalField( 

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

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

348 # dBm_AntSignal 

349 ConditionalField( 

350 ScalingField("dBm_AntSignal", 0, 

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

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

353 # dBm_AntNoise 

354 ConditionalField( 

355 ScalingField("dBm_AntNoise", 0, 

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

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

358 # Lock_Quality 

359 ConditionalField( 

360 ReversePadField( 

361 LEShortField("Lock_Quality", 0), 

362 2 

363 ), 

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

365 # Antenna 

366 ConditionalField( 

367 ByteField("Antenna", 0), 

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

369 # RX Flags 

370 ConditionalField( 

371 ReversePadField( 

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

373 2 

374 ), 

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

376 # TX Flags 

377 ConditionalField( 

378 ReversePadField( 

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

380 2 

381 ), 

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

383 # ChannelPlus 

384 ConditionalField( 

385 ReversePadField( 

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

387 4 

388 ), 

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

390 ConditionalField( 

391 LEShortField("ChannelPlusFrequency", 0), 

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

393 ConditionalField( 

394 ByteField("ChannelPlusNumber", 0), 

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

396 # MCS 

397 ConditionalField( 

398 ReversePadField( 

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

400 2 

401 ), 

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

403 ConditionalField( 

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

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

406 ConditionalField( 

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

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

409 ConditionalField( 

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

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

412 ConditionalField( 

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

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

415 ConditionalField( 

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

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

418 ConditionalField( 

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

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

421 ConditionalField( 

422 ByteField("MCS_index", 0), 

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

424 # A_MPDU 

425 ConditionalField( 

426 ReversePadField( 

427 LEIntField("A_MPDU_ref", 0), 

428 4 

429 ), 

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

431 ConditionalField( 

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

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

434 # VHT 

435 ConditionalField( 

436 ReversePadField( 

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

438 2 

439 ), 

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

441 ConditionalField( 

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

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

444 ConditionalField( 

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

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

447 ConditionalField( 

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

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

450 ConditionalField( 

451 ByteField("GroupID", 0), 

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

453 ConditionalField( 

454 ShortField("PartialAID", 0), 

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

456 # timestamp 

457 ConditionalField( 

458 ReversePadField( 

459 LELongField("timestamp", 0), 

460 8 

461 ), 

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

463 ConditionalField( 

464 LEShortField("ts_accuracy", 0), 

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

466 ConditionalField( 

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

468 0: 'milliseconds', 

469 1: 'microseconds', 

470 2: 'nanoseconds'}), 

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

472 ConditionalField( 

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

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

475 ConditionalField( 

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

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

478 # HE - XXX not complete 

479 ConditionalField( 

480 ReversePadField( 

481 LEShortField("he_data1", 0), 

482 2 

483 ), 

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

485 ConditionalField( 

486 LEShortField("he_data2", 0), 

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

488 ConditionalField( 

489 LEShortField("he_data3", 0), 

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

491 ConditionalField( 

492 LEShortField("he_data4", 0), 

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

494 ConditionalField( 

495 LEShortField("he_data5", 0), 

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

497 ConditionalField( 

498 LEShortField("he_data6", 0), 

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

500 # HE_MU 

501 ConditionalField( 

502 ReversePadField( 

503 LEShortField("hemu_flags1", 0), 

504 2 

505 ), 

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

507 ConditionalField( 

508 LEShortField("hemu_flags2", 0), 

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

510 ConditionalField( 

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

512 length_from=lambda x: 4), 

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

514 ConditionalField( 

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

516 length_from=lambda x: 4), 

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

518 # HE_MU_other_user 

519 ConditionalField( 

520 ReversePadField( 

521 LEShortField("hemuou_per_user_1", 0x7fff), 

522 2 

523 ), 

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

525 ConditionalField( 

526 LEShortField("hemuou_per_user_2", 0x003f), 

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

528 ConditionalField( 

529 ByteField("hemuou_per_user_position", 0), 

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

531 ConditionalField( 

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

533 _rt_hemuother_per_user_known), 

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

535 # L_SIG 

536 ConditionalField( 

537 ReversePadField( 

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

539 2 

540 ), 

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

542 ConditionalField( 

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

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

545 ConditionalField( 

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

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

548 # TLV fields 

549 ConditionalField( 

550 ReversePadField( 

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

552 4 

553 ), 

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

555 ), 

556 # Remaining 

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

558 ] 

559 

560 def guess_payload_class(self, payload): 

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

562 return Dot11FCS 

563 return Dot11 

564 

565 def post_dissect(self, s): 

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

567 self.notdecoded = s[:length] 

568 return s[length:] 

569 

570 def post_build(self, p, pay): 

571 if self.len is None: 

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

573 return p + pay 

574 

575 

576########## 

577# 802.11 # 

578########## 

579 

580# Note: 

581# 802.11-2016 includes the spec for 

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

583 

584# 802.11-2016 9.2 

585 

586# 802.11-2016 9.2.4.1.3 

587_dot11_subtypes = { 

588 0: { # Management 

589 0: "Association Request", 

590 1: "Association Response", 

591 2: "Reassociation Request", 

592 3: "Reassociation Response", 

593 4: "Probe Request", 

594 5: "Probe Response", 

595 6: "Timing Advertisement", 

596 8: "Beacon", 

597 9: "ATIM", 

598 10: "Disassociation", 

599 11: "Authentication", 

600 12: "Deauthentication", 

601 13: "Action", 

602 14: "Action No Ack", 

603 }, 

604 1: { # Control 

605 2: "Trigger", 

606 3: "TACK", 

607 4: "Beamforming Report Poll", 

608 5: "VHT/HE NDP Announcement", 

609 6: "Control Frame Extension", 

610 7: "Control Wrapper", 

611 8: "Block Ack Request", 

612 9: "Block Ack", 

613 10: "PS-Poll", 

614 11: "RTS", 

615 12: "CTS", 

616 13: "Ack", 

617 14: "CF-End", 

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

619 }, 

620 2: { # Data 

621 0: "Data", 

622 1: "Data+CF-Ack", 

623 2: "Data+CF-Poll", 

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

625 4: "Null (no data)", 

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

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

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

629 8: "QoS Data", 

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

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

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

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

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

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

636 }, 

637 3: { # Extension 

638 0: "DMG Beacon", 

639 1: "S1G Beacon" 

640 } 

641} 

642 

643_dot11_cfe = { 

644 2: "Poll", 

645 3: "SPR", 

646 4: "Grant", 

647 5: "DMG CTS", 

648 6: "DMG DTS", 

649 7: "Grant Ack", 

650 8: "SSW", 

651 9: "SSW-Feedback", 

652 10: "SSW-Ack", 

653} 

654 

655 

656_dot11_addr_meaning = [ 

657 [ # Management: 802.11-2016 9.3.3.2 

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

659 ], 

660 [ # Control 

661 "RA", "TA", None, None 

662 ], 

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

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

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

666 [["BSSID", "SA"], ["DA", "DA"]], 

667 [[None, None], ["SA", "BSSID"]], 

668 ], 

669 [ # Extension 

670 "BSSID", None, None, None 

671 ], 

672] 

673 

674 

675class _Dot11MacField(MACField): 

676 """ 

677 A MACField that displays the address type depending on the 

678 802.11 flags 

679 """ 

680 __slots__ = ["index"] 

681 

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

683 self.index = index 

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

685 

686 def i2repr(self, pkt, val): 

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

688 meaning = pkt.address_meaning(self.index) 

689 if meaning: 

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

691 return s 

692 

693 

694# 802.11-2020 9.2.4.1.1 

695class Dot11(Packet): 

696 name = "802.11" 

697 fields_desc = [ 

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

699 lambda pkt: pkt.type), 

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

701 "Extension"]), 

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

703 ConditionalField( 

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

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

706 ), 

707 MultipleTypeField( 

708 [ 

709 ( 

710 FlagsField("FCfield", 0, 4, 

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

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

713 ), 

714 ( 

715 FlagsField("FCfield", 0, 2, 

716 ["security", "AP_PM"]), 

717 lambda pkt: (pkt.type, pkt.subtype) == (3, 1) 

718 ) 

719 ], 

720 FlagsField("FCfield", 0, 8, 

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

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

723 ), 

724 ConditionalField( 

725 BitField("FCfield_bw", 0, 3), 

726 lambda pkt: (pkt.type, pkt.subtype) == (3, 1) 

727 ), 

728 ConditionalField( 

729 FlagsField("FCfield2", 0, 3, 

730 ["next_tbtt", "comp_ssid", "ano"]), 

731 lambda pkt: (pkt.type, pkt.subtype) == (3, 1) 

732 ), 

733 LEShortField("ID", 0), 

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

735 ConditionalField( 

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

737 lambda pkt: (pkt.type not in {1, 3} or 

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

739 ), 

740 ConditionalField( 

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

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

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

744 ), 

745 ConditionalField(LEShortField("SC", 0), lambda pkt: pkt.type not in {1, 3}), 

746 ConditionalField( 

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

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

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

750 ) 

751 ] 

752 

753 def mysummary(self): 

754 # Supports both Dot11 and Dot11FCS 

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

756 

757 def guess_payload_class(self, payload): 

758 if self.type == 0x02 and ( 

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

760 return Dot11QoS 

761 elif hasattr(self.FCfield, "protected") and self.FCfield.protected: 

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

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

764 # begins with the appropriate cryptographic header. 

765 return Dot11Encrypted 

766 else: 

767 return Packet.guess_payload_class(self, payload) 

768 

769 def answers(self, other): 

770 if isinstance(other, Dot11): 

771 if self.type == 0: # management 

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

773 return 0 

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

775 return 1 

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

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

778 elif self.type == 1: # control 

779 return 0 

780 elif self.type == 2: # data 

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

782 elif self.type == 3: # reserved 

783 return 0 

784 return 0 

785 

786 def address_meaning(self, index): 

787 """ 

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

789 """ 

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

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

792 index = index - 1 

793 if self.type == 0: # Management 

794 return _dot11_addr_meaning[0][index] 

795 elif self.type == 1: # Control 

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

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

798 return _dot11_addr_meaning[1][index] 

799 elif self.type == 2: # Data 

800 meaning = _dot11_addr_meaning[2][index][ 

801 self.FCfield.to_DS 

802 ][self.FCfield.from_DS] 

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

804 if isinstance(self.payload, Dot11QoS): 

805 # MSDU and Short A-MSDU 

806 if self.payload.A_MSDU_Present: 

807 meaning = "BSSID" 

808 return meaning 

809 elif self.type == 3: # Extension 

810 return _dot11_addr_meaning[3][index] 

811 return None 

812 

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

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

815 if warn: 

816 warning("No WEP to remove") 

817 return 

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

819 if key or conf.wepkey: 

820 self.payload.decrypt(key) 

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

822 if warn: 

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

824 return 

825 self.FCfield &= ~0x40 

826 self.payload = self.payload.payload 

827 

828 

829class Dot11FCS(Dot11): 

830 name = "802.11-FCS" 

831 match_subclass = True 

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

833 

834 def compute_fcs(self, s): 

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

836 

837 def post_build(self, p, pay): 

838 p += pay 

839 if self.fcs is None: 

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

841 return p 

842 

843 

844class Dot11QoS(Packet): 

845 name = "802.11 QoS" 

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

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

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

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

850 ByteField("TXOP", 0)] 

851 

852 def guess_payload_class(self, payload): 

853 if isinstance(self.underlayer, Dot11): 

854 if self.underlayer.FCfield.protected: 

855 return Dot11Encrypted 

856 return Packet.guess_payload_class(self, payload) 

857 

858 

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

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

861 "ESS", "IBSS", "CFP", "CFP-req", 

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

863 

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

865 3: "deauth-ST-leaving", 

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

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

868 9: "ST-not-auth"} 

869 

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

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

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

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

874 

875 

876class _Dot11EltUtils(Packet): 

877 """ 

878 Contains utils for classes that have Dot11Elt as payloads 

879 """ 

880 def network_stats(self): 

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

882 elements fields 

883 """ 

884 summary = {} 

885 crypto = set() 

886 p = self.payload 

887 while isinstance(p, Dot11Elt): 

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

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

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

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

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

893 elif p.ID == 3: 

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

895 elif isinstance(p, Dot11EltCountry): 

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

897 country_descriptor_types = { 

898 b"I": "Indoor", 

899 b"O": "Outdoor", 

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

901 b"\xff": "Ignored" 

902 } 

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

904 p.country_string[-1:] 

905 ) 

906 elif isinstance(p, Dot11EltRates): 

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

908 if "rates" in summary: 

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

910 else: 

911 summary["rates"] = rates 

912 elif isinstance(p, Dot11EltRSN): 

913 wpa_version = "WPA2" 

914 # WPA3-only: 

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

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

917 # 00-0F-AC:6 

918 # - AP shall set MFPC and MFPR to 1 

919 # - AP shall not enable WEP and TKIP 

920 # WPA3-transition: 

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

922 # and 00-0F-AC:8 

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

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

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

926 p.mfp_capable and p.mfp_required and \ 

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

928 for x in p.pairwise_cipher_suites): 

929 # WPA3 only mode 

930 wpa_version = "WPA3" 

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

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

933 p.mfp_capable and not p.mfp_required: 

934 # WPA3 transition mode 

935 wpa_version = "WPA3-transition" 

936 # Append suite 

937 if p.akm_suites: 

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

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

940 else: 

941 crypto.add(wpa_version) 

942 elif p.ID == 221: 

943 if isinstance(p, Dot11EltMicrosoftWPA): 

944 if p.akm_suites: 

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

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

947 else: 

948 crypto.add("WPA") 

949 p = p.payload 

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

951 if self.cap.privacy: 

952 crypto.add("WEP") 

953 else: 

954 crypto.add("OPN") 

955 if crypto: 

956 summary["crypto"] = crypto 

957 return summary 

958 

959 

960############# 

961# 802.11 IE # 

962############# 

963 

964# 802.11-2016 - 9.4.2 

965 

966_dot11_info_elts_ids = { 

967 0: "SSID", 

968 1: "Supported Rates", 

969 2: "FHset", 

970 3: "DSSS Set", 

971 4: "CF Set", 

972 5: "TIM", 

973 6: "IBSS Set", 

974 7: "Country", 

975 10: "Request", 

976 11: "BSS Load", 

977 12: "EDCA Set", 

978 13: "TSPEC", 

979 14: "TCLAS", 

980 15: "Schedule", 

981 16: "Challenge text", 

982 32: "Power Constraint", 

983 33: "Power Capability", 

984 36: "Supported Channels", 

985 37: "Channel Switch Announcement", 

986 42: "ERP", 

987 45: "HT Capabilities", 

988 46: "QoS Capability", 

989 48: "RSN", 

990 50: "Extended Supported Rates", 

991 52: "Neighbor Report", 

992 61: "HT Operation", 

993 74: "Overlapping BSS Scan Parameters", 

994 107: "Interworking", 

995 127: "Extended Capabilities", 

996 191: "VHT Capabilities", 

997 192: "VHT Operation", 

998 221: "Vendor Specific" 

999} 

1000 

1001# Backward compatibility 

1002_dot11_elt_deprecated_names = { 

1003 "Rates": 1, 

1004 "DSset": 3, 

1005 "CFset": 4, 

1006 "IBSSset": 6, 

1007 "challenge": 16, 

1008 "PowerCapability": 33, 

1009 "Channels": 36, 

1010 "ERPinfo": 42, 

1011 "HTinfo": 45, 

1012 "RSNinfo": 48, 

1013 "ESRates": 50, 

1014 "ExtendendCapatibilities": 127, 

1015 "VHTCapabilities": 191, 

1016 "Vendor": 221, 

1017} 

1018 

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

1020_dot11_info_elts_ids_rev.update(_dot11_elt_deprecated_names) 

1021_dot11_id_enum = ( 

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

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

1024) 

1025 

1026 

1027# 802.11-2020 9.4.2.1 

1028 

1029class Dot11Elt(Packet): 

1030 """ 

1031 A Generic 802.11 Element 

1032 """ 

1033 __slots__ = ["info"] 

1034 name = "802.11 Information Element" 

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

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

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

1038 max_length=255)] 

1039 show_indent = 0 

1040 

1041 def __setattr__(self, attr, val): 

1042 if attr == "info": 

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

1044 try: 

1045 self.setfieldval(attr, val) 

1046 except AttributeError: 

1047 pass 

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

1049 

1050 def mysummary(self): 

1051 if self.ID == 0: 

1052 ssid = plain_str(self.info) 

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

1054 else: 

1055 return "" 

1056 

1057 registered_ies = {} 

1058 

1059 @classmethod 

1060 def register_variant(cls, id=None): 

1061 id = id or cls.ID.default 

1062 if id not in cls.registered_ies: 

1063 cls.registered_ies[id] = cls 

1064 

1065 @classmethod 

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

1067 if _pkt: 

1068 _id = ord(_pkt[:1]) 

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

1070 if idcls.dispatch_hook != cls.dispatch_hook: 

1071 # Vendor has its own dispatch_hook 

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

1073 cls = idcls 

1074 return cls 

1075 

1076 def pre_dissect(self, s): 

1077 # Backward compatibility: add info to all elements 

1078 # This allows to introduce new Dot11Elt classes without breaking 

1079 # previous code 

1080 if len(s) >= 3: 

1081 length = orb(s[1]) 

1082 if length > 0 and length <= 255: 

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

1084 return s 

1085 

1086 def post_build(self, p, pay): 

1087 if self.len is None: 

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

1089 return p + pay 

1090 

1091 

1092# 802.11-2020 9.4.2.4 

1093 

1094class Dot11EltDSSSet(Dot11Elt): 

1095 name = "802.11 DSSS Parameter Set" 

1096 match_subclass = True 

1097 fields_desc = [ 

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

1099 ByteField("len", 1), 

1100 ByteField("channel", 0), 

1101 ] 

1102 

1103 

1104# 802.11-2020 9.4.2.11 

1105 

1106class Dot11EltERP(Dot11Elt): 

1107 name = "802.11 ERP" 

1108 match_subclass = True 

1109 fields_desc = [ 

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

1111 ByteField("len", 1), 

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

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

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

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

1116 ] 

1117 

1118 

1119# 802.11-2020 9.4.2.24.2 

1120 

1121class RSNCipherSuite(Packet): 

1122 name = "Cipher suite" 

1123 fields_desc = [ 

1124 OUIField("oui", 0x000fac), 

1125 ByteEnumField("cipher", 0x04, { 

1126 0x00: "Use group cipher suite", 

1127 0x01: "WEP-40", 

1128 0x02: "TKIP", 

1129 0x03: "OCB", 

1130 0x04: "CCMP-128", 

1131 0x05: "WEP-104", 

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

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

1134 0x08: "GCMP-128", 

1135 0x09: "GCMP-256", 

1136 0x0A: "CCMP-256", 

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

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

1139 0x0D: "BIP-CMAC-256" 

1140 }) 

1141 ] 

1142 

1143 def extract_padding(self, s): 

1144 return "", s 

1145 

1146 

1147# 802.11-2020 9.4.2.24.3 

1148 

1149class AKMSuite(Packet): 

1150 name = "AKM suite" 

1151 fields_desc = [ 

1152 OUIField("oui", 0x000fac), 

1153 ByteEnumField("suite", 0x01, { 

1154 0x00: "Reserved", 

1155 0x01: "802.1X", 

1156 0x02: "PSK", 

1157 0x03: "FT-802.1X", 

1158 0x04: "FT-PSK", 

1159 0x05: "WPA-SHA256", 

1160 0x06: "PSK-SHA256", 

1161 0x07: "TDLS", 

1162 0x08: "SAE", 

1163 0x09: "FT-SAE", 

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

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

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

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

1168 0x0E: "FILS-SHA256", 

1169 0x0F: "FILS-SHA384", 

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

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

1172 0x12: "OWE" 

1173 }) 

1174 ] 

1175 

1176 def extract_padding(self, s): 

1177 return "", s 

1178 

1179 

1180# 802.11-2020 9.4.2.24.5 

1181 

1182class PMKIDListPacket(Packet): 

1183 name = "PMKIDs" 

1184 fields_desc = [ 

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

1186 FieldListField( 

1187 "pmkid_list", 

1188 None, 

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

1190 count_from=lambda pkt: pkt.nb_pmkids 

1191 ) 

1192 ] 

1193 

1194 def extract_padding(self, s): 

1195 return "", s 

1196 

1197 

1198# 802.11-2020 9.4.2.24.1 

1199 

1200class Dot11EltRSN(Dot11Elt): 

1201 name = "802.11 RSN information" 

1202 match_subclass = True 

1203 fields_desc = [ 

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

1205 ByteField("len", None), 

1206 LEShortField("version", 1), 

1207 PacketField("group_cipher_suite", RSNCipherSuite(), RSNCipherSuite), 

1208 LEFieldLenField( 

1209 "nb_pairwise_cipher_suites", 

1210 None, 

1211 count_of="pairwise_cipher_suites" 

1212 ), 

1213 PacketListField( 

1214 "pairwise_cipher_suites", 

1215 [RSNCipherSuite()], 

1216 RSNCipherSuite, 

1217 count_from=lambda p: p.nb_pairwise_cipher_suites 

1218 ), 

1219 LEFieldLenField( 

1220 "nb_akm_suites", 

1221 None, 

1222 count_of="akm_suites" 

1223 ), 

1224 PacketListField( 

1225 "akm_suites", 

1226 [AKMSuite()], 

1227 AKMSuite, 

1228 count_from=lambda p: p.nb_akm_suites 

1229 ), 

1230 # RSN Capabilities 

1231 # 802.11-2020 9.4.2.24.4 

1232 BitField("mfp_capable", 1, 1), 

1233 BitField("mfp_required", 1, 1), 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1249 ConditionalField( 

1250 PacketField("pmkids", PMKIDListPacket(), PMKIDListPacket), 

1251 lambda pkt: ( 

1252 True if pkt.len is None else 

1253 pkt.len - ( 

1254 12 + 

1255 (pkt.nb_pairwise_cipher_suites or 0) * 4 + 

1256 (pkt.nb_akm_suites or 0) * 4 

1257 ) >= 2 

1258 ) 

1259 ), 

1260 ConditionalField( 

1261 PacketField("group_management_cipher_suite", 

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

1263 lambda pkt: ( 

1264 True if pkt.len is None else 

1265 pkt.len - ( 

1266 12 + 

1267 (pkt.nb_pairwise_cipher_suites or 0) * 4 + 

1268 (pkt.nb_akm_suites or 0) * 4 + 

1269 (2 if pkt.pmkids else 0) + 

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

1271 ) >= 4 

1272 ) 

1273 ) 

1274 ] 

1275 

1276 

1277class Dot11EltCountryConstraintTriplet(Packet): 

1278 name = "802.11 Country Constraint Triplet" 

1279 fields_desc = [ 

1280 ByteField("first_channel_number", 1), 

1281 ByteField("num_channels", 24), 

1282 ByteField("mtp", 0) 

1283 ] 

1284 

1285 def extract_padding(self, s): 

1286 return b"", s 

1287 

1288 

1289class Dot11EltCountry(Dot11Elt): 

1290 name = "802.11 Country" 

1291 match_subclass = True 

1292 fields_desc = [ 

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

1294 ByteField("len", None), 

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

1296 MayEnd(PacketListField( 

1297 "descriptors", 

1298 [], 

1299 Dot11EltCountryConstraintTriplet, 

1300 length_from=lambda pkt: ( 

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

1302 ) 

1303 )), 

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

1305 ConditionalField( 

1306 ByteField("pad", 0), 

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

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

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

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

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

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

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

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

1315 ) 

1316 ] 

1317 

1318 

1319class _RateField(ByteField): 

1320 def i2repr(self, pkt, val): 

1321 if val is None: 

1322 return "" 

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

1324 if val & 0x80: 

1325 s += "(B)" 

1326 return s + " Mbps" 

1327 

1328 

1329class Dot11EltRates(Dot11Elt): 

1330 name = "802.11 Rates" 

1331 match_subclass = True 

1332 fields_desc = [ 

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

1334 ByteField("len", None), 

1335 FieldListField( 

1336 "rates", 

1337 [0x82], 

1338 _RateField("", 0), 

1339 length_from=lambda p: p.len 

1340 ) 

1341 ] 

1342 

1343 

1344Dot11EltRates.register_variant(50) # Extended rates 

1345 

1346 

1347class Dot11EltHTCapabilities(Dot11Elt): 

1348 name = "802.11 HT Capabilities" 

1349 match_subclass = True 

1350 fields_desc = [ 

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

1352 ByteField("len", None), 

1353 # HT Capabilities Info: 2B 

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

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

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

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

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

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

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

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

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

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

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

1365 BitEnumField("SM_Power_Save", 0, 2, 

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

1367 BitEnumField("Supported_Channel_Width", 0, 1, 

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

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

1370 # A-MPDU Parameters: 1B 

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

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

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

1374 # Supported MCS set: 16B 

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

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

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

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

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

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

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

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

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

1384 # HT Extended capabilities: 2B 

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

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

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

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

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

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

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

1392 # TX Beamforming Capabilities TxBF: 4B 

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

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

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

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

1397 BitField("Noncompressed_Steering_n_Beamformer_Antennas_Supported", 

1398 0, 2), 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1413 BitField("Implicit_Transmit_Beamforming_Receiving", 0, 1, 

1414 end_tot_size=-4), 

1415 # ASEL Capabilities: 1B 

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

1417 "res", 

1418 "Transmit_Sounding_PPDUs", 

1419 "Receive_ASEL", 

1420 "Antenna_Indices_Feedback", 

1421 "Explicit_CSI_Feedback", 

1422 "Explicit_CSI_Feedback_Based_Transmit_ASEL", 

1423 "Antenna_Selection", 

1424 ]) 

1425 ] 

1426 

1427 

1428class Dot11EltVendorSpecific(Dot11Elt): 

1429 name = "802.11 Vendor Specific" 

1430 match_subclass = True 

1431 fields_desc = [ 

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

1433 ByteField("len", None), 

1434 OUIField("oui", 0x000000), 

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

1436 ] 

1437 

1438 @classmethod 

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

1440 if _pkt: 

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

1442 ouicls = cls.registered_ouis.get(oui, cls) 

1443 if ouicls.dispatch_hook != cls.dispatch_hook: 

1444 # Sub-classes can have their own dispatch_hook 

1445 return ouicls.dispatch_hook(_pkt=_pkt, *args, **kargs) 

1446 cls = ouicls 

1447 return cls 

1448 

1449 registered_ouis = {} 

1450 

1451 @classmethod 

1452 def register_variant(cls): 

1453 oui = cls.oui.default 

1454 if not oui: 

1455 # This is Dot11EltVendorSpecific, register it in the super-class. 

1456 super().register_variant() 

1457 elif oui not in cls.registered_ouis: 

1458 # Sub-Vendor (e.g. Dot11EltMicrosoftWPA) 

1459 cls.registered_ouis[oui] = cls 

1460 

1461 

1462class Dot11EltMicrosoftWPA(Dot11EltVendorSpecific): 

1463 name = "802.11 Microsoft WPA" 

1464 match_subclass = True 

1465 ID = 221 

1466 oui = 0x0050f2 

1467 # It appears many WPA implementations ignore the fact 

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

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

1470 XByteField("type", 0x01) 

1471 ] + Dot11EltRSN.fields_desc[2:8] 

1472 

1473 @classmethod 

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

1475 if _pkt: 

1476 type_ = orb(_pkt[5]) 

1477 if type_ == 0x01: 

1478 # MS WPA IE 

1479 return Dot11EltMicrosoftWPA 

1480 elif type_ == 0x02: 

1481 # MS WME IE TODO 

1482 # return Dot11EltMicrosoftWME 

1483 pass 

1484 elif type_ == 0x04: 

1485 # MS WPS IE TODO 

1486 # return Dot11EltWPS 

1487 pass 

1488 return Dot11EltVendorSpecific 

1489 return cls 

1490 

1491 

1492# 802.11-2016 9.4.2.19 

1493 

1494class Dot11EltCSA(Dot11Elt): 

1495 name = "802.11 CSA Element" 

1496 match_subclass = True 

1497 fields_desc = [ 

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

1499 ByteField("len", 3), 

1500 ByteField("mode", 0), 

1501 ByteField("new_channel", 0), 

1502 ByteField("channel_switch_count", 0) 

1503 ] 

1504 

1505 

1506# 802.11-2016 9.4.2.59 

1507 

1508class Dot11EltOBSS(Dot11Elt): 

1509 name = "802.11 OBSS Scan Parameters Element" 

1510 match_subclass = True 

1511 fields_desc = [ 

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

1513 ByteField("len", 14), 

1514 LEShortField("Passive_Dwell", 0), 

1515 LEShortField("Active_Dwell", 0), 

1516 LEShortField("Scan_Interval", 0), 

1517 LEShortField("Passive_Total_Per_Channel", 0), 

1518 LEShortField("Active_Total_Per_Channel", 0), 

1519 LEShortField("Delay", 0), 

1520 LEShortField("Activity_Threshold", 0), 

1521 ] 

1522 

1523 

1524# 802.11-2016 9.4.2.159 

1525 

1526class Dot11VHTOperationInfo(Packet): 

1527 name = "802.11 VHT Operation Information" 

1528 fields_desc = [ 

1529 ByteField("channel_width", 0), 

1530 ByteField("channel_center0", 36), 

1531 ByteField("channel_center1", 0), 

1532 ] 

1533 

1534 def extract_padding(self, s): 

1535 return "", s 

1536 

1537 

1538class Dot11EltVHTOperation(Dot11Elt): 

1539 name = "802.11 VHT Operation Element" 

1540 match_subclass = True 

1541 fields_desc = [ 

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

1543 ByteField("len", 5), 

1544 PacketField( 

1545 "VHT_Operation_Info", 

1546 Dot11VHTOperationInfo(), 

1547 Dot11VHTOperationInfo 

1548 ), 

1549 FieldListField( 

1550 "mcs_set", 

1551 [0x00], 

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

1553 count_from=lambda x: 8 

1554 ) 

1555 ] 

1556 

1557 

1558###################### 

1559# 802.11 Frame types # 

1560###################### 

1561 

1562# 802.11-2016 9.3 

1563 

1564class Dot11Beacon(_Dot11EltUtils): 

1565 name = "802.11 Beacon" 

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

1567 LEShortField("beacon_interval", 0x0064), 

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

1569 

1570 

1571class Dot11ATIM(Packet): 

1572 name = "802.11 ATIM" 

1573 

1574 

1575class Dot11Disas(Packet): 

1576 name = "802.11 Disassociation" 

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

1578 

1579 

1580class Dot11AssoReq(_Dot11EltUtils): 

1581 name = "802.11 Association Request" 

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

1583 LEShortField("listen_interval", 0x00c8)] 

1584 

1585 

1586class Dot11AssoResp(_Dot11EltUtils): 

1587 name = "802.11 Association Response" 

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

1589 LEShortField("status", 0), 

1590 LEShortField("AID", 0)] 

1591 

1592 

1593class Dot11ReassoReq(_Dot11EltUtils): 

1594 name = "802.11 Reassociation Request" 

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

1596 LEShortField("listen_interval", 0x00c8), 

1597 MACField("current_AP", ETHER_ANY)] 

1598 

1599 

1600class Dot11ReassoResp(Dot11AssoResp): 

1601 name = "802.11 Reassociation Response" 

1602 

1603 

1604class Dot11ProbeReq(_Dot11EltUtils): 

1605 name = "802.11 Probe Request" 

1606 

1607 

1608class Dot11ProbeResp(_Dot11EltUtils): 

1609 name = "802.11 Probe Response" 

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

1611 LEShortField("beacon_interval", 0x0064), 

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

1613 

1614 

1615class Dot11Auth(_Dot11EltUtils): 

1616 name = "802.11 Authentication" 

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

1618 LEShortField("seqnum", 0), 

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

1620 

1621 def answers(self, other): 

1622 if self.algo != other.algo: 

1623 return 0 

1624 

1625 if ( 

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

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

1628 ): 

1629 return 1 

1630 return 0 

1631 

1632 

1633class Dot11Deauth(Packet): 

1634 name = "802.11 Deauthentication" 

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

1636 

1637 

1638class Dot11Ack(Packet): 

1639 name = "802.11 Ack packet" 

1640 

1641 

1642# 802.11-2016 9.4.1.11 

1643 

1644class Dot11Action(Packet): 

1645 name = "802.11 Action" 

1646 fields_desc = [ 

1647 ByteEnumField("category", 0x00, { 

1648 0x00: "Spectrum Management", 

1649 0x01: "QoS", 

1650 0x02: "DLS", 

1651 0x03: "Block", 

1652 0x04: "Public", 

1653 0x05: "Radio Measurement", 

1654 0x06: "Fast BSS Transition", 

1655 0x07: "HT", 

1656 0x08: "SA Query", 

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

1658 0x0A: "WNM", 

1659 0x0B: "Unprotected WNM", 

1660 0x0C: "TDLS", 

1661 0x0D: "Mesh", 

1662 0x0E: "Multihop", 

1663 0x0F: "Self-protected", 

1664 0x10: "DMG", 

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

1666 0x12: "Fast Session Transfer", 

1667 0x13: "Robust AV Streaming", 

1668 0x14: "Unprotected DMG", 

1669 0x15: "VHT" 

1670 }) 

1671 ] 

1672 

1673 

1674# 802.11-2016 9.6.14.1 

1675 

1676class Dot11WNM(Packet): 

1677 name = "802.11 WNM Action" 

1678 fields_desc = [ 

1679 ByteEnumField("action", 0x00, { 

1680 0x00: "Event Request", 

1681 0x01: "Event Report", 

1682 0x02: "Diagnostic Request", 

1683 0x03: "Diagnostic Report", 

1684 0x04: "Location Configuration Request", 

1685 0x05: "Location Configuration Response", 

1686 0x06: "BSS Transition Management Query", 

1687 0x07: "BSS Transition Management Request", 

1688 0x08: "BSS Transition Management Response", 

1689 0x09: "FMS Request", 

1690 0x0A: "FMS Response", 

1691 0x0B: "Collocated Interference Request", 

1692 0x0C: "Collocated Interference Report", 

1693 0x0D: "TFS Request", 

1694 0x0E: "TFS Response", 

1695 0x0F: "TFS Notify", 

1696 0x10: "WNM Sleep Mode Request", 

1697 0x11: "WNM Sleep Mode Response", 

1698 0x12: "TIM Broadcast Request", 

1699 0x13: "TIM Broadcast Response", 

1700 0x14: "QoS Traffic Capability Update", 

1701 0x15: "Channel Usage Request", 

1702 0x16: "Channel Usage Response", 

1703 0x17: "DMS Request", 

1704 0x18: "DMS Response", 

1705 0x19: "Timing Measurement Request", 

1706 0x1A: "WNM Notification Request", 

1707 0x1B: "WNM Notification Response", 

1708 0x1C: "WNM-Notify Response" 

1709 }) 

1710 ] 

1711 

1712 

1713# 802.11-2016 9.4.2.37 

1714 

1715class SubelemTLV(Packet): 

1716 fields_desc = [ 

1717 ByteField("type", 0), 

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

1719 FieldListField( 

1720 "value", 

1721 [], 

1722 ByteField('', 0), 

1723 length_from=lambda p: p.len 

1724 ) 

1725 ] 

1726 

1727 

1728class BSSTerminationDuration(Packet): 

1729 name = "BSS Termination Duration" 

1730 fields_desc = [ 

1731 ByteField("id", 4), 

1732 ByteField("len", 10), 

1733 LELongField("TSF", 0), 

1734 LEShortField("duration", 0) 

1735 ] 

1736 

1737 def extract_padding(self, s): 

1738 return "", s 

1739 

1740 

1741class NeighborReport(Packet): 

1742 name = "Neighbor Report" 

1743 fields_desc = [ 

1744 ByteField("type", 0), 

1745 ByteField("len", 13), 

1746 MACField("BSSID", ETHER_ANY), 

1747 # BSSID Information 

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

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

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

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

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

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

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

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

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

1757 # BSSID Information end 

1758 ByteField("op_class", 0), 

1759 ByteField("channel", 0), 

1760 ByteField("phy_type", 0), 

1761 ConditionalField( 

1762 PacketListField( 

1763 "subelems", 

1764 SubelemTLV(), 

1765 SubelemTLV, 

1766 length_from=lambda p: p.len - 13 

1767 ), 

1768 lambda p: p.len > 13 

1769 ) 

1770 ] 

1771 

1772 

1773# 802.11-2016 9.6.14.9 

1774 

1775btm_request_mode = [ 

1776 "Preferred_Candidate_List_Included", 

1777 "Abridged", 

1778 "Disassociation_Imminent", 

1779 "BSS_Termination_Included", 

1780 "ESS_Disassociation_Imminent" 

1781] 

1782 

1783 

1784class Dot11BSSTMRequest(Packet): 

1785 name = "BSS Transition Management Request" 

1786 fields_desc = [ 

1787 ByteField("token", 0), 

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

1789 LEShortField("disassociation_timer", 0), 

1790 ByteField("validity_interval", 0), 

1791 ConditionalField( 

1792 PacketField( 

1793 "termination_duration", 

1794 BSSTerminationDuration(), 

1795 BSSTerminationDuration 

1796 ), 

1797 lambda p: p.mode and p.mode.BSS_Termination_Included 

1798 ), 

1799 ConditionalField( 

1800 ByteField("url_len", 0), 

1801 lambda p: p.mode and p.mode.ESS_Disassociation_Imminent 

1802 ), 

1803 ConditionalField( 

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

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

1806 ), 

1807 ConditionalField( 

1808 PacketListField( 

1809 "neighbor_report", 

1810 NeighborReport(), 

1811 NeighborReport 

1812 ), 

1813 lambda p: p.mode and p.mode.Preferred_Candidate_List_Included 

1814 ) 

1815 ] 

1816 

1817 

1818# 802.11-2016 9.6.14.10 

1819 

1820btm_status_code = [ 

1821 "Accept", 

1822 "Reject-Unspecified_reject_reason", 

1823 "Reject-Insufficient_Beacon_or_Probe_Response_frames", 

1824 "Reject-Insufficient_available_capacity_from_all_candidates", 

1825 "Reject-BSS_termination_undesired", 

1826 "Reject-BSS_termination_delay_requested", 

1827 "Reject-STA_BSS_Transition_Candidate_List_provided", 

1828 "Reject-No_suitable_BSS_transition_candidates", 

1829 "Reject-Leaving_ESS" 

1830] 

1831 

1832 

1833class Dot11BSSTMResponse(Packet): 

1834 name = "BSS Transition Management Response" 

1835 fields_desc = [ 

1836 ByteField("token", 0), 

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

1838 ByteField("termination_delay", 0), 

1839 ConditionalField( 

1840 MACField("target", ETHER_ANY), 

1841 lambda p: p.status == 0 

1842 ), 

1843 ConditionalField( 

1844 PacketListField( 

1845 "neighbor_report", 

1846 NeighborReport(), 

1847 NeighborReport 

1848 ), 

1849 lambda p: p.status == 6 

1850 ) 

1851 ] 

1852 

1853 

1854# 802.11-2016 9.6.2.1 

1855 

1856class Dot11SpectrumManagement(Packet): 

1857 name = "802.11 Spectrum Management Action" 

1858 fields_desc = [ 

1859 ByteEnumField("action", 0x00, { 

1860 0x00: "Measurement Request", 

1861 0x01: "Measurement Report", 

1862 0x02: "TPC Request", 

1863 0x03: "TPC Report", 

1864 0x04: "Channel Switch Announcement", 

1865 }) 

1866 ] 

1867 

1868 

1869# 802.11-2016 9.6.2.6 

1870 

1871class Dot11CSA(Packet): 

1872 name = "Channel Switch Announcement Frame" 

1873 fields_desc = [ 

1874 PacketField("CSA", Dot11EltCSA(), Dot11EltCSA), 

1875 ] 

1876 

1877 

1878class Dot11S1GBeacon(_Dot11EltUtils): 

1879 name = "802.11 S1G Beacon" 

1880 fields_desc = [LEIntField("timestamp", 0), 

1881 ByteField("change_seq", 0)] 

1882 

1883 

1884################### 

1885# 802.11 Security # 

1886################### 

1887 

1888# 802.11-2016 12 

1889 

1890class Dot11Encrypted(Packet): 

1891 name = "802.11 Encrypted (unknown algorithm)" 

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

1893 

1894 @classmethod 

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

1896 # Extracted from 

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

1898 KEY_EXTIV = 0x20 

1899 EXTIV_LEN = 8 

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

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

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

1903 return Dot11TKIP 

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

1905 return Dot11CCMP 

1906 else: 

1907 # Unknown encryption algorithm 

1908 return Dot11Encrypted 

1909 else: 

1910 return Dot11WEP 

1911 return conf.raw_layer 

1912 

1913 

1914# 802.11-2016 12.3.2 

1915 

1916class Dot11WEP(Dot11Encrypted): 

1917 name = "802.11 WEP packet" 

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

1919 ByteField("keyid", 0), 

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

1921 IntField("icv", None)] 

1922 

1923 def decrypt(self, key=None): 

1924 if key is None: 

1925 key = conf.wepkey 

1926 if key and conf.crypto_valid: 

1927 d = Cipher( 

1928 decrepit_algorithms.ARC4(self.iv + key.encode("utf8")), 

1929 None, 

1930 default_backend(), 

1931 ).decryptor() 

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

1933 

1934 def post_dissect(self, s): 

1935 self.decrypt() 

1936 

1937 def build_payload(self): 

1938 if self.wepdata is None: 

1939 return Packet.build_payload(self) 

1940 return b"" 

1941 

1942 @crypto_validator 

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

1944 if key is None: 

1945 key = conf.wepkey 

1946 if key: 

1947 if self.icv is None: 

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

1949 icv = b"" 

1950 else: 

1951 icv = p[4:8] 

1952 e = Cipher( 

1953 decrepit_algorithms.ARC4(self.iv + key.encode("utf8")), 

1954 None, 

1955 default_backend(), 

1956 ).encryptor() 

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

1958 else: 

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

1960 return b"" 

1961 

1962 def post_build(self, p, pay): 

1963 if self.wepdata is None: 

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

1965 return p 

1966 

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

1968 

1969# 802.11-2016 12.5.2.2 

1970 

1971 

1972class Dot11TKIP(Dot11Encrypted): 

1973 name = "802.11 TKIP packet" 

1974 fields_desc = [ 

1975 # iv - 4 bytes 

1976 ByteField("TSC1", 0), 

1977 ByteField("WEPSeed", 0), 

1978 ByteField("TSC0", 0), 

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

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

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

1982 # ext_iv - 4 bytes 

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

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

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

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

1987 # data 

1988 StrField("data", None), 

1989 ] 

1990 

1991# 802.11-2016 12.5.3.2 

1992 

1993 

1994class Dot11CCMP(Dot11Encrypted): 

1995 name = "802.11 CCMP packet" 

1996 fields_desc = [ 

1997 # iv - 8 bytes 

1998 ByteField("PN0", 0), 

1999 ByteField("PN1", 0), 

2000 ByteField("res0", 0), 

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

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

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

2004 ByteField("PN2", 0), 

2005 ByteField("PN3", 0), 

2006 ByteField("PN4", 0), 

2007 ByteField("PN5", 0), 

2008 # data 

2009 StrField("data", None), 

2010 ] 

2011 

2012 

2013############ 

2014# Bindings # 

2015############ 

2016 

2017 

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

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

2020 

2021bind_layers(PrismHeader, Dot11,) 

2022bind_layers(Dot11, LLC, type=2) 

2023bind_layers(Dot11QoS, LLC,) 

2024 

2025# 802.11-2016 9.2.4.1.3 Type and Subtype subfields 

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

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

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

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

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

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

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

2033bind_layers(Dot11, Dot11S1GBeacon, subtype=1, type=3) 

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

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

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

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

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

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

2040bind_layers(Dot11Beacon, Dot11Elt,) 

2041bind_layers(Dot11S1GBeacon, Dot11Elt,) 

2042bind_layers(Dot11AssoReq, Dot11Elt,) 

2043bind_layers(Dot11AssoResp, Dot11Elt,) 

2044bind_layers(Dot11ReassoReq, Dot11Elt,) 

2045bind_layers(Dot11ReassoResp, Dot11Elt,) 

2046bind_layers(Dot11ProbeReq, Dot11Elt,) 

2047bind_layers(Dot11ProbeResp, Dot11Elt,) 

2048bind_layers(Dot11Auth, Dot11Elt,) 

2049bind_layers(Dot11Elt, Dot11Elt,) 

2050bind_layers(Dot11TKIP, conf.raw_layer) 

2051bind_layers(Dot11CCMP, conf.raw_layer) 

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

2053bind_layers(Dot11SpectrumManagement, Dot11CSA, action=4) 

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

2055bind_layers(Dot11WNM, Dot11BSSTMRequest, action=7) 

2056bind_layers(Dot11WNM, Dot11BSSTMResponse, action=8) 

2057 

2058 

2059conf.l2types.register(DLT_IEEE802_11, Dot11) 

2060conf.l2types.register_num2layer(801, Dot11) 

2061conf.l2types.register(DLT_PRISM_HEADER, PrismHeader) 

2062conf.l2types.register_num2layer(802, PrismHeader) 

2063conf.l2types.register(DLT_IEEE802_11_RADIO, RadioTap) 

2064conf.l2types.register_num2layer(803, RadioTap) 

2065 

2066#################### 

2067# Other WiFi utils # 

2068#################### 

2069 

2070 

2071class WiFi_am(AnsweringMachine): 

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

2073iwconfig iffrom mode monitor 

2074iwpriv orig_ifto hostapd 1 

2075ifconfig ifto up 

2076note: if ifto=wlan0ap then orig_ifto=wlan0 

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

2078ex: 

2079ifconfig eth1 up 

2080iwconfig eth1 mode monitor 

2081iwconfig eth1 channel 11 

2082iwpriv wlan0 hostapd 1 

2083ifconfig wlan0ap up 

2084iwconfig wlan0 channel 11 

2085iwconfig wlan0 essid dontexist 

2086iwconfig wlan0 mode managed 

2087""" 

2088 function_name = "airpwn" 

2089 filter = None 

2090 

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

2092 pattern="", ignorepattern=""): 

2093 self.iffrom = iffrom 

2094 self.ifto = ifto 

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

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

2097 self.replace = replace 

2098 

2099 def is_request(self, pkt): 

2100 if not isinstance(pkt, Dot11): 

2101 return 0 

2102 if not pkt.FCfield & 1: 

2103 return 0 

2104 if not pkt.haslayer(TCP): 

2105 return 0 

2106 tcp = pkt.getlayer(TCP) 

2107 pay = raw(tcp.payload) 

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

2109 return 0 

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

2111 return 0 

2112 return True 

2113 

2114 def make_reply(self, p): 

2115 ip = p.getlayer(IP) 

2116 tcp = p.getlayer(TCP) 

2117 pay = raw(tcp.payload) 

2118 p[IP].underlayer.remove_payload() 

2119 p.FCfield = "from-DS" 

2120 p.addr1, p.addr2 = p.addr2, p.addr1 

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

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

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

2124 flags="PA") 

2125 q = p.copy() 

2126 p /= self.replace 

2127 q.ID += 1 

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

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

2130 return [p, q] 

2131 

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

2133 p = reply[0][0] 

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

2135 

2136 def send_reply(self, reply): 

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

2138 

2139 def sniff(self): 

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

2141 

2142 

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

2144 

2145 

2146class Dot11PacketList(PacketList): 

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

2148 if stats is None: 

2149 stats = conf.stats_dot11_protocols 

2150 

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

2152 

2153 def toEthernet(self): 

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

2155 r2 = [] 

2156 for p in data: 

2157 q = p.copy() 

2158 q.unwep() 

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

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