3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2025-09-16 20:47:26 +02:00

Compare commits

..

No commits in common. "master" and "3.3" have entirely different histories.
master ... 3.3

70 changed files with 502 additions and 2088 deletions

1
.gitignore vendored
View File

@ -68,7 +68,6 @@ unit/test-dpp
unit/test-json unit/test-json
unit/test-nl80211util unit/test-nl80211util
unit/test-pmksa unit/test-pmksa
unit/test-storage
unit/cert-*.pem unit/cert-*.pem
unit/cert-*.csr unit/cert-*.csr
unit/cert-*.srl unit/cert-*.srl

View File

@ -1,30 +1,3 @@
ver 3.9:
Fix issue with Access Point mode and frequency unlocking.
Fix issue with network configuration and BSS retry logic.
Fix issue with handling busy notification from Access Point.
Fix issue with handling P-192, P-224 and P-521 for SAE.
ver 3.8:
Fix issue with handling unit tests and missing kernel features.
ver 3.7:
Fix issue with handling length of EncryptedSecurity.
Fix issue with handling empty affinities lists.
Fix issue with handling survey scanning results.
Fix issue with handling duplicate values in DPP URI.
ver 3.6:
Fix issue with handling blacklisting and roaming requests.
Fix issue with handling CQM thresholds for FullMAC devices.
Add support for PMKSA when using FullMAC devices.
ver 3.5:
Add support for option to disable blacklist handling.
Add support for option to disable SAE for broken drivers.
ver 3.4:
Add support for the Test Anything Protocol.
ver 3.3: ver 3.3:
Fix issue with handling External Authentication. Fix issue with handling External Authentication.

View File

@ -71,9 +71,7 @@ ell_headers = ell/util.h \
ell_sources = ell/private.h \ ell_sources = ell/private.h \
ell/missing.h \ ell/missing.h \
ell/util.c \ ell/util.c \
ell/test-private.h \
ell/test.c \ ell/test.c \
ell/test-dbus.c \
ell/strv.c \ ell/strv.c \
ell/utf8.c \ ell/utf8.c \
ell/queue.c \ ell/queue.c \
@ -274,8 +272,6 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h \
src/dpp.c \ src/dpp.c \
src/udev.c \ src/udev.c \
src/pmksa.h src/pmksa.c \ src/pmksa.h src/pmksa.c \
src/vendor_quirks.h \
src/vendor_quirks.c \
$(eap_sources) \ $(eap_sources) \
$(builtin_sources) $(builtin_sources)
@ -443,7 +439,7 @@ unit_tests += unit/test-cmac-aes \
unit/test-arc4 unit/test-wsc unit/test-eap-mschapv2 \ unit/test-arc4 unit/test-wsc unit/test-eap-mschapv2 \
unit/test-eap-sim unit/test-sae unit/test-p2p unit/test-band \ unit/test-eap-sim unit/test-sae unit/test-p2p unit/test-band \
unit/test-dpp unit/test-json unit/test-nl80211util \ unit/test-dpp unit/test-json unit/test-nl80211util \
unit/test-pmksa unit/test-storage unit/test-pmksa
endif endif
if CLIENT if CLIENT
@ -607,11 +603,6 @@ unit_test_nl80211util_LDADD = $(ell_ldadd)
unit_test_pmksa_SOURCES = unit/test-pmksa.c src/pmksa.c src/pmksa.h \ unit_test_pmksa_SOURCES = unit/test-pmksa.c src/pmksa.c src/pmksa.h \
src/module.h src/util.h src/module.h src/util.h
unit_test_pmksa_LDADD = $(ell_ldadd) unit_test_pmksa_LDADD = $(ell_ldadd)
unit_test_storage_SOURCES = unit/test-storage.c src/storage.c src/storage.h \
src/crypto.c src/crypto.h \
src/common.c src/common.h
unit_test_storage_LDADD = $(ell_ldadd)
endif endif
if CLIENT if CLIENT
@ -627,9 +618,6 @@ unit_test_client_SOURCES = unit/test-client.c \
unit_test_client_LDADD = $(ell_ldadd) $(client_ldadd) unit_test_client_LDADD = $(ell_ldadd) $(client_ldadd)
endif endif
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
$(top_srcdir)/build-aux/tap-driver.sh
TESTS = $(unit_tests) TESTS = $(unit_tests)
EXTRA_DIST = src/genbuiltin src/iwd.service.in src/net.connman.iwd.service \ EXTRA_DIST = src/genbuiltin src/iwd.service.in src/net.connman.iwd.service \

View File

@ -1,156 +0,0 @@
#!/usr/bin/python3
import unittest
import sys
sys.path.append('../util')
import iwd
from iwd import IWD
from iwd import NetworkType
from hostapd import HostapdCLI
class Test(unittest.TestCase):
def initial_connection(self):
ordered_network = self.device.get_ordered_network('TestAPRoam')
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
self.device.connect_bssid(self.bss_hostapd[0].bssid)
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device, condition)
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED')
self.assertFalse(self.bss_hostapd[1].list_sta())
def test_full_scan(self):
"""
Tests that IWD first tries a limited scan, then a full scan after
an AP directed roam. After the full scan yields no results IWD
should stop trying to roam.
"""
self.initial_connection()
# Disable other APs, so the scans come up empty
self.bss_hostapd[1].disable()
self.bss_hostapd[2].disable()
# Send a bad candidate list with the BSS TM request which contains a
# channel with no AP operating on it.
self.bss_hostapd[0].send_bss_transition(
self.device.address,
[(self.bss_hostapd[1].bssid, "8f0000005105060603000000")]
)
self.device.wait_for_event("roam-scan-triggered")
self.device.wait_for_event("no-roam-candidates")
# IWD should then trigger a full scan
self.device.wait_for_event("full-roam-scan")
self.device.wait_for_event("no-roam-candidates", timeout=30)
# IWD should not trigger a roam again after the above 2 failures.
with self.assertRaises(TimeoutError):
self.device.wait_for_event("roam-scan-triggered", timeout=60)
def test_bad_candidate_list(self):
"""
Tests behavior when the AP sends a candidate list but the scan
finds no BSS's. IWD should fall back to a full scan after.
"""
self.initial_connection()
# Send a bad candidate list with the BSS TM request which contains a
# channel with no AP operating on it.
self.bss_hostapd[0].send_bss_transition(
self.device.address,
[(self.bss_hostapd[1].bssid, "8f0000005105060603000000")]
)
self.device.wait_for_event("roam-scan-triggered")
self.device.wait_for_event("no-roam-candidates")
# IWD should then trigger a full scan
self.device.wait_for_event("full-roam-scan")
self.device.wait_for_event("roaming", timeout=30)
self.device.wait_for_event("connected")
def test_bad_neighbor_report(self):
"""
Tests behavior when the AP sends no candidate list. IWD should
request a neighbor report. If the limited scan yields no BSS's IWD
should fall back to a full scan.
"""
# Set a bad neighbor (channel that no AP is on) to force the limited
# roam scan to fail
self.bss_hostapd[0].set_neighbor(
self.bss_hostapd[1].bssid,
"TestAPRoam",
'%s8f000000%s%s060603000000' % (self.bss_hostapd[1].bssid.replace(':', ''), "51", "0b")
)
self.initial_connection()
self.bss_hostapd[0].send_bss_transition(self.device.address, [])
self.device.wait_for_event("roam-scan-triggered")
# The AP will have sent a neighbor report with a single BSS but on
# channel 11 which no AP is on. This should result in a limited scan
# picking up no candidates.
self.device.wait_for_event("no-roam-candidates", timeout=30)
# IWD should then trigger a full scan
self.device.wait_for_event("full-roam-scan")
self.device.wait_for_event("roaming", timeout=30)
self.device.wait_for_event("connected")
def test_ignore_candidate_list_quirk(self):
"""
Tests that IWD ignores the candidate list sent by the AP since its
OUI indicates it should be ignored.
"""
# Set the OUI so the candidate list should be ignored
for hapd in self.bss_hostapd:
hapd.set_value('vendor_elements', 'dd0400180a01')
self.initial_connection()
# Send with a candidate list (should be ignored)
self.bss_hostapd[0].send_bss_transition(
self.device.address,
[(self.bss_hostapd[1].bssid, "8f0000005105060603000000")]
)
# IWD should ignore the list and trigger a full scan since we have not
# set any neighbors
self.device.wait_for_event("full-roam-scan")
self.device.wait_for_event("roaming", timeout=30)
self.device.wait_for_event("connected")
def setUp(self):
self.wd = IWD(True)
devices = self.wd.list_devices(1)
self.device = devices[0]
def tearDown(self):
self.wd = None
self.device = None
for hapd in self.bss_hostapd:
hapd.reload()
@classmethod
def setUpClass(cls):
IWD.copy_to_storage('TestAPRoam.psk')
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
HostapdCLI(config='ssid2.conf'),
HostapdCLI(config='ssid3.conf') ]
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -11,58 +11,52 @@ from iwd import NetworkType
from hostapd import HostapdCLI from hostapd import HostapdCLI
class Test(unittest.TestCase): class Test(unittest.TestCase):
def initial_connection(self):
ordered_network = self.device.get_ordered_network('TestAPRoam') def validate(self, expect_roam=True):
wd = IWD()
devices = wd.list_devices(1)
device = devices[0]
ordered_network = device.get_ordered_network('TestAPRoam')
self.assertEqual(ordered_network.type, NetworkType.psk) self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected' condition = 'not obj.connected'
self.wd.wait_for_object_condition(ordered_network.network_object, condition) wd.wait_for_object_condition(ordered_network.network_object, condition)
self.device.connect_bssid(self.bss_hostapd[0].bssid) device.connect_bssid(self.bss_hostapd[0].bssid)
condition = 'obj.state == DeviceState.connected' condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device, condition) wd.wait_for_object_condition(device, condition)
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED') self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED')
self.assertFalse(self.bss_hostapd[1].list_sta()) self.assertFalse(self.bss_hostapd[1].list_sta())
def validate_roam(self, from_bss, to_bss, expect_roam=True): self.bss_hostapd[0].send_bss_transition(device.address,
from_bss.send_bss_transition(self.device.address, [(self.bss_hostapd[1].bssid, '8f0000005102060603000000')],
self.neighbor_list,
disassoc_imminent=expect_roam) disassoc_imminent=expect_roam)
if expect_roam: if expect_roam:
from_condition = 'obj.state == DeviceState.roaming' from_condition = 'obj.state == DeviceState.roaming'
to_condition = 'obj.state == DeviceState.connected' to_condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_change(self.device, from_condition, to_condition) wd.wait_for_object_change(device, from_condition, to_condition)
to_bss.wait_for_event('AP-STA-CONNECTED %s' % self.device.address) self.bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % device.address)
else: else:
self.device.wait_for_event("no-roam-candidates") device.wait_for_event("no-roam-candidates")
device.disconnect()
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
def test_disassoc_imminent(self): def test_disassoc_imminent(self):
self.initial_connection() self.validate(expect_roam=True)
self.validate_roam(self.bss_hostapd[0], self.bss_hostapd[1])
def test_no_candidates(self): def test_no_candidates(self):
self.initial_connection() self.validate(expect_roam=False)
# We now have BSS0 roam blacklisted
self.validate_roam(self.bss_hostapd[0], self.bss_hostapd[1])
# Try and trigger another roam back, which shouldn't happen since now
# both BSS's are roam blacklisted
self.validate_roam(self.bss_hostapd[1], self.bss_hostapd[0], expect_roam=False)
def setUp(self):
self.wd = IWD(True)
devices = self.wd.list_devices(1)
self.device = devices[0]
def tearDown(self):
self.wd = None
self.device = None
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
@ -71,10 +65,6 @@ class Test(unittest.TestCase):
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'), cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
HostapdCLI(config='ssid2.conf'), HostapdCLI(config='ssid2.conf'),
HostapdCLI(config='ssid3.conf') ] HostapdCLI(config='ssid3.conf') ]
cls.neighbor_list = [
(cls.bss_hostapd[0].bssid, "8f0000005101060603000000"),
(cls.bss_hostapd[1].bssid, "8f0000005102060603000000"),
]
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):

View File

@ -1,7 +1,5 @@
[SETUP] [SETUP]
num_radios=4 num_radios=4
hwsim_medium=true
start_iwd=false
[HOSTAPD] [HOSTAPD]
rad0=ssid1.conf rad0=ssid1.conf

View File

@ -1,6 +0,0 @@
[General]
RoamThreshold=-72
CriticalRoamThreshold=-72
[Blacklist]
InitialAccessPointBusyTimeout=20

View File

@ -1,183 +0,0 @@
#!/usr/bin/python3
import unittest
import sys
sys.path.append('../util')
import iwd
from iwd import IWD, IWD_CONFIG_DIR
from iwd import NetworkType
from hostapd import HostapdCLI
from hwsim import Hwsim
class Test(unittest.TestCase):
def validate_connected(self, hostapd):
ordered_network = self.device.get_ordered_network('TestAPRoam')
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
self.device.connect_bssid(hostapd.bssid)
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device, condition)
hostapd.wait_for_event('AP-STA-CONNECTED')
def validate_ap_roamed(self, from_hostapd, to_hostapd):
from_hostapd.send_bss_transition(
self.device.address, self.neighbor_list, disassoc_imminent=True
)
from_condition = 'obj.state == DeviceState.roaming'
to_condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
to_hostapd.wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
self.device.wait_for_event("ap-roam-blacklist-added")
def test_roam_to_optimal_candidates(self):
# In this test IWD will naturally transition down the list after each
# BSS gets roam blacklisted. All BSS's are above the RSSI thresholds.
self.rule_ssid1.signal = -5000
self.rule_ssid2.signal = -6500
self.rule_ssid3.signal = -6900
# Connect to BSS0
self.validate_connected(self.bss_hostapd[0])
# AP directed roam to BSS1
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
# AP directed roam to BSS2
self.validate_ap_roamed(self.bss_hostapd[1], self.bss_hostapd[2])
def test_avoiding_under_threshold_bss(self):
# In this test IWD will blacklist BSS0, then roam the BSS1. BSS1 will
# then tell IWD to roam, but it should go back to BSS0 since the only
# non-blacklisted BSS is under the roam threshold.
self.rule_ssid1.signal = -5000
self.rule_ssid2.signal = -6500
self.rule_ssid3.signal = -7300
# Connect to BSS0
self.validate_connected(self.bss_hostapd[0])
# AP directed roam to BSS1
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
# AP directed roam, but IWD should choose BSS0 since BSS2 is -73dB
self.validate_ap_roamed(self.bss_hostapd[1], self.bss_hostapd[0])
def test_connect_to_roam_blacklisted_bss(self):
# In this test a BSS will be roam blacklisted, but all other options are
# below the RSSI threshold so IWD should roam back to the blacklisted
# BSS.
self.rule_ssid1.signal = -5000
self.rule_ssid2.signal = -8000
self.rule_ssid3.signal = -8500
# Connect to BSS0
self.validate_connected(self.bss_hostapd[0])
# AP directed roam, should connect to BSS1 as its the next best
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
# Connected to BSS1, but the signal is bad, so IWD should try to roam
# again. BSS0 is still blacklisted, but its the only reasonable option
# since both BSS1 and BSS2 are below the set RSSI threshold (-72dB)
from_condition = 'obj.state == DeviceState.roaming'
to_condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
# IWD should have connected to BSS0, even though its roam blacklisted
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
def test_blacklist_during_roam_scan(self):
# Tests that an AP roam request mid-roam results in the AP still being
# blacklisted even though the request itself doesn't directly trigger
# a roam.
self.rule_ssid1.signal = -7300
self.rule_ssid2.signal = -7500
self.rule_ssid3.signal = -8500
# Connect to BSS0 under the roam threshold so IWD will immediately try
# roaming elsewhere
self.validate_connected(self.bss_hostapd[0])
self.device.wait_for_event("roam-scan-triggered")
self.bss_hostapd[0].send_bss_transition(
self.device.address, self.neighbor_list, disassoc_imminent=True
)
self.device.wait_for_event("ap-roam-blacklist-added")
# BSS0 should have gotten blacklisted even though IWD was mid-roam,
# causing IWD to choose BSS1 when it gets is results.
from_condition = 'obj.state == DeviceState.roaming'
to_condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
self.bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
def setUp(self):
self.wd = IWD(True)
devices = self.wd.list_devices(1)
self.device = devices[0]
def tearDown(self):
self.wd = None
self.device = None
@classmethod
def setUpClass(cls):
IWD.copy_to_storage("main.conf.roaming", IWD_CONFIG_DIR, "main.conf")
IWD.copy_to_storage('TestAPRoam.psk')
hwsim = Hwsim()
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
HostapdCLI(config='ssid2.conf'),
HostapdCLI(config='ssid3.conf') ]
HostapdCLI.group_neighbors(*cls.bss_hostapd)
rad0 = hwsim.get_radio('rad0')
rad1 = hwsim.get_radio('rad1')
rad2 = hwsim.get_radio('rad2')
cls.neighbor_list = [
(cls.bss_hostapd[0].bssid, "8f0000005101060603000000"),
(cls.bss_hostapd[1].bssid, "8f0000005102060603000000"),
(cls.bss_hostapd[2].bssid, "8f0000005103060603000000"),
]
cls.rule_ssid1 = hwsim.rules.create()
cls.rule_ssid1.source = rad0.addresses[0]
cls.rule_ssid1.bidirectional = True
cls.rule_ssid1.enabled = True
cls.rule_ssid2 = hwsim.rules.create()
cls.rule_ssid2.source = rad1.addresses[0]
cls.rule_ssid2.bidirectional = True
cls.rule_ssid2.enabled = True
cls.rule_ssid3 = hwsim.rules.create()
cls.rule_ssid3.source = rad2.addresses[0]
cls.rule_ssid3.bidirectional = True
cls.rule_ssid3.enabled = True
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -1,2 +0,0 @@
[Security]
Passphrase=secret123

View File

@ -260,69 +260,12 @@ class Test(unittest.TestCase):
self.wd.unregister_psk_agent(psk_agent) self.wd.unregister_psk_agent(psk_agent)
def test_blacklist_disabled(self):
wd = self.wd
bss_hostapd = self.bss_hostapd
rule0 = self.rule0
rule1 = self.rule1
rule2 = self.rule2
psk_agent = PSKAgent(["secret123", 'secret123'])
wd.register_psk_agent(psk_agent)
devices = wd.list_devices(1)
device = devices[0]
rule0.drop = True
rule0.enabled = True
device.autoconnect = True
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
ordered_network = device.get_ordered_network("TestBlacklist", full_scan=True)
self.assertEqual(ordered_network.type, NetworkType.psk)
# The first BSS should fail, and we should connect to the second. This
# should not result in a connection blacklist though since its disabled.
bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % device.address)
device.disconnect()
rule0.drop = False
device.autoconnect = True
# Verify the first BSS wasn't blacklisted.
bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % device.address)
def setUp(self): def setUp(self):
_, _, name = self.id().split(".")
# TODO: If we have this pattern elsewhere it might be nice to turn this
# into a decorator e.g.
#
# @config("main.conf.disabled")
# @profile("TestBlacklist.psk")
# def test_blacklist_disabled(self)
# ...
#
if name == "test_blacklist_disabled":
IWD.copy_to_storage("main.conf.disabled", IWD_CONFIG_DIR, "main.conf")
IWD.copy_to_storage("TestBlacklist.psk")
else:
IWD.copy_to_storage("main.conf.default", IWD_CONFIG_DIR, "main.conf")
self.wd = IWD(True) self.wd = IWD(True)
def tearDown(self): def tearDown(self):
IWD.clear_storage() IWD.clear_storage()
self.wd = None self.wd = None
self.rule0.drop = False
self.rule1.drop = False
self.rule2.drop = False
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):

View File

@ -1,2 +0,0 @@
[Blacklist]
InitialTimeout=0

View File

@ -3,11 +3,7 @@ import sys
import sys import sys
import os import os
from scapy.layers.dot11 import * from scapy.layers.dot11 import *
from scapy.arch import str2mac from scapy.arch import str2mac, get_if_raw_hwaddr
try:
from scapy.arch import get_if_raw_hwaddr
except:
from scapy.arch.unix import get_if_raw_hwaddr
from time import time, sleep from time import time, sleep
from threading import Thread from threading import Thread

View File

@ -91,11 +91,16 @@ class Test(unittest.TestCase):
# using the same static config. The new client's ACD client should # using the same static config. The new client's ACD client should
# detect an IP conflict and not allow the device to reach the # detect an IP conflict and not allow the device to reach the
# "connected" state although the DBus .Connect call will succeed. # "connected" state although the DBus .Connect call will succeed.
with self.assertRaises(iwd.FailedEx): ordered_network.network_object.connect()
ordered_network.network_object.connect(timeout=500) self.assertEqual(dev2.state, iwd.DeviceState.connecting)
try:
condition = 'obj.state == DeviceState.disconnected' # We should either stay in "connecting" indefinitely or move to
# "disconnecting"
condition = 'obj.state != DeviceState.connecting'
iwd_ns0_1.wait_for_object_condition(dev2, condition, max_wait=21) iwd_ns0_1.wait_for_object_condition(dev2, condition, max_wait=21)
self.assertEqual(dev2.state, iwd.DeviceState.disconnecting)
except TimeoutError:
dev2.disconnect()
iwd_ns0_1.unregister_psk_agent(psk_agent_ns0_1) iwd_ns0_1.unregister_psk_agent(psk_agent_ns0_1)
del dev2 del dev2

View File

@ -8,8 +8,6 @@ from iwd import PSKAgent
from iwd import NetworkType from iwd import NetworkType
class Test(unittest.TestCase): class Test(unittest.TestCase):
def connect_failure(self, ex):
self.failure_triggered = True
def test_netconfig_timeout(self): def test_netconfig_timeout(self):
IWD.copy_to_storage('autoconnect.psk', name='ap-ns1.psk') IWD.copy_to_storage('autoconnect.psk', name='ap-ns1.psk')
@ -29,34 +27,23 @@ class Test(unittest.TestCase):
condition = 'not obj.connected' condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition) wd.wait_for_object_condition(ordered_network.network_object, condition)
self.failure_triggered = False ordered_network.network_object.connect()
# Set our error handler here so we can check if it fails condition = 'obj.state == DeviceState.connecting'
ordered_network.network_object.connect(
wait=False,
timeout=1000,
error_handler=self.connect_failure
)
# IWD should attempt to try both BSS's with both failing netconfig.
# Then the autoconnect list should be exhausted, and IWD should
# transition to a disconnected state, then proceed to full autoconnect.
device.wait_for_event("netconfig-failed", timeout=1000)
device.wait_for_event("netconfig-failed", timeout=1000)
device.wait_for_event("disconnected")
device.wait_for_event("autoconnect_full")
# The connect call should have failed
self.assertTrue(self.failure_triggered)
condition = "obj.scanning"
wd.wait_for_object_condition(device, condition)
condition = "not obj.scanning"
wd.wait_for_object_condition(device, condition) wd.wait_for_object_condition(device, condition)
# IWD should attempt to connect, but it will of course fail again. device.wait_for_event("connecting (netconfig)")
device.wait_for_event("netconfig-failed", timeout=1000)
# Netconfig should fail, and IWD should disconnect
from_condition = 'obj.state == DeviceState.connecting'
to_condition = 'obj.state == DeviceState.disconnecting'
wd.wait_for_object_change(device, from_condition, to_condition, max_wait=60)
# Autoconnect should then try again
condition = 'obj.state == DeviceState.connecting'
wd.wait_for_object_condition(device, condition)
device.wait_for_event("connecting (netconfig)")
device.disconnect() device.disconnect()
condition = 'obj.state == DeviceState.disconnected' condition = 'obj.state == DeviceState.disconnected'

View File

@ -19,7 +19,7 @@ class Test(unittest.TestCase):
device = wd.list_devices(1)[0] device = wd.list_devices(1)[0]
device.get_ordered_network('TestFT', full_scan=True) device.get_ordered_network('TestFT', full_scan=True)
device.connect_bssid(self.bss_hostapd[1].bssid, wait=False) device.connect_bssid(self.bss_hostapd[1].bssid)
self.bss_hostapd[1].wait_for_event(f'AP-STA-CONNECTED {device.address}') self.bss_hostapd[1].wait_for_event(f'AP-STA-CONNECTED {device.address}')
device.wait_for_event("connecting (netconfig)") device.wait_for_event("connecting (netconfig)")

View File

@ -1,114 +0,0 @@
#! /usr/bin/python3
import unittest
import sys, os
sys.path.append('../util')
from iwd import IWD
from iwd import NetworkType
from hostapd import HostapdCLI
from packaging import version
from subprocess import run
import re
import testutil
#
# The CSA handling was added in kernel 6.8, so for any earlier kernel this test
# won't pass.
#
def kernel_is_newer(min_version="6.8"):
proc = run(["uname", "-r"], capture_output=True)
version_str = proc.stdout.decode("utf-8")
match = re.match(r"(\d+\.\d+)", version_str)
if not match:
return False
return version.parse(match.group(1)) >= version.parse(min_version)
class Test(unittest.TestCase):
def test_channel_switch_during_roam(self):
wd = self.wd
device = wd.list_devices(1)[0]
ordered_network = device.get_ordered_network('TestFT', full_scan=True)
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
self.assertFalse(self.bss_hostapd[0].list_sta())
self.assertFalse(self.bss_hostapd[1].list_sta())
device.connect_bssid(self.bss_hostapd[0].bssid)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % device.address)
testutil.test_iface_operstate(device.name)
testutil.test_ifaces_connected(self.bss_hostapd[0].ifname, device.name)
self.assertRaises(Exception, testutil.test_ifaces_connected,
(self.bss_hostapd[1].ifname, device.name, True, True))
# Start a channel switch and wait for it to begin
self.bss_hostapd[1].chan_switch(6, wait=False)
self.bss_hostapd[1].wait_for_event("CTRL-EVENT-STARTED-CHANNEL-SWITCH")
# Initiate a roam immediately which should get rejected by the kernel
device.roam(self.bss_hostapd[1].bssid)
# IWD should authenticate, then proceed to association
device.wait_for_event("ft-authenticating")
device.wait_for_event("ft-roaming")
# The kernel should reject the association, which should trigger a
# disconnect
condition = 'obj.state == DeviceState.disconnected'
wd.wait_for_object_condition(device, condition)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
def tearDown(self):
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" up')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" up')
for hapd in self.bss_hostapd:
hapd.default()
self.wd.stop()
self.wd = None
def setUp(self):
self.wd = IWD(True)
@classmethod
def setUpClass(cls):
if not kernel_is_newer():
raise unittest.SkipTest()
IWD.copy_to_storage('TestFT.psk')
cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
HostapdCLI(config='ft-psk-ccmp-2.conf'),
HostapdCLI(config='ft-psk-ccmp-3.conf') ]
unused = HostapdCLI(config='ft-psk-ccmp-3.conf')
unused.disable()
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
cls.bss_hostapd[2].set_address('12:00:00:00:00:03')
HostapdCLI.group_neighbors(*cls.bss_hostapd)
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
cls.bss_hostapd = None

View File

@ -288,14 +288,12 @@ class HostapdCLI(object):
cmd = 'RESEND_M3 %s' % address cmd = 'RESEND_M3 %s' % address
self.ctrl_sock.sendall(cmd.encode('utf-8')) self.ctrl_sock.sendall(cmd.encode('utf-8'))
def chan_switch(self, channel, wait=True): def chan_switch(self, channel):
if channel > len(chan_freq_map): if channel > len(chan_freq_map):
raise Exception("Only 2.4GHz channels supported for chan_switch") raise Exception("Only 2.4GHz channels supported for chan_switch")
cmd = self.cmdline + ['chan_switch', '50', str(chan_freq_map[channel])] cmd = self.cmdline + ['chan_switch', '50', str(chan_freq_map[channel])]
ctx.start_process(cmd).wait() ctx.start_process(cmd).wait()
if wait:
self.wait_for_event('AP-CSA-FINISHED') self.wait_for_event('AP-CSA-FINISHED')
def _get_status(self): def _get_status(self):

View File

@ -7,10 +7,7 @@ from weakref import WeakValueDictionary
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from enum import Enum from enum import Enum
from scapy.all import * from scapy.all import *
try:
from scapy.contrib.wpa_eapol import WPA_key from scapy.contrib.wpa_eapol import WPA_key
except:
from scapy.layers.eap import EAPOL_KEY
import iwd import iwd
from config import ctx from config import ctx
@ -447,15 +444,9 @@ class Hwsim(iwd.AsyncOpAbstract):
# NOTE: Expected key_info is 0x008a, with the install flag # NOTE: Expected key_info is 0x008a, with the install flag
# this becomes 0x00ca. # this becomes 0x00ca.
try:
eapol = WPA_key( descriptor_type = 2, eapol = WPA_key( descriptor_type = 2,
key_info = 0x00ca, # Includes an invalid install flag! key_info = 0x00ca, # Includes an invalid install flag!
replay_counter = struct.pack(">Q", 100)) replay_counter = struct.pack(">Q", 100))
except:
eapol = EAPOL_KEY( key_descriptor_type = 2,
install = 1,
key_ack = 1,
key_replay_counter = 1)
frame /= LLC()/SNAP()/EAPOL(version="802.1X-2004", type="EAPOL-Key") frame /= LLC()/SNAP()/EAPOL(version="802.1X-2004", type="EAPOL-Key")
frame /= eapol frame /= eapol

View File

@ -112,8 +112,8 @@ class AsyncOpAbstract(object):
self._is_completed = True self._is_completed = True
self._exception = _convert_dbus_ex(ex) self._exception = _convert_dbus_ex(ex)
def _wait_for_async_op(self, timeout=50): def _wait_for_async_op(self):
ctx.non_block_wait(lambda s: s._is_completed, timeout, self, exception=None) ctx.non_block_wait(lambda s: s._is_completed, 30, self, exception=None)
self._is_completed = False self._is_completed = False
if self._exception is not None: if self._exception is not None:
@ -280,15 +280,8 @@ class StationDebug(IWDDBusAbstract):
def autoconnect(self): def autoconnect(self):
return self._properties['AutoConnect'] return self._properties['AutoConnect']
def connect_bssid(self, address, wait=True): def connect_bssid(self, address):
self._iface.ConnectBssid( self._iface.ConnectBssid(dbus.ByteArray.fromhex(address.replace(':', '')))
dbus.ByteArray.fromhex(address.replace(':', '')),
reply_handler=self._success,
error_handler=self._failure
)
if wait:
self._wait_for_async_op()
def roam(self, address): def roam(self, address):
self._iface.Roam(dbus.ByteArray.fromhex(address.replace(':', ''))) self._iface.Roam(dbus.ByteArray.fromhex(address.replace(':', '')))
@ -877,8 +870,8 @@ class Device(IWDDBusAbstract):
def stop_adhoc(self): def stop_adhoc(self):
self._prop_proxy.Set(IWD_DEVICE_INTERFACE, 'Mode', 'station') self._prop_proxy.Set(IWD_DEVICE_INTERFACE, 'Mode', 'station')
def connect_bssid(self, address, wait=True): def connect_bssid(self, address):
self._station_debug.connect_bssid(address, wait=wait) self._station_debug.connect_bssid(address)
def roam(self, address): def roam(self, address):
self._station_debug.roam(address) self._station_debug.roam(address)
@ -1006,7 +999,7 @@ class Network(IWDDBusAbstract):
def extended_service_set(self): def extended_service_set(self):
return self._properties['ExtendedServiceSet'] return self._properties['ExtendedServiceSet']
def connect(self, wait=True, timeout=50, reply_handler=None, error_handler=None): def connect(self, wait=True):
''' '''
Connect to the network. Request the device implied by the object Connect to the network. Request the device implied by the object
path to connect to specified network. path to connect to specified network.
@ -1021,19 +1014,12 @@ class Network(IWDDBusAbstract):
@rtype: void @rtype: void
''' '''
if not reply_handler:
reply_handler = self._success
if not error_handler:
error_handler = self._failure
self._iface.Connect(dbus_interface=self._iface_name, self._iface.Connect(dbus_interface=self._iface_name,
reply_handler=reply_handler, reply_handler=self._success,
error_handler=error_handler, error_handler=self._failure)
timeout=timeout)
if wait: if wait:
self._wait_for_async_op(timeout=timeout) self._wait_for_async_op()
def __str__(self, prefix = ''): def __str__(self, prefix = ''):
return prefix + 'Network:\n' \ return prefix + 'Network:\n' \

View File

@ -95,8 +95,6 @@ static const struct diagnostic_dict_mapping diagnostic_mapping[] = {
{ "Frequency", 'u' }, { "Frequency", 'u' },
{ "Channel", 'q' }, { "Channel", 'q' },
{ "Security", 's' }, { "Security", 's' },
{ "InactiveTime", 'u', "ms" },
{ "ConnectedTime", 'u', "s" },
{ NULL } { NULL }
}; };

View File

@ -1,12 +1,10 @@
AC_PREREQ([2.69]) AC_PREREQ([2.69])
AC_INIT([iwd],[3.9]) AC_INIT([iwd],[3.3])
AC_CONFIG_HEADERS(config.h) AC_CONFIG_HEADERS(config.h)
AC_CONFIG_AUX_DIR(build-aux) AC_CONFIG_AUX_DIR(build-aux)
AC_CONFIG_MACRO_DIR(build-aux) AC_CONFIG_MACRO_DIR(build-aux)
AC_REQUIRE_AUX_FILE([tap-driver.sh])
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
tar-pax no-dist-gzip dist-xz]) tar-pax no-dist-gzip dist-xz])
@ -31,7 +29,6 @@ AC_PROG_CC_GCOV
AC_PROG_INSTALL AC_PROG_INSTALL
AC_PROG_MKDIR_P AC_PROG_MKDIR_P
AC_PROG_LN_S AC_PROG_LN_S
AC_PROG_AWK
AC_SYS_LARGEFILE AC_SYS_LARGEFILE
@ -300,7 +297,7 @@ if (test "${enable_external_ell}" = "yes"); then
test "${enable_monitor}" != "no" || test "${enable_monitor}" != "no" ||
test "${enable_wired}" = "yes" || test "${enable_wired}" = "yes" ||
test "${enable_hwsim}" = "yes"); then test "${enable_hwsim}" = "yes"); then
ell_min_version="0.77" ell_min_version="0.69"
else else
ell_min_version="0.5" ell_min_version="0.5"
fi fi

View File

@ -31,12 +31,6 @@ Methods array{dict} GetDiagnostics()
TxMCS [optional] - Transmitting MCS index TxMCS [optional] - Transmitting MCS index
InactiveTime [optional] - Time duration (in ms) for which the STA
connected to this BSS is currently inactive.
ConnectedTime [optional] - Time duration (in s) for which the STA
remains connected to this BSS.
Possible errors: net.connman.iwd.Failed Possible errors: net.connman.iwd.Failed
net.connman.iwd.NotConnected net.connman.iwd.NotConnected
net.connman.iwd.NotFound net.connman.iwd.NotFound

View File

@ -11,12 +11,6 @@ Methods void Connect()
the object path to connect to specified network. the object path to connect to specified network.
Connecting to WEP networks is not supported. Connecting to WEP networks is not supported.
Note: When [General].EnableNetworkConfiguration is set
to true a call to Connect() has the potential to take
a significant amount of time. Specifically if DHCP is
either slow, or is unable to complete. The timeout for
DHCP is roughly 30 seconds per BSS.
Possible errors: net.connman.iwd.Aborted Possible errors: net.connman.iwd.Aborted
net.connman.iwd.Busy net.connman.iwd.Busy
net.connman.iwd.Failed net.connman.iwd.Failed

View File

@ -53,12 +53,6 @@ Methods dict GetDiagnostics()
- GCMP-256 - GCMP-256
- CCMP-256 - CCMP-256
InactiveTime [optional] - Time duration (in ms) for which this STA
is currently inactive.
ConnectedTime [optional] - Time Duration (in s) for which this STA
remains connected to the BSS.
Possible errors: net.connman.iwd.Busy Possible errors: net.connman.iwd.Busy
net.connman.iwd.Failed net.connman.iwd.Failed
net.connman.iwd.NotConnected net.connman.iwd.NotConnected

View File

@ -404,7 +404,6 @@ static const struct {
{ { 0x00, 0x50, 0xf2 }, "Microsoft" }, { { 0x00, 0x50, 0xf2 }, "Microsoft" },
{ { 0x00, 0x90, 0x4c }, "Epigram" }, { { 0x00, 0x90, 0x4c }, "Epigram" },
{ { 0x50, 0x6f, 0x9a }, "Wi-Fi Alliance" }, { { 0x50, 0x6f, 0x9a }, "Wi-Fi Alliance" },
{ { 0x00, 0x18, 0x0a }, "Cisco Meraki" },
{ } { }
}; };
@ -1916,7 +1915,7 @@ static void print_ie_interworking(unsigned int level,
size--; size--;
ptr++; ptr++;
if (size < 2) if (!size)
return; return;
/* /*
@ -7434,7 +7433,7 @@ static bool check_pcap(struct nlmon *nlmon, size_t next_size)
pcap_close(nlmon->pcap); pcap_close(nlmon->pcap);
/* Exhausted the single PCAP file */ /* Exausted the single PCAP file */
if (nlmon->max_files < 2) { if (nlmon->max_files < 2) {
printf("Reached maximum size of PCAP, exiting\n"); printf("Reached maximum size of PCAP, exiting\n");
nlmon->pcap = NULL; nlmon->pcap = NULL;

View File

@ -109,8 +109,6 @@ struct ap_state {
struct l_timeout *rekey_timeout; struct l_timeout *rekey_timeout;
unsigned int rekey_time; unsigned int rekey_time;
uint32_t pre_scan_cmd_id;
bool started : 1; bool started : 1;
bool gtk_set : 1; bool gtk_set : 1;
bool netconfig_set_addr4 : 1; bool netconfig_set_addr4 : 1;
@ -356,12 +354,6 @@ static void ap_reset(struct ap_state *ap)
l_timeout_remove(ap->rekey_timeout); l_timeout_remove(ap->rekey_timeout);
ap->rekey_timeout = NULL; ap->rekey_timeout = NULL;
} }
if (ap->pre_scan_cmd_id) {
scan_cancel(netdev_get_wdev_id(ap->netdev),
ap->pre_scan_cmd_id);
ap->pre_scan_cmd_id = 0;
}
} }
static bool ap_event_done(struct ap_state *ap, bool prev_in_event) static bool ap_event_done(struct ap_state *ap, bool prev_in_event)
@ -3860,70 +3852,6 @@ static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
return 0; return 0;
} }
static void ap_pre_scan_trigger(int err, void *user_data)
{
struct ap_state *ap = user_data;
if (err < 0) {
l_error("AP pre-scan failed: %i", err);
ap_start_failed(ap, err);
return;
}
}
static bool ap_check_channel(struct ap_state *ap)
{
const struct band_freq_attrs *freq_attr;
freq_attr = wiphy_get_frequency_info(netdev_get_wiphy(ap->netdev),
band_channel_to_freq(ap->channel, ap->band));
if (L_WARN_ON(!freq_attr))
return false;
/* Check if disabled/no-IR */
if (freq_attr->disabled || freq_attr->no_ir)
return false;
return true;
}
static bool ap_pre_scan_notify(int err, struct l_queue *bss_list,
const struct scan_freq_set *freqs,
void *user_data)
{
struct ap_state *ap = user_data;
if (!ap_check_channel(ap)) {
l_error("Unable to channel %u even after pre-scan",
ap->channel);
goto error;
}
if (ap_start_send(ap))
return false;
error:
ap_start_failed(ap, -ENOTSUP);
return false;
}
static void ap_pre_scan_destroy(void *user_data)
{
struct ap_state *ap = user_data;
ap->pre_scan_cmd_id = 0;
}
static bool ap_pre_scan(struct ap_state *ap)
{
ap->pre_scan_cmd_id = scan_passive(netdev_get_wdev_id(ap->netdev),
NULL, ap_pre_scan_trigger,
ap_pre_scan_notify,
ap, ap_pre_scan_destroy);
return ap->pre_scan_cmd_id != 0;
}
/* /*
* Start a simple independent WPA2 AP on given netdev. * Start a simple independent WPA2 AP on given netdev.
* *
@ -4034,20 +3962,6 @@ struct ap_state *ap_start(struct netdev *netdev, struct l_settings *config,
return ap; return ap;
} }
if (!ap_check_channel(ap)) {
l_debug("Channel %u is disabled/no-IR, pre-scanning",
ap->channel);
if (ap_pre_scan(ap)) {
if (err_out)
*err_out = 0;
return ap;
}
goto error;
}
if (ap_start_send(ap)) { if (ap_start_send(ap)) {
if (err_out) if (err_out)
*err_out = 0; *err_out = 0;

View File

@ -45,42 +45,22 @@
static uint64_t blacklist_multiplier; static uint64_t blacklist_multiplier;
static uint64_t blacklist_initial_timeout; static uint64_t blacklist_initial_timeout;
static uint64_t blacklist_ap_busy_initial_timeout;
static uint64_t blacklist_max_timeout; static uint64_t blacklist_max_timeout;
struct blacklist_entry { struct blacklist_entry {
uint8_t addr[6]; uint8_t addr[6];
uint64_t added_time; uint64_t added_time;
uint64_t expire_time; uint64_t expire_time;
enum blacklist_reason reason;
};
struct blacklist_search {
const uint8_t *addr;
enum blacklist_reason reason;
}; };
static struct l_queue *blacklist; static struct l_queue *blacklist;
static uint64_t get_reason_timeout(enum blacklist_reason reason)
{
switch (reason) {
case BLACKLIST_REASON_CONNECT_FAILED:
return blacklist_initial_timeout;
case BLACKLIST_REASON_AP_BUSY:
return blacklist_ap_busy_initial_timeout;
default:
l_warn("Unhandled blacklist reason: %u", reason);
return 0;
}
}
static bool check_if_expired(void *data, void *user_data) static bool check_if_expired(void *data, void *user_data)
{ {
struct blacklist_entry *entry = data; struct blacklist_entry *entry = data;
uint64_t now = l_get_u64(user_data); uint64_t now = l_get_u64(user_data);
if (l_time_after(now, entry->expire_time)) { if (l_time_diff(now, entry->added_time) > blacklist_max_timeout) {
l_debug("Removing entry "MAC" on prune", MAC_STR(entry->addr)); l_debug("Removing entry "MAC" on prune", MAC_STR(entry->addr));
l_free(entry); l_free(entry);
return true; return true;
@ -107,53 +87,17 @@ static bool match_addr(const void *a, const void *b)
return false; return false;
} }
static bool match_addr_and_reason(const void *a, const void *b) void blacklist_add_bss(const uint8_t *addr)
{
const struct blacklist_entry *entry = a;
const struct blacklist_search *search = b;
if (entry->reason != search->reason)
return false;
if (!memcmp(entry->addr, search->addr, 6))
return true;
return false;
}
void blacklist_add_bss(const uint8_t *addr, enum blacklist_reason reason)
{ {
struct blacklist_entry *entry; struct blacklist_entry *entry;
uint64_t timeout;
blacklist_prune(); blacklist_prune();
timeout = get_reason_timeout(reason);
if (!timeout)
return;
entry = l_queue_find(blacklist, match_addr, addr); entry = l_queue_find(blacklist, match_addr, addr);
if (entry) { if (entry) {
uint64_t offset; uint64_t offset = l_time_diff(entry->added_time,
entry->expire_time);
if (reason < entry->reason) {
l_debug("Promoting "MAC" blacklist to reason %u",
MAC_STR(addr), reason);
/* Reset this to the new timeout and reason */
entry->reason = reason;
entry->added_time = l_time_now();
entry->expire_time = l_time_offset(entry->added_time,
timeout);
return;
} else if (reason > entry->reason) {
l_debug("Ignoring blacklist extension of "MAC", "
"current blacklist status is more severe!",
MAC_STR(addr));
return;
}
offset = l_time_diff(entry->added_time, entry->expire_time);
offset *= blacklist_multiplier; offset *= blacklist_multiplier;
@ -168,36 +112,40 @@ void blacklist_add_bss(const uint8_t *addr, enum blacklist_reason reason)
entry = l_new(struct blacklist_entry, 1); entry = l_new(struct blacklist_entry, 1);
entry->added_time = l_time_now(); entry->added_time = l_time_now();
entry->expire_time = l_time_offset(entry->added_time, timeout); entry->expire_time = l_time_offset(entry->added_time,
entry->reason = reason; blacklist_initial_timeout);
memcpy(entry->addr, addr, 6); memcpy(entry->addr, addr, 6);
l_queue_push_tail(blacklist, entry); l_queue_push_tail(blacklist, entry);
} }
bool blacklist_contains_bss(const uint8_t *addr, enum blacklist_reason reason) bool blacklist_contains_bss(const uint8_t *addr)
{ {
struct blacklist_search search = { bool ret;
.addr = addr, uint64_t time_now;
.reason = reason struct blacklist_entry *entry;
};
blacklist_prune(); blacklist_prune();
return l_queue_find(blacklist, match_addr_and_reason, &search) != NULL; entry = l_queue_find(blacklist, match_addr, addr);
if (!entry)
return false;
time_now = l_time_now();
ret = l_time_after(time_now, entry->expire_time) ? false : true;
return ret;
} }
void blacklist_remove_bss(const uint8_t *addr, enum blacklist_reason reason) void blacklist_remove_bss(const uint8_t *addr)
{ {
struct blacklist_entry *entry; struct blacklist_entry *entry;
struct blacklist_search search = {
.addr = addr,
.reason = reason
};
blacklist_prune(); blacklist_prune();
entry = l_queue_remove_if(blacklist, match_addr_and_reason, &search); entry = l_queue_remove_if(blacklist, match_addr, addr);
if (!entry) if (!entry)
return; return;
@ -214,47 +162,19 @@ static int blacklist_init(void)
blacklist_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT; blacklist_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT;
/* For easier user configuration the timeout values are in seconds */ /* For easier user configuration the timeout values are in seconds */
blacklist_initial_timeout *= L_USEC_PER_SEC; blacklist_initial_timeout *= 1000000;
if (!l_settings_get_uint64(config, "Blacklist",
"InitialRoamRequestedTimeout",
&blacklist_ap_busy_initial_timeout))
blacklist_ap_busy_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT;
else
l_warn("[Blacklist].InitialRoamRequestedTimeout is deprecated, "
"use [Blacklist].InitialAccessPointBusyTimeout");
if (!l_settings_get_uint64(config, "Blacklist",
"InitialAccessPointBusyTimeout",
&blacklist_ap_busy_initial_timeout))
blacklist_ap_busy_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT;
/* For easier user configuration the timeout values are in seconds */
blacklist_ap_busy_initial_timeout *= L_USEC_PER_SEC;
if (!l_settings_get_uint64(config, "Blacklist", if (!l_settings_get_uint64(config, "Blacklist",
"Multiplier", "Multiplier",
&blacklist_multiplier)) &blacklist_multiplier))
blacklist_multiplier = BLACKLIST_DEFAULT_MULTIPLIER; blacklist_multiplier = BLACKLIST_DEFAULT_MULTIPLIER;
if (blacklist_multiplier == 0) {
l_warn("[Blacklist].Multiplier cannot be zero, setting to 1");
blacklist_multiplier = 1;
}
if (!l_settings_get_uint64(config, "Blacklist", if (!l_settings_get_uint64(config, "Blacklist",
"MaximumTimeout", "MaximumTimeout",
&blacklist_max_timeout)) &blacklist_max_timeout))
blacklist_max_timeout = BLACKLIST_DEFAULT_MAX_TIMEOUT; blacklist_max_timeout = BLACKLIST_DEFAULT_MAX_TIMEOUT;
blacklist_max_timeout *= L_USEC_PER_SEC; blacklist_max_timeout *= 1000000;
if (blacklist_initial_timeout > blacklist_max_timeout)
l_warn("[Blacklist].InitialTimeout exceeded "
"[Blacklist].MaximumTimeout!");
if (!blacklist_initial_timeout)
l_debug("initial timeout was zero, blacklist will be disabled");
blacklist = l_queue_new(); blacklist = l_queue_new();

View File

@ -20,23 +20,6 @@
* *
*/ */
enum blacklist_reason { void blacklist_add_bss(const uint8_t *addr);
/* bool blacklist_contains_bss(const uint8_t *addr);
* When a BSS is blacklisted using this reason IWD will refuse to void blacklist_remove_bss(const uint8_t *addr);
* connect to it via autoconnect
*/
BLACKLIST_REASON_CONNECT_FAILED,
/*
* This type of blacklist is added when an AP indicates that its unable
* to handle more connections. This is done via BSS-TM requests or
* denied authentications/associations with certain status codes.
*
* Once this type of blacklist is applied to a BSS IWD will attempt to
* avoid roaming to it for a configured period of time.
*/
BLACKLIST_REASON_AP_BUSY,
};
void blacklist_add_bss(const uint8_t *addr, enum blacklist_reason reason);
bool blacklist_contains_bss(const uint8_t *addr, enum blacklist_reason reason);
void blacklist_remove_bss(const uint8_t *addr, enum blacklist_reason reason);

View File

@ -110,14 +110,6 @@ bool diagnostic_info_to_dict(const struct diagnostic_station_info *info,
dbus_append_dict_basic(builder, "ExpectedThroughput", 'u', dbus_append_dict_basic(builder, "ExpectedThroughput", 'u',
&info->expected_throughput); &info->expected_throughput);
if (info->have_inactive_time)
dbus_append_dict_basic(builder, "InactiveTime", 'u',
&info->inactive_time);
if (info->have_connected_time)
dbus_append_dict_basic(builder, "ConnectedTime", 'u',
&info->connected_time);
return true; return true;
} }

View File

@ -43,9 +43,6 @@ struct diagnostic_station_info {
uint32_t expected_throughput; uint32_t expected_throughput;
uint32_t inactive_time;
uint32_t connected_time;
bool have_cur_rssi : 1; bool have_cur_rssi : 1;
bool have_avg_rssi : 1; bool have_avg_rssi : 1;
bool have_rx_mcs : 1; bool have_rx_mcs : 1;
@ -53,8 +50,6 @@ struct diagnostic_station_info {
bool have_rx_bitrate : 1; bool have_rx_bitrate : 1;
bool have_tx_bitrate : 1; bool have_tx_bitrate : 1;
bool have_expected_throughput : 1; bool have_expected_throughput : 1;
bool have_inactive_time : 1;
bool have_connected_time : 1;
}; };
bool diagnostic_info_to_dict(const struct diagnostic_station_info *info, bool diagnostic_info_to_dict(const struct diagnostic_station_info *info,

View File

@ -1166,34 +1166,21 @@ struct dpp_uri_info *dpp_parse_uri(const char *uri)
switch (*pos) { switch (*pos) {
case 'C': case 'C':
if (L_WARN_ON(info->freqs))
goto free_info;
info->freqs = dpp_parse_class_and_channel(pos + 2, len); info->freqs = dpp_parse_class_and_channel(pos + 2, len);
if (!info->freqs) if (!info->freqs)
goto free_info; goto free_info;
break; break;
case 'M': case 'M':
if (L_WARN_ON(!l_memeqzero(info->mac,
sizeof(info->mac))))
goto free_info;
ret = dpp_parse_mac(pos + 2, len, info->mac); ret = dpp_parse_mac(pos + 2, len, info->mac);
if (ret < 0) if (ret < 0)
goto free_info; goto free_info;
break; break;
case 'V': case 'V':
if (L_WARN_ON(info->version != 0))
goto free_info;
ret = dpp_parse_version(pos + 2, len, &info->version); ret = dpp_parse_version(pos + 2, len, &info->version);
if (ret < 0) if (ret < 0)
goto free_info; goto free_info;
break; break;
case 'K': case 'K':
if (L_WARN_ON(info->boot_public))
goto free_info;
info->boot_public = dpp_parse_key(pos + 2, len); info->boot_public = dpp_parse_key(pos + 2, len);
if (!info->boot_public) if (!info->boot_public)
goto free_info; goto free_info;

View File

@ -544,8 +544,7 @@ static bool eap_mschapv2_load_settings(struct eap_state *eap,
return true; return true;
error: error:
l_free(state->user); free(state);
l_free(state);
return false; return false;
} }

View File

@ -425,8 +425,8 @@ static void eap_handle_response(struct eap_state *eap, const uint8_t *pkt,
size_t len) size_t len)
{ {
enum eap_type type; enum eap_type type;
uint32_t vendor_id = 0; uint32_t vendor_id;
uint32_t vendor_type = 0; uint32_t vendor_type;
enum eap_type our_type = eap->method->request_type; enum eap_type our_type = eap->method->request_type;
uint32_t our_vendor_id = (eap->method->vendor_id[0] << 16) | uint32_t our_vendor_id = (eap->method->vendor_id[0] << 16) |
(eap->method->vendor_id[1] << 8) | (eap->method->vendor_id[1] << 8) |

View File

@ -1810,7 +1810,7 @@ static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm,
if ((rsne[1] != hs->authenticator_ie[1] || if ((rsne[1] != hs->authenticator_ie[1] ||
memcmp(rsne + 2, hs->authenticator_ie + 2, rsne[1])) && memcmp(rsne + 2, hs->authenticator_ie + 2, rsne[1])) &&
!handshake_util_ap_ie_matches(hs, &rsn_info, !handshake_util_ap_ie_matches(&rsn_info,
hs->authenticator_ie, hs->authenticator_ie,
hs->wpa_ie)) hs->wpa_ie))
goto error_ie_different; goto error_ie_different;

View File

@ -223,8 +223,7 @@ static bool ft_parse_associate_resp_frame(const uint8_t *frame, size_t frame_len
return true; return true;
} }
static bool ft_verify_rsne(struct handshake_state *hs, static bool ft_verify_rsne(const uint8_t *rsne, const uint8_t *pmk_r0_name,
const uint8_t *rsne, const uint8_t *pmk_r0_name,
const uint8_t *authenticator_ie) const uint8_t *authenticator_ie)
{ {
/* /*
@ -254,7 +253,7 @@ static bool ft_verify_rsne(struct handshake_state *hs,
memcmp(msg2_rsne.pmkids, pmk_r0_name, 16)) memcmp(msg2_rsne.pmkids, pmk_r0_name, 16))
return false; return false;
if (!handshake_util_ap_ie_matches(hs, &msg2_rsne, authenticator_ie, false)) if (!handshake_util_ap_ie_matches(&msg2_rsne, authenticator_ie, false))
return false; return false;
return true; return true;
@ -302,8 +301,7 @@ static int parse_ies(struct handshake_state *hs,
is_rsn = hs->supplicant_ie != NULL; is_rsn = hs->supplicant_ie != NULL;
if (is_rsn) { if (is_rsn) {
if (!ft_verify_rsne(hs, rsne, hs->pmk_r0_name, if (!ft_verify_rsne(rsne, hs->pmk_r0_name, authenticator_ie))
authenticator_ie))
goto ft_error; goto ft_error;
} else if (rsne) } else if (rsne)
goto ft_error; goto ft_error;
@ -482,7 +480,7 @@ int __ft_rx_associate(uint32_t ifindex, const uint8_t *frame, size_t frame_len)
memcmp(msg4_rsne.pmkids, hs->pmk_r1_name, 16)) memcmp(msg4_rsne.pmkids, hs->pmk_r1_name, 16))
return -EBADMSG; return -EBADMSG;
if (!handshake_util_ap_ie_matches(hs, &msg4_rsne, if (!handshake_util_ap_ie_matches(&msg4_rsne,
hs->authenticator_ie, hs->authenticator_ie,
false)) false))
return -EBADMSG; return -EBADMSG;

View File

@ -368,12 +368,6 @@ void handshake_state_set_vendor_ies(struct handshake_state *s,
} }
} }
void handshake_state_set_vendor_quirks(struct handshake_state *s,
struct vendor_quirk quirks)
{
s->vendor_quirks = quirks;
}
void handshake_state_set_kh_ids(struct handshake_state *s, void handshake_state_set_kh_ids(struct handshake_state *s,
const uint8_t *r0khid, size_t r0khid_len, const uint8_t *r0khid, size_t r0khid_len,
const uint8_t *r1khid) const uint8_t *r1khid)
@ -883,8 +877,7 @@ void handshake_state_set_igtk(struct handshake_state *s, const uint8_t *key,
* results vs the RSN/WPA IE obtained as part of the 4-way handshake. If they * results vs the RSN/WPA IE obtained as part of the 4-way handshake. If they
* don't match, the EAPoL packet must be silently discarded. * don't match, the EAPoL packet must be silently discarded.
*/ */
bool handshake_util_ap_ie_matches(struct handshake_state *s, bool handshake_util_ap_ie_matches(const struct ie_rsn_info *msg_info,
const struct ie_rsn_info *msg_info,
const uint8_t *scan_ie, bool is_wpa) const uint8_t *scan_ie, bool is_wpa)
{ {
struct ie_rsn_info scan_info; struct ie_rsn_info scan_info;
@ -914,15 +907,11 @@ bool handshake_util_ap_ie_matches(struct handshake_state *s,
if (msg_info->no_pairwise != scan_info.no_pairwise) if (msg_info->no_pairwise != scan_info.no_pairwise)
return false; return false;
if (!(s->vendor_quirks.replay_counter_mismatch)) { if (msg_info->ptksa_replay_counter != scan_info.ptksa_replay_counter)
if (msg_info->ptksa_replay_counter !=
scan_info.ptksa_replay_counter)
return false; return false;
if (msg_info->gtksa_replay_counter != if (msg_info->gtksa_replay_counter != scan_info.gtksa_replay_counter)
scan_info.gtksa_replay_counter)
return false; return false;
}
if (msg_info->mfpr != scan_info.mfpr) if (msg_info->mfpr != scan_info.mfpr)
return false; return false;
@ -1250,7 +1239,7 @@ static struct pmksa *handshake_state_steal_pmksa(struct handshake_state *s)
s->have_pmksa = false; s->have_pmksa = false;
if (l_time_after(now, pmksa->expiration)) { if (l_time_after(now, pmksa->expiration)) {
pmksa_cache_free(pmksa); l_free(pmksa);
pmksa = NULL; pmksa = NULL;
} }
@ -1283,15 +1272,13 @@ void handshake_state_cache_pmksa(struct handshake_state *s)
{ {
struct pmksa *pmksa = handshake_state_steal_pmksa(s); struct pmksa *pmksa = handshake_state_steal_pmksa(s);
if (!pmksa) { l_debug("%p", pmksa);
l_debug("No PMKSA for "MAC, MAC_STR(s->aa));
return;
}
l_debug("Caching PMKSA for "MAC, MAC_STR(s->aa)); if (!pmksa)
return;
if (L_WARN_ON(pmksa_cache_put(pmksa) < 0)) if (L_WARN_ON(pmksa_cache_put(pmksa) < 0))
pmksa_cache_free(pmksa); l_free(pmksa);
} }
bool handshake_state_remove_pmksa(struct handshake_state *s) bool handshake_state_remove_pmksa(struct handshake_state *s)
@ -1305,7 +1292,7 @@ bool handshake_state_remove_pmksa(struct handshake_state *s)
if (!pmksa) if (!pmksa)
return false; return false;
pmksa_cache_free(pmksa); l_free(pmksa);
return true; return true;
} }

View File

@ -26,8 +26,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <ell/cleanup.h> #include <ell/cleanup.h>
#include "src/vendor_quirks.h"
struct handshake_state; struct handshake_state;
enum crypto_cipher; enum crypto_cipher;
struct eapol_frame; struct eapol_frame;
@ -109,7 +107,6 @@ struct handshake_state {
uint8_t *authenticator_fte; uint8_t *authenticator_fte;
uint8_t *supplicant_fte; uint8_t *supplicant_fte;
uint8_t *vendor_ies; uint8_t *vendor_ies;
struct vendor_quirk vendor_quirks;
size_t vendor_ies_len; size_t vendor_ies_len;
enum ie_rsn_cipher_suite pairwise_cipher; enum ie_rsn_cipher_suite pairwise_cipher;
enum ie_rsn_cipher_suite group_cipher; enum ie_rsn_cipher_suite group_cipher;
@ -240,9 +237,6 @@ void handshake_state_set_vendor_ies(struct handshake_state *s,
const struct iovec *iov, const struct iovec *iov,
size_t n_iovs); size_t n_iovs);
void handshake_state_set_vendor_quirks(struct handshake_state *s,
struct vendor_quirk quirks);
void handshake_state_set_kh_ids(struct handshake_state *s, void handshake_state_set_kh_ids(struct handshake_state *s,
const uint8_t *r0khid, size_t r0khid_len, const uint8_t *r0khid, size_t r0khid_len,
const uint8_t *r1khid); const uint8_t *r1khid);
@ -318,8 +312,7 @@ bool handshake_state_set_pmksa(struct handshake_state *s, struct pmksa *pmksa);
void handshake_state_cache_pmksa(struct handshake_state *s); void handshake_state_cache_pmksa(struct handshake_state *s);
bool handshake_state_remove_pmksa(struct handshake_state *s); bool handshake_state_remove_pmksa(struct handshake_state *s);
bool handshake_util_ap_ie_matches(struct handshake_state *s, bool handshake_util_ap_ie_matches(const struct ie_rsn_info *msg_info,
const struct ie_rsn_info *msg_info,
const uint8_t *scan_ie, bool is_wpa); const uint8_t *scan_ie, bool is_wpa);
const uint8_t *handshake_util_find_kde(enum handshake_kde selector, const uint8_t *handshake_util_find_kde(enum handshake_kde selector,

View File

@ -290,27 +290,9 @@ control how long a misbehaved BSS spends on the blacklist.
* - InitialTimeout * - InitialTimeout
- Values: uint64 value in seconds (default: **60**) - Values: uint64 value in seconds (default: **60**)
The initial time that a BSS spends on the blacklist. Setting this to zero The initial time that a BSS spends on the blacklist.
will disable blacklisting functionality in IWD.
* - InitialRoamRequestedTimeout (**deprecated**)
- Values: uint64 value in seconds (default: **30**)
This setting is deprecated, please use
[Blacklist].InitialAccessPointBusyTimeout instead.
* - InitialAccessPointBusyTimeout
- Values: uint64 value in seconds (default: **30**)
The initial time that a BSS will be blacklisted after indicating it
cannot handle more connections. This is triggered by either a BSS
transition management request (telling IWD to roam elsewhere) or by a
denied authentication or association with the NO_MORE_STAS status code.
Once a BSS is blacklisted in this manor IWD will attempt to avoid it for
the configured amount of time.
* - Multiplier * - Multiplier
- Values: unsigned int value greater than zero, in seconds - Values: unsigned int value in seconds (default: **30**)
(default: **30**)
If the BSS was blacklisted previously and another connection attempt If the BSS was blacklisted previously and another connection attempt
has failed after the initial timeout has expired, then the BSS blacklist has failed after the initial timeout has expired, then the BSS blacklist
@ -483,14 +465,6 @@ are buggy or just don't behave similar enough to the majority of other drivers.
If a driver in use matches one in this list, multicast RX will be If a driver in use matches one in this list, multicast RX will be
disabled. disabled.
* - SaeDisable
- Values: comma-separated list of drivers or glob matches
If a driver in use matches one in this list, SAE/WPA3 will be disabled
for connections. This will prevent connections to WPA3-only networks, but
will allow for connections to WPA3/WPA2 hybrid networks by utilizing
WPA2.
SEE ALSO SEE ALSO
======== ========

View File

@ -463,14 +463,6 @@ uint8_t netdev_get_rssi_level_idx(struct netdev *netdev)
return netdev->cur_rssi_level_idx; return netdev->cur_rssi_level_idx;
} }
int netdev_get_low_signal_threshold(uint32_t frequency)
{
if (frequency > 4000)
return LOW_SIGNAL_THRESHOLD_5GHZ;
return LOW_SIGNAL_THRESHOLD;
}
static void netdev_set_powered_result(int error, uint16_t type, static void netdev_set_powered_result(int error, uint16_t type,
const void *data, const void *data,
uint32_t len, void *user_data) uint32_t len, void *user_data)
@ -637,6 +629,7 @@ static bool netdev_parse_sta_info(struct l_genl_attr *attr,
info->have_tx_mcs = true; info->have_tx_mcs = true;
break; break;
case NL80211_STA_INFO_EXPECTED_THROUGHPUT: case NL80211_STA_INFO_EXPECTED_THROUGHPUT:
if (len != 4) if (len != 4)
return false; return false;
@ -644,22 +637,6 @@ static bool netdev_parse_sta_info(struct l_genl_attr *attr,
info->expected_throughput = l_get_u32(data); info->expected_throughput = l_get_u32(data);
info->have_expected_throughput = true; info->have_expected_throughput = true;
break;
case NL80211_STA_INFO_INACTIVE_TIME:
if (len != 4)
return false;
info->inactive_time = l_get_u32(data);
info->have_inactive_time = true;
break;
case NL80211_STA_INFO_CONNECTED_TIME:
if (len != 4)
return false;
info->connected_time = l_get_u32(data);
info->have_connected_time = true;
break; break;
} }
} }
@ -1124,7 +1101,6 @@ static void netdev_free(void *data)
l_timeout_remove(netdev->rssi_poll_timeout); l_timeout_remove(netdev->rssi_poll_timeout);
scan_wdev_remove(netdev->wdev_id); scan_wdev_remove(netdev->wdev_id);
frame_watch_wdev_remove(netdev->wdev_id);
watchlist_destroy(&netdev->station_watches); watchlist_destroy(&netdev->station_watches);
@ -1522,105 +1498,6 @@ static void netdev_setting_keys_failed(struct netdev_handshake_state *nhs,
handshake_event(&nhs->super, HANDSHAKE_EVENT_SETTING_KEYS_FAILED, &err); handshake_event(&nhs->super, HANDSHAKE_EVENT_SETTING_KEYS_FAILED, &err);
} }
static bool netdev_match_addr(const void *a, const void *b)
{
const struct netdev *netdev = a;
const uint8_t *addr = b;
return memcmp(netdev->addr, addr, ETH_ALEN) == 0;
}
static struct netdev *netdev_find_by_address(const uint8_t *addr)
{
return l_queue_find(netdev_list, netdev_match_addr, addr);
}
static void netdev_pmksa_driver_add(const struct pmksa *pmksa)
{
struct l_genl_msg *msg;
struct netdev *netdev = netdev_find_by_address(pmksa->spa);
uint32_t expiration = (uint32_t)pmksa->expiration;
if (!netdev)
return;
/* Only need to set the PMKSA into the kernel for fullmac drivers */
if (wiphy_supports_cmds_auth_assoc(netdev->wiphy))
return;
l_debug("Adding PMKSA to kernel");
msg = l_genl_msg_new(NL80211_CMD_SET_PMKSA);
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
l_genl_msg_append_attr(msg, NL80211_ATTR_PMKID, 16, pmksa->pmkid);
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, pmksa->aa);
l_genl_msg_append_attr(msg, NL80211_ATTR_SSID,
pmksa->ssid_len, pmksa->ssid);
l_genl_msg_append_attr(msg, NL80211_ATTR_PMK_LIFETIME, 4, &expiration);
l_genl_msg_append_attr(msg, NL80211_ATTR_PMK,
pmksa->pmk_len, pmksa->pmk);
if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
l_error("error sending SET_PMKSA");
}
static void netdev_pmksa_driver_remove(const struct pmksa *pmksa)
{
struct l_genl_msg *msg;
struct netdev *netdev = netdev_find_by_address(pmksa->spa);
if (!netdev)
return;
/* Only need to set the PMKSA into the kernel for fullmac drivers */
if (wiphy_supports_cmds_auth_assoc(netdev->wiphy))
return;
l_debug("Removing PMKSA from kernel");
msg = l_genl_msg_new(NL80211_CMD_DEL_PMKSA);
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
l_genl_msg_append_attr(msg, NL80211_ATTR_PMKID, 16, pmksa->pmkid);
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, pmksa->aa);
l_genl_msg_append_attr(msg, NL80211_ATTR_SSID,
pmksa->ssid_len, pmksa->ssid);
if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
l_error("error sending DEL_PMKSA");
}
static void netdev_flush_pmksa(struct netdev *netdev)
{
struct l_genl_msg *msg;
/*
* We only utilize the kernel's PMKSA cache for fullmac cards,
* so no need to flush if this is a softmac.
*/
if (wiphy_supports_cmds_auth_assoc(netdev->wiphy))
return;
msg = l_genl_msg_new(NL80211_CMD_FLUSH_PMKSA);
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
l_error("Failed to flush PMKSA for %u", netdev->index);
}
static void netdev_pmksa_driver_flush(void)
{
const struct l_queue_entry *e;
for (e = l_queue_get_entries(netdev_list); e; e = e->next) {
struct netdev *netdev = e->data;
netdev_flush_pmksa(netdev);
}
}
static void try_handshake_complete(struct netdev_handshake_state *nhs) static void try_handshake_complete(struct netdev_handshake_state *nhs)
{ {
l_debug("ptk_installed: %u, gtk_installed: %u, igtk_installed: %u", l_debug("ptk_installed: %u, gtk_installed: %u, igtk_installed: %u",
@ -3008,26 +2885,13 @@ static void netdev_cmd_ft_reassociate_cb(struct l_genl_msg *msg,
void *user_data) void *user_data)
{ {
struct netdev *netdev = user_data; struct netdev *netdev = user_data;
int err = l_genl_msg_get_error(msg);
netdev->connect_cmd_id = 0; netdev->connect_cmd_id = 0;
l_debug("%d", err); if (l_genl_msg_get_error(msg) >= 0)
if (err >= 0)
return; return;
/* netdev_deauth_and_fail_connection(netdev,
* TODO: It is possible to not trigger a disconnect here and maintain
* the current connection. The issue is that IWD has already
* modified the handshake and we've lost all reference to the old
* BSS keys.
*
* This could be remedied in the future by creating an entirely
* new handshake_state object for the association and only when
* the ack indicates success do we clear out the old object.
*/
netdev_disconnect_and_fail_connection(netdev,
NETDEV_RESULT_ASSOCIATION_FAILED, NETDEV_RESULT_ASSOCIATION_FAILED,
MMPDU_STATUS_CODE_UNSPECIFIED); MMPDU_STATUS_CODE_UNSPECIFIED);
} }
@ -3952,15 +3816,6 @@ static void netdev_cmd_set_cqm_cb(struct l_genl_msg *msg, void *user_data)
static int netdev_cqm_rssi_update(struct netdev *netdev) static int netdev_cqm_rssi_update(struct netdev *netdev)
{ {
struct l_genl_msg *msg; struct l_genl_msg *msg;
struct netdev_handshake_state *nhs = l_container_of(netdev->handshake,
struct netdev_handshake_state, super);
/*
* Fullmac cards handle roaming in firmware, there is no need to set
* CQM thresholds
*/
if (nhs->type == CONNECTION_TYPE_FULLMAC)
return 0;
l_debug(""); l_debug("");
@ -5430,9 +5285,6 @@ static void netdev_channel_switch_event(struct l_genl_msg *msg,
if (netdev->type != NL80211_IFTYPE_STATION) if (netdev->type != NL80211_IFTYPE_STATION)
return; return;
if (L_WARN_ON(!netdev->connected))
return;
chandef = l_new(struct band_chandef, 1); chandef = l_new(struct band_chandef, 1);
if (nl80211_parse_chandef(msg, chandef) < 0) { if (nl80211_parse_chandef(msg, chandef) < 0) {
@ -5482,39 +5334,6 @@ static void netdev_michael_mic_failure(struct l_genl_msg *msg,
l_debug("ifindex=%u key_idx=%u type=%u", netdev->index, idx, type); l_debug("ifindex=%u key_idx=%u type=%u", netdev->index, idx, type);
} }
#define MAX_COMEBACK_DELAY 1200
static void netdev_assoc_comeback(struct l_genl_msg *msg,
struct netdev *netdev)
{
const uint8_t *mac;
uint32_t timeout;
if (L_WARN_ON(!netdev->connected))
return;
if (nl80211_parse_attrs(msg, NL80211_ATTR_MAC, &mac,
NL80211_ATTR_TIMEOUT, &timeout,
NL80211_ATTR_UNSPEC) < 0)
return;
if (L_WARN_ON(memcmp(mac, netdev->handshake->aa, ETH_ALEN)))
return;
if (timeout <= MAX_COMEBACK_DELAY) {
l_debug(MAC" requested an association comeback delay of %u TU",
MAC_STR(netdev->handshake->aa), timeout);
return;
}
l_debug("Comeback delay of %u exceeded maximum of %u, deauthenticating",
timeout, MAX_COMEBACK_DELAY);
netdev_deauth_and_fail_connection(netdev,
NETDEV_RESULT_ASSOCIATION_FAILED,
MMPDU_STATUS_CODE_REFUSED_TEMPORARILY);
}
static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data) static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data)
{ {
struct netdev *netdev = NULL; struct netdev *netdev = NULL;
@ -5568,9 +5387,6 @@ static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data)
case NL80211_CMD_MICHAEL_MIC_FAILURE: case NL80211_CMD_MICHAEL_MIC_FAILURE:
netdev_michael_mic_failure(msg, netdev); netdev_michael_mic_failure(msg, netdev);
break; break;
case NL80211_CMD_ASSOC_COMEBACK:
netdev_assoc_comeback(msg, netdev);
break;
} }
} }
@ -5688,18 +5504,23 @@ static void netdev_external_auth_event(struct l_genl_msg *msg,
} }
if (action == NL80211_EXTERNAL_AUTH_ABORT) { if (action == NL80211_EXTERNAL_AUTH_ABORT) {
l_warn("External Auth Aborted"); iwd_notice(IWD_NOTICE_CONNECT_INFO, "External Auth Aborted");
goto error; goto error;
} }
iwd_notice(IWD_NOTICE_CONNECT_INFO,
"External Auth to SSID: %s, bssid: "MAC,
util_ssid_to_utf8(ssid.iov_len, ssid.iov_base),
MAC_STR(bssid));
if (hs->ssid_len != ssid.iov_len || if (hs->ssid_len != ssid.iov_len ||
memcmp(hs->ssid, ssid.iov_base, hs->ssid_len)) { memcmp(hs->ssid, ssid.iov_base, hs->ssid_len)) {
l_warn("Target SSID mismatch"); iwd_notice(IWD_NOTICE_CONNECT_INFO, "Target SSID mismatch");
goto error; goto error;
} }
if (memcmp(hs->aa, bssid, ETH_ALEN)) { if (memcmp(hs->aa, bssid, ETH_ALEN)) {
l_warn("Target BSSID mismatch"); iwd_notice(IWD_NOTICE_CONNECT_INFO, "Target BSSID mismatch");
goto error; goto error;
} }
@ -6708,16 +6529,6 @@ struct netdev *netdev_create_from_genl(struct l_genl_msg *msg,
netdev_get_link(netdev); netdev_get_link(netdev);
/*
* Call the netdev-specific variant to flush only this devices PMKSA
* cache in the kernel. This will make IWD's cache and the kernel's
* cache consistent, i.e. no entries
*
* TODO: If we ever are storing PMKSA's on disk we would first need to
* flush, then add all the PMKSA entries at this time.
*/
netdev_flush_pmksa(netdev);
return netdev; return netdev;
} }
@ -6833,10 +6644,6 @@ static int netdev_init(void)
__ft_set_tx_frame_func(netdev_tx_ft_frame); __ft_set_tx_frame_func(netdev_tx_ft_frame);
__pmksa_set_driver_callbacks(netdev_pmksa_driver_add,
netdev_pmksa_driver_remove,
netdev_pmksa_driver_flush);
unicast_watch = l_genl_add_unicast_watch(genl, NL80211_GENL_NAME, unicast_watch = l_genl_add_unicast_watch(genl, NL80211_GENL_NAME,
netdev_unicast_notify, netdev_unicast_notify,
NULL, NULL); NULL, NULL);

View File

@ -158,7 +158,6 @@ const char *netdev_get_name(struct netdev *netdev);
bool netdev_get_is_up(struct netdev *netdev); bool netdev_get_is_up(struct netdev *netdev);
const char *netdev_get_path(struct netdev *netdev); const char *netdev_get_path(struct netdev *netdev);
uint8_t netdev_get_rssi_level_idx(struct netdev *netdev); uint8_t netdev_get_rssi_level_idx(struct netdev *netdev);
int netdev_get_low_signal_threshold(uint32_t frequency);
struct handshake_state *netdev_handshake_state_new(struct netdev *netdev); struct handshake_state *netdev_handshake_state_new(struct netdev *netdev);
struct handshake_state *netdev_get_handshake(struct netdev *netdev); struct handshake_state *netdev_get_handshake(struct netdev *netdev);

View File

@ -168,11 +168,6 @@ static bool network_secret_check_cacheable(void *data, void *user_data)
return false; return false;
} }
void network_clear_blacklist(struct network *network)
{
l_queue_clear(network->blacklist, NULL);
}
void network_connected(struct network *network) void network_connected(struct network *network)
{ {
enum security security = network_get_security(network); enum security security = network_get_security(network);
@ -203,6 +198,8 @@ void network_connected(struct network *network)
l_queue_foreach_remove(network->secrets, l_queue_foreach_remove(network->secrets,
network_secret_check_cacheable, network); network_secret_check_cacheable, network);
l_queue_clear(network->blacklist, NULL);
network->provisioning_hidden = false; network->provisioning_hidden = false;
} }
@ -210,7 +207,7 @@ void network_disconnected(struct network *network)
{ {
network_settings_close(network); network_settings_close(network);
network_clear_blacklist(network); l_queue_clear(network->blacklist, NULL);
if (network->provisioning_hidden) if (network->provisioning_hidden)
station_hide_network(network->station, network); station_hide_network(network->station, network);
@ -1283,8 +1280,7 @@ struct scan_bss *network_bss_select(struct network *network,
if (l_queue_find(network->blacklist, match_bss, bss)) if (l_queue_find(network->blacklist, match_bss, bss))
continue; continue;
if (blacklist_contains_bss(bss->addr, if (blacklist_contains_bss(bss->addr))
BLACKLIST_REASON_CONNECT_FAILED))
continue; continue;
/* OWE Transition BSS */ /* OWE Transition BSS */

View File

@ -74,7 +74,6 @@ bool network_bss_update(struct network *network, struct scan_bss *bss);
const char *network_bss_get_path(const struct network *network, const char *network_bss_get_path(const struct network *network,
const struct scan_bss *bss); const struct scan_bss *bss);
bool network_bss_list_isempty(struct network *network); bool network_bss_list_isempty(struct network *network);
void network_clear_blacklist(struct network *network);
const char *__network_path_append_bss(const char *network_path, const char *__network_path_append_bss(const char *network_path,
const struct scan_bss *bss); const struct scan_bss *bss);

View File

@ -177,7 +177,6 @@ static const struct {
{ NL80211_CMD_UNPROT_BEACON, "Unprotected Beacon" }, { NL80211_CMD_UNPROT_BEACON, "Unprotected Beacon" },
{ NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, { NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,
"Control Port TX Status" }, "Control Port TX Status" },
{ NL80211_CMD_ASSOC_COMEBACK, "Association comeback delay" },
{ } { }
}; };

View File

@ -190,7 +190,6 @@ static attr_handler handler_for_nl80211(int type)
case NL80211_ATTR_CENTER_FREQ2: case NL80211_ATTR_CENTER_FREQ2:
case NL80211_ATTR_AKM_SUITES: case NL80211_ATTR_AKM_SUITES:
case NL80211_ATTR_EXTERNAL_AUTH_ACTION: case NL80211_ATTR_EXTERNAL_AUTH_ACTION:
case NL80211_ATTR_TIMEOUT:
return extract_uint32; return extract_uint32;
case NL80211_ATTR_FRAME: case NL80211_ATTR_FRAME:
return extract_iovec; return extract_iovec;

View File

@ -40,9 +40,6 @@
static uint64_t dot11RSNAConfigPMKLifetime = 43200ULL * L_USEC_PER_SEC; static uint64_t dot11RSNAConfigPMKLifetime = 43200ULL * L_USEC_PER_SEC;
static uint32_t pmksa_cache_capacity = 255; static uint32_t pmksa_cache_capacity = 255;
static pmksa_cache_add_func_t driver_add;
static pmksa_cache_remove_func_t driver_remove;
static pmksa_cache_flush_func_t driver_flush;
struct min_heap { struct min_heap {
struct pmksa **data; struct pmksa **data;
@ -145,7 +142,7 @@ int pmksa_cache_put(struct pmksa *pmksa)
l_debug("Adding entry with PMKID: "PMKID, PMKID_STR(pmksa->pmkid)); l_debug("Adding entry with PMKID: "PMKID, PMKID_STR(pmksa->pmkid));
if (cache.used == cache.capacity) { if (cache.used == cache.capacity) {
pmksa_cache_free(cache.data[0]); l_free(cache.data[0]);
cache.data[0] = pmksa; cache.data[0] = pmksa;
__minheap_sift_down(cache.data, cache.used, 0, &ops); __minheap_sift_down(cache.data, cache.used, 0, &ops);
return 0; return 0;
@ -155,9 +152,6 @@ int pmksa_cache_put(struct pmksa *pmksa)
__minheap_sift_up(cache.data, cache.used, &ops); __minheap_sift_up(cache.data, cache.used, &ops);
cache.used += 1; cache.used += 1;
if (driver_add)
driver_add(pmksa);
return 0; return 0;
} }
@ -173,7 +167,7 @@ int pmksa_cache_expire(uint64_t cutoff)
for (i = 0; i < used; i++) { for (i = 0; i < used; i++) {
if (cache.data[i]->expiration <= cutoff) { if (cache.data[i]->expiration <= cutoff) {
pmksa_cache_free(cache.data[i]); l_free(cache.data[i]);
continue; continue;
} }
@ -196,30 +190,11 @@ int pmksa_cache_flush(void)
{ {
uint32_t i; uint32_t i;
/*
* The driver flush operation is done via a single kernel API call which
* is why below we use l_free instead of pmksa_cache_free as to not
* induce a DEL_PMKSA kernel call for each entry.
*/
if (driver_flush)
driver_flush();
for (i = 0; i < cache.used; i++) for (i = 0; i < cache.used; i++)
l_free(cache.data[i]); l_free(cache.data[i]);
memset(cache.data, 0, cache.capacity * sizeof(struct pmksa *)); memset(cache.data, 0, cache.capacity * sizeof(struct pmksa *));
cache.used = 0; cache.used = 0;
return 0;
}
int pmksa_cache_free(struct pmksa *pmksa)
{
if (driver_remove)
driver_remove(pmksa);
l_free(pmksa);
return 0; return 0;
} }
@ -242,15 +217,6 @@ void __pmksa_set_config(const struct l_settings *config)
&pmksa_cache_capacity); &pmksa_cache_capacity);
} }
void __pmksa_set_driver_callbacks(pmksa_cache_add_func_t add,
pmksa_cache_remove_func_t remove,
pmksa_cache_flush_func_t flush)
{
driver_add = add;
driver_remove = remove;
driver_flush = flush;
}
static int pmksa_init(void) static int pmksa_init(void)
{ {
cache.capacity = pmksa_cache_capacity; cache.capacity = pmksa_cache_capacity;

View File

@ -32,10 +32,6 @@ struct pmksa {
size_t pmk_len; size_t pmk_len;
}; };
typedef void (*pmksa_cache_add_func_t)(const struct pmksa *pmksa);
typedef void (*pmksa_cache_remove_func_t)(const struct pmksa *pmksa);
typedef void (*pmksa_cache_flush_func_t)(void);
struct pmksa **__pmksa_cache_get_all(uint32_t *out_n_entries); struct pmksa **__pmksa_cache_get_all(uint32_t *out_n_entries);
struct pmksa *pmksa_cache_get(const uint8_t spa[static 6], struct pmksa *pmksa_cache_get(const uint8_t spa[static 6],
@ -45,11 +41,6 @@ struct pmksa *pmksa_cache_get(const uint8_t spa[static 6],
int pmksa_cache_put(struct pmksa *pmksa); int pmksa_cache_put(struct pmksa *pmksa);
int pmksa_cache_expire(uint64_t cutoff); int pmksa_cache_expire(uint64_t cutoff);
int pmksa_cache_flush(void); int pmksa_cache_flush(void);
int pmksa_cache_free(struct pmksa *pmksa);
uint64_t pmksa_lifetime(void); uint64_t pmksa_lifetime(void);
void __pmksa_set_config(const struct l_settings *config); void __pmksa_set_config(const struct l_settings *config);
void __pmksa_set_driver_callbacks(pmksa_cache_add_func_t add,
pmksa_cache_remove_func_t remove,
pmksa_cache_flush_func_t flush);

View File

@ -169,14 +169,6 @@ static int sae_choose_next_group(struct sae_sm *sm)
!sm->handshake->ecc_sae_pts[sm->group_retry]) !sm->handshake->ecc_sae_pts[sm->group_retry])
continue; continue;
/*
* TODO: Groups for P192, P224 and P521 are currently
* non-functional with SAE. Until this is fixed we need to
* avoid these groups from being used.
*/
if (group == 21 || group == 25 || group == 26)
continue;
break; break;
} }
@ -1002,8 +994,7 @@ static int sae_process_anti_clogging(struct sae_sm *sm, const uint8_t *ptr,
sm->token_len = len; sm->token_len = len;
sm->sync = 0; sm->sync = 0;
if (L_WARN_ON(!sae_send_commit(sm, true))) sae_send_commit(sm, true);
return -EPROTO;
return -EAGAIN; return -EAGAIN;
} }
@ -1083,9 +1074,7 @@ static int sae_verify_committed(struct sae_sm *sm, uint16_t transaction,
return -ETIMEDOUT; return -ETIMEDOUT;
sm->sync++; sm->sync++;
sae_send_commit(sm, true);
if (L_WARN_ON(!sae_send_commit(sm, true)))
return -EPROTO;
return -EAGAIN; return -EAGAIN;
} }
@ -1140,9 +1129,7 @@ static int sae_verify_committed(struct sae_sm *sm, uint16_t transaction,
sm->group); sm->group);
sm->sync = 0; sm->sync = 0;
sae_send_commit(sm, false);
if (L_WARN_ON(!sae_send_commit(sm, false)))
return -EPROTO;
return -EAGAIN; return -EAGAIN;
} }
@ -1307,8 +1294,7 @@ static int sae_verify_confirmed(struct sae_sm *sm, uint16_t trans,
sm->sync++; sm->sync++;
sm->sc++; sm->sc++;
if (L_WARN_ON(!sae_send_commit(sm, true))) sae_send_commit(sm, true);
return -EPROTO;
if (!sae_send_confirm(sm)) if (!sae_send_confirm(sm))
return -EPROTO; return -EPROTO;

View File

@ -51,7 +51,6 @@
#include "src/mpdu.h" #include "src/mpdu.h"
#include "src/band.h" #include "src/band.h"
#include "src/scan.h" #include "src/scan.h"
#include "src/vendor_quirks.h"
/* User configurable options */ /* User configurable options */
static double RANK_2G_FACTOR; static double RANK_2G_FACTOR;
@ -144,9 +143,9 @@ struct scan_survey {
}; };
struct scan_survey_results { struct scan_survey_results {
struct scan_survey survey_2_4[15]; struct scan_survey survey_2_4[14];
struct scan_survey survey_5[197]; struct scan_survey survey_5[196];
struct scan_survey survey_6[234]; struct scan_survey survey_6[233];
}; };
struct scan_results { struct scan_results {
@ -415,7 +414,6 @@ static struct l_genl_msg *scan_build_cmd(struct scan_context *sc,
if (params->ap_scan) if (params->ap_scan)
flags |= NL80211_SCAN_FLAG_AP; flags |= NL80211_SCAN_FLAG_AP;
if (wiphy_supports_colocated_flag(sc->wiphy))
flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ; flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
if (flags) if (flags)
@ -1222,11 +1220,6 @@ static void scan_parse_vendor_specific(struct scan_bss *bss, const void *data,
uint16_t cost_flags; uint16_t cost_flags;
bool dgaf_disable; bool dgaf_disable;
if (L_WARN_ON(len < 3))
return;
vendor_quirks_append_for_oui(data, &bss->vendor_quirks);
if (!bss->wpa && is_ie_wpa_ie(data, len)) { if (!bss->wpa && is_ie_wpa_ie(data, len)) {
bss->wpa = l_memdup(data - 2, len + 2); bss->wpa = l_memdup(data - 2, len + 2);
return; return;

View File

@ -21,7 +21,6 @@
*/ */
#include "src/defs.h" #include "src/defs.h"
#include "src/vendor_quirks.h"
struct scan_freq_set; struct scan_freq_set;
struct ie_rsn_info; struct ie_rsn_info;
@ -80,7 +79,6 @@ struct scan_bss {
uint8_t *wfd; /* Concatenated WFD IEs */ uint8_t *wfd; /* Concatenated WFD IEs */
ssize_t wfd_size; /* Size of Concatenated WFD IEs */ ssize_t wfd_size; /* Size of Concatenated WFD IEs */
int8_t snr; int8_t snr;
struct vendor_quirk vendor_quirks;
bool mde_present : 1; bool mde_present : 1;
bool cc_present : 1; bool cc_present : 1;
bool cap_rm_neighbor_report : 1; bool cap_rm_neighbor_report : 1;

View File

@ -64,7 +64,6 @@
#include "src/eap-tls-common.h" #include "src/eap-tls-common.h"
#include "src/storage.h" #include "src/storage.h"
#include "src/pmksa.h" #include "src/pmksa.h"
#include "src/vendor_quirks.h"
#define STATION_RECENT_NETWORK_LIMIT 5 #define STATION_RECENT_NETWORK_LIMIT 5
#define STATION_RECENT_FREQS_LIMIT 5 #define STATION_RECENT_FREQS_LIMIT 5
@ -156,54 +155,6 @@ struct anqp_entry {
uint32_t pending; uint32_t pending;
}; };
/*
* Rather than sorting BSS's purely based on ranking a higher level grouping
* is used. The purpose of this higher order grouping is the consider the BSS's
* roam blacklist status. The roam blacklist is a "soft" blacklist in that we
* still should connect to these BSS's if they are the only "good" option.
* The question here is: what makes a BSS "good" vs "bad".
*
* For an initial (probably naive) approach here we can use the
* RoamThreshold[5G] which indicates the signal level that would not
* be of an acceptable connection quality. BSS can then be sorted either
* above or below this threshold. Within each of these groups a BSS may be
* blacklisted, meaning it should get sorted lower on the list compared to
* others within the same group.
*
* This sorting is achieved by extending rank to a uint32_t where the first 16
* bits are the standard rank calculated by scan.c. Above that bits can be
* reserved for this higher level grouping:
*
* Bit 16 indicates the BSS is not blacklisted
* Bit 17 indicates the BSS is above the critical signal threshold
*/
#define ABOVE_THRESHOLD_BIT 17
#define NOT_BLACKLISTED_BIT 16
static uint32_t evaluate_bss_group_rank(const uint8_t *addr, uint32_t freq,
int16_t signal_strength, uint16_t rank)
{
int signal = signal_strength / 100;
bool roam_blacklist;
bool good_signal;
uint32_t rank_out = (uint32_t) rank;
if (blacklist_contains_bss(addr, BLACKLIST_REASON_CONNECT_FAILED))
return 0;
roam_blacklist = blacklist_contains_bss(addr, BLACKLIST_REASON_AP_BUSY);
good_signal = signal >= netdev_get_low_signal_threshold(freq);
if (good_signal)
set_bit(&rank_out, ABOVE_THRESHOLD_BIT);
if (!roam_blacklist)
set_bit(&rank_out, NOT_BLACKLISTED_BIT);
return rank_out;
}
/* /*
* Used as entries for the roam list since holding scan_bss pointers directly * Used as entries for the roam list since holding scan_bss pointers directly
* from station->bss_list is not 100% safe due to the possibility of the * from station->bss_list is not 100% safe due to the possibility of the
@ -211,13 +162,13 @@ static uint32_t evaluate_bss_group_rank(const uint8_t *addr, uint32_t freq,
*/ */
struct roam_bss { struct roam_bss {
uint8_t addr[6]; uint8_t addr[6];
uint32_t rank; uint16_t rank;
int32_t signal_strength; int32_t signal_strength;
bool ft_failed: 1; bool ft_failed: 1;
}; };
static struct roam_bss *roam_bss_from_scan_bss(const struct scan_bss *bss, static struct roam_bss *roam_bss_from_scan_bss(const struct scan_bss *bss,
uint32_t rank) uint16_t rank)
{ {
struct roam_bss *rbss = l_new(struct roam_bss, 1); struct roam_bss *rbss = l_new(struct roam_bss, 1);
@ -1447,8 +1398,6 @@ static struct handshake_state *station_handshake_setup(struct station *station,
vendor_ies = network_info_get_extra_ies(info, bss, &iov_elems); vendor_ies = network_info_get_extra_ies(info, bss, &iov_elems);
handshake_state_set_vendor_ies(hs, vendor_ies, iov_elems); handshake_state_set_vendor_ies(hs, vendor_ies, iov_elems);
handshake_state_set_vendor_quirks(hs, bss->vendor_quirks);
/* /*
* It can't hurt to try the FILS IP Address Assignment independent of * It can't hurt to try the FILS IP Address Assignment independent of
* which auth-proto is actually used. * which auth-proto is actually used.
@ -1798,15 +1747,6 @@ static void station_enter_state(struct station *station,
periodic_scan_stop(station); periodic_scan_stop(station);
break; break;
case STATION_STATE_CONNECTED: case STATION_STATE_CONNECTED:
network_clear_blacklist(station->connected_network);
if (station->connect_pending) {
struct l_dbus_message *reply =
l_dbus_message_new_method_return(
station->connect_pending);
dbus_pending_reply(&station->connect_pending, reply);
}
l_dbus_object_add_interface(dbus, l_dbus_object_add_interface(dbus,
netdev_get_path(station->netdev), netdev_get_path(station->netdev),
IWD_STATION_DIAGNOSTIC_INTERFACE, IWD_STATION_DIAGNOSTIC_INTERFACE,
@ -2226,26 +2166,6 @@ static void station_early_neighbor_report_cb(struct netdev *netdev, int err,
&station->roam_freqs); &station->roam_freqs);
} }
static bool station_try_next_bss(struct station *station)
{
struct scan_bss *next;
int ret;
next = network_bss_select(station->connected_network, false);
if (!next)
return false;
ret = __station_connect_network(station, station->connected_network,
next, station->state);
if (ret < 0)
return false;
l_debug("Attempting to connect to next BSS "MAC, MAC_STR(next->addr));
return true;
}
static bool station_can_fast_transition(struct station *station, static bool station_can_fast_transition(struct station *station,
struct handshake_state *hs, struct handshake_state *hs,
struct scan_bss *bss) struct scan_bss *bss)
@ -2288,26 +2208,28 @@ static bool station_can_fast_transition(struct station *station,
return true; return true;
} }
static void station_disconnect_on_netconfig_failed(struct netdev *netdev, static void station_disconnect_on_error_cb(struct netdev *netdev, bool success,
bool success,
void *user_data) void *user_data)
{ {
struct station *station = user_data; struct station *station = user_data;
bool continue_autoconnect;
if (station_try_next_bss(station))
return;
if (station->connect_pending) {
struct l_dbus_message *reply = dbus_error_failed(
station->connect_pending);
dbus_pending_reply(&station->connect_pending, reply);
}
station_reset_connection_state(station);
station_enter_state(station, STATION_STATE_DISCONNECTED); station_enter_state(station, STATION_STATE_DISCONNECTED);
station_enter_state(station, STATION_STATE_AUTOCONNECT_FULL);
continue_autoconnect = station->state == STATION_STATE_CONNECTING_AUTO;
if (continue_autoconnect) {
if (station_autoconnect_next(station) < 0) {
l_debug("Nothing left on autoconnect list");
station_enter_state(station,
STATION_STATE_AUTOCONNECT_FULL);
}
return;
}
if (station->autoconnect)
station_enter_state(station, STATION_STATE_AUTOCONNECT_QUICK);
} }
static void station_netconfig_event_handler(enum netconfig_event event, static void station_netconfig_event_handler(enum netconfig_event event,
@ -2320,20 +2242,23 @@ static void station_netconfig_event_handler(enum netconfig_event event,
station_enter_state(station, STATION_STATE_CONNECTED); station_enter_state(station, STATION_STATE_CONNECTED);
break; break;
case NETCONFIG_EVENT_FAILED: case NETCONFIG_EVENT_FAILED:
station_debug_event(station, "netconfig-failed"); if (station->connect_pending) {
struct l_dbus_message *reply = dbus_error_failed(
station->connect_pending);
netconfig_reset(station->netconfig); dbus_pending_reply(&station->connect_pending, reply);
}
if (station->state == STATION_STATE_NETCONFIG) if (station->state == STATION_STATE_NETCONFIG)
network_connect_failed(station->connected_network, network_connect_failed(station->connected_network,
false); false);
network_blacklist_add(station->connected_network,
station->connected_bss);
netdev_disconnect(station->netdev, netdev_disconnect(station->netdev,
station_disconnect_on_netconfig_failed, station_disconnect_on_error_cb,
station); station);
station_reset_connection_state(station);
station_enter_state(station, STATION_STATE_DISCONNECTING);
break; break;
default: default:
l_error("station: Unsupported netconfig event: %d.", event); l_error("station: Unsupported netconfig event: %d.", event);
@ -2407,11 +2332,6 @@ static void station_roam_retry(struct station *station)
station->roam_scan_full = false; station->roam_scan_full = false;
station->ap_directed_roaming = false; station->ap_directed_roaming = false;
if (station->roam_freqs) {
scan_freq_set_free(station->roam_freqs);
station->roam_freqs = NULL;
}
if (station->signal_low) if (station->signal_low)
station_roam_timeout_rearm(station, roam_retry_interval); station_roam_timeout_rearm(station, roam_retry_interval);
} }
@ -2441,16 +2361,8 @@ static void station_roam_failed(struct station *station)
* We were told by the AP to roam, but failed. Try ourselves or * We were told by the AP to roam, but failed. Try ourselves or
* wait for the AP to tell us to roam again * wait for the AP to tell us to roam again
*/ */
if (station->ap_directed_roaming) { if (station->ap_directed_roaming)
/*
* The candidate list from the AP (or neighbor report) found
* no BSS's. Force a full scan
*/
if (!station->roam_scan_full)
goto full_scan;
goto delayed_retry; goto delayed_retry;
}
/* /*
* If we tried a limited scan, failed and the signal is still low, * If we tried a limited scan, failed and the signal is still low,
@ -2462,7 +2374,6 @@ static void station_roam_failed(struct station *station)
* the scan here, so that the destroy callback is not called * the scan here, so that the destroy callback is not called
* after the return of this function * after the return of this function
*/ */
full_scan:
scan_cancel(netdev_get_wdev_id(station->netdev), scan_cancel(netdev_get_wdev_id(station->netdev),
station->roam_scan_id); station->roam_scan_id);
@ -2750,15 +2661,11 @@ static bool station_try_next_transition(struct station *station,
enum security security = network_get_security(connected); enum security security = network_get_security(connected);
struct handshake_state *new_hs; struct handshake_state *new_hs;
struct ie_rsn_info cur_rsne, target_rsne; struct ie_rsn_info cur_rsne, target_rsne;
const char *vendor_quirks = vendor_quirks_to_string(bss->vendor_quirks);
iwd_notice(IWD_NOTICE_ROAM_INFO, "bss: "MAC", signal: %d, load: %d/255", iwd_notice(IWD_NOTICE_ROAM_INFO, "bss: "MAC", signal: %d, load: %d/255",
MAC_STR(bss->addr), MAC_STR(bss->addr),
bss->signal_strength / 100, bss->signal_strength / 100,
bss->utilization); bss->utilization);
if (vendor_quirks)
l_debug("vendor quirks for "MAC": %s",
MAC_STR(bss->addr), vendor_quirks);
/* Reset AP roam flag, at this point the roaming behaves the same */ /* Reset AP roam flag, at this point the roaming behaves the same */
station->ap_directed_roaming = false; station->ap_directed_roaming = false;
@ -2898,7 +2805,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
struct handshake_state *hs = netdev_get_handshake(station->netdev); struct handshake_state *hs = netdev_get_handshake(station->netdev);
struct scan_bss *current_bss = station->connected_bss; struct scan_bss *current_bss = station->connected_bss;
struct scan_bss *bss; struct scan_bss *bss;
uint32_t cur_bss_group_rank = 0; double cur_bss_rank = 0.0;
static const double RANK_FT_FACTOR = 1.3; static const double RANK_FT_FACTOR = 1.3;
uint16_t mdid; uint16_t mdid;
enum security orig_security, security; enum security orig_security, security;
@ -2927,15 +2834,10 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
*/ */
bss = l_queue_find(bss_list, bss_match_bssid, current_bss->addr); bss = l_queue_find(bss_list, bss_match_bssid, current_bss->addr);
if (bss && !station->ap_directed_roaming) { if (bss && !station->ap_directed_roaming) {
double cur_bss_rank = bss->rank; cur_bss_rank = bss->rank;
if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid) if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid)
cur_bss_rank *= RANK_FT_FACTOR; cur_bss_rank *= RANK_FT_FACTOR;
cur_bss_group_rank = evaluate_bss_group_rank(bss->addr,
bss->frequency,
bss->signal_strength,
(uint16_t) cur_bss_rank);
} }
/* /*
@ -2957,7 +2859,6 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
while ((bss = l_queue_pop_head(bss_list))) { while ((bss = l_queue_pop_head(bss_list))) {
double rank; double rank;
struct roam_bss *rbss; struct roam_bss *rbss;
uint32_t group_rank;
station_print_scan_bss(bss); station_print_scan_bss(bss);
@ -2979,8 +2880,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
if (network_can_connect_bss(network, bss) < 0) if (network_can_connect_bss(network, bss) < 0)
goto next; goto next;
if (blacklist_contains_bss(bss->addr, if (blacklist_contains_bss(bss->addr))
BLACKLIST_REASON_CONNECT_FAILED))
goto next; goto next;
rank = bss->rank; rank = bss->rank;
@ -2988,11 +2888,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid) if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid)
rank *= RANK_FT_FACTOR; rank *= RANK_FT_FACTOR;
group_rank = evaluate_bss_group_rank(bss->addr, bss->frequency, if (rank <= cur_bss_rank)
bss->signal_strength,
(uint16_t) rank);
if (group_rank <= cur_bss_group_rank)
goto next; goto next;
/* /*
@ -3001,7 +2897,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
*/ */
station_update_roam_bss(station, bss); station_update_roam_bss(station, bss);
rbss = roam_bss_from_scan_bss(bss, group_rank); rbss = roam_bss_from_scan_bss(bss, rank);
l_queue_insert(station->roam_bss_list, rbss, l_queue_insert(station->roam_bss_list, rbss,
roam_bss_rank_compare, NULL); roam_bss_rank_compare, NULL);
@ -3059,7 +2955,6 @@ static int station_roam_scan(struct station *station,
if (!freq_set) { if (!freq_set) {
station->roam_scan_full = true; station->roam_scan_full = true;
params.freqs = allowed; params.freqs = allowed;
station_debug_event(station, "full-roam-scan");
} else } else
scan_freq_set_constrain(freq_set, allowed); scan_freq_set_constrain(freq_set, allowed);
@ -3270,12 +3165,12 @@ static void station_ap_directed_roam(struct station *station,
uint8_t req_mode; uint8_t req_mode;
uint16_t dtimer; uint16_t dtimer;
uint8_t valid_interval; uint8_t valid_interval;
bool can_roam = !station_cannot_roam(station);
bool ignore_candidates =
station->connected_bss->vendor_quirks.ignore_bss_tm_candidates;
l_debug("ifindex: %u", netdev_get_ifindex(station->netdev)); l_debug("ifindex: %u", netdev_get_ifindex(station->netdev));
if (station_cannot_roam(station))
return;
if (station->state != STATION_STATE_CONNECTED) { if (station->state != STATION_STATE_CONNECTED) {
l_debug("roam: unexpected AP directed roam -- ignore"); l_debug("roam: unexpected AP directed roam -- ignore");
return; return;
@ -3339,13 +3234,8 @@ static void station_ap_directed_roam(struct station *station,
* disassociating us. If either of these bits are set, set the * disassociating us. If either of these bits are set, set the
* ap_directed_roaming flag. Otherwise still try roaming but don't * ap_directed_roaming flag. Otherwise still try roaming but don't
* treat it any different than a normal roam. * treat it any different than a normal roam.
*
* The only exception here is if we are in the middle of roaming
* (can_roam == false) since we cannot reliably know if the roam scan
* included frequencies from potential candidates in this request,
* forcing a roam in this case might result in unintended behavior.
*/ */
if (can_roam && req_mode & (WNM_REQUEST_MODE_DISASSOCIATION_IMMINENT | if (req_mode & (WNM_REQUEST_MODE_DISASSOCIATION_IMMINENT |
WNM_REQUEST_MODE_TERMINATION_IMMINENT | WNM_REQUEST_MODE_TERMINATION_IMMINENT |
WNM_REQUEST_MODE_ESS_DISASSOCIATION_IMMINENT)) WNM_REQUEST_MODE_ESS_DISASSOCIATION_IMMINENT))
station->ap_directed_roaming = true; station->ap_directed_roaming = true;
@ -3372,39 +3262,17 @@ static void station_ap_directed_roam(struct station *station,
pos += url_len; pos += url_len;
} }
blacklist_add_bss(station->connected_bss->addr,
BLACKLIST_REASON_AP_BUSY);
station_debug_event(station, "ap-roam-blacklist-added");
/*
* Validating the frame and blacklisting should still be done even if
* we are mid-roam. Its important to track the BSS requesting the
* transition so when the current roam completes IWD will be less likely
* to roam back to the current BSS.
*/
if (!can_roam)
return;
station->preparing_roam = true; station->preparing_roam = true;
l_timeout_remove(station->roam_trigger_timeout); l_timeout_remove(station->roam_trigger_timeout);
station->roam_trigger_timeout = NULL; station->roam_trigger_timeout = NULL;
if ((req_mode & WNM_REQUEST_MODE_PREFERRED_CANDIDATE_LIST) && if (req_mode & WNM_REQUEST_MODE_PREFERRED_CANDIDATE_LIST) {
!ignore_candidates) {
l_debug("roam: AP sent a preferred candidate list"); l_debug("roam: AP sent a preferred candidate list");
station_neighbor_report_cb(station->netdev, 0, body + pos, station_neighbor_report_cb(station->netdev, 0, body + pos,
body_len - pos, station); body_len - pos, station);
} else { } else {
if (station->connected_bss->cap_rm_neighbor_report) { l_debug("roam: AP did not include a preferred candidate list");
if (!netdev_neighbor_report_req(station->netdev,
station_neighbor_report_cb))
return;
l_warn("failed to request neighbor report!");
}
l_debug("full scan after BSS transition request");
if (station_roam_scan(station, NULL) < 0) if (station_roam_scan(station, NULL) < 0)
station_roam_failed(station); station_roam_failed(station);
} }
@ -3466,6 +3334,26 @@ static void station_event_channel_switched(struct station *station,
network_bss_update(network, station->connected_bss); network_bss_update(network, station->connected_bss);
} }
static bool station_try_next_bss(struct station *station)
{
struct scan_bss *next;
int ret;
next = network_bss_select(station->connected_network, false);
if (!next)
return false;
ret = __station_connect_network(station, station->connected_network,
next, station->state);
if (ret < 0)
return false;
l_debug("Attempting to connect to next BSS "MAC, MAC_STR(next->addr));
return true;
}
static bool station_retry_owe_default_group(struct station *station) static bool station_retry_owe_default_group(struct station *station)
{ {
/* /*
@ -3512,15 +3400,7 @@ static bool station_retry_with_reason(struct station *station,
break; break;
} }
blacklist_add_bss(station->connected_bss->addr, blacklist_add_bss(station->connected_bss->addr);
BLACKLIST_REASON_CONNECT_FAILED);
/*
* Network blacklist the BSS as well, since the timeout blacklist could
* be disabled
*/
network_blacklist_add(station->connected_network,
station->connected_bss);
try_next: try_next:
return station_try_next_bss(station); return station_try_next_bss(station);
@ -3559,54 +3439,32 @@ static bool station_pmksa_fallback(struct station *station, uint16_t status)
return true; return true;
} }
/* A bit more concise for trying to fit these into 80 characters */
#define IS_TEMPORARY_STATUS(code) \
((code) == MMPDU_STATUS_CODE_DENIED_UNSUFFICIENT_BANDWIDTH || \
(code) == MMPDU_STATUS_CODE_DENIED_POOR_CHAN_CONDITIONS || \
(code) == MMPDU_STATUS_CODE_REJECTED_WITH_SUGG_BSS_TRANS || \
(code) == MMPDU_STATUS_CODE_DENIED_NO_MORE_STAS)
static bool station_retry_with_status(struct station *station, static bool station_retry_with_status(struct station *station,
uint16_t status_code) uint16_t status_code)
{ {
/* If PMKSA failed don't blacklist so we can retry this BSS */
if (station_pmksa_fallback(station, status_code))
goto try_next;
switch (status_code) {
/* /*
* Certain Auth/Assoc failures should not cause a timeout blacklist. * Certain Auth/Assoc failures should not cause a timeout blacklist.
* In these cases we want to only temporarily blacklist the BSS until * In these cases we want to only temporarily blacklist the BSS until
* the connection is complete. * the connection is complete.
*/ *
case MMPDU_STATUS_CODE_DENIED_UNSUFFICIENT_BANDWIDTH:
case MMPDU_STATUS_CODE_DENIED_POOR_CHAN_CONDITIONS:
/*
* TODO: The WITH_SUGG_BSS_TRANS case should also include a neighbor * TODO: The WITH_SUGG_BSS_TRANS case should also include a neighbor
* report IE in the frame. This would allow us to target a * report IE in the frame. This would allow us to target a
* specific BSS on our next attempt. There is currently no way to * specific BSS on our next attempt. There is currently no way to
* obtain that IE, but this should be done in the future. * obtain that IE, but this should be done in the future.
*/ */
case MMPDU_STATUS_CODE_REJECTED_WITH_SUGG_BSS_TRANS: if (IS_TEMPORARY_STATUS(status_code))
break;
/*
* If a BSS is indicating its unable to handle more connections we will
* blacklist this the same way we do for BSS's issuing BSS-TM requests
* thereby avoiding roams to this BSS for the configured timeout.
*/
case MMPDU_STATUS_CODE_DENIED_NO_MORE_STAS:
blacklist_add_bss(station->connected_bss->addr,
BLACKLIST_REASON_AP_BUSY);
break;
/* For any other status codes, blacklist the BSS */
default:
blacklist_add_bss(station->connected_bss->addr,
BLACKLIST_REASON_CONNECT_FAILED);
break;
}
/*
* Unconditionally network blacklist the BSS if we are retrying. This
* will allow network_bss_select to traverse the BSS list and ignore
* BSS's which have previously failed
*/
network_blacklist_add(station->connected_network, network_blacklist_add(station->connected_network,
station->connected_bss); station->connected_bss);
else if (!station_pmksa_fallback(station, status_code))
blacklist_add_bss(station->connected_bss->addr);
try_next:
iwd_notice(IWD_NOTICE_CONNECT_FAILED, "status: %u", status_code); iwd_notice(IWD_NOTICE_CONNECT_FAILED, "status: %u", status_code);
return station_try_next_bss(station); return station_try_next_bss(station);
@ -3618,6 +3476,13 @@ static void station_connect_ok(struct station *station)
l_debug(""); l_debug("");
if (station->connect_pending) {
struct l_dbus_message *reply =
l_dbus_message_new_method_return(
station->connect_pending);
dbus_pending_reply(&station->connect_pending, reply);
}
/* /*
* Get a neighbor report now so future roams can avoid waiting for * Get a neighbor report now so future roams can avoid waiting for
* a report at that time * a report at that time
@ -3684,8 +3549,7 @@ static void station_connect_cb(struct netdev *netdev, enum netdev_result result,
switch (result) { switch (result) {
case NETDEV_RESULT_OK: case NETDEV_RESULT_OK:
blacklist_remove_bss(station->connected_bss->addr, blacklist_remove_bss(station->connected_bss->addr);
BLACKLIST_REASON_CONNECT_FAILED);
station_connect_ok(station); station_connect_ok(station);
return; return;
case NETDEV_RESULT_DISCONNECTED: case NETDEV_RESULT_DISCONNECTED:
@ -3917,7 +3781,6 @@ int __station_connect_network(struct station *station, struct network *network,
{ {
struct handshake_state *hs; struct handshake_state *hs;
int r; int r;
const char *vendor_quirks = vendor_quirks_to_string(bss->vendor_quirks);
/* /*
* If we already have a handshake_state ref this is due to a retry, * If we already have a handshake_state ref this is due to a retry,
@ -3952,10 +3815,6 @@ int __station_connect_network(struct station *station, struct network *network,
bss->signal_strength / 100, bss->signal_strength / 100,
bss->utilization); bss->utilization);
if (vendor_quirks)
l_debug("vendor quirks for "MAC": %s",
MAC_STR(bss->addr), vendor_quirks);
station->connected_bss = bss; station->connected_bss = bss;
station->connected_network = network; station->connected_network = network;
station->hs = handshake_state_ref(hs); station->hs = handshake_state_ref(hs);
@ -4860,7 +4719,7 @@ static struct l_dbus_message *station_property_set_affinities(
struct l_dbus_message_iter array; struct l_dbus_message_iter array;
const char *sender = l_dbus_message_get_sender(message); const char *sender = l_dbus_message_get_sender(message);
char *old_path = l_queue_peek_head(station->affinities); char *old_path = l_queue_peek_head(station->affinities);
const char *new_path; const char *new_path = NULL;
struct scan_bss *new_bss = NULL; struct scan_bss *new_bss = NULL;
struct scan_bss *old_bss = NULL; struct scan_bss *old_bss = NULL;
bool lower_threshold = false; bool lower_threshold = false;
@ -4880,15 +4739,10 @@ static struct l_dbus_message *station_property_set_affinities(
if (!l_dbus_message_iter_get_variant(new_value, "ao", &array)) if (!l_dbus_message_iter_get_variant(new_value, "ao", &array))
return dbus_error_invalid_args(message); return dbus_error_invalid_args(message);
/* Get first entry, or if an empty array set the path to NULL */ /* Get first entry, there should be only one */
if (!l_dbus_message_iter_next_entry(&array, &new_path)) l_dbus_message_iter_next_entry(&array, &new_path);
new_path = NULL;
/* if (l_dbus_message_iter_next_entry(&array, &new_path))
* Only allowing single values for now. If there is more than a single
* value, fail
*/
if (new_path && l_dbus_message_iter_next_entry(&array, &new_path))
return dbus_error_invalid_args(message); return dbus_error_invalid_args(message);
old_path = l_queue_peek_head(station->affinities); old_path = l_queue_peek_head(station->affinities);

View File

@ -500,13 +500,6 @@ int __storage_decrypt(struct l_settings *settings, const char *ssid,
return 0; return 0;
} }
/*
* It should likely be far larger than this, but that will get caught
* later when reloading the decrypted data.
*/
if (elen < 16)
return -EBADMSG;
/* /*
* AES-SIV automatically verifies the IV (16 bytes) and returns only * AES-SIV automatically verifies the IV (16 bytes) and returns only
* the decrypted data portion. We add one here for the NULL terminator * the decrypted data portion. We add one here for the NULL terminator

View File

@ -1,84 +0,0 @@
/*
*
* Wireless daemon for Linux
*
* Copyright (C) 2025 Locus Robotics Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdio.h>
#include <ell/ell.h>
#include "src/vendor_quirks.h"
static const struct {
uint8_t oui[3];
struct vendor_quirk quirks;
} oui_quirk_db[] = {
{
/* Cisco Meraki */
{ 0x00, 0x18, 0x0a },
{ .ignore_bss_tm_candidates = true },
},
{
/* Hewlett Packard, owns Aruba */
{ 0x00, 0x0b, 0x86 },
{ .replay_counter_mismatch = true },
},
};
void vendor_quirks_append_for_oui(const uint8_t *oui,
struct vendor_quirk *quirks)
{
size_t i;
for (i = 0; i < L_ARRAY_SIZE(oui_quirk_db); i++) {
const struct vendor_quirk *quirk = &oui_quirk_db[i].quirks;
if (memcmp(oui_quirk_db[i].oui, oui, 3))
continue;
quirks->ignore_bss_tm_candidates |=
quirk->ignore_bss_tm_candidates;
quirks->replay_counter_mismatch |=
quirk->replay_counter_mismatch;
}
}
const char *vendor_quirks_to_string(struct vendor_quirk quirks)
{
static char out[1024];
char *pos = out;
size_t s = 0;
if (quirks.ignore_bss_tm_candidates)
s += snprintf(pos, sizeof(out) - s, "IgnoreBssTmCandidateList");
if (quirks.replay_counter_mismatch)
s += snprintf(pos, sizeof(out) - s, "ReplayCounterMismatch");
if (!s)
return NULL;
return out;
}

View File

@ -1,39 +0,0 @@
/*
*
* Wireless daemon for Linux
*
* Copyright (C) 2025 Locus Robotics Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __IWD_VENDOR_QUIRKS_H
#define __IWD_VENDOR_QUIRKS_H
#include <stdint.h>
struct vendor_quirk {
bool ignore_bss_tm_candidates : 1;
bool replay_counter_mismatch : 1;
};
void vendor_quirks_append_for_oui(const uint8_t *oui,
struct vendor_quirk *quirks);
const char *vendor_quirks_to_string(struct vendor_quirk quirks);
#endif /* __IWD_VENDOR_QUIRKS_H */

View File

@ -69,26 +69,11 @@ static uint32_t work_ids;
static unsigned int wiphy_dump_id; static unsigned int wiphy_dump_id;
enum driver_flag { enum driver_flag {
/* Force the use of the default interface created by the kernel */
DEFAULT_IF = 0x1, DEFAULT_IF = 0x1,
/*
* Force the use of the PAE socket rather than control port, even if
* control port is supported
*/
FORCE_PAE = 0x2, FORCE_PAE = 0x2,
/* Disable power save on the adapter during initialization */
POWER_SAVE_DISABLE = 0x4, POWER_SAVE_DISABLE = 0x4,
/* Don't use OWE when connecting to open networks */
OWE_DISABLE = 0x8, OWE_DISABLE = 0x8,
/* Disables multicast RX frame registration */
MULTICAST_RX_DISABLE = 0x10, MULTICAST_RX_DISABLE = 0x10,
/*
* Don't use SAE (WPA3) when connecting to hybrid networks. This will
* prevent IWD from connecting to WPA3-only networks
*/
SAE_DISABLE = 0x20,
/* Disables use of the NL80211_SCAN_FLAG_COLOCATED_6GHZ flag in scans */
COLOCATED_SCAN_DISABLE = 0x40,
}; };
struct driver_flag_name { struct driver_flag_name {
@ -121,9 +106,7 @@ static const struct driver_flag_name driver_flag_names[] = {
{ "ForcePae", FORCE_PAE }, { "ForcePae", FORCE_PAE },
{ "PowerSaveDisable", POWER_SAVE_DISABLE }, { "PowerSaveDisable", POWER_SAVE_DISABLE },
{ "OweDisable", OWE_DISABLE }, { "OweDisable", OWE_DISABLE },
{ "MulticastRxDisable", MULTICAST_RX_DISABLE }, { "MulticastRxDisable", MULTICAST_RX_DISABLE }
{ "SaeDisable", SAE_DISABLE },
{ "ColocatedScanDisable", COLOCATED_SCAN_DISABLE },
}; };
struct wiphy { struct wiphy {
@ -219,9 +202,6 @@ uint16_t wiphy_get_supported_ciphers(struct wiphy *wiphy, uint16_t mask)
static bool wiphy_can_connect_sae(struct wiphy *wiphy) static bool wiphy_can_connect_sae(struct wiphy *wiphy)
{ {
if (wiphy->driver_flags & SAE_DISABLE)
return false;
/* /*
* WPA3 Specification version 3, Section 2.2: * WPA3 Specification version 3, Section 2.2:
* A STA shall not enable WEP and TKIP * A STA shall not enable WEP and TKIP
@ -978,11 +958,6 @@ bool wiphy_supports_multicast_rx(const struct wiphy *wiphy)
!(wiphy->driver_flags & MULTICAST_RX_DISABLE); !(wiphy->driver_flags & MULTICAST_RX_DISABLE);
} }
bool wiphy_supports_colocated_flag(const struct wiphy *wiphy)
{
return !(wiphy->driver_flags & COLOCATED_SCAN_DISABLE);
}
const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy, const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy,
enum band_freq band, enum band_freq band,
size_t *size) size_t *size)
@ -1399,12 +1374,6 @@ static void wiphy_print_basic_info(struct wiphy *wiphy)
if (wiphy->driver_flags & MULTICAST_RX_DISABLE) if (wiphy->driver_flags & MULTICAST_RX_DISABLE)
flags = l_strv_append(flags, "MulticastRxDisable"); flags = l_strv_append(flags, "MulticastRxDisable");
if (wiphy->driver_flags & SAE_DISABLE)
flags = l_strv_append(flags, "SaeDisable");
if (wiphy->driver_flags & COLOCATED_SCAN_DISABLE)
flags = l_strv_append(flags, "ColocatedScanDisable");
joined = l_strjoinv(flags, ' '); joined = l_strjoinv(flags, ' ');
l_info("\tDriver Flags: %s", joined); l_info("\tDriver Flags: %s", joined);

View File

@ -144,7 +144,6 @@ bool wiphy_country_is_unknown(struct wiphy *wiphy);
bool wiphy_supports_uapsd(const struct wiphy *wiphy); bool wiphy_supports_uapsd(const struct wiphy *wiphy);
bool wiphy_supports_cmd_offchannel(const struct wiphy *wiphy); bool wiphy_supports_cmd_offchannel(const struct wiphy *wiphy);
bool wiphy_supports_multicast_rx(const struct wiphy *wiphy); bool wiphy_supports_multicast_rx(const struct wiphy *wiphy);
bool wiphy_supports_colocated_flag(const struct wiphy *wiphy);
const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy, const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy,
enum band_freq band, enum band_freq band,

View File

@ -138,22 +138,20 @@ static const struct cmac_data example_4 = {
.tag_len = sizeof(tag_4), .tag_len = sizeof(tag_4),
}; };
static bool test_precheck(const void *data)
{
return l_checksum_cmac_aes_supported();
}
#define add_test(name, func, data) l_test_add_data_func_precheck(name, data, \
func, test_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
add_test("/cmac-aes/Example 1", cmac_test, &example_1); if (!l_checksum_cmac_aes_supported()) {
add_test("/cmac-aes/Example 2", cmac_test, &example_2); printf("AES-CMAC support missing, skipping...\n");
add_test("/cmac-aes/Example 3", cmac_test, &example_3); goto done;
add_test("/cmac-aes/Example 4", cmac_test, &example_4); }
l_test_add("/cmac-aes/Example 1", cmac_test, &example_1);
l_test_add("/cmac-aes/Example 2", cmac_test, &example_2);
l_test_add("/cmac-aes/Example 3", cmac_test, &example_3);
l_test_add("/cmac-aes/Example 4", cmac_test, &example_4);
done:
return l_test_run(); return l_test_run();
} }

View File

@ -403,32 +403,40 @@ static void aes_siv_test(const void *data)
assert(memcmp(decrypted, plaintext, sizeof(decrypted)) == 0); assert(memcmp(decrypted, plaintext, sizeof(decrypted)) == 0);
} }
static bool test_precheck(const void *data)
{
return (l_cipher_is_supported(L_CIPHER_AES) &&
l_checksum_is_supported(L_CHECKSUM_SHA1, true));
}
#define add_test(name, func, data) l_test_add_data_func_precheck(name, data, \
func, test_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
add_test("/Passphrase Generator/PSK Test Case 1", if (!l_checksum_is_supported(L_CHECKSUM_SHA1, true)) {
printf("SHA1 support missing, skipping...\n");
goto done;
}
if (!l_cipher_is_supported(L_CIPHER_AES)) {
printf("AES support missing, skipping...\n");
goto done;
}
l_test_add("/Passphrase Generator/PSK Test Case 1",
psk_test, &psk_test_case_1); psk_test, &psk_test_case_1);
add_test("/Passphrase Generator/PSK Test Case 2", l_test_add("/Passphrase Generator/PSK Test Case 2",
psk_test, &psk_test_case_2); psk_test, &psk_test_case_2);
add_test("/Passphrase Generator/PSK Test Case 3", l_test_add("/Passphrase Generator/PSK Test Case 3",
psk_test, &psk_test_case_3); psk_test, &psk_test_case_3);
add_test("/PTK Derivation/PTK Test Case 1", ptk_test, &ptk_test_1); l_test_add("/PTK Derivation/PTK Test Case 1",
add_test("/PTK Derivation/PTK Test Case 2", ptk_test, &ptk_test_2); ptk_test, &ptk_test_1);
add_test("/PTK Derivation/PTK Test Case 3", ptk_test, &ptk_test_3); l_test_add("/PTK Derivation/PTK Test Case 2",
add_test("/PTK Derivation/PTK Test Case 4", ptk_test, &ptk_test_4); ptk_test, &ptk_test_2);
l_test_add("/PTK Derivation/PTK Test Case 3",
ptk_test, &ptk_test_3);
l_test_add("/PTK Derivation/PTK Test Case 4",
ptk_test, &ptk_test_4);
add_test("/AES Key-wrap/Wrap & unwrap", aes_wrap_test, NULL); l_test_add("/AES Key-wrap/Wrap & unwrap",
add_test("/AES-SIV", aes_siv_test, NULL); aes_wrap_test, NULL);
l_test_add("/AES-SIV", aes_siv_test, NULL);
done:
return l_test_run(); return l_test_run();
} }

View File

@ -116,29 +116,6 @@ struct dpp_test_info bad_channels[] = {
}, },
}; };
struct dpp_test_info duplicates[] = {
/* Duplicate key */
{
.uri = "DPP:K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgADURzxmttZoIRIPWGoQMV00XHWCAQIhXruVWOz0NjlkIA=;K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgADURzxmttZoIRIPWGoQMV00XHWCAQIhXruVWOz0NjlkIA=;;",
.expect_fail = true
},
/* Duplicate frequencies*/
{
.uri = "DPP:C:81/1,115/36;C:81/1,115/36;;",
.expect_fail = true
},
/* Duplicate MACs*/
{
.uri = "DPP:M:5254005828e5;M:5254005828e5;;",
.expect_fail = true
},
/* Duplicate versions */
{
.uri = "DPP:V:2;V:2;;",
.expect_fail = true
},
};
static bool verify_info(const struct dpp_uri_info *parsed, static bool verify_info(const struct dpp_uri_info *parsed,
const struct dpp_test_info *result) const struct dpp_test_info *result)
{ {
@ -181,14 +158,6 @@ static void test_bad_channels(const void *data)
test_uri_parse(&bad_channels[i]); test_uri_parse(&bad_channels[i]);
} }
static void test_duplicate_in_uri(const void *data)
{
unsigned int i;
for (i = 0; i < L_ARRAY_SIZE(duplicates); i++)
test_uri_parse(&duplicates[i]);
}
struct dpp_test_vector { struct dpp_test_vector {
/* Initiator values */ /* Initiator values */
const char *i_proto_public; const char *i_proto_public;
@ -577,25 +546,22 @@ static void test_pkex_key_derivation(const void *user_data)
CHECK_FROM_STR(vector->v, tmp, 32); CHECK_FROM_STR(vector->v, tmp, 32);
} }
static bool test_precheck(const void *data)
{
return (l_getrandom_is_supported() &&
l_checksum_is_supported(L_CHECKSUM_SHA256, true));
}
#define add_test(name, func, data) l_test_add_data_func_precheck(name, data, \
func, test_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
add_test("DPP test responder-only key derivation", test_key_derivation, if (l_checksum_is_supported(L_CHECKSUM_SHA256, true) &&
l_getrandom_is_supported()) {
l_test_add("DPP test responder-only key derivation",
test_key_derivation,
&responder_only_p256); &responder_only_p256);
add_test("DPP test mutual key derivation", test_key_derivation, l_test_add("DPP test mutual key derivation",
test_key_derivation,
&mutual_p256); &mutual_p256);
add_test("DPP test PKEX key derivation", test_pkex_key_derivation, l_test_add("DPP test PKEX key derivation",
test_pkex_key_derivation,
&pkex_vector); &pkex_vector);
}
l_test_add("DPP URI parse", test_uri_parse, &all_values); l_test_add("DPP URI parse", test_uri_parse, &all_values);
l_test_add("DPP URI no type", test_uri_parse, &no_type); l_test_add("DPP URI no type", test_uri_parse, &no_type);
@ -610,7 +576,6 @@ int main(int argc, char *argv[])
l_test_add("DPP URI bad key", test_uri_parse, &bad_key); l_test_add("DPP URI bad key", test_uri_parse, &bad_key);
l_test_add("DPP URI bad channels", test_bad_channels, &bad_channels); l_test_add("DPP URI bad channels", test_bad_channels, &bad_channels);
l_test_add("DPP URI unexpected ID", test_uri_parse, &unexpected_id); l_test_add("DPP URI unexpected ID", test_uri_parse, &unexpected_id);
l_test_add("DPP URI duplicates", test_duplicate_in_uri, &duplicates);
return l_test_run(); return l_test_run();
} }

View File

@ -131,23 +131,27 @@ static void test_get_asym_key(const void *data)
assert(!memcmp(msk, m_session_key, sizeof(m_session_key))); assert(!memcmp(msk, m_session_key, sizeof(m_session_key)));
} }
static bool test_precheck(const void *data)
{
return l_checksum_is_supported(L_CHECKSUM_MD4, false);
}
#define add_test(name, func) l_test_add_func_precheck(name, func, \
test_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
add_test("MSHAPv2 nt_password-hash", test_nt_password_hash); if (!l_checksum_is_supported(L_CHECKSUM_MD4, false)) {
add_test("MSHAPv2 generate_nt_response", test_generate_nt_response); printf("MD4 support missing, skipping...\n");
add_test("MSHAPv2 get_master_key", test_get_master_key); goto done;
add_test("MSHAPv2 get_asym_state_key", test_get_asym_key); }
add_test("MSHAPv2 authenticator_response", test_authenticator_response);
l_test_add("MSHAPv2 nt_password-hash",
test_nt_password_hash, NULL);
l_test_add("MSHAPv2 generate_nt_response",
test_generate_nt_response, NULL);
l_test_add("MSHAPv2 get_master_key",
test_get_master_key, NULL);
l_test_add("MSHAPv2 get_asym_state_key",
test_get_asym_key, NULL);
l_test_add("MSHAPv2 authenticator_response",
test_authenticator_response, NULL);
done:
return l_test_run(); return l_test_run();
} }

View File

@ -3908,38 +3908,6 @@ static void eapol_ap_sta_handshake_ip_alloc_no_req_test(const void *data)
#define _IS_ENABLED2(one_or_two_args) _IS_ENABLED3(one_or_two_args true, false) #define _IS_ENABLED2(one_or_two_args) _IS_ENABLED3(one_or_two_args true, false)
#define _IS_ENABLED3(ignore_this, val, ...) val #define _IS_ENABLED3(ignore_this, val, ...) val
static bool hash_precheck(const void *data)
{
return (l_checksum_is_supported(L_CHECKSUM_MD5, true) &&
l_checksum_is_supported(L_CHECKSUM_SHA1, true));
}
static bool aes_precheck(const void *data)
{
return (l_cipher_is_supported(L_CIPHER_AES) &&
l_checksum_is_supported(L_CHECKSUM_MD5, true) &&
l_checksum_is_supported(L_CHECKSUM_SHA1, true));
}
static bool pkcs8_precheck(const void *data)
{
return (IS_ENABLED(HAVE_PKCS8_SUPPORT) &&
l_cipher_is_supported(L_CIPHER_AES) &&
l_cipher_is_supported(L_CIPHER_AES_CBC) &&
l_cipher_is_supported(L_CIPHER_DES3_EDE_CBC) &&
l_checksum_is_supported(L_CHECKSUM_MD5, true) &&
l_checksum_is_supported(L_CHECKSUM_SHA1, true) &&
l_key_is_supported(L_KEY_FEATURE_CRYPTO) &&
l_key_is_supported(L_KEY_FEATURE_RESTRICT));
}
#define add_hash_test(name, func, data) l_test_add_data_func_precheck(name, \
data, func, hash_precheck, 0)
#define add_aes_test(name, func, data) l_test_add_data_func_precheck(name, \
data, func, aes_precheck, 0)
#define add_pkcs8_test(name, func, data) l_test_add_data_func_precheck(name, \
data, func, pkcs8_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
@ -4009,55 +3977,80 @@ int main(int argc, char *argv[])
l_test_add("/EAPoL Key/Key Frame 32", l_test_add("/EAPoL Key/Key Frame 32",
eapol_key_test, &eapol_key_test_32); eapol_key_test, &eapol_key_test_32);
add_hash_test("/EAPoL Key/MIC Test 1", if (!l_checksum_is_supported(L_CHECKSUM_MD5, true) ||
!l_checksum_is_supported(L_CHECKSUM_SHA1, true))
goto done;
l_test_add("/EAPoL Key/MIC Test 1",
eapol_key_mic_test, &eapol_key_mic_test_1); eapol_key_mic_test, &eapol_key_mic_test_1);
add_hash_test("/EAPoL Key/MIC Test 2", l_test_add("/EAPoL Key/MIC Test 2",
eapol_key_mic_test, &eapol_key_mic_test_2); eapol_key_mic_test, &eapol_key_mic_test_2);
add_hash_test("/EAPoL Key/Calculate MIC Test 1",
l_test_add("/EAPoL Key/Calculate MIC Test 1",
eapol_calculate_mic_test, &eapol_calculate_mic_test_1); eapol_calculate_mic_test, &eapol_calculate_mic_test_1);
add_aes_test("EAPoL/WPA2 4-Way Handshake", if (!l_cipher_is_supported(L_CIPHER_AES))
eapol_4way_test, NULL); goto done;
add_aes_test("EAPoL/WPA2 4-Way & GTK Handshake",
eapol_wpa2_handshake_test, NULL);
add_aes_test("EAPoL/WPA 4-Way & GTK Handshake",
eapol_wpa_handshake_test, NULL);
add_aes_test("EAPoL/WPA2 PTK State Machine",
eapol_sm_test_ptk, NULL);
add_aes_test("EAPoL IGTK & 4-Way Handshake",
eapol_sm_test_igtk, NULL);
add_aes_test("EAPoL/WPA2 PTK & GTK State Machine",
eapol_sm_test_wpa2_ptk_gtk, NULL);
add_aes_test("EAPoL/WPA PTK & GTK State Machine Test 1",
eapol_sm_test_wpa_ptk_gtk, NULL);
add_aes_test("EAPoL/WPA PTK & GTK State Machine Test 2",
eapol_sm_test_wpa_ptk_gtk_2, NULL);
add_aes_test("EAPoL/WPA2 Retransmit Test",
eapol_sm_wpa2_retransmit_test, NULL);
add_pkcs8_test("EAPoL/8021x EAP-TLS & 4-Way Handshake", l_test_add("EAPoL/WPA2 4-Way Handshake",
eapol_sm_test_eap_tls, NULL); &eapol_4way_test, NULL);
add_pkcs8_test("EAPoL/8021x EAP-TTLS+EAP-MD5 & 4-Way Handshake",
eapol_sm_test_eap_ttls_md5, NULL);
add_pkcs8_test("EAPoL/8021x EAP NAK",
eapol_sm_test_eap_nak, NULL);
add_pkcs8_test("EAPoL/8021x EAP-TLS subject name match",
eapol_sm_test_eap_tls_subject_good, NULL);
add_pkcs8_test("EAPoL/8021x EAP-TLS subject name mismatch",
eapol_sm_test_eap_tls_subject_bad, NULL);
add_pkcs8_test("EAPoL/8021x EAP-TLS embedded certs",
eapol_sm_test_eap_tls_embedded, NULL);
add_aes_test("EAPoL/FT-Using-PSK 4-Way Handshake", l_test_add("EAPoL/WPA2 4-Way & GTK Handshake",
eapol_ft_handshake_test, NULL); &eapol_wpa2_handshake_test, NULL);
add_aes_test("EAPoL/Supplicant+Authenticator 4-Way Handshake",
eapol_ap_sta_handshake_test, NULL);
add_aes_test("EAPoL/Supplicant+Authenticator 4-Way Handshake Bad PSK",
eapol_ap_sta_handshake_bad_psk_test, NULL);
add_aes_test("EAPoL/Supplicant+Authenticator IP Allocation OK",
eapol_ap_sta_handshake_ip_alloc_ok_test, NULL);
add_aes_test("EAPoL/Supplicant+Authenticator IP Allocation no request",
eapol_ap_sta_handshake_ip_alloc_no_req_test, NULL);
l_test_add("EAPoL/WPA 4-Way & GTK Handshake",
&eapol_wpa_handshake_test, NULL);
l_test_add("EAPoL/WPA2 PTK State Machine", &eapol_sm_test_ptk, NULL);
l_test_add("EAPoL IGTK & 4-Way Handshake",
&eapol_sm_test_igtk, NULL);
l_test_add("EAPoL/WPA2 PTK & GTK State Machine",
&eapol_sm_test_wpa2_ptk_gtk, NULL);
l_test_add("EAPoL/WPA PTK & GTK State Machine Test 1",
&eapol_sm_test_wpa_ptk_gtk, NULL);
l_test_add("EAPoL/WPA PTK & GTK State Machine Test 2",
&eapol_sm_test_wpa_ptk_gtk_2, NULL);
l_test_add("EAPoL/WPA2 Retransmit Test",
&eapol_sm_wpa2_retransmit_test, NULL);
if (IS_ENABLED(HAVE_PKCS8_SUPPORT) &&
l_cipher_is_supported(L_CIPHER_DES3_EDE_CBC) &&
l_cipher_is_supported(L_CIPHER_AES_CBC) &&
l_key_is_supported(L_KEY_FEATURE_RESTRICT |
L_KEY_FEATURE_CRYPTO)) {
l_test_add("EAPoL/8021x EAP-TLS & 4-Way Handshake",
&eapol_sm_test_eap_tls, NULL);
l_test_add("EAPoL/8021x EAP-TTLS+EAP-MD5 & 4-Way Handshake",
&eapol_sm_test_eap_ttls_md5, NULL);
l_test_add("EAPoL/8021x EAP NAK",
&eapol_sm_test_eap_nak, NULL);
l_test_add("EAPoL/8021x EAP-TLS subject name match",
&eapol_sm_test_eap_tls_subject_good, NULL);
l_test_add("EAPoL/8021x EAP-TLS subject name mismatch",
&eapol_sm_test_eap_tls_subject_bad, NULL);
l_test_add("EAPoL/8021x EAP-TLS embedded certs",
&eapol_sm_test_eap_tls_embedded, NULL);
}
l_test_add("EAPoL/FT-Using-PSK 4-Way Handshake",
&eapol_ft_handshake_test, NULL);
l_test_add("EAPoL/Supplicant+Authenticator 4-Way Handshake",
&eapol_ap_sta_handshake_test, NULL);
l_test_add("EAPoL/Supplicant+Authenticator 4-Way Handshake Bad PSK",
&eapol_ap_sta_handshake_bad_psk_test, NULL);
l_test_add("EAPoL/Supplicant+Authenticator IP Allocation OK",
&eapol_ap_sta_handshake_ip_alloc_ok_test, NULL);
l_test_add("EAPoL/Supplicant+Authenticator IP Allocation no request",
&eapol_ap_sta_handshake_ip_alloc_no_req_test, NULL);
done:
return l_test_run(); return l_test_run();
} }

View File

@ -81,20 +81,18 @@ static const struct hmac_data test_case_2 = {
.hmac = "80070713463e7749b90c2dc24911e275", .hmac = "80070713463e7749b90c2dc24911e275",
}; };
static bool test_precheck(const void *data)
{
return l_checksum_is_supported(L_CHECKSUM_MD5, true);
}
#define add_test(name, func, data) l_test_add_data_func_precheck(name, data, \
func, test_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
add_test("/hmac-md5/Test case 1", hmac_test, &test_case_1); if (!l_checksum_is_supported(L_CHECKSUM_MD5, true)) {
add_test("/hmac-md5/Test case 2", hmac_test, &test_case_2); printf("MD5 support missing, skipping...\n");
goto done;
}
l_test_add("/hmac-md5/Test case 1", hmac_test, &test_case_1);
l_test_add("/hmac-md5/Test case 2", hmac_test, &test_case_2);
done:
return l_test_run(); return l_test_run();
} }

View File

@ -81,20 +81,18 @@ static const struct hmac_data test_case_2 = {
.hmac = "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9", .hmac = "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9",
}; };
static bool test_precheck(const void *data)
{
return l_checksum_is_supported(L_CHECKSUM_SHA1, true);
}
#define add_test(name, func, data) l_test_add_data_func_precheck(name, data, \
func, test_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
add_test("/hmac-sha1/Test case 1", hmac_test, &test_case_1); if (!l_checksum_is_supported(L_CHECKSUM_SHA1, true)) {
add_test("/hmac-sha1/Test case 2", hmac_test, &test_case_2); printf("SHA1 support missing, skipping...\n");
goto done;
}
l_test_add("/hmac-sha1/Test case 1", hmac_test, &test_case_1);
l_test_add("/hmac-sha1/Test case 2", hmac_test, &test_case_2);
done:
return l_test_run(); return l_test_run();
} }

View File

@ -83,20 +83,18 @@ static const struct hmac_data test_case_2 = {
"ef4d59a14946175997479dbc2d1a3cd8", "ef4d59a14946175997479dbc2d1a3cd8",
}; };
static bool test_precheck(const void *data)
{
return l_checksum_is_supported(L_CHECKSUM_SHA256, true);
}
#define add_test(name, func, data) l_test_add_data_func_precheck(name, data, \
func, test_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
add_test("/hmac-sha256/Test case 1", hmac_test, &test_case_1); if (!l_checksum_is_supported(L_CHECKSUM_SHA256, true)) {
add_test("/hmac-sha256/Test case 2", hmac_test, &test_case_2); printf("SHA256 support missing, skipping...\n");
goto done;
}
l_test_add("/hmac-sha256/Test case 1", hmac_test, &test_case_1);
l_test_add("/hmac-sha256/Test case 2", hmac_test, &test_case_2);
done:
return l_test_run(); return l_test_run();
} }

View File

@ -81,19 +81,17 @@ static const struct kdf_data test_case_1 = {
"84f7d2291143d4d4", "84f7d2291143d4d4",
}; };
static bool test_precheck(const void *data)
{
return l_checksum_is_supported(L_CHECKSUM_SHA256, true);
}
#define add_test(name, func, data) l_test_add_data_func_precheck(name, data, \
func, test_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
add_test("/kdf-sha256/Test case 1", kdf_test, &test_case_1); if (!l_checksum_is_supported(L_CHECKSUM_SHA256, true)) {
printf("SHA256 support missing, skipping...\n");
goto done;
}
l_test_add("/kdf-sha256/Test case 1", kdf_test, &test_case_1);
done:
return l_test_run(); return l_test_run();
} }

View File

@ -341,7 +341,7 @@ static const struct p2p_probe_req_data p2p_probe_req_data_1 = {
.group_caps = 0, .group_caps = 0,
}, },
.listen_channel = { .listen_channel = {
.country = { 'X', 'X', '\x04' }, .country = "XX\x04",
.oper_class = 81, .oper_class = 81,
.channel_num = 1, .channel_num = 1,
}, },

View File

@ -113,21 +113,19 @@ static const struct prf_data test_case_3 = {
"f7b4abd43d87f0a68f1cbd9e2b6f7607", "f7b4abd43d87f0a68f1cbd9e2b6f7607",
}; };
static bool test_precheck(const void *data)
{
return l_checksum_is_supported(L_CHECKSUM_SHA1, true);
}
#define add_test(name, func, data) l_test_add_data_func_precheck(name, data, \
func, test_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
add_test("/prf-sha1/Test case 1", prf_test, &test_case_1); if (!l_checksum_is_supported(L_CHECKSUM_SHA1, true)) {
add_test("/prf-sha1/Test case 2", prf_test, &test_case_2); printf("SHA1 support missing, skipping...\n");
add_test("/prf-sha1/Test case 3", prf_test, &test_case_3); goto done;
}
l_test_add("/prf-sha1/Test case 1", prf_test, &test_case_1);
l_test_add("/prf-sha1/Test case 2", prf_test, &test_case_2);
l_test_add("/prf-sha1/Test case 3", prf_test, &test_case_3);
done:
return l_test_run(); return l_test_run();
} }

View File

@ -871,29 +871,32 @@ static void test_pt_pwe(const void *data)
l_ecc_point_free(pt); l_ecc_point_free(pt);
} }
static bool test_precheck(const void *data)
{
return (l_getrandom_is_supported() &&
l_checksum_is_supported(L_CHECKSUM_SHA256, true));
}
#define add_test(name, func) l_test_add_func_precheck(name, func, \
test_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
add_test("SAE anti-clogging", test_clogging); if (!l_getrandom_is_supported()) {
add_test("SAE early confirm", test_early_confirm); l_info("l_getrandom not supported, skipping...");
add_test("SAE reflection", test_reflection); goto done;
add_test("SAE malformed commit", test_malformed_commit); }
add_test("SAE malformed confirm", test_malformed_confirm);
add_test("SAE bad group", test_bad_group);
add_test("SAE bad confirm", test_bad_confirm);
add_test("SAE confirm after accept", test_confirm_after_accept);
add_test("SAE end-to-end", test_end_to_end);
add_test("SAE pt-pwe", test_pt_pwe);
if (!l_checksum_is_supported(L_CHECKSUM_SHA256, true)) {
l_info("SHA256/HMAC_SHA256 not supported, skipping...");
goto done;
}
l_test_add("SAE anti-clogging", test_clogging, NULL);
l_test_add("SAE early confirm", test_early_confirm, NULL);
l_test_add("SAE reflection", test_reflection, NULL);
l_test_add("SAE malformed commit", test_malformed_commit, NULL);
l_test_add("SAE malformed confirm", test_malformed_confirm, NULL);
l_test_add("SAE bad group", test_bad_group, NULL);
l_test_add("SAE bad confirm", test_bad_confirm, NULL);
l_test_add("SAE confirm after accept", test_confirm_after_accept, NULL);
l_test_add("SAE end-to-end", test_end_to_end, NULL);
l_test_add("SAE pt-pwe", test_pt_pwe, NULL);
done:
return l_test_run(); return l_test_run();
} }

View File

@ -1,66 +0,0 @@
/*
*
* Wireless daemon for Linux
*
* Copyright (C) 2025 Locus Robotics. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include <ell/ell.h>
#include "src/storage.h"
static bool aes_ctr_supported(const void *data)
{
return l_cipher_is_supported(L_CIPHER_AES_CTR);
}
static void test_short_encrypted_bytes(const void *data)
{
struct l_settings *settings = l_settings_new();
bool changed;
int err;
storage_init((const uint8_t *)"abc123", 6);
l_settings_set_string(settings, "Security", "EncryptedSecurity", "012345");
l_settings_set_string(settings, "Security", "EncryptedSalt", "012345");
err = __storage_decrypt(settings, "mySSID", &changed);
assert(err == -EBADMSG);
l_settings_free(settings);
storage_exit();
}
int main(int argc, char *argv[])
{
l_test_init(&argc, &argv);
l_test_add_func_precheck("/storage/profile encryption",
test_short_encrypted_bytes,
aes_ctr_supported, 0);
return l_test_run();
}

View File

@ -2574,40 +2574,6 @@ struct wsc_credential wsc_r_test_open_cred = {
.encryption_type = WSC_ENCRYPTION_TYPE_NONE, .encryption_type = WSC_ENCRYPTION_TYPE_NONE,
}; };
static bool getrandom_precheck(const void *data)
{
return l_getrandom_is_supported();
}
static bool aes_cbc_precheck(const void *data)
{
return (l_key_is_supported(L_KEY_FEATURE_DH) &&
l_cipher_is_supported(L_CIPHER_AES_CBC));
}
static bool key_crypto_precheck(const void *data)
{
return (l_key_is_supported(L_KEY_FEATURE_CRYPTO) &&
l_checksum_is_supported(L_CHECKSUM_SHA256, true));
}
static bool key_dh_precheck(const void *data)
{
return (l_key_is_supported(L_KEY_FEATURE_DH) &&
l_key_is_supported(L_KEY_FEATURE_CRYPTO) &&
l_checksum_is_supported(L_CHECKSUM_SHA256, true));
}
#define add_aes_cbc_test(name, func, data) l_test_add_data_func_precheck(name, \
data, func, \
aes_cbc_precheck, 0)
#define add_crypto_test(name, func, data) l_test_add_data_func_precheck(name, \
data, func, \
key_crypto_precheck, 0)
#define add_dh_test(name, func, data) l_test_add_data_func_precheck(name, \
data, func, \
key_dh_precheck, 0)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
l_test_init(&argc, &argv); l_test_init(&argc, &argv);
@ -2629,8 +2595,8 @@ int main(int argc, char *argv[])
l_test_add("/wsc/pin/valid pin", wsc_test_pin_valid, NULL); l_test_add("/wsc/pin/valid pin", wsc_test_pin_valid, NULL);
l_test_add("/wsc/pin/valid checksum", wsc_test_pin_checksum, NULL); l_test_add("/wsc/pin/valid checksum", wsc_test_pin_checksum, NULL);
l_test_add_func_precheck("/wsc/pin/generate", wsc_test_pin_generate, if (l_getrandom_is_supported())
getrandom_precheck, 0); l_test_add("/wsc/pin/generate", wsc_test_pin_generate, NULL);
l_test_add("/wsc/gen_uuid/1", wsc_test_uuid_from_addr, l_test_add("/wsc/gen_uuid/1", wsc_test_uuid_from_addr,
&uuid_from_addr_data_1); &uuid_from_addr_data_1);
@ -2641,77 +2607,96 @@ int main(int argc, char *argv[])
l_test_add("/wsc/build/m1 1", wsc_test_build_m1, &m1_data_1); l_test_add("/wsc/build/m1 1", wsc_test_build_m1, &m1_data_1);
l_test_add("/wsc/build/m1 2", wsc_test_build_m1, &m1_data_2); l_test_add("/wsc/build/m1 2", wsc_test_build_m1, &m1_data_2);
add_dh_test("/wsc/parse/m2 1", wsc_test_parse_m2, &m2_data_1); if (!l_checksum_is_supported(L_CHECKSUM_SHA256, true)) {
add_dh_test("/wsc/parse/m2 2", wsc_test_parse_m2, &m2_data_2); printf("SHA256 support missing, skipping other tests...\n");
goto done;
}
add_crypto_test("/wsc/build/m2 1", wsc_test_build_m2, &m2_data_1); if (!l_key_is_supported(L_KEY_FEATURE_CRYPTO)) {
printf("Key crypto not supported, skipping other tests...\n");
goto done;
}
add_crypto_test("/wsc/parse/m3 1", wsc_test_parse_m3, &m3_data_1); if (l_key_is_supported(L_KEY_FEATURE_DH)) {
add_crypto_test("/wsc/build/m3 1", wsc_test_build_m3, &m3_data_1); l_test_add("/wsc/parse/m2 1", wsc_test_parse_m2, &m2_data_1);
l_test_add("/wsc/parse/m2 2", wsc_test_parse_m2, &m2_data_2);
}
add_crypto_test("/wsc/parse/m4 1", wsc_test_parse_m4, &m4_data_1); l_test_add("/wsc/build/m2 1", wsc_test_build_m2, &m2_data_1);
add_crypto_test("/wsc/build/m4 1", wsc_test_build_m4, &m4_data_1);
add_crypto_test("/wsc/parse/m4 encrypted settings 1", l_test_add("/wsc/parse/m3 1", wsc_test_parse_m3, &m3_data_1);
l_test_add("/wsc/build/m3 1", wsc_test_build_m3, &m3_data_1);
l_test_add("/wsc/parse/m4 1", wsc_test_parse_m4, &m4_data_1);
l_test_add("/wsc/build/m4 1", wsc_test_build_m4, &m4_data_1);
l_test_add("/wsc/parse/m4 encrypted settings 1",
wsc_test_parse_m4_encrypted_settings, wsc_test_parse_m4_encrypted_settings,
&m4_encrypted_settings_data_1); &m4_encrypted_settings_data_1);
add_crypto_test("/wsc/build/m4 encrypted settings 1", l_test_add("/wsc/build/m4 encrypted settings 1",
wsc_test_build_m4_encrypted_settings, wsc_test_build_m4_encrypted_settings,
&m4_encrypted_settings_data_1); &m4_encrypted_settings_data_1);
add_crypto_test("/wsc/parse/m5 1", wsc_test_parse_m5, &m5_data_1); l_test_add("/wsc/parse/m5 1", wsc_test_parse_m5, &m5_data_1);
add_crypto_test("/wsc/build/m5 1", wsc_test_build_m5, &m5_data_1); l_test_add("/wsc/build/m5 1", wsc_test_build_m5, &m5_data_1);
add_crypto_test("/wsc/parse/m6 1", wsc_test_parse_m6, &m6_data_1); l_test_add("/wsc/parse/m6 1", wsc_test_parse_m6, &m6_data_1);
add_crypto_test("/wsc/build/m6 1", wsc_test_build_m6, &m6_data_1); l_test_add("/wsc/build/m6 1", wsc_test_build_m6, &m6_data_1);
add_crypto_test("/wsc/parse/m6 encrypted settings 1", l_test_add("/wsc/parse/m6 encrypted settings 1",
wsc_test_parse_m6_encrypted_settings, wsc_test_parse_m6_encrypted_settings,
&m6_encrypted_settings_data_1); &m6_encrypted_settings_data_1);
add_crypto_test("/wsc/build/m6 encrypted settings 1", l_test_add("/wsc/build/m6 encrypted settings 1",
wsc_test_build_m6_encrypted_settings, wsc_test_build_m6_encrypted_settings,
&m6_encrypted_settings_data_1); &m6_encrypted_settings_data_1);
add_crypto_test("/wsc/parse/m7 1", wsc_test_parse_m7, &m7_data_1); l_test_add("/wsc/parse/m7 1", wsc_test_parse_m7, &m7_data_1);
add_crypto_test("/wsc/build/m7 1", wsc_test_build_m7, &m7_data_1); l_test_add("/wsc/build/m7 1", wsc_test_build_m7, &m7_data_1);
add_crypto_test("/wsc/parse/m8 1", wsc_test_parse_m8, &m8_data_1); l_test_add("/wsc/parse/m8 1", wsc_test_parse_m8, &m8_data_1);
add_crypto_test("/wsc/build/m8 1", wsc_test_build_m8, &m8_data_1); l_test_add("/wsc/build/m8 1", wsc_test_build_m8, &m8_data_1);
add_crypto_test("/wsc/parse/m8 encrypted settings 1", l_test_add("/wsc/parse/m8 encrypted settings 1",
wsc_test_parse_m8_encrypted_settings, wsc_test_parse_m8_encrypted_settings,
&m8_encrypted_settings_data_1); &m8_encrypted_settings_data_1);
add_crypto_test("/wsc/build/m8 encrypted settings 1", l_test_add("/wsc/build/m8 encrypted settings 1",
wsc_test_build_m8_encrypted_settings, wsc_test_build_m8_encrypted_settings,
&m8_encrypted_settings_data_1); &m8_encrypted_settings_data_1);
add_crypto_test("/wsc/parse/wsc_done 1", wsc_test_parse_wsc_done, l_test_add("/wsc/parse/wsc_done 1", wsc_test_parse_wsc_done,
&wsc_done_data_1); &wsc_done_data_1);
add_crypto_test("/wsc/build/wsc_done 1", wsc_test_build_wsc_done, l_test_add("/wsc/build/wsc_done 1", wsc_test_build_wsc_done,
&wsc_done_data_1); &wsc_done_data_1);
add_dh_test("/wsc/diffie-hellman/generate pubkey 1", if (!l_key_is_supported(L_KEY_FEATURE_DH))
goto done;
l_test_add("/wsc/diffie-hellman/generate pubkey 1",
wsc_test_dh_generate_pubkey, wsc_test_dh_generate_pubkey,
&dh_generate_pubkey_test_data_1); &dh_generate_pubkey_test_data_1);
add_dh_test("/wsc/diffie-hellman/generate pubkey 2", l_test_add("/wsc/diffie-hellman/generate pubkey 2",
wsc_test_dh_generate_pubkey, wsc_test_dh_generate_pubkey,
&dh_generate_pubkey_test_data_2); &dh_generate_pubkey_test_data_2);
add_aes_cbc_test("/wsc/handshake/PBC Handshake Test", if (!l_cipher_is_supported(L_CIPHER_AES_CBC))
goto done;
l_test_add("/wsc/handshake/PBC Handshake Test",
wsc_test_pbc_handshake, NULL); wsc_test_pbc_handshake, NULL);
add_aes_cbc_test("/wsc/retransmission/no fragmentation", l_test_add("/wsc/retransmission/no fragmentation",
wsc_test_retransmission_no_fragmentation, NULL); wsc_test_retransmission_no_fragmentation, NULL);
add_aes_cbc_test("/wsc-r/handshake/PBC Handshake WPA2 passphrase test", l_test_add("/wsc-r/handshake/PBC Handshake WPA2 passphrase test",
wsc_r_test_pbc_handshake, wsc_r_test_pbc_handshake,
&wsc_r_test_wpa2_cred_passphrase); &wsc_r_test_wpa2_cred_passphrase);
add_aes_cbc_test("/wsc-r/handshake/PBC Handshake WPA2 PSK test", l_test_add("/wsc-r/handshake/PBC Handshake WPA2 PSK test",
wsc_r_test_pbc_handshake, wsc_r_test_pbc_handshake,
&wsc_r_test_wpa2_cred_psk); &wsc_r_test_wpa2_cred_psk);
add_aes_cbc_test("/wsc-r/handshake/PBC Handshake Open test", l_test_add("/wsc-r/handshake/PBC Handshake Open test",
wsc_r_test_pbc_handshake, wsc_r_test_pbc_handshake,
&wsc_r_test_open_cred); &wsc_r_test_open_cred);
done:
return l_test_run(); return l_test_run();
} }