mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-25 00:38:24 -05:00
fragattacks: import latest frame injection tests
This commit is contained in:
parent
7ca38f02ab
commit
abf9b9bd8b
@ -1,15 +1,25 @@
|
|||||||
# Copyright (c) 2020, Mathy Vanhoef <mathy.vanhoef@nyu.edu>
|
# Copyright (c) 2020-2023, Mathy Vanhoef <mathy.vanhoef@kuleuven.be>
|
||||||
#
|
#
|
||||||
# This code may be distributed under the terms of the BSD license.
|
# This code may be distributed under the terms of the BSD license.
|
||||||
# See README for more details.
|
# See README for more details.
|
||||||
|
|
||||||
from scapy.all import *
|
from scapy.all import *
|
||||||
from .wifi import *
|
from .wifi import *
|
||||||
|
import select
|
||||||
|
|
||||||
FLAG_FAIL, FLAG_NOCAPTURE = [2**i for i in range(2)]
|
FLAG_FAIL, FLAG_NOCAPTURE = [2**i for i in range(2)]
|
||||||
|
|
||||||
#### Utility ####
|
#### Utility ####
|
||||||
|
|
||||||
|
def flush_socket(s):
|
||||||
|
"""
|
||||||
|
@param s An L2Socket
|
||||||
|
"""
|
||||||
|
i = 0
|
||||||
|
while i < 10000 and len(select.select([s], [], [], 0)[0]) > 0:
|
||||||
|
L2Socket.recv(s, MTU)
|
||||||
|
i += 1
|
||||||
|
|
||||||
def get_nearby_ap_addr(sin):
|
def get_nearby_ap_addr(sin):
|
||||||
# If this interface itself is also hosting an AP, the beacons transmitted by it might be
|
# If this interface itself is also hosting an AP, the beacons transmitted by it might be
|
||||||
# returned as well. We filter these out by the condition `p.dBm_AntSignal != None`.
|
# returned as well. We filter these out by the condition `p.dBm_AntSignal != None`.
|
||||||
@ -35,8 +45,13 @@ def inject_and_capture(sout, sin, p, count=0, retries=1):
|
|||||||
# Note: this workaround for Intel is only needed if the fragmented frame is injected using
|
# Note: this workaround for Intel is only needed if the fragmented frame is injected using
|
||||||
# valid MAC addresses. But for simplicity just execute it after any fragmented frame.
|
# valid MAC addresses. But for simplicity just execute it after any fragmented frame.
|
||||||
if sout.mf_workaround and toinject.FCfield & Dot11(FCfield="MF").FCfield != 0:
|
if sout.mf_workaround and toinject.FCfield & Dot11(FCfield="MF").FCfield != 0:
|
||||||
sout.send(RadioTap(present="TXFlags", TXFlags="NOSEQ+ORDER")/Dot11())
|
fix = Dot11(type=p.type, subtype=p.subtype)
|
||||||
log(DEBUG, "Sending dummy frame after injecting frame with MF flag set")
|
# Note: for RT5572 the workaround is always needed. Additionally, we need to send
|
||||||
|
# the dummy frame using the same QoS TID. Just use same QoD TID for all devices.
|
||||||
|
if Dot11QoS in p:
|
||||||
|
fix = fix/Dot11QoS(TID=p[Dot11QoS].TID)
|
||||||
|
sout.send(RadioTap(present="TXFlags", TXFlags="NOSEQ+ORDER")/fix)
|
||||||
|
log(DEBUG, "Sending dummy frame after injecting frame with MF flag set: {}".format(repr(fix)))
|
||||||
|
|
||||||
# 1. When using a 2nd interface: capture the actual packet that was injected in the air.
|
# 1. When using a 2nd interface: capture the actual packet that was injected in the air.
|
||||||
# 2. Not using 2nd interface: capture the "reflected" frame sent back by the kernel. This allows
|
# 2. Not using 2nd interface: capture the "reflected" frame sent back by the kernel. This allows
|
||||||
@ -52,19 +67,42 @@ def inject_and_capture(sout, sin, p, count=0, retries=1):
|
|||||||
|
|
||||||
return packets
|
return packets
|
||||||
|
|
||||||
|
def capture_probe_response_ack(sout, sin, probe_req, count=0, retries=1):
|
||||||
|
# Filter to use to capture frames from the independent monitor interface
|
||||||
|
probe_resp_ack_filter = lambda p: p != None and ( \
|
||||||
|
# Capture Probe Responses
|
||||||
|
(p.addr1 == probe_req.addr2 and p.addr2 == probe_req.addr1 and Dot11ProbeResp in p) or \
|
||||||
|
# Capture ACKs send by us
|
||||||
|
(p.addr1 == probe_req.addr1 and p.type == FRAME_TYPE_CONTROL and p.subtype == FRAME_CONTROL_ACK) )
|
||||||
|
|
||||||
|
attempt = 0
|
||||||
|
while True:
|
||||||
|
log(DEBUG, "Injecting probe request: " + repr(probe_req))
|
||||||
|
flush_socket(sin)
|
||||||
|
sout.send(RadioTap(present="TXFlags", TXFlags="NOSEQ+ORDER")/probe_req)
|
||||||
|
packets = sniff(opened_socket=sin, timeout=1, count=count, lfilter=probe_resp_ack_filter)
|
||||||
|
rx_probes = [p for p in packets if Dot11ProbeResp in p]
|
||||||
|
tx_acks = [p for p in packets if p.type == FRAME_TYPE_CONTROL and p.subtype == FRAME_CONTROL_ACK]
|
||||||
|
if (len(rx_probes) > 0 and len(tx_acks) > 0) or attempt >= retries:
|
||||||
|
break
|
||||||
|
|
||||||
|
log(STATUS, " Unable to capture probe request, retrying.")
|
||||||
|
attempt += 1
|
||||||
|
|
||||||
|
return rx_probes, tx_acks
|
||||||
|
|
||||||
#### Injection tests ####
|
#### Injection tests ####
|
||||||
|
|
||||||
def test_injection_fragment(sout, sin, ref):
|
def test_injection_more_fragments(sout, sin, ref, strtype):
|
||||||
log(STATUS, "--- Testing injection of fragmented frame using (partly) valid MAC addresses")
|
log(STATUS, "--- Testing injection of frame with more fragments flag using {}".format(strtype))
|
||||||
p = Dot11(FCfield=ref.FCfield, addr1=ref.addr1, addr2=ref.addr2, type=2, subtype=8, SC=33<<4)
|
p = Dot11(FCfield=ref.FCfield, addr1=ref.addr1, addr2=ref.addr2, type=2, subtype=8, SC=33<<4)
|
||||||
p = p/Dot11QoS(TID=2)/LLC()/SNAP()/EAPOL()/EAP()
|
p = p/Dot11QoS(TID=2)/LLC()/SNAP()/EAPOL()/EAP()
|
||||||
p.FCfield |= Dot11(FCfield="MF").FCfield
|
p.FCfield |= Dot11(FCfield="MF").FCfield
|
||||||
captured = inject_and_capture(sout, sin, p, count=1)
|
captured = inject_and_capture(sout, sin, p, count=1)
|
||||||
if len(captured) == 0:
|
if len(captured) == 0:
|
||||||
log(ERROR, "[-] Unable to inject frame with More Fragment flag using (partly) valid MAC addresses.")
|
log(ERROR, "[-] Unable to inject frame with More Fragment flag using {}.".format(strtype))
|
||||||
else:
|
else:
|
||||||
log(STATUS, "[+] Frame with More Fragment flag using (partly) valid MAC addresses can be injected.", color="green")
|
log(STATUS, "[+] Properly captured injected frame with More Fragment flag using {}.".format(strtype), color="green")
|
||||||
return FLAG_FAIL if len(captured) == 0 else 0
|
return FLAG_FAIL if len(captured) == 0 else 0
|
||||||
|
|
||||||
def test_packet_injection(sout, sin, p, test_func, frametype, msgfail):
|
def test_packet_injection(sout, sin, p, test_func, frametype, msgfail):
|
||||||
@ -103,7 +141,7 @@ def test_injection_fields(sout, sin, ref, strtype):
|
|||||||
set_amsdu(p[Dot11QoS])
|
set_amsdu(p[Dot11QoS])
|
||||||
status |= test_packet_injection(sout, sin, p, \
|
status |= test_packet_injection(sout, sin, p, \
|
||||||
lambda cap: cap.TID == p.TID and is_amsdu(cap) and b"BBBB" in raw(cap), \
|
lambda cap: cap.TID == p.TID and is_amsdu(cap) and b"BBBB" in raw(cap), \
|
||||||
"A-MSDU frame with {}".format(strtype), "A-MSDU frame is not properly injected!")
|
"A-MSDU frame with {}", "A-MSDU frame is not properly injected!".format(strtype))
|
||||||
|
|
||||||
if status == 0: log(STATUS, "[+] All tested fields are properly injected when using {}.".format(strtype), color="green")
|
if status == 0: log(STATUS, "[+] All tested fields are properly injected when using {}.".format(strtype), color="green")
|
||||||
return status
|
return status
|
||||||
@ -140,7 +178,7 @@ def test_injection_order(sout, sin, ref, strtype, retries=1):
|
|||||||
log(STATUS, "[+] Frames with different QoS TIDs are not reordered during injection with {}.".format(strtype), color="green")
|
log(STATUS, "[+] Frames with different QoS TIDs are not reordered during injection with {}.".format(strtype), color="green")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def test_injection_ack(sout, sin, addr1, addr2):
|
def test_injection_retrans(sout, sin, addr1, addr2):
|
||||||
suspicious = False
|
suspicious = False
|
||||||
test_fail = False
|
test_fail = False
|
||||||
|
|
||||||
@ -155,7 +193,7 @@ def test_injection_ack(sout, sin, addr1, addr2):
|
|||||||
log(WARNING, "Injected frames don't seem to be retransmitted!")
|
log(WARNING, "Injected frames don't seem to be retransmitted!")
|
||||||
suspicious = True
|
suspicious = True
|
||||||
|
|
||||||
# Test ACK towards an unassigned MAC address
|
# Test receiving ACK towards an unassigned MAC address
|
||||||
p = Dot11(FCfield="to-DS", addr1=addr1, addr2="00:22:00:00:00:01", type=2, SC=33<<4)
|
p = Dot11(FCfield="to-DS", addr1=addr1, addr2="00:22:00:00:00:01", type=2, SC=33<<4)
|
||||||
num = len(inject_and_capture(sout, sin, p, retries=1))
|
num = len(inject_and_capture(sout, sin, p, retries=1))
|
||||||
log(STATUS, "Captured {} (re)transmitted frames to the AP when using a spoofed sender address".format(num))
|
log(STATUS, "Captured {} (re)transmitted frames to the AP when using a spoofed sender address".format(num))
|
||||||
@ -165,7 +203,7 @@ def test_injection_ack(sout, sin, addr1, addr2):
|
|||||||
if num > 2:
|
if num > 2:
|
||||||
log(STATUS, " => Acknowledged frames with a spoofed sender address are still retransmitted. This has low impact.")
|
log(STATUS, " => Acknowledged frames with a spoofed sender address are still retransmitted. This has low impact.")
|
||||||
|
|
||||||
# Test ACK towards an assigned MAC address
|
# Test receiving ACK towards an assigned MAC address
|
||||||
p = Dot11(FCfield="to-DS", addr1=addr1, addr2=addr2, type=2, SC=33<<4)
|
p = Dot11(FCfield="to-DS", addr1=addr1, addr2=addr2, type=2, SC=33<<4)
|
||||||
num = len(inject_and_capture(sout, sin, p, retries=1))
|
num = len(inject_and_capture(sout, sin, p, retries=1))
|
||||||
log(STATUS, "Captured {} (re)transmitted frames to the AP when using the real sender address".format(num))
|
log(STATUS, "Captured {} (re)transmitted frames to the AP when using the real sender address".format(num))
|
||||||
@ -182,9 +220,39 @@ def test_injection_ack(sout, sin, addr1, addr2):
|
|||||||
log(STATUS, "[+] Retransmission behaviour is good. This test can be unreliable (e.g. due to background noise).", color="green")
|
log(STATUS, "[+] Retransmission behaviour is good. This test can be unreliable (e.g. due to background noise).", color="green")
|
||||||
|
|
||||||
|
|
||||||
|
def test_injection_txack(sout, sin, destmac, ownmac):
|
||||||
|
# We have to use the current MAC address of the sending interface. Since we can't
|
||||||
|
# expect the network card to ACK frames to other MAC addresses.
|
||||||
|
p = Dot11(addr1=destmac, addr2=ownmac, addr3=destmac, SC=33<<4)/Dot11ProbeReq() \
|
||||||
|
/ Dot11Elt(ID='SSID')/Dot11Elt(ID='Rates',info=b"\x03\x12\x96\x18")
|
||||||
|
rx_probes, tx_acks = capture_probe_response_ack(sout, sin, p, retries=1)
|
||||||
|
|
||||||
|
log(STATUS, "Captured {} probe responses and {} ACKs in response.".format(len(rx_probes), len(tx_acks)))
|
||||||
|
if len(rx_probes) == 0:
|
||||||
|
log(ERROR, "Didn't recieve a probe response to test ack generation. Re-run the test.")
|
||||||
|
return FLAG_NOCAPTURE
|
||||||
|
elif len(tx_acks) == 0:
|
||||||
|
log(WARNING, "[-] Acknowledgement frames aren't sent when recieving a frame.")
|
||||||
|
return FLAG_FAIL
|
||||||
|
else:
|
||||||
|
log(STATUS, "[+] Acknowledgement frames are sent when recieving a frame.", color="green")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
#### Main test function ####
|
#### Main test function ####
|
||||||
|
|
||||||
def test_injection(iface_out, iface_in=None, peermac=None, ownmac=None, testack=True):
|
def test_injection(iface_out, iface_in=None, peermac=None, ownmac=None, testack=True, skip_mf=False):
|
||||||
|
"""
|
||||||
|
@param iface_out Interface used to inject frames
|
||||||
|
@param iface_in Interface used to capture injected frames. If not given, the
|
||||||
|
iface_out is also used to monitor how/whether frames are sent.
|
||||||
|
@param peermac Destination MAC address used for retransmission tests, if no
|
||||||
|
neary AP can be found. Also used in frames that have as sender
|
||||||
|
MAC address the real MAC address of iface_out.
|
||||||
|
@param ownmac Can be used to override the real sender MAC address of iface_out.
|
||||||
|
@param testack Test whether frames are transmitted and whether a received ACK
|
||||||
|
will stop the retransmission of frames.
|
||||||
|
"""
|
||||||
status = 0
|
status = 0
|
||||||
|
|
||||||
# We start monitoring iface_in already so injected frame won't be missed
|
# We start monitoring iface_in already so injected frame won't be missed
|
||||||
@ -192,7 +260,7 @@ def test_injection(iface_out, iface_in=None, peermac=None, ownmac=None, testack=
|
|||||||
driver_out = get_device_driver(iface_out)
|
driver_out = get_device_driver(iface_out)
|
||||||
|
|
||||||
# Workaround to properly inject fragmented frames (and prevent it from blocking Tx queue).
|
# Workaround to properly inject fragmented frames (and prevent it from blocking Tx queue).
|
||||||
sout.mf_workaround = driver_out in ["iwlwifi", "ath9k_htc"]
|
sout.mf_workaround = driver_out in ["iwlwifi", "ath9k_htc", "rt2800usb"]
|
||||||
if sout.mf_workaround:
|
if sout.mf_workaround:
|
||||||
log(WARNING, "Detected {}, using workaround to reliably inject fragmented frames.".format(driver_out))
|
log(WARNING, "Detected {}, using workaround to reliably inject fragmented frames.".format(driver_out))
|
||||||
|
|
||||||
@ -200,11 +268,11 @@ def test_injection(iface_out, iface_in=None, peermac=None, ownmac=None, testack=
|
|||||||
log(STATUS, "Injection test: using {} ({}) to inject frames".format(iface_out, driver_out))
|
log(STATUS, "Injection test: using {} ({}) to inject frames".format(iface_out, driver_out))
|
||||||
if iface_in == None:
|
if iface_in == None:
|
||||||
log(WARNING, "Injection selftest: also using {} to capture frames. This means the tests can detect if the kernel".format(iface_out))
|
log(WARNING, "Injection selftest: also using {} to capture frames. This means the tests can detect if the kernel".format(iface_out))
|
||||||
log(WARNING, " interferes with injection, but it cannot check the behaviour of the device itself.")
|
log(WARNING, " interferes with injection, but it cannot check the behaviour of the network card itself.")
|
||||||
if driver_out in ["mt76x2u"]:
|
if driver_out in ["mt76x2u"]:
|
||||||
log(WARNING, " WARNING: self-test with the {} driver can be unreliable.".format(driver_out))
|
log(WARNING, " WARNING: self-test with the {} driver can be unreliable.".format(driver_out))
|
||||||
elif not driver_out in ["iwlwifi", "ath9k_htc"]:
|
elif not driver_out in ["iwlwifi", "ath9k_htc", "mac80211_hwsim", "rt2800usb"]:
|
||||||
log(WARNING, " WARNING: it is unknown whether a self-test works with the {} driver.".format(driver_out))
|
log(WARNING, " WARNING: it is unknown whether a self-test is reliable with the {} driver.".format(driver_out))
|
||||||
|
|
||||||
sin = sout
|
sin = sout
|
||||||
else:
|
else:
|
||||||
@ -225,9 +293,15 @@ def test_injection(iface_out, iface_in=None, peermac=None, ownmac=None, testack=
|
|||||||
# so set one of them as well.
|
# so set one of them as well.
|
||||||
spoofed = Dot11(FCfield="from-DS", addr1="00:11:00:00:02:01", addr2="00:22:00:00:02:01")
|
spoofed = Dot11(FCfield="from-DS", addr1="00:11:00:00:02:01", addr2="00:22:00:00:02:01")
|
||||||
valid = Dot11(FCfield="from-DS", addr1=peermac, addr2=ownmac)
|
valid = Dot11(FCfield="from-DS", addr1=peermac, addr2=ownmac)
|
||||||
|
if iface_in != None:
|
||||||
|
log(STATUS, "NOTE: Frames sent using a (partly) valid MAC address may be harder to capture due to higher bitrates.")
|
||||||
|
log(STATUS, " Connecting using old Wi-Fi versions such as 802.11b can help with capturing injected frames.")
|
||||||
|
|
||||||
# This tests basic injection capabilities
|
# Test injection of More Fragment flags. Causes some device to crash, so make it
|
||||||
status |= test_injection_fragment(sout, sin, valid)
|
# possible to easily skip this test.
|
||||||
|
if not skip_mf:
|
||||||
|
status |= test_injection_more_fragments(sout, sin, spoofed, "spoofed MAC addresses")
|
||||||
|
status |= test_injection_more_fragments(sout, sin, valid, "(partly) valid MAC addresses")
|
||||||
|
|
||||||
# Perform some actual injection tests
|
# Perform some actual injection tests
|
||||||
status |= test_injection_fields(sout, sin, spoofed, "spoofed MAC addresses")
|
status |= test_injection_fields(sout, sin, spoofed, "spoofed MAC addresses")
|
||||||
@ -235,24 +309,33 @@ def test_injection(iface_out, iface_in=None, peermac=None, ownmac=None, testack=
|
|||||||
status |= test_injection_order(sout, sin, spoofed, "spoofed MAC addresses")
|
status |= test_injection_order(sout, sin, spoofed, "spoofed MAC addresses")
|
||||||
status |= test_injection_order(sout, sin, valid, "(partly) valid MAC addresses")
|
status |= test_injection_order(sout, sin, valid, "(partly) valid MAC addresses")
|
||||||
|
|
||||||
# Acknowledgement behaviour tests
|
# 1. Test retransmission behaviour and *recieving* of acknowledgements
|
||||||
|
# 2. Test the *transmission* of acknowledgements on the reception of non-control frames
|
||||||
if iface_in != None and testack:
|
if iface_in != None and testack:
|
||||||
# We search for an AP on the interface that injects frames because:
|
# We search for an AP on the interface that injects frames because:
|
||||||
# 1. In mixed managed/monitor mode, we will otherwise detect our own AP on the sout interface
|
# 1. In mixed managed/monitor mode, we will otherwise detect our own AP on the sout interface
|
||||||
# 2. If sout interface "sees" the AP this assure it will also receive its ACK frames
|
# 2. If sout interface "sees" the AP this assure it will also receive its ACK frames
|
||||||
# 3. The given peermac might be a client that goes into sleep mode
|
# 3. The given peermac might be a client that goes into sleep mode
|
||||||
channel = get_channel(sin.iface)
|
channel = get_channel(sin.iface)
|
||||||
log(STATUS, "--- Searching for AP on channel {} to test ACK behaviour.".format(channel))
|
log(STATUS, "--- Searching for AP on channel {} to test retransmission behaviour.".format(channel))
|
||||||
apmac, ssid = get_nearby_ap_addr(sout)
|
apmac, ssid = get_nearby_ap_addr(sout)
|
||||||
if apmac == None and peermac == None:
|
if apmac == None and peermac == None:
|
||||||
raise IOError("Unable to find nearby AP to test injection")
|
raise IOError("Unable to find nearby AP to test injection")
|
||||||
elif apmac == None:
|
elif apmac == None:
|
||||||
log(WARNING, "Unable to find AP. Try a different channel? Testing ACK behaviour with peer {}.".format(peermac))
|
peer_description = "peer {}".format(peermac)
|
||||||
|
log(WARNING, "Unable to find AP. Try a different channel? Testing retransmission behaviour with {}.".format(peer_description))
|
||||||
destmac = peermac
|
destmac = peermac
|
||||||
else:
|
else:
|
||||||
log(STATUS, "Testing ACK behaviour by injecting frames to AP {} ({}).".format(ssid, apmac))
|
peer_description = "AP {} ({})".format(ssid, apmac)
|
||||||
|
log(STATUS, "Testing retransmission behaviour by injecting frames to {}.".format(peer_description))
|
||||||
destmac = apmac
|
destmac = apmac
|
||||||
test_injection_ack(sout, sin, addr1=destmac, addr2=ownmac)
|
test_injection_retrans(sout, sin, addr1=destmac, addr2=ownmac)
|
||||||
|
|
||||||
|
if apmac != None:
|
||||||
|
log(STATUS, "--- Testing ACK generation by sending probe requests to {}.".format(peer_description))
|
||||||
|
test_injection_txack(sout, sin, destmac, ownmac)
|
||||||
|
else:
|
||||||
|
log(WARNING, "--- Cannot test ACK generation behaviour because no nearby AP was found.")
|
||||||
|
|
||||||
# Show a summary of results/advice
|
# Show a summary of results/advice
|
||||||
log(STATUS, "")
|
log(STATUS, "")
|
||||||
@ -261,7 +344,7 @@ def test_injection(iface_out, iface_in=None, peermac=None, ownmac=None, testack=
|
|||||||
if status & FLAG_NOCAPTURE != 0:
|
if status & FLAG_NOCAPTURE != 0:
|
||||||
log(WARNING, "==> Failed to capture some frames. Try another channel or use another monitoring device.")
|
log(WARNING, "==> Failed to capture some frames. Try another channel or use another monitoring device.")
|
||||||
if status & FLAG_FAIL !=0 :
|
if status & FLAG_FAIL !=0 :
|
||||||
log(ERROR, "==> Some tests failed. Are you using patched drivers/firmware?")
|
log(ERROR, "==> Some tests failed. Consider using/searching for patched drivers/firmware.")
|
||||||
|
|
||||||
sout.close()
|
sout.close()
|
||||||
sin.close()
|
sin.close()
|
||||||
|
@ -9,8 +9,18 @@ import binascii
|
|||||||
|
|
||||||
#### Constants ####
|
#### Constants ####
|
||||||
|
|
||||||
|
FRAME_TYPE_MANAGEMENT = 0
|
||||||
|
FRAME_TYPE_CONTROL = 1
|
||||||
|
FRAME_TYPE_DATA = 2
|
||||||
|
|
||||||
|
FRAME_CONTROL_ACK = 13
|
||||||
|
|
||||||
|
FRAME_DATA_NULLFUNC = 4
|
||||||
|
FRAME_DATA_QOSNULL = 12
|
||||||
|
|
||||||
IEEE_TLV_TYPE_SSID = 0
|
IEEE_TLV_TYPE_SSID = 0
|
||||||
IEEE_TLV_TYPE_CHANNEL = 3
|
IEEE_TLV_TYPE_CHANNEL = 3
|
||||||
|
IEEE_TLV_TYPE_TIM = 5
|
||||||
IEEE_TLV_TYPE_RSN = 48
|
IEEE_TLV_TYPE_RSN = 48
|
||||||
IEEE_TLV_TYPE_CSA = 37
|
IEEE_TLV_TYPE_CSA = 37
|
||||||
IEEE_TLV_TYPE_FT = 55
|
IEEE_TLV_TYPE_FT = 55
|
||||||
|
Loading…
Reference in New Issue
Block a user