mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2025-11-26 06:07:26 +01:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e7a8feee0 | ||
|
|
3760a49650 | ||
|
|
c4d114d804 | ||
|
|
ffe79bfada | ||
|
|
c0efaf21ad | ||
|
|
cee079da5b | ||
|
|
df30309aac | ||
|
|
2fe8c13016 | ||
|
|
84666b9703 | ||
|
|
54c0dbb3c8 | ||
|
|
6e9e0928b0 | ||
|
|
a1247fe46e | ||
|
|
088bb2e308 | ||
|
|
57dc5d843c | ||
|
|
8cb134f935 | ||
|
|
46037c428c | ||
|
|
161de4a3ad | ||
|
|
77ee863f04 | ||
|
|
405d1ab77c | ||
|
|
dc1589f3fe | ||
|
|
755280a4cc | ||
|
|
df2c5cf7fa | ||
|
|
fee0e5de33 | ||
|
|
601d9b0e02 | ||
|
|
f209e00dde | ||
|
|
86523b0597 | ||
|
|
85a2637fc5 | ||
|
|
2f991918b1 | ||
|
|
5b5a9b60fb | ||
|
|
5287809043 | ||
|
|
ea9ff2dcaf | ||
|
|
9dce36fe3d | ||
|
|
c4718a5355 | ||
|
|
c9c8790ff2 | ||
|
|
d135bfc4b8 | ||
|
|
e269beadba | ||
|
|
3e55fc855a | ||
|
|
c8d9936f9d | ||
|
|
79940956ef | ||
|
|
9f98c6c3c8 | ||
|
|
93eef7b02d | ||
|
|
26ed1f8b9f | ||
|
|
243db1d256 | ||
|
|
5224b0b0e7 | ||
|
|
3267d356d2 | ||
|
|
78f4e6240e | ||
|
|
36b1086f60 | ||
|
|
266eb405f2 | ||
|
|
0a8e646231 | ||
|
|
8ebc4780ea | ||
|
|
4ded663e68 | ||
|
|
c00bc3a065 | ||
|
|
f469db8a95 | ||
|
|
c3a27354ff | ||
|
|
d927fd07c1 | ||
|
|
8dff156eb6 | ||
|
|
e5c41a8024 | ||
|
|
603d6b2881 | ||
|
|
d1aa4009bc | ||
|
|
3c5081c7a6 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -68,6 +68,7 @@ unit/test-dpp
|
||||
unit/test-json
|
||||
unit/test-nl80211util
|
||||
unit/test-pmksa
|
||||
unit/test-storage
|
||||
unit/cert-*.pem
|
||||
unit/cert-*.csr
|
||||
unit/cert-*.srl
|
||||
|
||||
20
ChangeLog
20
ChangeLog
@ -1,3 +1,23 @@
|
||||
ver 3.10:
|
||||
Fix issue with handling neighbor report on BSS TM request.
|
||||
Fix issue with handling deauth and FT association failure.
|
||||
Fix issue with handling roaming and old frequencies.
|
||||
|
||||
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.
|
||||
|
||||
@ -274,6 +274,8 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h \
|
||||
src/dpp.c \
|
||||
src/udev.c \
|
||||
src/pmksa.h src/pmksa.c \
|
||||
src/vendor_quirks.h \
|
||||
src/vendor_quirks.c \
|
||||
$(eap_sources) \
|
||||
$(builtin_sources)
|
||||
|
||||
@ -441,7 +443,7 @@ unit_tests += unit/test-cmac-aes \
|
||||
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-dpp unit/test-json unit/test-nl80211util \
|
||||
unit/test-pmksa
|
||||
unit/test-pmksa unit/test-storage
|
||||
endif
|
||||
|
||||
if CLIENT
|
||||
@ -605,6 +607,11 @@ unit_test_nl80211util_LDADD = $(ell_ldadd)
|
||||
unit_test_pmksa_SOURCES = unit/test-pmksa.c src/pmksa.c src/pmksa.h \
|
||||
src/module.h src/util.h
|
||||
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
|
||||
|
||||
if CLIENT
|
||||
|
||||
156
autotests/testAPRoam/bad_neighbor_report_test.py
Normal file
156
autotests/testAPRoam/bad_neighbor_report_test.py
Normal file
@ -0,0 +1,156 @@
|
||||
#!/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)
|
||||
@ -3,4 +3,4 @@ RoamThreshold=-72
|
||||
CriticalRoamThreshold=-72
|
||||
|
||||
[Blacklist]
|
||||
InitialRoamRequestedTimeout=20
|
||||
InitialAccessPointBusyTimeout=20
|
||||
|
||||
@ -91,16 +91,11 @@ class Test(unittest.TestCase):
|
||||
# using the same static config. The new client's ACD client should
|
||||
# detect an IP conflict and not allow the device to reach the
|
||||
# "connected" state although the DBus .Connect call will succeed.
|
||||
ordered_network.network_object.connect()
|
||||
self.assertEqual(dev2.state, iwd.DeviceState.connecting)
|
||||
try:
|
||||
# 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)
|
||||
self.assertEqual(dev2.state, iwd.DeviceState.disconnecting)
|
||||
except TimeoutError:
|
||||
dev2.disconnect()
|
||||
with self.assertRaises(iwd.FailedEx):
|
||||
ordered_network.network_object.connect(timeout=500)
|
||||
|
||||
condition = 'obj.state == DeviceState.disconnected'
|
||||
iwd_ns0_1.wait_for_object_condition(dev2, condition, max_wait=21)
|
||||
|
||||
iwd_ns0_1.unregister_psk_agent(psk_agent_ns0_1)
|
||||
del dev2
|
||||
|
||||
@ -8,6 +8,8 @@ from iwd import PSKAgent
|
||||
from iwd import NetworkType
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
def connect_failure(self, ex):
|
||||
self.failure_triggered = True
|
||||
|
||||
def test_netconfig_timeout(self):
|
||||
IWD.copy_to_storage('autoconnect.psk', name='ap-ns1.psk')
|
||||
@ -27,23 +29,34 @@ class Test(unittest.TestCase):
|
||||
condition = 'not obj.connected'
|
||||
wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||
|
||||
ordered_network.network_object.connect()
|
||||
self.failure_triggered = False
|
||||
|
||||
condition = 'obj.state == DeviceState.connecting'
|
||||
# Set our error handler here so we can check if it fails
|
||||
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)
|
||||
|
||||
device.wait_for_event("connecting (netconfig)")
|
||||
|
||||
# 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)")
|
||||
# IWD should attempt to connect, but it will of course fail again.
|
||||
device.wait_for_event("netconfig-failed", timeout=1000)
|
||||
|
||||
device.disconnect()
|
||||
condition = 'obj.state == DeviceState.disconnected'
|
||||
|
||||
@ -19,7 +19,7 @@ class Test(unittest.TestCase):
|
||||
|
||||
device = wd.list_devices(1)[0]
|
||||
device.get_ordered_network('TestFT', full_scan=True)
|
||||
device.connect_bssid(self.bss_hostapd[1].bssid)
|
||||
device.connect_bssid(self.bss_hostapd[1].bssid, wait=False)
|
||||
|
||||
self.bss_hostapd[1].wait_for_event(f'AP-STA-CONNECTED {device.address}')
|
||||
device.wait_for_event("connecting (netconfig)")
|
||||
|
||||
114
autotests/testPSK-roam/chan_switch_test.py
Normal file
114
autotests/testPSK-roam/chan_switch_test.py
Normal file
@ -0,0 +1,114 @@
|
||||
#! /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
|
||||
@ -288,13 +288,15 @@ class HostapdCLI(object):
|
||||
cmd = 'RESEND_M3 %s' % address
|
||||
self.ctrl_sock.sendall(cmd.encode('utf-8'))
|
||||
|
||||
def chan_switch(self, channel):
|
||||
def chan_switch(self, channel, wait=True):
|
||||
if channel > len(chan_freq_map):
|
||||
raise Exception("Only 2.4GHz channels supported for chan_switch")
|
||||
|
||||
cmd = self.cmdline + ['chan_switch', '50', str(chan_freq_map[channel])]
|
||||
ctx.start_process(cmd).wait()
|
||||
self.wait_for_event('AP-CSA-FINISHED')
|
||||
|
||||
if wait:
|
||||
self.wait_for_event('AP-CSA-FINISHED')
|
||||
|
||||
def _get_status(self):
|
||||
ret = {}
|
||||
|
||||
@ -112,8 +112,8 @@ class AsyncOpAbstract(object):
|
||||
self._is_completed = True
|
||||
self._exception = _convert_dbus_ex(ex)
|
||||
|
||||
def _wait_for_async_op(self):
|
||||
ctx.non_block_wait(lambda s: s._is_completed, 30, self, exception=None)
|
||||
def _wait_for_async_op(self, timeout=50):
|
||||
ctx.non_block_wait(lambda s: s._is_completed, timeout, self, exception=None)
|
||||
|
||||
self._is_completed = False
|
||||
if self._exception is not None:
|
||||
@ -280,8 +280,15 @@ class StationDebug(IWDDBusAbstract):
|
||||
def autoconnect(self):
|
||||
return self._properties['AutoConnect']
|
||||
|
||||
def connect_bssid(self, address):
|
||||
self._iface.ConnectBssid(dbus.ByteArray.fromhex(address.replace(':', '')))
|
||||
def connect_bssid(self, address, wait=True):
|
||||
self._iface.ConnectBssid(
|
||||
dbus.ByteArray.fromhex(address.replace(':', '')),
|
||||
reply_handler=self._success,
|
||||
error_handler=self._failure
|
||||
)
|
||||
|
||||
if wait:
|
||||
self._wait_for_async_op()
|
||||
|
||||
def roam(self, address):
|
||||
self._iface.Roam(dbus.ByteArray.fromhex(address.replace(':', '')))
|
||||
@ -870,8 +877,8 @@ class Device(IWDDBusAbstract):
|
||||
def stop_adhoc(self):
|
||||
self._prop_proxy.Set(IWD_DEVICE_INTERFACE, 'Mode', 'station')
|
||||
|
||||
def connect_bssid(self, address):
|
||||
self._station_debug.connect_bssid(address)
|
||||
def connect_bssid(self, address, wait=True):
|
||||
self._station_debug.connect_bssid(address, wait=wait)
|
||||
|
||||
def roam(self, address):
|
||||
self._station_debug.roam(address)
|
||||
@ -999,7 +1006,7 @@ class Network(IWDDBusAbstract):
|
||||
def extended_service_set(self):
|
||||
return self._properties['ExtendedServiceSet']
|
||||
|
||||
def connect(self, wait=True):
|
||||
def connect(self, wait=True, timeout=50, reply_handler=None, error_handler=None):
|
||||
'''
|
||||
Connect to the network. Request the device implied by the object
|
||||
path to connect to specified network.
|
||||
@ -1014,12 +1021,19 @@ class Network(IWDDBusAbstract):
|
||||
@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,
|
||||
reply_handler=self._success,
|
||||
error_handler=self._failure)
|
||||
reply_handler=reply_handler,
|
||||
error_handler=error_handler,
|
||||
timeout=timeout)
|
||||
|
||||
if wait:
|
||||
self._wait_for_async_op()
|
||||
self._wait_for_async_op(timeout=timeout)
|
||||
|
||||
def __str__(self, prefix = ''):
|
||||
return prefix + 'Network:\n' \
|
||||
|
||||
@ -95,6 +95,8 @@ static const struct diagnostic_dict_mapping diagnostic_mapping[] = {
|
||||
{ "Frequency", 'u' },
|
||||
{ "Channel", 'q' },
|
||||
{ "Security", 's' },
|
||||
{ "InactiveTime", 'u', "ms" },
|
||||
{ "ConnectedTime", 'u', "s" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([iwd],[3.6])
|
||||
AC_INIT([iwd],[3.10])
|
||||
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
AC_CONFIG_AUX_DIR(build-aux)
|
||||
@ -300,7 +300,7 @@ if (test "${enable_external_ell}" = "yes"); then
|
||||
test "${enable_monitor}" != "no" ||
|
||||
test "${enable_wired}" = "yes" ||
|
||||
test "${enable_hwsim}" = "yes"); then
|
||||
ell_min_version="0.72"
|
||||
ell_min_version="0.77"
|
||||
else
|
||||
ell_min_version="0.5"
|
||||
fi
|
||||
|
||||
@ -31,6 +31,12 @@ Methods array{dict} GetDiagnostics()
|
||||
|
||||
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
|
||||
net.connman.iwd.NotConnected
|
||||
net.connman.iwd.NotFound
|
||||
|
||||
@ -11,6 +11,12 @@ Methods void Connect()
|
||||
the object path to connect to specified network.
|
||||
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
|
||||
net.connman.iwd.Busy
|
||||
net.connman.iwd.Failed
|
||||
|
||||
@ -53,6 +53,12 @@ Methods dict GetDiagnostics()
|
||||
- GCMP-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
|
||||
net.connman.iwd.Failed
|
||||
net.connman.iwd.NotConnected
|
||||
|
||||
@ -404,6 +404,7 @@ static const struct {
|
||||
{ { 0x00, 0x50, 0xf2 }, "Microsoft" },
|
||||
{ { 0x00, 0x90, 0x4c }, "Epigram" },
|
||||
{ { 0x50, 0x6f, 0x9a }, "Wi-Fi Alliance" },
|
||||
{ { 0x00, 0x18, 0x0a }, "Cisco Meraki" },
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -1915,7 +1916,7 @@ static void print_ie_interworking(unsigned int level,
|
||||
size--;
|
||||
ptr++;
|
||||
|
||||
if (!size)
|
||||
if (size < 2)
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -7433,7 +7434,7 @@ static bool check_pcap(struct nlmon *nlmon, size_t next_size)
|
||||
|
||||
pcap_close(nlmon->pcap);
|
||||
|
||||
/* Exausted the single PCAP file */
|
||||
/* Exhausted the single PCAP file */
|
||||
if (nlmon->max_files < 2) {
|
||||
printf("Reached maximum size of PCAP, exiting\n");
|
||||
nlmon->pcap = NULL;
|
||||
|
||||
86
src/ap.c
86
src/ap.c
@ -109,6 +109,8 @@ struct ap_state {
|
||||
struct l_timeout *rekey_timeout;
|
||||
unsigned int rekey_time;
|
||||
|
||||
uint32_t pre_scan_cmd_id;
|
||||
|
||||
bool started : 1;
|
||||
bool gtk_set : 1;
|
||||
bool netconfig_set_addr4 : 1;
|
||||
@ -354,6 +356,12 @@ static void ap_reset(struct ap_state *ap)
|
||||
l_timeout_remove(ap->rekey_timeout);
|
||||
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)
|
||||
@ -3852,6 +3860,70 @@ static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
|
||||
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.
|
||||
*
|
||||
@ -3962,6 +4034,20 @@ struct ap_state *ap_start(struct netdev *netdev, struct l_settings *config,
|
||||
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 (err_out)
|
||||
*err_out = 0;
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
|
||||
static uint64_t blacklist_multiplier;
|
||||
static uint64_t blacklist_initial_timeout;
|
||||
static uint64_t blacklist_roam_initial_timeout;
|
||||
static uint64_t blacklist_ap_busy_initial_timeout;
|
||||
static uint64_t blacklist_max_timeout;
|
||||
|
||||
struct blacklist_entry {
|
||||
@ -67,8 +67,8 @@ static uint64_t get_reason_timeout(enum blacklist_reason reason)
|
||||
switch (reason) {
|
||||
case BLACKLIST_REASON_CONNECT_FAILED:
|
||||
return blacklist_initial_timeout;
|
||||
case BLACKLIST_REASON_ROAM_REQUESTED:
|
||||
return blacklist_roam_initial_timeout;
|
||||
case BLACKLIST_REASON_AP_BUSY:
|
||||
return blacklist_ap_busy_initial_timeout;
|
||||
default:
|
||||
l_warn("Unhandled blacklist reason: %u", reason);
|
||||
return 0;
|
||||
@ -218,11 +218,19 @@ static int blacklist_init(void)
|
||||
|
||||
if (!l_settings_get_uint64(config, "Blacklist",
|
||||
"InitialRoamRequestedTimeout",
|
||||
&blacklist_roam_initial_timeout))
|
||||
blacklist_roam_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT;
|
||||
&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_roam_initial_timeout *= L_USEC_PER_SEC;
|
||||
blacklist_ap_busy_initial_timeout *= L_USEC_PER_SEC;
|
||||
|
||||
if (!l_settings_get_uint64(config, "Blacklist",
|
||||
"Multiplier",
|
||||
|
||||
@ -27,12 +27,14 @@ enum blacklist_reason {
|
||||
*/
|
||||
BLACKLIST_REASON_CONNECT_FAILED,
|
||||
/*
|
||||
* This type of blacklist is added when a BSS requests IWD roams
|
||||
* elsewhere. This is to aid in preventing IWD from roaming/connecting
|
||||
* back to that BSS in the future unless there are no other "good"
|
||||
* candidates to connect to.
|
||||
* 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_ROAM_REQUESTED,
|
||||
BLACKLIST_REASON_AP_BUSY,
|
||||
};
|
||||
|
||||
void blacklist_add_bss(const uint8_t *addr, enum blacklist_reason reason);
|
||||
|
||||
@ -110,6 +110,14 @@ bool diagnostic_info_to_dict(const struct diagnostic_station_info *info,
|
||||
dbus_append_dict_basic(builder, "ExpectedThroughput", 'u',
|
||||
&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;
|
||||
}
|
||||
|
||||
|
||||
@ -43,6 +43,9 @@ struct diagnostic_station_info {
|
||||
|
||||
uint32_t expected_throughput;
|
||||
|
||||
uint32_t inactive_time;
|
||||
uint32_t connected_time;
|
||||
|
||||
bool have_cur_rssi : 1;
|
||||
bool have_avg_rssi : 1;
|
||||
bool have_rx_mcs : 1;
|
||||
@ -50,6 +53,8 @@ struct diagnostic_station_info {
|
||||
bool have_rx_bitrate : 1;
|
||||
bool have_tx_bitrate : 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,
|
||||
|
||||
@ -1166,21 +1166,34 @@ struct dpp_uri_info *dpp_parse_uri(const char *uri)
|
||||
|
||||
switch (*pos) {
|
||||
case 'C':
|
||||
if (L_WARN_ON(info->freqs))
|
||||
goto free_info;
|
||||
|
||||
info->freqs = dpp_parse_class_and_channel(pos + 2, len);
|
||||
if (!info->freqs)
|
||||
goto free_info;
|
||||
break;
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto free_info;
|
||||
break;
|
||||
case 'V':
|
||||
if (L_WARN_ON(info->version != 0))
|
||||
goto free_info;
|
||||
|
||||
ret = dpp_parse_version(pos + 2, len, &info->version);
|
||||
if (ret < 0)
|
||||
goto free_info;
|
||||
break;
|
||||
case 'K':
|
||||
if (L_WARN_ON(info->boot_public))
|
||||
goto free_info;
|
||||
|
||||
info->boot_public = dpp_parse_key(pos + 2, len);
|
||||
if (!info->boot_public)
|
||||
goto free_info;
|
||||
|
||||
@ -544,7 +544,8 @@ static bool eap_mschapv2_load_settings(struct eap_state *eap,
|
||||
return true;
|
||||
|
||||
error:
|
||||
free(state);
|
||||
l_free(state->user);
|
||||
l_free(state);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -425,8 +425,8 @@ static void eap_handle_response(struct eap_state *eap, const uint8_t *pkt,
|
||||
size_t len)
|
||||
{
|
||||
enum eap_type type;
|
||||
uint32_t vendor_id;
|
||||
uint32_t vendor_type;
|
||||
uint32_t vendor_id = 0;
|
||||
uint32_t vendor_type = 0;
|
||||
enum eap_type our_type = eap->method->request_type;
|
||||
uint32_t our_vendor_id = (eap->method->vendor_id[0] << 16) |
|
||||
(eap->method->vendor_id[1] << 8) |
|
||||
|
||||
@ -1810,7 +1810,7 @@ static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm,
|
||||
|
||||
if ((rsne[1] != hs->authenticator_ie[1] ||
|
||||
memcmp(rsne + 2, hs->authenticator_ie + 2, rsne[1])) &&
|
||||
!handshake_util_ap_ie_matches(&rsn_info,
|
||||
!handshake_util_ap_ie_matches(hs, &rsn_info,
|
||||
hs->authenticator_ie,
|
||||
hs->wpa_ie))
|
||||
goto error_ie_different;
|
||||
|
||||
10
src/ft.c
10
src/ft.c
@ -223,7 +223,8 @@ static bool ft_parse_associate_resp_frame(const uint8_t *frame, size_t frame_len
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ft_verify_rsne(const uint8_t *rsne, const uint8_t *pmk_r0_name,
|
||||
static bool ft_verify_rsne(struct handshake_state *hs,
|
||||
const uint8_t *rsne, const uint8_t *pmk_r0_name,
|
||||
const uint8_t *authenticator_ie)
|
||||
{
|
||||
/*
|
||||
@ -253,7 +254,7 @@ static bool ft_verify_rsne(const uint8_t *rsne, const uint8_t *pmk_r0_name,
|
||||
memcmp(msg2_rsne.pmkids, pmk_r0_name, 16))
|
||||
return false;
|
||||
|
||||
if (!handshake_util_ap_ie_matches(&msg2_rsne, authenticator_ie, false))
|
||||
if (!handshake_util_ap_ie_matches(hs, &msg2_rsne, authenticator_ie, false))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -301,7 +302,8 @@ static int parse_ies(struct handshake_state *hs,
|
||||
is_rsn = hs->supplicant_ie != NULL;
|
||||
|
||||
if (is_rsn) {
|
||||
if (!ft_verify_rsne(rsne, hs->pmk_r0_name, authenticator_ie))
|
||||
if (!ft_verify_rsne(hs, rsne, hs->pmk_r0_name,
|
||||
authenticator_ie))
|
||||
goto ft_error;
|
||||
} else if (rsne)
|
||||
goto ft_error;
|
||||
@ -480,7 +482,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))
|
||||
return -EBADMSG;
|
||||
|
||||
if (!handshake_util_ap_ie_matches(&msg4_rsne,
|
||||
if (!handshake_util_ap_ie_matches(hs, &msg4_rsne,
|
||||
hs->authenticator_ie,
|
||||
false))
|
||||
return -EBADMSG;
|
||||
|
||||
@ -368,6 +368,12 @@ 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,
|
||||
const uint8_t *r0khid, size_t r0khid_len,
|
||||
const uint8_t *r1khid)
|
||||
@ -877,7 +883,8 @@ 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
|
||||
* don't match, the EAPoL packet must be silently discarded.
|
||||
*/
|
||||
bool handshake_util_ap_ie_matches(const struct ie_rsn_info *msg_info,
|
||||
bool handshake_util_ap_ie_matches(struct handshake_state *s,
|
||||
const struct ie_rsn_info *msg_info,
|
||||
const uint8_t *scan_ie, bool is_wpa)
|
||||
{
|
||||
struct ie_rsn_info scan_info;
|
||||
@ -907,11 +914,15 @@ bool handshake_util_ap_ie_matches(const struct ie_rsn_info *msg_info,
|
||||
if (msg_info->no_pairwise != scan_info.no_pairwise)
|
||||
return false;
|
||||
|
||||
if (msg_info->ptksa_replay_counter != scan_info.ptksa_replay_counter)
|
||||
return false;
|
||||
if (!(s->vendor_quirks.replay_counter_mismatch)) {
|
||||
if (msg_info->ptksa_replay_counter !=
|
||||
scan_info.ptksa_replay_counter)
|
||||
return false;
|
||||
|
||||
if (msg_info->gtksa_replay_counter != scan_info.gtksa_replay_counter)
|
||||
return false;
|
||||
if (msg_info->gtksa_replay_counter !=
|
||||
scan_info.gtksa_replay_counter)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (msg_info->mfpr != scan_info.mfpr)
|
||||
return false;
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
#include <linux/types.h>
|
||||
#include <ell/cleanup.h>
|
||||
|
||||
#include "src/vendor_quirks.h"
|
||||
|
||||
struct handshake_state;
|
||||
enum crypto_cipher;
|
||||
struct eapol_frame;
|
||||
@ -107,6 +109,7 @@ struct handshake_state {
|
||||
uint8_t *authenticator_fte;
|
||||
uint8_t *supplicant_fte;
|
||||
uint8_t *vendor_ies;
|
||||
struct vendor_quirk vendor_quirks;
|
||||
size_t vendor_ies_len;
|
||||
enum ie_rsn_cipher_suite pairwise_cipher;
|
||||
enum ie_rsn_cipher_suite group_cipher;
|
||||
@ -237,6 +240,9 @@ void handshake_state_set_vendor_ies(struct handshake_state *s,
|
||||
const struct iovec *iov,
|
||||
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,
|
||||
const uint8_t *r0khid, size_t r0khid_len,
|
||||
const uint8_t *r1khid);
|
||||
@ -312,7 +318,8 @@ bool handshake_state_set_pmksa(struct handshake_state *s, struct pmksa *pmksa);
|
||||
void handshake_state_cache_pmksa(struct handshake_state *s);
|
||||
bool handshake_state_remove_pmksa(struct handshake_state *s);
|
||||
|
||||
bool handshake_util_ap_ie_matches(const struct ie_rsn_info *msg_info,
|
||||
bool handshake_util_ap_ie_matches(struct handshake_state *s,
|
||||
const struct ie_rsn_info *msg_info,
|
||||
const uint8_t *scan_ie, bool is_wpa);
|
||||
|
||||
const uint8_t *handshake_util_find_kde(enum handshake_kde selector,
|
||||
|
||||
@ -292,12 +292,22 @@ control how long a misbehaved BSS spends on the blacklist.
|
||||
|
||||
The initial time that a BSS spends on the blacklist. Setting this to zero
|
||||
will disable blacklisting functionality in IWD.
|
||||
* - InitialRoamRequestedTimeout
|
||||
* - InitialRoamRequestedTimeout (**deprecated**)
|
||||
- Values: uint64 value in seconds (default: **30**)
|
||||
|
||||
The initial time that a BSS will be marked after a BSS requests a roam.
|
||||
This is to aid in avoiding roaming back to BSS's which are likely
|
||||
overloaded. Setting this to zero will disabled this form of blacklisting.
|
||||
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
|
||||
- Values: unsigned int value greater than zero, in seconds
|
||||
(default: **30**)
|
||||
|
||||
73
src/netdev.c
73
src/netdev.c
@ -637,7 +637,6 @@ static bool netdev_parse_sta_info(struct l_genl_attr *attr,
|
||||
info->have_tx_mcs = true;
|
||||
|
||||
break;
|
||||
|
||||
case NL80211_STA_INFO_EXPECTED_THROUGHPUT:
|
||||
if (len != 4)
|
||||
return false;
|
||||
@ -645,6 +644,22 @@ static bool netdev_parse_sta_info(struct l_genl_attr *attr,
|
||||
info->expected_throughput = l_get_u32(data);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2993,13 +3008,26 @@ static void netdev_cmd_ft_reassociate_cb(struct l_genl_msg *msg,
|
||||
void *user_data)
|
||||
{
|
||||
struct netdev *netdev = user_data;
|
||||
int err = l_genl_msg_get_error(msg);
|
||||
|
||||
netdev->connect_cmd_id = 0;
|
||||
|
||||
if (l_genl_msg_get_error(msg) >= 0)
|
||||
l_debug("%d", err);
|
||||
|
||||
if (err >= 0)
|
||||
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,
|
||||
MMPDU_STATUS_CODE_UNSPECIFIED);
|
||||
}
|
||||
@ -5402,6 +5430,9 @@ static void netdev_channel_switch_event(struct l_genl_msg *msg,
|
||||
if (netdev->type != NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
|
||||
if (L_WARN_ON(!netdev->connected))
|
||||
return;
|
||||
|
||||
chandef = l_new(struct band_chandef, 1);
|
||||
|
||||
if (nl80211_parse_chandef(msg, chandef) < 0) {
|
||||
@ -5451,6 +5482,39 @@ static void netdev_michael_mic_failure(struct l_genl_msg *msg,
|
||||
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)
|
||||
{
|
||||
struct netdev *netdev = NULL;
|
||||
@ -5504,6 +5568,9 @@ static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data)
|
||||
case NL80211_CMD_MICHAEL_MIC_FAILURE:
|
||||
netdev_michael_mic_failure(msg, netdev);
|
||||
break;
|
||||
case NL80211_CMD_ASSOC_COMEBACK:
|
||||
netdev_assoc_comeback(msg, netdev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -168,6 +168,11 @@ static bool network_secret_check_cacheable(void *data, void *user_data)
|
||||
return false;
|
||||
}
|
||||
|
||||
void network_clear_blacklist(struct network *network)
|
||||
{
|
||||
l_queue_clear(network->blacklist, NULL);
|
||||
}
|
||||
|
||||
void network_connected(struct network *network)
|
||||
{
|
||||
enum security security = network_get_security(network);
|
||||
@ -198,8 +203,6 @@ void network_connected(struct network *network)
|
||||
l_queue_foreach_remove(network->secrets,
|
||||
network_secret_check_cacheable, network);
|
||||
|
||||
l_queue_clear(network->blacklist, NULL);
|
||||
|
||||
network->provisioning_hidden = false;
|
||||
}
|
||||
|
||||
@ -207,7 +210,7 @@ void network_disconnected(struct network *network)
|
||||
{
|
||||
network_settings_close(network);
|
||||
|
||||
l_queue_clear(network->blacklist, NULL);
|
||||
network_clear_blacklist(network);
|
||||
|
||||
if (network->provisioning_hidden)
|
||||
station_hide_network(network->station, network);
|
||||
|
||||
@ -74,6 +74,7 @@ bool network_bss_update(struct network *network, struct scan_bss *bss);
|
||||
const char *network_bss_get_path(const struct network *network,
|
||||
const struct scan_bss *bss);
|
||||
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 struct scan_bss *bss);
|
||||
|
||||
@ -177,6 +177,7 @@ static const struct {
|
||||
{ NL80211_CMD_UNPROT_BEACON, "Unprotected Beacon" },
|
||||
{ NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,
|
||||
"Control Port TX Status" },
|
||||
{ NL80211_CMD_ASSOC_COMEBACK, "Association comeback delay" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@ -190,6 +190,7 @@ static attr_handler handler_for_nl80211(int type)
|
||||
case NL80211_ATTR_CENTER_FREQ2:
|
||||
case NL80211_ATTR_AKM_SUITES:
|
||||
case NL80211_ATTR_EXTERNAL_AUTH_ACTION:
|
||||
case NL80211_ATTR_TIMEOUT:
|
||||
return extract_uint32;
|
||||
case NL80211_ATTR_FRAME:
|
||||
return extract_iovec;
|
||||
|
||||
22
src/sae.c
22
src/sae.c
@ -169,6 +169,14 @@ static int sae_choose_next_group(struct sae_sm *sm)
|
||||
!sm->handshake->ecc_sae_pts[sm->group_retry])
|
||||
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;
|
||||
}
|
||||
|
||||
@ -994,7 +1002,8 @@ static int sae_process_anti_clogging(struct sae_sm *sm, const uint8_t *ptr,
|
||||
sm->token_len = len;
|
||||
sm->sync = 0;
|
||||
|
||||
sae_send_commit(sm, true);
|
||||
if (L_WARN_ON(!sae_send_commit(sm, true)))
|
||||
return -EPROTO;
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
@ -1074,7 +1083,9 @@ static int sae_verify_committed(struct sae_sm *sm, uint16_t transaction,
|
||||
return -ETIMEDOUT;
|
||||
|
||||
sm->sync++;
|
||||
sae_send_commit(sm, true);
|
||||
|
||||
if (L_WARN_ON(!sae_send_commit(sm, true)))
|
||||
return -EPROTO;
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
@ -1129,7 +1140,9 @@ static int sae_verify_committed(struct sae_sm *sm, uint16_t transaction,
|
||||
sm->group);
|
||||
|
||||
sm->sync = 0;
|
||||
sae_send_commit(sm, false);
|
||||
|
||||
if (L_WARN_ON(!sae_send_commit(sm, false)))
|
||||
return -EPROTO;
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
@ -1294,7 +1307,8 @@ static int sae_verify_confirmed(struct sae_sm *sm, uint16_t trans,
|
||||
sm->sync++;
|
||||
sm->sc++;
|
||||
|
||||
sae_send_commit(sm, true);
|
||||
if (L_WARN_ON(!sae_send_commit(sm, true)))
|
||||
return -EPROTO;
|
||||
|
||||
if (!sae_send_confirm(sm))
|
||||
return -EPROTO;
|
||||
|
||||
15
src/scan.c
15
src/scan.c
@ -51,6 +51,7 @@
|
||||
#include "src/mpdu.h"
|
||||
#include "src/band.h"
|
||||
#include "src/scan.h"
|
||||
#include "src/vendor_quirks.h"
|
||||
|
||||
/* User configurable options */
|
||||
static double RANK_2G_FACTOR;
|
||||
@ -143,9 +144,9 @@ struct scan_survey {
|
||||
};
|
||||
|
||||
struct scan_survey_results {
|
||||
struct scan_survey survey_2_4[14];
|
||||
struct scan_survey survey_5[196];
|
||||
struct scan_survey survey_6[233];
|
||||
struct scan_survey survey_2_4[15];
|
||||
struct scan_survey survey_5[197];
|
||||
struct scan_survey survey_6[234];
|
||||
};
|
||||
|
||||
struct scan_results {
|
||||
@ -414,7 +415,8 @@ static struct l_genl_msg *scan_build_cmd(struct scan_context *sc,
|
||||
if (params->ap_scan)
|
||||
flags |= NL80211_SCAN_FLAG_AP;
|
||||
|
||||
flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
|
||||
if (wiphy_supports_colocated_flag(sc->wiphy))
|
||||
flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
|
||||
|
||||
if (flags)
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_SCAN_FLAGS, 4, &flags);
|
||||
@ -1220,6 +1222,11 @@ static void scan_parse_vendor_specific(struct scan_bss *bss, const void *data,
|
||||
uint16_t cost_flags;
|
||||
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)) {
|
||||
bss->wpa = l_memdup(data - 2, len + 2);
|
||||
return;
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include "src/defs.h"
|
||||
#include "src/vendor_quirks.h"
|
||||
|
||||
struct scan_freq_set;
|
||||
struct ie_rsn_info;
|
||||
@ -79,6 +80,7 @@ struct scan_bss {
|
||||
uint8_t *wfd; /* Concatenated WFD IEs */
|
||||
ssize_t wfd_size; /* Size of Concatenated WFD IEs */
|
||||
int8_t snr;
|
||||
struct vendor_quirk vendor_quirks;
|
||||
bool mde_present : 1;
|
||||
bool cc_present : 1;
|
||||
bool cap_rm_neighbor_report : 1;
|
||||
|
||||
194
src/station.c
194
src/station.c
@ -64,6 +64,7 @@
|
||||
#include "src/eap-tls-common.h"
|
||||
#include "src/storage.h"
|
||||
#include "src/pmksa.h"
|
||||
#include "src/vendor_quirks.h"
|
||||
|
||||
#define STATION_RECENT_NETWORK_LIMIT 5
|
||||
#define STATION_RECENT_FREQS_LIMIT 5
|
||||
@ -191,8 +192,7 @@ static uint32_t evaluate_bss_group_rank(const uint8_t *addr, uint32_t freq,
|
||||
if (blacklist_contains_bss(addr, BLACKLIST_REASON_CONNECT_FAILED))
|
||||
return 0;
|
||||
|
||||
roam_blacklist = blacklist_contains_bss(addr,
|
||||
BLACKLIST_REASON_ROAM_REQUESTED);
|
||||
roam_blacklist = blacklist_contains_bss(addr, BLACKLIST_REASON_AP_BUSY);
|
||||
good_signal = signal >= netdev_get_low_signal_threshold(freq);
|
||||
|
||||
if (good_signal)
|
||||
@ -1447,6 +1447,8 @@ static struct handshake_state *station_handshake_setup(struct station *station,
|
||||
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_quirks(hs, bss->vendor_quirks);
|
||||
|
||||
/*
|
||||
* It can't hurt to try the FILS IP Address Assignment independent of
|
||||
* which auth-proto is actually used.
|
||||
@ -1796,6 +1798,15 @@ static void station_enter_state(struct station *station,
|
||||
periodic_scan_stop(station);
|
||||
break;
|
||||
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,
|
||||
netdev_get_path(station->netdev),
|
||||
IWD_STATION_DIAGNOSTIC_INTERFACE,
|
||||
@ -2215,6 +2226,26 @@ static void station_early_neighbor_report_cb(struct netdev *netdev, int err,
|
||||
&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,
|
||||
struct handshake_state *hs,
|
||||
struct scan_bss *bss)
|
||||
@ -2257,28 +2288,26 @@ static bool station_can_fast_transition(struct station *station,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void station_disconnect_on_error_cb(struct netdev *netdev, bool success,
|
||||
void *user_data)
|
||||
static void station_disconnect_on_netconfig_failed(struct netdev *netdev,
|
||||
bool success,
|
||||
void *user_data)
|
||||
{
|
||||
struct station *station = user_data;
|
||||
bool continue_autoconnect;
|
||||
|
||||
station_enter_state(station, STATION_STATE_DISCONNECTED);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (station->autoconnect)
|
||||
station_enter_state(station, STATION_STATE_AUTOCONNECT_QUICK);
|
||||
station_reset_connection_state(station);
|
||||
|
||||
station_enter_state(station, STATION_STATE_DISCONNECTED);
|
||||
station_enter_state(station, STATION_STATE_AUTOCONNECT_FULL);
|
||||
}
|
||||
|
||||
static void station_netconfig_event_handler(enum netconfig_event event,
|
||||
@ -2291,23 +2320,20 @@ static void station_netconfig_event_handler(enum netconfig_event event,
|
||||
station_enter_state(station, STATION_STATE_CONNECTED);
|
||||
break;
|
||||
case NETCONFIG_EVENT_FAILED:
|
||||
if (station->connect_pending) {
|
||||
struct l_dbus_message *reply = dbus_error_failed(
|
||||
station->connect_pending);
|
||||
station_debug_event(station, "netconfig-failed");
|
||||
|
||||
dbus_pending_reply(&station->connect_pending, reply);
|
||||
}
|
||||
netconfig_reset(station->netconfig);
|
||||
|
||||
if (station->state == STATION_STATE_NETCONFIG)
|
||||
network_connect_failed(station->connected_network,
|
||||
false);
|
||||
|
||||
netdev_disconnect(station->netdev,
|
||||
station_disconnect_on_error_cb,
|
||||
station);
|
||||
station_reset_connection_state(station);
|
||||
network_blacklist_add(station->connected_network,
|
||||
station->connected_bss);
|
||||
|
||||
station_enter_state(station, STATION_STATE_DISCONNECTING);
|
||||
netdev_disconnect(station->netdev,
|
||||
station_disconnect_on_netconfig_failed,
|
||||
station);
|
||||
break;
|
||||
default:
|
||||
l_error("station: Unsupported netconfig event: %d.", event);
|
||||
@ -2381,6 +2407,11 @@ static void station_roam_retry(struct station *station)
|
||||
station->roam_scan_full = 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)
|
||||
station_roam_timeout_rearm(station, roam_retry_interval);
|
||||
}
|
||||
@ -2410,8 +2441,16 @@ static void station_roam_failed(struct station *station)
|
||||
* We were told by the AP to roam, but failed. Try ourselves or
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we tried a limited scan, failed and the signal is still low,
|
||||
@ -2423,6 +2462,7 @@ static void station_roam_failed(struct station *station)
|
||||
* the scan here, so that the destroy callback is not called
|
||||
* after the return of this function
|
||||
*/
|
||||
full_scan:
|
||||
scan_cancel(netdev_get_wdev_id(station->netdev),
|
||||
station->roam_scan_id);
|
||||
|
||||
@ -2710,11 +2750,15 @@ static bool station_try_next_transition(struct station *station,
|
||||
enum security security = network_get_security(connected);
|
||||
struct handshake_state *new_hs;
|
||||
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",
|
||||
MAC_STR(bss->addr),
|
||||
bss->signal_strength / 100,
|
||||
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 */
|
||||
station->ap_directed_roaming = false;
|
||||
@ -3015,6 +3059,7 @@ static int station_roam_scan(struct station *station,
|
||||
if (!freq_set) {
|
||||
station->roam_scan_full = true;
|
||||
params.freqs = allowed;
|
||||
station_debug_event(station, "full-roam-scan");
|
||||
} else
|
||||
scan_freq_set_constrain(freq_set, allowed);
|
||||
|
||||
@ -3226,6 +3271,8 @@ static void station_ap_directed_roam(struct station *station,
|
||||
uint16_t dtimer;
|
||||
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));
|
||||
|
||||
@ -3326,7 +3373,7 @@ static void station_ap_directed_roam(struct station *station,
|
||||
}
|
||||
|
||||
blacklist_add_bss(station->connected_bss->addr,
|
||||
BLACKLIST_REASON_ROAM_REQUESTED);
|
||||
BLACKLIST_REASON_AP_BUSY);
|
||||
station_debug_event(station, "ap-roam-blacklist-added");
|
||||
|
||||
/*
|
||||
@ -3343,12 +3390,21 @@ static void station_ap_directed_roam(struct station *station,
|
||||
l_timeout_remove(station->roam_trigger_timeout);
|
||||
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");
|
||||
station_neighbor_report_cb(station->netdev, 0, body + pos,
|
||||
body_len - pos, station);
|
||||
} else {
|
||||
l_debug("roam: AP did not include a preferred candidate list");
|
||||
if (station->connected_bss->cap_rm_neighbor_report) {
|
||||
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)
|
||||
station_roam_failed(station);
|
||||
}
|
||||
@ -3410,26 +3466,6 @@ static void station_event_channel_switched(struct station *station,
|
||||
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)
|
||||
{
|
||||
/*
|
||||
@ -3523,13 +3559,6 @@ static bool station_pmksa_fallback(struct station *station, uint16_t status)
|
||||
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,
|
||||
uint16_t status_code)
|
||||
{
|
||||
@ -3537,19 +3566,37 @@ static bool station_retry_with_status(struct station *station,
|
||||
if (station_pmksa_fallback(station, status_code))
|
||||
goto try_next;
|
||||
|
||||
switch (status_code) {
|
||||
/*
|
||||
* Certain Auth/Assoc failures should not cause a timeout blacklist.
|
||||
* In these cases we want to only temporarily blacklist the BSS until
|
||||
* 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
|
||||
* report IE in the frame. This would allow us to target a
|
||||
* specific BSS on our next attempt. There is currently no way to
|
||||
* obtain that IE, but this should be done in the future.
|
||||
*/
|
||||
case MMPDU_STATUS_CODE_REJECTED_WITH_SUGG_BSS_TRANS:
|
||||
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.
|
||||
*/
|
||||
if (!IS_TEMPORARY_STATUS(status_code))
|
||||
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
|
||||
@ -3571,13 +3618,6 @@ static void station_connect_ok(struct station *station)
|
||||
|
||||
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
|
||||
* a report at that time
|
||||
@ -3877,6 +3917,7 @@ int __station_connect_network(struct station *station, struct network *network,
|
||||
{
|
||||
struct handshake_state *hs;
|
||||
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,
|
||||
@ -3911,6 +3952,10 @@ int __station_connect_network(struct station *station, struct network *network,
|
||||
bss->signal_strength / 100,
|
||||
bss->utilization);
|
||||
|
||||
if (vendor_quirks)
|
||||
l_debug("vendor quirks for "MAC": %s",
|
||||
MAC_STR(bss->addr), vendor_quirks);
|
||||
|
||||
station->connected_bss = bss;
|
||||
station->connected_network = network;
|
||||
station->hs = handshake_state_ref(hs);
|
||||
@ -4815,7 +4860,7 @@ static struct l_dbus_message *station_property_set_affinities(
|
||||
struct l_dbus_message_iter array;
|
||||
const char *sender = l_dbus_message_get_sender(message);
|
||||
char *old_path = l_queue_peek_head(station->affinities);
|
||||
const char *new_path = NULL;
|
||||
const char *new_path;
|
||||
struct scan_bss *new_bss = NULL;
|
||||
struct scan_bss *old_bss = NULL;
|
||||
bool lower_threshold = false;
|
||||
@ -4835,10 +4880,15 @@ static struct l_dbus_message *station_property_set_affinities(
|
||||
if (!l_dbus_message_iter_get_variant(new_value, "ao", &array))
|
||||
return dbus_error_invalid_args(message);
|
||||
|
||||
/* Get first entry, there should be only one */
|
||||
l_dbus_message_iter_next_entry(&array, &new_path);
|
||||
/* Get first entry, or if an empty array set the path to NULL */
|
||||
if (!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);
|
||||
|
||||
old_path = l_queue_peek_head(station->affinities);
|
||||
|
||||
@ -500,6 +500,13 @@ int __storage_decrypt(struct l_settings *settings, const char *ssid,
|
||||
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
|
||||
* the decrypted data portion. We add one here for the NULL terminator
|
||||
|
||||
84
src/vendor_quirks.c
Normal file
84
src/vendor_quirks.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
39
src/vendor_quirks.h
Normal file
39
src/vendor_quirks.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
*
|
||||
* 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 */
|
||||
35
src/wiphy.c
35
src/wiphy.c
@ -69,12 +69,26 @@ static uint32_t work_ids;
|
||||
static unsigned int wiphy_dump_id;
|
||||
|
||||
enum driver_flag {
|
||||
/* Force the use of the default interface created by the kernel */
|
||||
DEFAULT_IF = 0x1,
|
||||
/*
|
||||
* Force the use of the PAE socket rather than control port, even if
|
||||
* control port is supported
|
||||
*/
|
||||
FORCE_PAE = 0x2,
|
||||
/* Disable power save on the adapter during initialization */
|
||||
POWER_SAVE_DISABLE = 0x4,
|
||||
/* Don't use OWE when connecting to open networks */
|
||||
OWE_DISABLE = 0x8,
|
||||
/* Disables multicast RX frame registration */
|
||||
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 {
|
||||
@ -103,12 +117,13 @@ static const struct driver_info driver_infos[] = {
|
||||
};
|
||||
|
||||
static const struct driver_flag_name driver_flag_names[] = {
|
||||
{ "DefaultInterface", DEFAULT_IF },
|
||||
{ "ForcePae", FORCE_PAE },
|
||||
{ "PowerSaveDisable", POWER_SAVE_DISABLE },
|
||||
{ "OweDisable", OWE_DISABLE },
|
||||
{ "MulticastRxDisable", MULTICAST_RX_DISABLE },
|
||||
{ "SaeDisable", SAE_DISABLE },
|
||||
{ "DefaultInterface", DEFAULT_IF },
|
||||
{ "ForcePae", FORCE_PAE },
|
||||
{ "PowerSaveDisable", POWER_SAVE_DISABLE },
|
||||
{ "OweDisable", OWE_DISABLE },
|
||||
{ "MulticastRxDisable", MULTICAST_RX_DISABLE },
|
||||
{ "SaeDisable", SAE_DISABLE },
|
||||
{ "ColocatedScanDisable", COLOCATED_SCAN_DISABLE },
|
||||
};
|
||||
|
||||
struct wiphy {
|
||||
@ -963,6 +978,11 @@ bool wiphy_supports_multicast_rx(const struct wiphy *wiphy)
|
||||
!(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,
|
||||
enum band_freq band,
|
||||
size_t *size)
|
||||
@ -1382,6 +1402,9 @@ static void wiphy_print_basic_info(struct wiphy *wiphy)
|
||||
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, ' ');
|
||||
|
||||
l_info("\tDriver Flags: %s", joined);
|
||||
|
||||
@ -144,6 +144,7 @@ bool wiphy_country_is_unknown(struct wiphy *wiphy);
|
||||
bool wiphy_supports_uapsd(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_colocated_flag(const struct wiphy *wiphy);
|
||||
|
||||
const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy,
|
||||
enum band_freq band,
|
||||
|
||||
@ -138,20 +138,22 @@ static const struct cmac_data example_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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
|
||||
if (!l_checksum_cmac_aes_supported()) {
|
||||
printf("AES-CMAC support missing, skipping...\n");
|
||||
goto done;
|
||||
}
|
||||
add_test("/cmac-aes/Example 1", cmac_test, &example_1);
|
||||
add_test("/cmac-aes/Example 2", cmac_test, &example_2);
|
||||
add_test("/cmac-aes/Example 3", cmac_test, &example_3);
|
||||
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();
|
||||
}
|
||||
|
||||
@ -403,40 +403,32 @@ static void aes_siv_test(const void *data)
|
||||
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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
|
||||
if (!l_checksum_is_supported(L_CHECKSUM_SHA1, true)) {
|
||||
printf("SHA1 support missing, skipping...\n");
|
||||
goto done;
|
||||
}
|
||||
add_test("/Passphrase Generator/PSK Test Case 1",
|
||||
psk_test, &psk_test_case_1);
|
||||
add_test("/Passphrase Generator/PSK Test Case 2",
|
||||
psk_test, &psk_test_case_2);
|
||||
add_test("/Passphrase Generator/PSK Test Case 3",
|
||||
psk_test, &psk_test_case_3);
|
||||
|
||||
if (!l_cipher_is_supported(L_CIPHER_AES)) {
|
||||
printf("AES support missing, skipping...\n");
|
||||
goto done;
|
||||
}
|
||||
add_test("/PTK Derivation/PTK Test Case 1", ptk_test, &ptk_test_1);
|
||||
add_test("/PTK Derivation/PTK Test Case 2", ptk_test, &ptk_test_2);
|
||||
add_test("/PTK Derivation/PTK Test Case 3", ptk_test, &ptk_test_3);
|
||||
add_test("/PTK Derivation/PTK Test Case 4", ptk_test, &ptk_test_4);
|
||||
|
||||
l_test_add("/Passphrase Generator/PSK Test Case 1",
|
||||
psk_test, &psk_test_case_1);
|
||||
l_test_add("/Passphrase Generator/PSK Test Case 2",
|
||||
psk_test, &psk_test_case_2);
|
||||
l_test_add("/Passphrase Generator/PSK Test Case 3",
|
||||
psk_test, &psk_test_case_3);
|
||||
add_test("/AES Key-wrap/Wrap & unwrap", aes_wrap_test, NULL);
|
||||
add_test("/AES-SIV", aes_siv_test, NULL);
|
||||
|
||||
l_test_add("/PTK Derivation/PTK Test Case 1",
|
||||
ptk_test, &ptk_test_1);
|
||||
l_test_add("/PTK Derivation/PTK Test Case 2",
|
||||
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);
|
||||
|
||||
l_test_add("/AES Key-wrap/Wrap & unwrap",
|
||||
aes_wrap_test, NULL);
|
||||
l_test_add("/AES-SIV", aes_siv_test, NULL);
|
||||
|
||||
done:
|
||||
return l_test_run();
|
||||
}
|
||||
|
||||
@ -116,6 +116,29 @@ 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,
|
||||
const struct dpp_test_info *result)
|
||||
{
|
||||
@ -158,6 +181,14 @@ static void test_bad_channels(const void *data)
|
||||
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 {
|
||||
/* Initiator values */
|
||||
const char *i_proto_public;
|
||||
@ -546,22 +577,25 @@ static void test_pkex_key_derivation(const void *user_data)
|
||||
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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
|
||||
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);
|
||||
l_test_add("DPP test mutual key derivation",
|
||||
test_key_derivation,
|
||||
&mutual_p256);
|
||||
l_test_add("DPP test PKEX key derivation",
|
||||
test_pkex_key_derivation,
|
||||
&pkex_vector);
|
||||
}
|
||||
add_test("DPP test responder-only key derivation", test_key_derivation,
|
||||
&responder_only_p256);
|
||||
add_test("DPP test mutual key derivation", test_key_derivation,
|
||||
&mutual_p256);
|
||||
add_test("DPP test PKEX key derivation", test_pkex_key_derivation,
|
||||
&pkex_vector);
|
||||
|
||||
l_test_add("DPP URI parse", test_uri_parse, &all_values);
|
||||
l_test_add("DPP URI no type", test_uri_parse, &no_type);
|
||||
@ -576,6 +610,7 @@ int main(int argc, char *argv[])
|
||||
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 unexpected ID", test_uri_parse, &unexpected_id);
|
||||
l_test_add("DPP URI duplicates", test_duplicate_in_uri, &duplicates);
|
||||
|
||||
return l_test_run();
|
||||
}
|
||||
|
||||
@ -131,27 +131,23 @@ static void test_get_asym_key(const void *data)
|
||||
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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
|
||||
if (!l_checksum_is_supported(L_CHECKSUM_MD4, false)) {
|
||||
printf("MD4 support missing, skipping...\n");
|
||||
goto done;
|
||||
}
|
||||
add_test("MSHAPv2 nt_password-hash", test_nt_password_hash);
|
||||
add_test("MSHAPv2 generate_nt_response", test_generate_nt_response);
|
||||
add_test("MSHAPv2 get_master_key", test_get_master_key);
|
||||
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();
|
||||
}
|
||||
|
||||
@ -3908,6 +3908,38 @@ 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_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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
@ -3977,80 +4009,55 @@ int main(int argc, char *argv[])
|
||||
l_test_add("/EAPoL Key/Key Frame 32",
|
||||
eapol_key_test, &eapol_key_test_32);
|
||||
|
||||
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",
|
||||
add_hash_test("/EAPoL Key/MIC Test 1",
|
||||
eapol_key_mic_test, &eapol_key_mic_test_1);
|
||||
l_test_add("/EAPoL Key/MIC Test 2",
|
||||
add_hash_test("/EAPoL Key/MIC Test 2",
|
||||
eapol_key_mic_test, &eapol_key_mic_test_2);
|
||||
|
||||
l_test_add("/EAPoL Key/Calculate MIC Test 1",
|
||||
add_hash_test("/EAPoL Key/Calculate MIC Test 1",
|
||||
eapol_calculate_mic_test, &eapol_calculate_mic_test_1);
|
||||
|
||||
if (!l_cipher_is_supported(L_CIPHER_AES))
|
||||
goto done;
|
||||
add_aes_test("EAPoL/WPA2 4-Way Handshake",
|
||||
eapol_4way_test, NULL);
|
||||
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);
|
||||
|
||||
l_test_add("EAPoL/WPA2 4-Way Handshake",
|
||||
&eapol_4way_test, NULL);
|
||||
add_pkcs8_test("EAPoL/8021x EAP-TLS & 4-Way Handshake",
|
||||
eapol_sm_test_eap_tls, 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);
|
||||
|
||||
l_test_add("EAPoL/WPA2 4-Way & GTK Handshake",
|
||||
&eapol_wpa2_handshake_test, NULL);
|
||||
add_aes_test("EAPoL/FT-Using-PSK 4-Way Handshake",
|
||||
eapol_ft_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();
|
||||
}
|
||||
|
||||
@ -81,18 +81,20 @@ static const struct hmac_data test_case_2 = {
|
||||
.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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
|
||||
if (!l_checksum_is_supported(L_CHECKSUM_MD5, true)) {
|
||||
printf("MD5 support missing, skipping...\n");
|
||||
goto done;
|
||||
}
|
||||
add_test("/hmac-md5/Test case 1", hmac_test, &test_case_1);
|
||||
add_test("/hmac-md5/Test case 2", hmac_test, &test_case_2);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -81,18 +81,20 @@ static const struct hmac_data test_case_2 = {
|
||||
.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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
|
||||
if (!l_checksum_is_supported(L_CHECKSUM_SHA1, true)) {
|
||||
printf("SHA1 support missing, skipping...\n");
|
||||
goto done;
|
||||
}
|
||||
add_test("/hmac-sha1/Test case 1", hmac_test, &test_case_1);
|
||||
add_test("/hmac-sha1/Test case 2", hmac_test, &test_case_2);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -83,18 +83,20 @@ static const struct hmac_data test_case_2 = {
|
||||
"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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
|
||||
if (!l_checksum_is_supported(L_CHECKSUM_SHA256, true)) {
|
||||
printf("SHA256 support missing, skipping...\n");
|
||||
goto done;
|
||||
}
|
||||
add_test("/hmac-sha256/Test case 1", hmac_test, &test_case_1);
|
||||
add_test("/hmac-sha256/Test case 2", hmac_test, &test_case_2);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -81,17 +81,19 @@ static const struct kdf_data test_case_1 = {
|
||||
"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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
|
||||
if (!l_checksum_is_supported(L_CHECKSUM_SHA256, true)) {
|
||||
printf("SHA256 support missing, skipping...\n");
|
||||
goto done;
|
||||
}
|
||||
add_test("/kdf-sha256/Test case 1", kdf_test, &test_case_1);
|
||||
|
||||
l_test_add("/kdf-sha256/Test case 1", kdf_test, &test_case_1);
|
||||
|
||||
done:
|
||||
return l_test_run();
|
||||
}
|
||||
|
||||
@ -341,7 +341,7 @@ static const struct p2p_probe_req_data p2p_probe_req_data_1 = {
|
||||
.group_caps = 0,
|
||||
},
|
||||
.listen_channel = {
|
||||
.country = "XX\x04",
|
||||
.country = { 'X', 'X', '\x04' },
|
||||
.oper_class = 81,
|
||||
.channel_num = 1,
|
||||
},
|
||||
|
||||
@ -113,19 +113,21 @@ static const struct prf_data test_case_3 = {
|
||||
"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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
|
||||
if (!l_checksum_is_supported(L_CHECKSUM_SHA1, true)) {
|
||||
printf("SHA1 support missing, skipping...\n");
|
||||
goto done;
|
||||
}
|
||||
add_test("/prf-sha1/Test case 1", prf_test, &test_case_1);
|
||||
add_test("/prf-sha1/Test case 2", prf_test, &test_case_2);
|
||||
add_test("/prf-sha1/Test case 3", prf_test, &test_case_3);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -871,32 +871,29 @@ static void test_pt_pwe(const void *data)
|
||||
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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
|
||||
if (!l_getrandom_is_supported()) {
|
||||
l_info("l_getrandom not supported, skipping...");
|
||||
goto done;
|
||||
}
|
||||
add_test("SAE anti-clogging", test_clogging);
|
||||
add_test("SAE early confirm", test_early_confirm);
|
||||
add_test("SAE reflection", test_reflection);
|
||||
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();
|
||||
}
|
||||
|
||||
66
unit/test-storage.c
Normal file
66
unit/test-storage.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
*
|
||||
* 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();
|
||||
}
|
||||
153
unit/test-wsc.c
153
unit/test-wsc.c
@ -2574,6 +2574,40 @@ struct wsc_credential wsc_r_test_open_cred = {
|
||||
.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[])
|
||||
{
|
||||
l_test_init(&argc, &argv);
|
||||
@ -2595,8 +2629,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 checksum", wsc_test_pin_checksum, NULL);
|
||||
|
||||
if (l_getrandom_is_supported())
|
||||
l_test_add("/wsc/pin/generate", wsc_test_pin_generate, NULL);
|
||||
l_test_add_func_precheck("/wsc/pin/generate", wsc_test_pin_generate,
|
||||
getrandom_precheck, 0);
|
||||
|
||||
l_test_add("/wsc/gen_uuid/1", wsc_test_uuid_from_addr,
|
||||
&uuid_from_addr_data_1);
|
||||
@ -2607,96 +2641,77 @@ 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 2", wsc_test_build_m1, &m1_data_2);
|
||||
|
||||
if (!l_checksum_is_supported(L_CHECKSUM_SHA256, true)) {
|
||||
printf("SHA256 support missing, skipping other tests...\n");
|
||||
goto done;
|
||||
}
|
||||
add_dh_test("/wsc/parse/m2 1", wsc_test_parse_m2, &m2_data_1);
|
||||
add_dh_test("/wsc/parse/m2 2", wsc_test_parse_m2, &m2_data_2);
|
||||
|
||||
if (!l_key_is_supported(L_KEY_FEATURE_CRYPTO)) {
|
||||
printf("Key crypto not supported, 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_DH)) {
|
||||
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/m3 1", wsc_test_parse_m3, &m3_data_1);
|
||||
add_crypto_test("/wsc/build/m3 1", wsc_test_build_m3, &m3_data_1);
|
||||
|
||||
l_test_add("/wsc/build/m2 1", wsc_test_build_m2, &m2_data_1);
|
||||
add_crypto_test("/wsc/parse/m4 1", wsc_test_parse_m4, &m4_data_1);
|
||||
add_crypto_test("/wsc/build/m4 1", wsc_test_build_m4, &m4_data_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);
|
||||
add_crypto_test("/wsc/parse/m4 encrypted settings 1",
|
||||
wsc_test_parse_m4_encrypted_settings,
|
||||
&m4_encrypted_settings_data_1);
|
||||
add_crypto_test("/wsc/build/m4 encrypted settings 1",
|
||||
wsc_test_build_m4_encrypted_settings,
|
||||
&m4_encrypted_settings_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);
|
||||
add_crypto_test("/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/parse/m4 encrypted settings 1",
|
||||
wsc_test_parse_m4_encrypted_settings,
|
||||
&m4_encrypted_settings_data_1);
|
||||
l_test_add("/wsc/build/m4 encrypted settings 1",
|
||||
wsc_test_build_m4_encrypted_settings,
|
||||
&m4_encrypted_settings_data_1);
|
||||
add_crypto_test("/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/parse/m5 1", wsc_test_parse_m5, &m5_data_1);
|
||||
l_test_add("/wsc/build/m5 1", wsc_test_build_m5, &m5_data_1);
|
||||
add_crypto_test("/wsc/parse/m6 encrypted settings 1",
|
||||
wsc_test_parse_m6_encrypted_settings,
|
||||
&m6_encrypted_settings_data_1);
|
||||
add_crypto_test("/wsc/build/m6 encrypted settings 1",
|
||||
wsc_test_build_m6_encrypted_settings,
|
||||
&m6_encrypted_settings_data_1);
|
||||
|
||||
l_test_add("/wsc/parse/m6 1", wsc_test_parse_m6, &m6_data_1);
|
||||
l_test_add("/wsc/build/m6 1", wsc_test_build_m6, &m6_data_1);
|
||||
add_crypto_test("/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/parse/m6 encrypted settings 1",
|
||||
wsc_test_parse_m6_encrypted_settings,
|
||||
&m6_encrypted_settings_data_1);
|
||||
l_test_add("/wsc/build/m6 encrypted settings 1",
|
||||
wsc_test_build_m6_encrypted_settings,
|
||||
&m6_encrypted_settings_data_1);
|
||||
add_crypto_test("/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/parse/m7 1", wsc_test_parse_m7, &m7_data_1);
|
||||
l_test_add("/wsc/build/m7 1", wsc_test_build_m7, &m7_data_1);
|
||||
add_crypto_test("/wsc/parse/m8 encrypted settings 1",
|
||||
wsc_test_parse_m8_encrypted_settings,
|
||||
&m8_encrypted_settings_data_1);
|
||||
add_crypto_test("/wsc/build/m8 encrypted settings 1",
|
||||
wsc_test_build_m8_encrypted_settings,
|
||||
&m8_encrypted_settings_data_1);
|
||||
|
||||
l_test_add("/wsc/parse/m8 1", wsc_test_parse_m8, &m8_data_1);
|
||||
l_test_add("/wsc/build/m8 1", wsc_test_build_m8, &m8_data_1);
|
||||
|
||||
l_test_add("/wsc/parse/m8 encrypted settings 1",
|
||||
wsc_test_parse_m8_encrypted_settings,
|
||||
&m8_encrypted_settings_data_1);
|
||||
l_test_add("/wsc/build/m8 encrypted settings 1",
|
||||
wsc_test_build_m8_encrypted_settings,
|
||||
&m8_encrypted_settings_data_1);
|
||||
|
||||
l_test_add("/wsc/parse/wsc_done 1", wsc_test_parse_wsc_done,
|
||||
add_crypto_test("/wsc/parse/wsc_done 1", wsc_test_parse_wsc_done,
|
||||
&wsc_done_data_1);
|
||||
l_test_add("/wsc/build/wsc_done 1", wsc_test_build_wsc_done,
|
||||
add_crypto_test("/wsc/build/wsc_done 1", wsc_test_build_wsc_done,
|
||||
&wsc_done_data_1);
|
||||
|
||||
if (!l_key_is_supported(L_KEY_FEATURE_DH))
|
||||
goto done;
|
||||
|
||||
l_test_add("/wsc/diffie-hellman/generate pubkey 1",
|
||||
add_dh_test("/wsc/diffie-hellman/generate pubkey 1",
|
||||
wsc_test_dh_generate_pubkey,
|
||||
&dh_generate_pubkey_test_data_1);
|
||||
l_test_add("/wsc/diffie-hellman/generate pubkey 2",
|
||||
add_dh_test("/wsc/diffie-hellman/generate pubkey 2",
|
||||
wsc_test_dh_generate_pubkey,
|
||||
&dh_generate_pubkey_test_data_2);
|
||||
|
||||
if (!l_cipher_is_supported(L_CIPHER_AES_CBC))
|
||||
goto done;
|
||||
|
||||
l_test_add("/wsc/handshake/PBC Handshake Test",
|
||||
add_aes_cbc_test("/wsc/handshake/PBC Handshake Test",
|
||||
wsc_test_pbc_handshake, NULL);
|
||||
|
||||
l_test_add("/wsc/retransmission/no fragmentation",
|
||||
add_aes_cbc_test("/wsc/retransmission/no fragmentation",
|
||||
wsc_test_retransmission_no_fragmentation, NULL);
|
||||
|
||||
l_test_add("/wsc-r/handshake/PBC Handshake WPA2 passphrase test",
|
||||
wsc_r_test_pbc_handshake,
|
||||
&wsc_r_test_wpa2_cred_passphrase);
|
||||
l_test_add("/wsc-r/handshake/PBC Handshake WPA2 PSK test",
|
||||
wsc_r_test_pbc_handshake,
|
||||
&wsc_r_test_wpa2_cred_psk);
|
||||
l_test_add("/wsc-r/handshake/PBC Handshake Open test",
|
||||
wsc_r_test_pbc_handshake,
|
||||
&wsc_r_test_open_cred);
|
||||
add_aes_cbc_test("/wsc-r/handshake/PBC Handshake WPA2 passphrase test",
|
||||
wsc_r_test_pbc_handshake,
|
||||
&wsc_r_test_wpa2_cred_passphrase);
|
||||
add_aes_cbc_test("/wsc-r/handshake/PBC Handshake WPA2 PSK test",
|
||||
wsc_r_test_pbc_handshake,
|
||||
&wsc_r_test_wpa2_cred_psk);
|
||||
add_aes_cbc_test("/wsc-r/handshake/PBC Handshake Open test",
|
||||
wsc_r_test_pbc_handshake,
|
||||
&wsc_r_test_open_cred);
|
||||
|
||||
done:
|
||||
return l_test_run();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user