mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2025-04-22 04:47:54 +02:00
Compare commits
No commits in common. "master" and "2.20" have entirely different histories.
@ -1,3 +0,0 @@
|
||||
[codespell]
|
||||
ignore-words-list = fils, FILS, SME, assertIn, OCE, clen, aci, ELL, sav, ths
|
||||
skip = build-aux, linux, autom4te.cache, aclocal.m4, AUTHORS, libtool, configure*, *.5, ell
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -67,7 +67,6 @@ unit/test-band
|
||||
unit/test-dpp
|
||||
unit/test-json
|
||||
unit/test-nl80211util
|
||||
unit/test-pmksa
|
||||
unit/cert-*.pem
|
||||
unit/cert-*.csr
|
||||
unit/cert-*.srl
|
||||
|
44
ChangeLog
44
ChangeLog
@ -1,47 +1,3 @@
|
||||
ver 3.6:
|
||||
Fix issue with handling blacklisting and roaming requests.
|
||||
Fix issue with handling CQM thresholds for FullMAC devices.
|
||||
Add support for PMKSA when using FullMAC devices.
|
||||
|
||||
ver 3.5:
|
||||
Add support for option to disable blacklist handling.
|
||||
Add support for option to disable SAE for broken drivers.
|
||||
|
||||
ver 3.4:
|
||||
Add support for the Test Anything Protocol.
|
||||
|
||||
ver 3.3:
|
||||
Fix issue with handling External Authentication.
|
||||
|
||||
ver 3.2:
|
||||
Fix issue with GCC 15 and -std=c23 build errors.
|
||||
Add support for using PMKSA over SAE if available.
|
||||
Add support for HighUtilization/StationCount thresholds.
|
||||
Add support for disabling Multicast RX option.
|
||||
|
||||
ver 3.1:
|
||||
Fix issue with handling OWE transition BSS selection.
|
||||
Fix issue with handling oper class 136 starting frequency.
|
||||
|
||||
ver 3.0:
|
||||
Fix issue with handling alpha2 code for United Kingdom.
|
||||
Fix issue with handling empty TX/RX bitrate attributes.
|
||||
Fix issue with handling RSSI polling fallback workaround.
|
||||
Fix issue with handling harmless cloned information elements.
|
||||
Add experimental support for External Authentication feature.
|
||||
|
||||
ver 2.22:
|
||||
Fix issue with handling the Affinities property.
|
||||
Fix issue with handling ConnectedAccessPoint signal when roaming.
|
||||
|
||||
ver 2.21:
|
||||
Fix issue with pending scan requests after regdom update.
|
||||
Fix issue with handling the rearming of the roaming timeout.
|
||||
Fix issue with survey request and externally triggered scans.
|
||||
Fix issue with RSSI fallback when setting CQM threshold fails.
|
||||
Fix issue with FT-over-Air without offchannel support.
|
||||
Add support for per station Affinities property.
|
||||
|
||||
ver 2.20:
|
||||
Fix issue with PKEX timeout and number of frequencies used.
|
||||
Fix issue with handling logic for handshake failures.
|
||||
|
28
Makefile.am
28
Makefile.am
@ -65,15 +65,12 @@ ell_headers = ell/util.h \
|
||||
ell/cleanup.h \
|
||||
ell/netconfig.h \
|
||||
ell/sysctl.h \
|
||||
ell/notifylist.h \
|
||||
ell/minheap.h
|
||||
ell/notifylist.h
|
||||
|
||||
ell_sources = ell/private.h \
|
||||
ell/missing.h \
|
||||
ell/util.c \
|
||||
ell/test-private.h \
|
||||
ell/test.c \
|
||||
ell/test-dbus.c \
|
||||
ell/strv.c \
|
||||
ell/utf8.c \
|
||||
ell/queue.c \
|
||||
@ -150,8 +147,7 @@ ell_sources = ell/private.h \
|
||||
ell/acd.c \
|
||||
ell/netconfig.c \
|
||||
ell/sysctl.c \
|
||||
ell/notifylist.c \
|
||||
ell/minheap.c
|
||||
ell/notifylist.c
|
||||
|
||||
ell_shared = ell/useful.h ell/asn1-private.h
|
||||
|
||||
@ -273,7 +269,6 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h \
|
||||
src/json.h src/json.c \
|
||||
src/dpp.c \
|
||||
src/udev.c \
|
||||
src/pmksa.h src/pmksa.c \
|
||||
$(eap_sources) \
|
||||
$(builtin_sources)
|
||||
|
||||
@ -440,8 +435,7 @@ unit_tests += unit/test-cmac-aes \
|
||||
unit/test-ie unit/test-util unit/test-ssid-security \
|
||||
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-storage
|
||||
unit/test-dpp unit/test-json unit/test-nl80211util
|
||||
endif
|
||||
|
||||
if CLIENT
|
||||
@ -460,7 +454,6 @@ unit_test_eap_sim_SOURCES = unit/test-eap-sim.c \
|
||||
src/eapol.h src/eapol.c \
|
||||
src/eapolutil.h src/eapolutil.c \
|
||||
src/handshake.h src/handshake.c \
|
||||
src/pmksa.h src/pmksa.c \
|
||||
src/eap.h src/eap.c src/eap-private.h \
|
||||
src/util.h src/util.c \
|
||||
src/simauth.h src/simauth.c \
|
||||
@ -520,7 +513,6 @@ unit_test_eapol_SOURCES = unit/test-eapol.c \
|
||||
src/eapol.h src/eapol.c \
|
||||
src/eapolutil.h src/eapolutil.c \
|
||||
src/handshake.h src/handshake.c \
|
||||
src/pmksa.h src/pmksa.c \
|
||||
src/eap.h src/eap.c src/eap-private.h \
|
||||
src/eap-tls.c src/eap-ttls.c \
|
||||
src/eap-md5.c src/util.c \
|
||||
@ -551,7 +543,6 @@ unit_test_wsc_SOURCES = unit/test-wsc.c src/wscutil.h src/wscutil.c \
|
||||
src/eapol.h src/eapol.c \
|
||||
src/eapolutil.h src/eapolutil.c \
|
||||
src/handshake.h src/handshake.c \
|
||||
src/pmksa.h src/pmksa.c \
|
||||
src/eap.h src/eap.c src/eap-private.h \
|
||||
src/util.h src/util.c \
|
||||
src/erp.h src/erp.c \
|
||||
@ -570,7 +561,6 @@ unit_test_sae_SOURCES = unit/test-sae.c \
|
||||
src/crypto.h src/crypto.c \
|
||||
src/ie.h src/ie.c \
|
||||
src/handshake.h src/handshake.c \
|
||||
src/pmksa.h src/pmksa.c \
|
||||
src/erp.h src/erp.c \
|
||||
src/band.h src/band.c \
|
||||
src/util.h src/util.c \
|
||||
@ -601,15 +591,6 @@ unit_test_nl80211util_SOURCES = unit/test-nl80211util.c \
|
||||
src/ie.h src/ie.c \
|
||||
src/util.h src/util.c
|
||||
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
|
||||
@ -625,9 +606,6 @@ unit_test_client_SOURCES = unit/test-client.c \
|
||||
unit_test_client_LDADD = $(ell_ldadd) $(client_ldadd)
|
||||
endif
|
||||
|
||||
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
|
||||
$(top_srcdir)/build-aux/tap-driver.sh
|
||||
|
||||
TESTS = $(unit_tests)
|
||||
|
||||
EXTRA_DIST = src/genbuiltin src/iwd.service.in src/net.connman.iwd.service \
|
||||
|
4
TODO
4
TODO
@ -110,7 +110,7 @@ Wireless monitor
|
||||
|
||||
- Subscribe to all nl80211 multicast groups at startup
|
||||
|
||||
It seems the nlmon packets are limited to actual subscribed multicast
|
||||
It seems the nlmon packets are limited to actual subscribed mutlicast
|
||||
groups. To get a complete picture of all the nl80211 commands and
|
||||
events, it is required that iwmon adds membership to all multicast
|
||||
groups that the nl80211 lists.
|
||||
@ -234,7 +234,7 @@ Wireless daemon
|
||||
|
||||
- Implement Enrollee Session Overlap Detection after WSC Protocol Run
|
||||
|
||||
WSC Best Practices v2.0.1, Section 3.15 describes an enhancement to detect
|
||||
WSC Best Practices v2.0.1, Section 3.15 describes an enhacement to detect
|
||||
PBC session overlaps. The Enrollee is asked to perform an extra scan without
|
||||
the PBC request in the ProbeRequest frames after EAP-WSC completes
|
||||
successfully. If another AP in PBC mode is found, then a SessionOverlap
|
||||
|
@ -11,58 +11,52 @@ from iwd import NetworkType
|
||||
from hostapd import HostapdCLI
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
def initial_connection(self):
|
||||
ordered_network = self.device.get_ordered_network('TestAPRoam')
|
||||
|
||||
def validate(self, expect_roam=True):
|
||||
wd = IWD()
|
||||
|
||||
devices = wd.list_devices(1)
|
||||
device = devices[0]
|
||||
|
||||
ordered_network = device.get_ordered_network('TestAPRoam')
|
||||
|
||||
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||
|
||||
condition = 'not obj.connected'
|
||||
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||
wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||
|
||||
self.device.connect_bssid(self.bss_hostapd[0].bssid)
|
||||
device.connect_bssid(self.bss_hostapd[0].bssid)
|
||||
|
||||
condition = 'obj.state == DeviceState.connected'
|
||||
self.wd.wait_for_object_condition(self.device, condition)
|
||||
wd.wait_for_object_condition(device, condition)
|
||||
|
||||
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED')
|
||||
|
||||
self.assertFalse(self.bss_hostapd[1].list_sta())
|
||||
|
||||
def validate_roam(self, from_bss, to_bss, expect_roam=True):
|
||||
from_bss.send_bss_transition(self.device.address,
|
||||
self.neighbor_list,
|
||||
self.bss_hostapd[0].send_bss_transition(device.address,
|
||||
[(self.bss_hostapd[1].bssid, '8f0000005102060603000000')],
|
||||
disassoc_imminent=expect_roam)
|
||||
|
||||
if expect_roam:
|
||||
from_condition = 'obj.state == DeviceState.roaming'
|
||||
to_condition = 'obj.state == DeviceState.connected'
|
||||
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
|
||||
wd.wait_for_object_change(device, from_condition, to_condition)
|
||||
|
||||
to_bss.wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
|
||||
self.bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % device.address)
|
||||
else:
|
||||
self.device.wait_for_event("no-roam-candidates")
|
||||
device.wait_for_event("no-roam-candidates")
|
||||
|
||||
device.disconnect()
|
||||
|
||||
condition = 'not obj.connected'
|
||||
wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||
|
||||
def test_disassoc_imminent(self):
|
||||
self.initial_connection()
|
||||
self.validate_roam(self.bss_hostapd[0], self.bss_hostapd[1])
|
||||
self.validate(expect_roam=True)
|
||||
|
||||
def test_no_candidates(self):
|
||||
self.initial_connection()
|
||||
# We now have BSS0 roam blacklisted
|
||||
self.validate_roam(self.bss_hostapd[0], self.bss_hostapd[1])
|
||||
# Try and trigger another roam back, which shouldn't happen since now
|
||||
# both BSS's are roam blacklisted
|
||||
self.validate_roam(self.bss_hostapd[1], self.bss_hostapd[0], expect_roam=False)
|
||||
|
||||
def setUp(self):
|
||||
self.wd = IWD(True)
|
||||
|
||||
devices = self.wd.list_devices(1)
|
||||
self.device = devices[0]
|
||||
|
||||
def tearDown(self):
|
||||
self.wd = None
|
||||
self.device = None
|
||||
self.validate(expect_roam=False)
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
@ -71,10 +65,6 @@ class Test(unittest.TestCase):
|
||||
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
|
||||
HostapdCLI(config='ssid2.conf'),
|
||||
HostapdCLI(config='ssid3.conf') ]
|
||||
cls.neighbor_list = [
|
||||
(cls.bss_hostapd[0].bssid, "8f0000005101060603000000"),
|
||||
(cls.bss_hostapd[1].bssid, "8f0000005102060603000000"),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
|
@ -1,7 +1,5 @@
|
||||
[SETUP]
|
||||
num_radios=4
|
||||
hwsim_medium=true
|
||||
start_iwd=false
|
||||
|
||||
[HOSTAPD]
|
||||
rad0=ssid1.conf
|
||||
|
@ -1,6 +0,0 @@
|
||||
[General]
|
||||
RoamThreshold=-72
|
||||
CriticalRoamThreshold=-72
|
||||
|
||||
[Blacklist]
|
||||
InitialRoamRequestedTimeout=20
|
@ -1,183 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import unittest
|
||||
import sys
|
||||
|
||||
sys.path.append('../util')
|
||||
import iwd
|
||||
from iwd import IWD, IWD_CONFIG_DIR
|
||||
from iwd import NetworkType
|
||||
|
||||
from hostapd import HostapdCLI
|
||||
from hwsim import Hwsim
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
def validate_connected(self, hostapd):
|
||||
ordered_network = self.device.get_ordered_network('TestAPRoam')
|
||||
|
||||
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||
|
||||
condition = 'not obj.connected'
|
||||
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||
|
||||
self.device.connect_bssid(hostapd.bssid)
|
||||
|
||||
condition = 'obj.state == DeviceState.connected'
|
||||
self.wd.wait_for_object_condition(self.device, condition)
|
||||
|
||||
hostapd.wait_for_event('AP-STA-CONNECTED')
|
||||
|
||||
def validate_ap_roamed(self, from_hostapd, to_hostapd):
|
||||
from_hostapd.send_bss_transition(
|
||||
self.device.address, self.neighbor_list, disassoc_imminent=True
|
||||
)
|
||||
|
||||
from_condition = 'obj.state == DeviceState.roaming'
|
||||
to_condition = 'obj.state == DeviceState.connected'
|
||||
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
|
||||
|
||||
to_hostapd.wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
|
||||
|
||||
self.device.wait_for_event("ap-roam-blacklist-added")
|
||||
|
||||
def test_roam_to_optimal_candidates(self):
|
||||
# In this test IWD will naturally transition down the list after each
|
||||
# BSS gets roam blacklisted. All BSS's are above the RSSI thresholds.
|
||||
self.rule_ssid1.signal = -5000
|
||||
self.rule_ssid2.signal = -6500
|
||||
self.rule_ssid3.signal = -6900
|
||||
|
||||
# Connect to BSS0
|
||||
self.validate_connected(self.bss_hostapd[0])
|
||||
|
||||
# AP directed roam to BSS1
|
||||
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
|
||||
|
||||
# AP directed roam to BSS2
|
||||
self.validate_ap_roamed(self.bss_hostapd[1], self.bss_hostapd[2])
|
||||
|
||||
def test_avoiding_under_threshold_bss(self):
|
||||
# In this test IWD will blacklist BSS0, then roam the BSS1. BSS1 will
|
||||
# then tell IWD to roam, but it should go back to BSS0 since the only
|
||||
# non-blacklisted BSS is under the roam threshold.
|
||||
self.rule_ssid1.signal = -5000
|
||||
self.rule_ssid2.signal = -6500
|
||||
self.rule_ssid3.signal = -7300
|
||||
|
||||
# Connect to BSS0
|
||||
self.validate_connected(self.bss_hostapd[0])
|
||||
|
||||
# AP directed roam to BSS1
|
||||
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
|
||||
|
||||
# AP directed roam, but IWD should choose BSS0 since BSS2 is -73dB
|
||||
self.validate_ap_roamed(self.bss_hostapd[1], self.bss_hostapd[0])
|
||||
|
||||
def test_connect_to_roam_blacklisted_bss(self):
|
||||
# In this test a BSS will be roam blacklisted, but all other options are
|
||||
# below the RSSI threshold so IWD should roam back to the blacklisted
|
||||
# BSS.
|
||||
self.rule_ssid1.signal = -5000
|
||||
self.rule_ssid2.signal = -8000
|
||||
self.rule_ssid3.signal = -8500
|
||||
|
||||
# Connect to BSS0
|
||||
self.validate_connected(self.bss_hostapd[0])
|
||||
|
||||
# AP directed roam, should connect to BSS1 as its the next best
|
||||
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
|
||||
|
||||
# Connected to BSS1, but the signal is bad, so IWD should try to roam
|
||||
# again. BSS0 is still blacklisted, but its the only reasonable option
|
||||
# since both BSS1 and BSS2 are below the set RSSI threshold (-72dB)
|
||||
|
||||
from_condition = 'obj.state == DeviceState.roaming'
|
||||
to_condition = 'obj.state == DeviceState.connected'
|
||||
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
|
||||
|
||||
# IWD should have connected to BSS0, even though its roam blacklisted
|
||||
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
|
||||
|
||||
def test_blacklist_during_roam_scan(self):
|
||||
# Tests that an AP roam request mid-roam results in the AP still being
|
||||
# blacklisted even though the request itself doesn't directly trigger
|
||||
# a roam.
|
||||
self.rule_ssid1.signal = -7300
|
||||
self.rule_ssid2.signal = -7500
|
||||
self.rule_ssid3.signal = -8500
|
||||
|
||||
# Connect to BSS0 under the roam threshold so IWD will immediately try
|
||||
# roaming elsewhere
|
||||
self.validate_connected(self.bss_hostapd[0])
|
||||
|
||||
self.device.wait_for_event("roam-scan-triggered")
|
||||
|
||||
self.bss_hostapd[0].send_bss_transition(
|
||||
self.device.address, self.neighbor_list, disassoc_imminent=True
|
||||
)
|
||||
self.device.wait_for_event("ap-roam-blacklist-added")
|
||||
|
||||
# BSS0 should have gotten blacklisted even though IWD was mid-roam,
|
||||
# causing IWD to choose BSS1 when it gets is results.
|
||||
|
||||
from_condition = 'obj.state == DeviceState.roaming'
|
||||
to_condition = 'obj.state == DeviceState.connected'
|
||||
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
|
||||
|
||||
self.bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
|
||||
|
||||
def setUp(self):
|
||||
self.wd = IWD(True)
|
||||
|
||||
devices = self.wd.list_devices(1)
|
||||
self.device = devices[0]
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
self.wd = None
|
||||
self.device = None
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
IWD.copy_to_storage("main.conf.roaming", IWD_CONFIG_DIR, "main.conf")
|
||||
IWD.copy_to_storage('TestAPRoam.psk')
|
||||
hwsim = Hwsim()
|
||||
|
||||
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
|
||||
HostapdCLI(config='ssid2.conf'),
|
||||
HostapdCLI(config='ssid3.conf') ]
|
||||
HostapdCLI.group_neighbors(*cls.bss_hostapd)
|
||||
|
||||
rad0 = hwsim.get_radio('rad0')
|
||||
rad1 = hwsim.get_radio('rad1')
|
||||
rad2 = hwsim.get_radio('rad2')
|
||||
|
||||
cls.neighbor_list = [
|
||||
(cls.bss_hostapd[0].bssid, "8f0000005101060603000000"),
|
||||
(cls.bss_hostapd[1].bssid, "8f0000005102060603000000"),
|
||||
(cls.bss_hostapd[2].bssid, "8f0000005103060603000000"),
|
||||
]
|
||||
|
||||
|
||||
cls.rule_ssid1 = hwsim.rules.create()
|
||||
cls.rule_ssid1.source = rad0.addresses[0]
|
||||
cls.rule_ssid1.bidirectional = True
|
||||
cls.rule_ssid1.enabled = True
|
||||
|
||||
cls.rule_ssid2 = hwsim.rules.create()
|
||||
cls.rule_ssid2.source = rad1.addresses[0]
|
||||
cls.rule_ssid2.bidirectional = True
|
||||
cls.rule_ssid2.enabled = True
|
||||
|
||||
cls.rule_ssid3 = hwsim.rules.create()
|
||||
cls.rule_ssid3.source = rad2.addresses[0]
|
||||
cls.rule_ssid3.bidirectional = True
|
||||
cls.rule_ssid3.enabled = True
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
IWD.clear_storage()
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(exit=True)
|
@ -1,2 +0,0 @@
|
||||
[Security]
|
||||
Passphrase=EasilyGuessedPassword
|
@ -1,41 +0,0 @@
|
||||
hw_mode=g
|
||||
channel=1
|
||||
ssid=TestFT
|
||||
utf8_ssid=1
|
||||
ctrl_interface=/var/run/hostapd
|
||||
|
||||
r1_key_holder=120000000001
|
||||
nas_identifier=dummy1
|
||||
|
||||
wpa=2
|
||||
# Can support WPA-PSK and FT-PSK (space separated list) and/or EAP at the same
|
||||
# time but we want to force FT
|
||||
wpa_key_mgmt=FT-PSK
|
||||
wpa_pairwise=CCMP
|
||||
wpa_passphrase=EasilyGuessedPassword
|
||||
ieee80211w=0
|
||||
rsn_preauth=1
|
||||
rsn_preauth_interfaces=lo
|
||||
disable_pmksa_caching=0
|
||||
# Allow PMK cache to be shared opportunistically among configured interfaces
|
||||
# and BSSes (i.e., all configurations within a single hostapd process).
|
||||
okc=1
|
||||
mobility_domain=1234
|
||||
reassociation_deadline=60000
|
||||
r0kh=12:00:00:00:00:01 dummy1 000102030405060708090a0b0c0d0e0f
|
||||
r0kh=12:00:00:00:00:02 dummy2 000102030405060708090a0b0c0d0e0f
|
||||
r1kh=12:00:00:00:00:01 00:00:00:00:00:01 000102030405060708090a0b0c0d0e0f
|
||||
r1kh=12:00:00:00:00:02 00:00:00:00:00:02 000102030405060708090a0b0c0d0e0f
|
||||
# Push mode only needed for 8021x, not PSK mode since msk already known
|
||||
pmk_r1_push=0
|
||||
# Allow locally generated FT response so we don't have to configure push/pull
|
||||
# between BSSes running as separate hostapd processes as in the test-runner
|
||||
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
|
||||
# CONFIG_BRIDGE enabled in the kernel.
|
||||
ft_psk_generate_local=1
|
||||
rkh_pull_timeout=50
|
||||
ft_over_ds=0
|
||||
ap_table_expiration_time=36000
|
||||
ap_table_max_size=10
|
||||
rrm_neighbor_report=1
|
||||
ocv=1
|
@ -1,41 +0,0 @@
|
||||
hw_mode=g
|
||||
channel=2
|
||||
ssid=TestFT
|
||||
utf8_ssid=1
|
||||
ctrl_interface=/var/run/hostapd
|
||||
|
||||
r1_key_holder=120000000002
|
||||
nas_identifier=dummy2
|
||||
|
||||
wpa=2
|
||||
# Can support WPA-PSK and FT-PSK (space separated list) and/or EAP at the same
|
||||
# time but we want to force FT
|
||||
wpa_key_mgmt=FT-PSK
|
||||
wpa_pairwise=CCMP
|
||||
wpa_passphrase=EasilyGuessedPassword
|
||||
ieee80211w=0
|
||||
rsn_preauth=1
|
||||
rsn_preauth_interfaces=lo
|
||||
disable_pmksa_caching=0
|
||||
# Allow PMK cache to be shared opportunistically among configured interfaces
|
||||
# and BSSes (i.e., all configurations within a single hostapd process).
|
||||
okc=1
|
||||
mobility_domain=1234
|
||||
reassociation_deadline=60000
|
||||
r0kh=12:00:00:00:00:01 dummy1 000102030405060708090a0b0c0d0e0f
|
||||
r0kh=12:00:00:00:00:02 dummy2 000102030405060708090a0b0c0d0e0f
|
||||
r1kh=12:00:00:00:00:01 00:00:00:00:00:01 000102030405060708090a0b0c0d0e0f
|
||||
r1kh=12:00:00:00:00:02 00:00:00:00:00:02 000102030405060708090a0b0c0d0e0f
|
||||
# Push mode only needed for 8021x, not PSK mode since msk already known
|
||||
pmk_r1_push=0
|
||||
# Allow locally generated FT response so we don't have to configure push/pull
|
||||
# between BSSes running as separate hostapd processes as in the test-runner
|
||||
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
|
||||
# CONFIG_BRIDGE enabled in the kernel.
|
||||
ft_psk_generate_local=1
|
||||
rkh_pull_timeout=50
|
||||
ft_over_ds=0
|
||||
ap_table_expiration_time=36000
|
||||
ap_table_max_size=10
|
||||
rrm_neighbor_report=1
|
||||
ocv=1
|
@ -1,8 +0,0 @@
|
||||
[SETUP]
|
||||
num_radios=3
|
||||
start_iwd=0
|
||||
hwsim_medium=yes
|
||||
|
||||
[HOSTAPD]
|
||||
rad0=ft-psk-ccmp-1.conf
|
||||
rad1=ft-psk-ccmp-2.conf
|
@ -1,5 +0,0 @@
|
||||
[Scan]
|
||||
DisableMacAddressRandomization=true
|
||||
|
||||
[General]
|
||||
RoamRetryInterval=1
|
@ -1,216 +0,0 @@
|
||||
#! /usr/bin/python3
|
||||
|
||||
import unittest
|
||||
import sys, os
|
||||
import dbus
|
||||
|
||||
sys.path.append('../util')
|
||||
from config import ctx
|
||||
import iwd
|
||||
from iwd import IWD, IWDDBusAbstract
|
||||
from iwd import NetworkType
|
||||
from hwsim import Hwsim
|
||||
from hostapd import HostapdCLI
|
||||
|
||||
#
|
||||
# Separate client used to test DBus disconnects so we don't bring down the
|
||||
# entire IWD python library
|
||||
#
|
||||
class AffinityClient(IWDDBusAbstract):
|
||||
def __init__(self, device_path):
|
||||
self._bus = dbus.bus.BusConnection(address_or_type=ctx.dbus_address)
|
||||
self._station_prop_if = dbus.Interface(
|
||||
self._bus.get_object(iwd.IWD_SERVICE, device_path),
|
||||
iwd.DBUS_PROPERTIES)
|
||||
|
||||
def set(self, values):
|
||||
self._station_prop_if.Set(iwd.IWD_STATION_INTERFACE, 'Affinities', dbus.Array([dbus.ObjectPath(v) for v in values], signature="o"))
|
||||
|
||||
def close(self):
|
||||
self._bus.close()
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
def connect(self, device, hapd):
|
||||
ordered_network = device.get_ordered_network('TestFT', full_scan=True)
|
||||
|
||||
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||
|
||||
condition = 'not obj.connected'
|
||||
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||
|
||||
device.connect_bssid(hapd.bssid)
|
||||
|
||||
condition = 'obj.state == DeviceState.connected'
|
||||
self.wd.wait_for_object_condition(device, condition)
|
||||
|
||||
def test_set_affinity(self):
|
||||
device = self.wd.list_devices(1)[0]
|
||||
|
||||
self.connect(device, self.bss_hostapd[0])
|
||||
|
||||
print(device.connected_bss)
|
||||
|
||||
device.affinities = [device.connected_bss]
|
||||
|
||||
# IWD should not attempt to roam
|
||||
with self.assertRaises(TimeoutError):
|
||||
device.wait_for_event("roam-scan-triggered")
|
||||
|
||||
device.affinities = []
|
||||
device.wait_for_event("roam-scan-triggered")
|
||||
|
||||
def test_roam_below_critical(self):
|
||||
device = self.wd.list_devices(1)[0]
|
||||
|
||||
self.connect(device, self.bss_hostapd[0])
|
||||
|
||||
device.affinities = [device.connected_bss]
|
||||
|
||||
# IWD should not attempt to roam
|
||||
with self.assertRaises(TimeoutError):
|
||||
device.wait_for_event("roam-scan-triggered")
|
||||
|
||||
# Lower signal past critical level
|
||||
self.bss0_rule.signal = -9000
|
||||
|
||||
device.wait_for_event("roam-scan-triggered")
|
||||
|
||||
def test_error_conditions(self):
|
||||
device = self.wd.list_devices(1)[0]
|
||||
|
||||
# Calling set while disconnected should fail
|
||||
with self.assertRaises(iwd.NotConnectedEx):
|
||||
device.affinities = ["/some/path"]
|
||||
|
||||
self.connect(device, self.bss_hostapd[0])
|
||||
|
||||
device.affinities = [device.connected_bss]
|
||||
|
||||
# An invalid path should fail
|
||||
with self.assertRaises(iwd.InvalidArgumentsEx):
|
||||
device.affinities = [device.connected_bss, "/an/invalid/path"]
|
||||
|
||||
def test_affinity_client_disconnect(self):
|
||||
device = self.wd.list_devices(1)[0]
|
||||
|
||||
client = AffinityClient(device.device_path)
|
||||
|
||||
self.connect(device, self.bss_hostapd[0])
|
||||
|
||||
client.set([device.connected_bss])
|
||||
|
||||
with self.assertRaises(TimeoutError):
|
||||
device.wait_for_event("roam-scan-triggered")
|
||||
|
||||
client._bus.close()
|
||||
|
||||
device.wait_for_event("roam-scan-triggered")
|
||||
|
||||
def test_affinity_client_reconnect_during_roam(self):
|
||||
device = self.wd.list_devices(1)[0]
|
||||
|
||||
client = AffinityClient(device.device_path)
|
||||
|
||||
self.connect(device, self.bss_hostapd[0])
|
||||
|
||||
client.set([device.connected_bss])
|
||||
|
||||
# Lower signal past critical level
|
||||
self.bss0_rule.signal = -9000
|
||||
|
||||
device.wait_for_event("roam-scan-triggered")
|
||||
|
||||
client.close()
|
||||
del client
|
||||
client = AffinityClient(device.device_path)
|
||||
# setting here should get cleared after connecting
|
||||
client.set([device.connected_bss])
|
||||
|
||||
device.wait_for_event("ft-authenticating")
|
||||
device.wait_for_event("associating")
|
||||
device.wait_for_event("connected")
|
||||
|
||||
# Affinity should be reset, and IWD should be trying to roam
|
||||
device.wait_for_event("roam-scan-triggered")
|
||||
|
||||
def test_cleanup_with_connected_client(self):
|
||||
device = self.wd.list_devices(1)[0]
|
||||
|
||||
client = AffinityClient(device.device_path)
|
||||
|
||||
self.connect(device, self.bss_hostapd[0])
|
||||
|
||||
client.set([device.connected_bss])
|
||||
self.wd.stop()
|
||||
|
||||
def test_affinity_removed_after_roam(self):
|
||||
device = self.wd.list_devices(1)[0]
|
||||
|
||||
self.connect(device, self.bss_hostapd[0])
|
||||
|
||||
device.affinities = [device.connected_bss]
|
||||
|
||||
# Lower signal past critical level
|
||||
self.bss0_rule.signal = -9000
|
||||
|
||||
device.wait_for_event("roam-scan-triggered")
|
||||
|
||||
device.wait_for_event("ft-authenticating")
|
||||
device.wait_for_event("associating")
|
||||
device.wait_for_event("connected")
|
||||
|
||||
self.assertEqual(device.affinities, [])
|
||||
|
||||
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')
|
||||
|
||||
self.wd.stop()
|
||||
self.wd = None
|
||||
|
||||
def setUp(self):
|
||||
self.bss0_rule.signal = -8000
|
||||
self.bss1_rule.signal = -8000
|
||||
|
||||
self.wd = IWD(True)
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
hwsim = Hwsim()
|
||||
|
||||
IWD.copy_to_storage('TestFT.psk')
|
||||
|
||||
cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
|
||||
HostapdCLI(config='ft-psk-ccmp-2.conf') ]
|
||||
|
||||
rad0 = hwsim.get_radio('rad0')
|
||||
rad1 = hwsim.get_radio('rad1')
|
||||
|
||||
cls.bss0_rule = hwsim.rules.create()
|
||||
cls.bss0_rule.source = rad0.addresses[0]
|
||||
cls.bss0_rule.bidirectional = True
|
||||
cls.bss0_rule.signal = -8000
|
||||
cls.bss0_rule.enabled = True
|
||||
|
||||
cls.bss1_rule = hwsim.rules.create()
|
||||
cls.bss1_rule.source = rad1.addresses[0]
|
||||
cls.bss1_rule.bidirectional = True
|
||||
cls.bss1_rule.signal = -8000
|
||||
cls.bss1_rule.enabled = True
|
||||
|
||||
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
|
||||
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
|
||||
|
||||
HostapdCLI.group_neighbors(*cls.bss_hostapd)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
IWD.clear_storage()
|
||||
cls.bss_hostapd = None
|
||||
cls.bss0_rule.remove()
|
||||
cls.bss1_rule.remove()
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(exit=True)
|
@ -1,2 +0,0 @@
|
||||
[Security]
|
||||
Passphrase=secret123
|
@ -260,69 +260,12 @@ class Test(unittest.TestCase):
|
||||
|
||||
self.wd.unregister_psk_agent(psk_agent)
|
||||
|
||||
def test_blacklist_disabled(self):
|
||||
wd = self.wd
|
||||
bss_hostapd = self.bss_hostapd
|
||||
|
||||
rule0 = self.rule0
|
||||
rule1 = self.rule1
|
||||
rule2 = self.rule2
|
||||
|
||||
psk_agent = PSKAgent(["secret123", 'secret123'])
|
||||
wd.register_psk_agent(psk_agent)
|
||||
|
||||
devices = wd.list_devices(1)
|
||||
device = devices[0]
|
||||
|
||||
rule0.drop = True
|
||||
rule0.enabled = True
|
||||
|
||||
device.autoconnect = True
|
||||
|
||||
condition = 'obj.state == DeviceState.connected'
|
||||
wd.wait_for_object_condition(device, condition)
|
||||
|
||||
ordered_network = device.get_ordered_network("TestBlacklist", full_scan=True)
|
||||
|
||||
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||
|
||||
# The first BSS should fail, and we should connect to the second. This
|
||||
# should not result in a connection blacklist though since its disabled.
|
||||
bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % device.address)
|
||||
|
||||
device.disconnect()
|
||||
|
||||
rule0.drop = False
|
||||
device.autoconnect = True
|
||||
|
||||
# Verify the first BSS wasn't blacklisted.
|
||||
bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % device.address)
|
||||
|
||||
def setUp(self):
|
||||
_, _, name = self.id().split(".")
|
||||
|
||||
# TODO: If we have this pattern elsewhere it might be nice to turn this
|
||||
# into a decorator e.g.
|
||||
#
|
||||
# @config("main.conf.disabled")
|
||||
# @profile("TestBlacklist.psk")
|
||||
# def test_blacklist_disabled(self)
|
||||
# ...
|
||||
#
|
||||
if name == "test_blacklist_disabled":
|
||||
IWD.copy_to_storage("main.conf.disabled", IWD_CONFIG_DIR, "main.conf")
|
||||
IWD.copy_to_storage("TestBlacklist.psk")
|
||||
else:
|
||||
IWD.copy_to_storage("main.conf.default", IWD_CONFIG_DIR, "main.conf")
|
||||
|
||||
self.wd = IWD(True)
|
||||
|
||||
def tearDown(self):
|
||||
IWD.clear_storage()
|
||||
self.wd = None
|
||||
self.rule0.drop = False
|
||||
self.rule1.drop = False
|
||||
self.rule2.drop = False
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
@ -1,2 +0,0 @@
|
||||
[Blacklist]
|
||||
InitialTimeout=0
|
@ -11,7 +11,7 @@ from iwd import IWD
|
||||
|
||||
class Test8021xNetwork(unittest.TestCase):
|
||||
'''
|
||||
The below test cases excesise the following connection scenarios:
|
||||
The bellow test cases excesise the following connection scenarios:
|
||||
|
||||
Network config is
|
||||
present at start time: Connect: AutoConnect: Result:
|
||||
|
@ -11,7 +11,7 @@ from iwd import IWD
|
||||
|
||||
class TestOpenNetwork(unittest.TestCase):
|
||||
'''
|
||||
The below test cases excesise the following connection scenarios:
|
||||
The bellow test cases excesise the following connection scenarios:
|
||||
|
||||
Network config is
|
||||
present at start time: Connect: AutoConnect: Result:
|
||||
|
@ -11,7 +11,7 @@ from iwd import IWD
|
||||
|
||||
class TestWpaNetwork(unittest.TestCase):
|
||||
'''
|
||||
The below test cases exercise the following connection scenarios:
|
||||
The bellow test cases exercise the following connection scenarios:
|
||||
|
||||
Network config is
|
||||
present at start time: Connect: AutoConnect: Result:
|
||||
|
@ -104,7 +104,7 @@ class Test(unittest.TestCase):
|
||||
|
||||
self.assertTrue(self.profile_is_encrypted('ssidCCMP.psk'))
|
||||
|
||||
# Tests that a profile that doesn't decrypt won't become a known network
|
||||
# Tests that a profile that doesn't decrypt wont become a known network
|
||||
def test_decryption_failure(self):
|
||||
bad_config = \
|
||||
'''
|
||||
|
@ -3,11 +3,7 @@ import sys
|
||||
import sys
|
||||
import os
|
||||
from scapy.layers.dot11 import *
|
||||
from scapy.arch import str2mac
|
||||
try:
|
||||
from scapy.arch import get_if_raw_hwaddr
|
||||
except:
|
||||
from scapy.arch.unix import get_if_raw_hwaddr
|
||||
from scapy.arch import str2mac, get_if_raw_hwaddr
|
||||
from time import time, sleep
|
||||
from threading import Thread
|
||||
|
||||
|
@ -12,7 +12,7 @@ from hostapd import HostapdCLI
|
||||
|
||||
class TestWpaNetwork(unittest.TestCase):
|
||||
'''
|
||||
The below test cases excesise the following connection scenarios:
|
||||
The bellow test cases excesise the following connection scenarios:
|
||||
|
||||
Network config is
|
||||
present at start time: Connect: AutoConnect: Result:
|
||||
|
@ -12,7 +12,7 @@ from hostapd import HostapdCLI
|
||||
|
||||
class TestOpenNetwork(unittest.TestCase):
|
||||
'''
|
||||
The below test cases excesise the following connection scenarios:
|
||||
The bellow test cases excesise the following connection scenarios:
|
||||
|
||||
Network config is
|
||||
present at start time: Connect: AutoConnect: Result:
|
||||
|
@ -12,7 +12,7 @@ from hostapd import HostapdCLI
|
||||
|
||||
class TestWpaNetwork(unittest.TestCase):
|
||||
'''
|
||||
The below test cases excesise the following connection scenarios:
|
||||
The bellow test cases excesise the following connection scenarios:
|
||||
|
||||
Network config is
|
||||
present at start time: Connect: AutoConnect: Result:
|
||||
|
@ -11,7 +11,7 @@ from iwd import NetworkType
|
||||
|
||||
class TestMFP(unittest.TestCase):
|
||||
'''
|
||||
The below test cases excesise the following MFP option setting scenarios:
|
||||
The bellow test cases excesise the following MFP option setting scenarios:
|
||||
|
||||
IWD_MFP: AP_MFP: Result:
|
||||
0 0 No MFP, connection succeeds
|
||||
|
@ -137,7 +137,7 @@ class Test(unittest.TestCase):
|
||||
# since (T2 - T1) / 2 is shorter than 60s. It is now about 10s since the last
|
||||
# renewal or 5s before the next DHCPREQUEST frame that is going to be lost. We'll
|
||||
# wait T1 seconds, so until about 10s after the failed attempt, we'll check that
|
||||
# there was no renewal by that time, just in case, and we'll re-enable frame delivery.
|
||||
# there was no renewal by that time, just in case, and we'll reenable frame delivery.
|
||||
# We'll then wait another 60s and we should see the lease has been successfully
|
||||
# renewed some 10 seconds earlier on the 1st DHCPREQUEST retransmission.
|
||||
#
|
||||
|
@ -1,114 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import unittest
|
||||
import sys
|
||||
|
||||
sys.path.append('../util')
|
||||
from iwd import IWD
|
||||
from iwd import PSKAgent
|
||||
from iwd import NetworkType
|
||||
from hostapd import HostapdCLI
|
||||
import testutil
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
def validate_connection(self, wd, ssid, hostapd, expected_group):
|
||||
psk_agent = PSKAgent("secret123")
|
||||
wd.register_psk_agent(psk_agent)
|
||||
|
||||
devices = wd.list_devices(1)
|
||||
self.assertIsNotNone(devices)
|
||||
device = devices[0]
|
||||
|
||||
device.disconnect()
|
||||
|
||||
network = device.get_ordered_network(ssid, full_scan=True)
|
||||
|
||||
self.assertEqual(network.type, NetworkType.psk)
|
||||
|
||||
network.network_object.connect()
|
||||
|
||||
condition = 'obj.state == DeviceState.connected'
|
||||
wd.wait_for_object_condition(device, condition)
|
||||
|
||||
wd.wait(2)
|
||||
|
||||
testutil.test_iface_operstate(intf=device.name)
|
||||
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
|
||||
|
||||
# Initial connection PMKSA should not be used. So we should see the
|
||||
# SAE group set.
|
||||
sta_status = hostapd.sta_status(device.address)
|
||||
self.assertEqual(int(sta_status["sae_group"]), expected_group)
|
||||
|
||||
device.disconnect()
|
||||
|
||||
condition = 'not obj.connected'
|
||||
wd.wait_for_object_condition(network.network_object, condition)
|
||||
|
||||
wd.unregister_psk_agent(psk_agent)
|
||||
|
||||
network.network_object.connect(wait=False)
|
||||
|
||||
condition = 'obj.state == DeviceState.connected'
|
||||
wd.wait_for_object_condition(device, condition)
|
||||
|
||||
wd.wait(2)
|
||||
|
||||
testutil.test_iface_operstate(intf=device.name)
|
||||
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
|
||||
|
||||
# Having connected once prior we should have a PMKSA and SAE should not
|
||||
# have been used.
|
||||
sta_status = hostapd.sta_status(device.address)
|
||||
self.assertNotIn("sae_group", sta_status.keys())
|
||||
|
||||
device.disconnect()
|
||||
|
||||
condition = 'not obj.connected'
|
||||
wd.wait_for_object_condition(network.network_object, condition)
|
||||
|
||||
hostapd.pmksa_flush()
|
||||
|
||||
wd.wait(5)
|
||||
|
||||
network.network_object.connect()
|
||||
|
||||
device.wait_for_event("pmksa-invalid-pmkid")
|
||||
|
||||
condition = 'obj.state == DeviceState.connected'
|
||||
wd.wait_for_object_condition(device, condition)
|
||||
|
||||
wd.wait(2)
|
||||
|
||||
testutil.test_iface_operstate(intf=device.name)
|
||||
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
|
||||
|
||||
# Manually flushing the PMKSA from the AP then reconnecting we should
|
||||
# have failed (INVALID_PMKID) then retried the same BSS with SAE, not
|
||||
# PMKSA.
|
||||
sta_status = hostapd.sta_status(device.address)
|
||||
self.assertEqual(int(sta_status["sae_group"]), expected_group)
|
||||
|
||||
def test_pmksa_sae(self):
|
||||
self.hostapd.wait_for_event("AP-ENABLED")
|
||||
self.validate_connection(self.wd, "ssidSAE", self.hostapd, 19)
|
||||
|
||||
def setUp(self):
|
||||
self.hostapd.default()
|
||||
self.wd = IWD(True)
|
||||
|
||||
def tearDown(self):
|
||||
self.wd.clear_storage()
|
||||
self.wd = None
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.hostapd = HostapdCLI(config='ssidSAE.conf')
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(exit=True)
|
@ -1,7 +0,0 @@
|
||||
[SETUP]
|
||||
num_radios=2
|
||||
start_iwd=0
|
||||
hwsim_medium=yes
|
||||
|
||||
[HOSTAPD]
|
||||
rad0=ssidSAE.conf
|
@ -1,12 +0,0 @@
|
||||
hw_mode=g
|
||||
channel=1
|
||||
ssid=ssidSAE
|
||||
|
||||
wpa=2
|
||||
wpa_key_mgmt=SAE
|
||||
wpa_pairwise=CCMP
|
||||
sae_password=secret123
|
||||
sae_groups=19
|
||||
ieee80211w=2
|
||||
sae_pwe=0
|
||||
rsn_preauth=1
|
@ -17,7 +17,7 @@ from hwsim import Hwsim
|
||||
class Test(unittest.TestCase):
|
||||
# Normally the time between a failed roam attempt and the next roam attempt
|
||||
# is 60 seconds (default RoamRetryInterval). Test that we retry roaming
|
||||
# faster if the transition looks like this: LOW [roam] [same bss] HIGH LOW.
|
||||
# faster if the transision looks like this: LOW [roam] [same bss] HIGH LOW.
|
||||
def test_fast_retry(self):
|
||||
hwsim = Hwsim()
|
||||
|
||||
|
@ -15,7 +15,7 @@ from hostapd import HostapdCLI
|
||||
from hwsim import Hwsim
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
# Test that we do not periodically retry roaming if the transition looks
|
||||
# Test that we do not periodically retry roaming if the transision looks
|
||||
# like this: LOW [roam] [new bss] HIGH.
|
||||
def test_stop_retry(self):
|
||||
hwsim = Hwsim()
|
||||
|
@ -13,7 +13,7 @@ import testutil
|
||||
from config import ctx
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
def validate_connection(self, wd, ft=True, check_used_pmksa=False):
|
||||
def validate_connection(self, wd, ft=True):
|
||||
device = wd.list_devices(1)[0]
|
||||
|
||||
# This won't guarantee all BSS's are found, but at least ensures that
|
||||
@ -37,14 +37,6 @@ class Test(unittest.TestCase):
|
||||
self.assertRaises(Exception, testutil.test_ifaces_connected,
|
||||
(self.bss_hostapd[1].ifname, device.name, True, True))
|
||||
|
||||
# If PMKSA was used, hostapd should not include the sae_group key in
|
||||
# its status for the station.
|
||||
sta_status = self.bss_hostapd[0].sta_status(device.address)
|
||||
if check_used_pmksa:
|
||||
self.assertNotIn("sae_group", sta_status.keys())
|
||||
else:
|
||||
self.assertIn("sae_group", sta_status.keys())
|
||||
|
||||
device.roam(self.bss_hostapd[1].bssid)
|
||||
|
||||
# Check that iwd is on BSS 1 once out of roaming state and doesn't
|
||||
@ -96,31 +88,6 @@ class Test(unittest.TestCase):
|
||||
|
||||
self.validate_connection(wd, True)
|
||||
|
||||
def test_ft_roam_pmksa(self):
|
||||
wd = IWD(True)
|
||||
|
||||
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'FT-SAE SAE')
|
||||
self.bss_hostapd[0].reload()
|
||||
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
|
||||
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'FT-SAE SAE')
|
||||
self.bss_hostapd[1].reload()
|
||||
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
|
||||
self.bss_hostapd[2].set_value('wpa_key_mgmt', 'FT-PSK')
|
||||
self.bss_hostapd[2].reload()
|
||||
self.bss_hostapd[2].wait_for_event("AP-ENABLED")
|
||||
|
||||
self.validate_connection(wd, True)
|
||||
|
||||
device = wd.list_devices(1)[0]
|
||||
device.disconnect()
|
||||
|
||||
for hapd in self.bss_hostapd:
|
||||
hapd.deauthenticate(device.address)
|
||||
|
||||
wd.wait(5)
|
||||
|
||||
self.validate_connection(wd, True, check_used_pmksa=True)
|
||||
|
||||
def test_reassociate_roam_success(self):
|
||||
wd = IWD(True)
|
||||
|
||||
@ -136,31 +103,6 @@ class Test(unittest.TestCase):
|
||||
|
||||
self.validate_connection(wd, False)
|
||||
|
||||
def test_reassociate_roam_pmksa(self):
|
||||
wd = IWD(True)
|
||||
|
||||
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'SAE')
|
||||
self.bss_hostapd[0].reload()
|
||||
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
|
||||
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'SAE')
|
||||
self.bss_hostapd[1].reload()
|
||||
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
|
||||
self.bss_hostapd[2].set_value('wpa_key_mgmt', 'WPA-PSK')
|
||||
self.bss_hostapd[2].reload()
|
||||
self.bss_hostapd[2].wait_for_event("AP-ENABLED")
|
||||
|
||||
self.validate_connection(wd, False)
|
||||
|
||||
device = wd.list_devices(1)[0]
|
||||
device.disconnect()
|
||||
|
||||
for hapd in self.bss_hostapd:
|
||||
hapd.deauthenticate(device.address)
|
||||
|
||||
wd.wait(5)
|
||||
|
||||
self.validate_connection(wd, False, check_used_pmksa=True)
|
||||
|
||||
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')
|
||||
|
@ -4,6 +4,3 @@
|
||||
# hardware, but fails when used in simulated environment with mac80211_hwsim.
|
||||
# Disable MAC randomization for the tests with hidden networks.
|
||||
DisableMacAddressRandomization=true
|
||||
|
||||
[General]
|
||||
DisablePMKSA=true
|
||||
|
@ -368,7 +368,3 @@ class HostapdCLI(object):
|
||||
others = [h for h in args if h != hapd]
|
||||
|
||||
hapd._add_neighbors(*others)
|
||||
|
||||
def pmksa_flush(self):
|
||||
cmd = self.cmdline + ['pmksa_flush']
|
||||
ctx.start_process(cmd).wait()
|
||||
|
@ -7,10 +7,7 @@ from weakref import WeakValueDictionary
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from enum import Enum
|
||||
from scapy.all import *
|
||||
try:
|
||||
from scapy.contrib.wpa_eapol import WPA_key
|
||||
except:
|
||||
from scapy.layers.eap import EAPOL_KEY
|
||||
from scapy.contrib.wpa_eapol import WPA_key
|
||||
|
||||
import iwd
|
||||
from config import ctx
|
||||
@ -447,15 +444,9 @@ class Hwsim(iwd.AsyncOpAbstract):
|
||||
|
||||
# NOTE: Expected key_info is 0x008a, with the install flag
|
||||
# this becomes 0x00ca.
|
||||
try:
|
||||
eapol = WPA_key( descriptor_type = 2,
|
||||
key_info = 0x00ca, # Includes an invalid install flag!
|
||||
replay_counter = struct.pack(">Q", 100))
|
||||
except:
|
||||
eapol = EAPOL_KEY( key_descriptor_type = 2,
|
||||
install = 1,
|
||||
key_ack = 1,
|
||||
key_replay_counter = 1)
|
||||
eapol = WPA_key( descriptor_type = 2,
|
||||
key_info = 0x00ca, # Includes an invalid install flag!
|
||||
replay_counter = struct.pack(">Q", 100))
|
||||
frame /= LLC()/SNAP()/EAPOL(version="802.1X-2004", type="EAPOL-Key")
|
||||
frame /= eapol
|
||||
|
||||
|
@ -450,15 +450,13 @@ class Device(IWDDBusAbstract):
|
||||
self._wps_manager_if = None
|
||||
self._station_if = None
|
||||
self._station_props = None
|
||||
self._station_debug_obj = None
|
||||
self._dpp_obj = None
|
||||
self._sc_dpp_obj = None
|
||||
self._ap_obj = None
|
||||
|
||||
IWDDBusAbstract.__init__(self, *args, **kwargs)
|
||||
|
||||
self._station_debug_obj = StationDebug(object_path=self._object_path,
|
||||
namespace=self._namespace)
|
||||
|
||||
@property
|
||||
def _wps_manager(self):
|
||||
if self._wps_manager_if is None:
|
||||
@ -598,11 +596,6 @@ class Device(IWDDBusAbstract):
|
||||
props = self._station_properties()
|
||||
return props.get('ConnectedNetwork')
|
||||
|
||||
@property
|
||||
def connected_bss(self):
|
||||
props = self._station_properties()
|
||||
return props.get('ConnectedAccessPoint')
|
||||
|
||||
@property
|
||||
def powered(self):
|
||||
'''
|
||||
@ -637,19 +630,6 @@ class Device(IWDDBusAbstract):
|
||||
self._station_debug._prop_proxy.Set(IWD_STATION_DEBUG_INTERFACE,
|
||||
'AutoConnect', value)
|
||||
|
||||
@property
|
||||
def affinities(self):
|
||||
return self._station_properties()['Affinities']
|
||||
|
||||
@affinities.setter
|
||||
def affinities(self, values):
|
||||
self._station_properties()
|
||||
self._station_prop_if.Set(
|
||||
IWD_STATION_INTERFACE, 'Affinities',
|
||||
dbus.Array([dbus.ObjectPath(v) for v in values], signature="o"),
|
||||
reply_handler=self._success, error_handler=self._failure)
|
||||
self._wait_for_async_op()
|
||||
|
||||
def scan(self, wait=True):
|
||||
'''Schedule a network scan.
|
||||
|
||||
@ -1483,10 +1463,10 @@ class IWD(AsyncOpAbstract):
|
||||
|
||||
@staticmethod
|
||||
def create_in_storage(file_name, file_content, storage_dir=IWD_STORAGE_DIR):
|
||||
f = open(storage_dir + '/' + file_name, 'w')
|
||||
fo = open(storage_dir + '/' + file_name, 'w')
|
||||
|
||||
f.write(file_content)
|
||||
f.close()
|
||||
fo.write(file_content)
|
||||
fo.close()
|
||||
|
||||
@staticmethod
|
||||
def _ensure_storage_dir_exists(storage_dir):
|
||||
|
@ -237,7 +237,7 @@ class Wpas:
|
||||
('' if go_intent is None else ' go_intent=' + str(go_intent)))
|
||||
self.wait_for_event('OK')
|
||||
|
||||
# Pre-accept the next GO Negotiation Request from this peer to avoid the extra Response + Request frames
|
||||
# Pre-accept the next GO Negotiation Request from this peer to avoid the extra Respone + Request frames
|
||||
def p2p_authorize(self, peer, pin=None, go_intent=None):
|
||||
self._rx_data = []
|
||||
self._ctrl_request('P2P_CONNECT ' + peer['p2p_dev_addr'] + ' ' + ('pbc' if pin is None else pin) +
|
||||
|
@ -186,5 +186,5 @@ void diagnostic_display(struct l_dbus_message_iter *dict,
|
||||
return;
|
||||
|
||||
parse_error:
|
||||
display_error("Error parsing diagnostics");
|
||||
display_error("Error parsing dignostics");
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ static void network_display_inline(const char *margin, const void *data)
|
||||
|
||||
display("%s%s %s %s\n", margin, network->name ? network->name : "",
|
||||
network->type ? network->type : "",
|
||||
network->connected ? "connected" : "disconnected");
|
||||
network->connected ? "connected" : "diconnected");
|
||||
}
|
||||
|
||||
static void *network_create(void)
|
||||
|
@ -1,12 +1,10 @@
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([iwd],[3.6])
|
||||
AC_INIT([iwd],[2.20])
|
||||
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
AC_CONFIG_AUX_DIR(build-aux)
|
||||
AC_CONFIG_MACRO_DIR(build-aux)
|
||||
|
||||
AC_REQUIRE_AUX_FILE([tap-driver.sh])
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
|
||||
tar-pax no-dist-gzip dist-xz])
|
||||
|
||||
@ -31,7 +29,6 @@ AC_PROG_CC_GCOV
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MKDIR_P
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_AWK
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
@ -300,7 +297,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.68"
|
||||
else
|
||||
ell_min_version="0.5"
|
||||
fi
|
||||
|
@ -322,10 +322,10 @@ M18: Use appropriate logging levels
|
||||
An appropriate log level should be used depending on the type of message
|
||||
being logged. Logging is done using the l_log APIs in ELL:
|
||||
|
||||
l_error An unexpected condition occurred. These are generally fatal to the
|
||||
l_error An unexpected condition ocurred. These are generally fatal to the
|
||||
current connection/protocol that is running but not generally to IWD's
|
||||
overall operation.
|
||||
l_warn An unexpected, but non-fatal condition occurred
|
||||
l_warn An unexpected, but non-fatal condition ocurred
|
||||
l_notice Should not be used directly. This log level is reserved for special
|
||||
event type notifications which is handled by iwd_notice().
|
||||
l_info Information that is expected during normal operation. l_info's use
|
||||
|
@ -135,7 +135,7 @@ Object path /net/connman/iwd/{phy0,phy1,...}/{1,2,...}
|
||||
void StartConfigurator(object agent_path)
|
||||
|
||||
Start a shared code configurator using an agent
|
||||
(distinguished by 'agent_path') to obtain the shared
|
||||
(distingushed by 'agent_path') to obtain the shared
|
||||
code. This method is meant for an automated use case
|
||||
where a configurator is capable of configuring multiple
|
||||
enrollees, and distinguishing between them by their
|
||||
@ -196,7 +196,7 @@ Methods void Release() [noreply]
|
||||
string RequestSharedCode(string identifier)
|
||||
|
||||
This method gets called when a shared code is requested
|
||||
for a particular enrollee, distinguished by the
|
||||
for a particular enrollee, distingushed by the
|
||||
identifier. The shared code agent should lookup the
|
||||
identifier and return the shared code, or return an
|
||||
error if not found.
|
||||
|
@ -5,7 +5,7 @@ credentials for your e.g. cable/cellular provider, or via a dedicated account
|
||||
like Boingo. Lots of these services also allow you to roam between networks.
|
||||
|
||||
The underlying authentication is standard WPA2-Enterprise but Hotspot 2.0 adds a
|
||||
'discovery' stage to identifying networks. This discovery is done using ANQP,
|
||||
'discovery' stage to identifiying networks. This discovery is done using ANQP,
|
||||
which queries the network for additional information to determine if the client
|
||||
has the credentials to connect.
|
||||
|
||||
|
@ -56,7 +56,7 @@ Methods array(on) GetPeers()
|
||||
between requested threshold values is a compromise
|
||||
between resolution and the frequency of system
|
||||
wakeups and context-switches that are going to be
|
||||
occurring to update the client's signal meter. Only
|
||||
occuring to update the client's signal meter. Only
|
||||
one agent can be registered at any time.
|
||||
|
||||
Possible errors: [service].Error.InvalidArguments
|
||||
|
@ -166,27 +166,10 @@ Properties string State [readonly]
|
||||
|
||||
object ConnectedAccessPoint [readonly, optional]
|
||||
|
||||
net.connman.iwd.BasicServiceSet object representing the
|
||||
net.connman.iwd.BasicServiceSet object represeting the
|
||||
BSS the device is currently connected to or to which
|
||||
a connection is in progress.
|
||||
|
||||
ao Affinities [optional] [experimental]
|
||||
|
||||
Array of net.connman.iwd.BasicServiceSet object paths
|
||||
that will be treated with higher affinity compared to
|
||||
other BSS's. Currently the only allowed value to be
|
||||
set in this array is the path to the currently connected
|
||||
BasicServiceSet object, i.e.
|
||||
Station.ConnectedAccessPoint.
|
||||
|
||||
Setting the affinity will lower the roaming threshold,
|
||||
effectively locking IWD to the current BSS unless the
|
||||
RSSI drops below the critical threshold set by
|
||||
[General].CriticalRoamThreshold{5G} at which point
|
||||
IWD will proceed with normal roaming behavior.
|
||||
|
||||
This property is cleared on roams/disconnections.
|
||||
|
||||
SignalLevelAgent hierarchy
|
||||
==========================
|
||||
|
||||
|
@ -218,7 +218,7 @@ supplicant running IWD:
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~ hw.conf ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# Lines starting with # are ignored
|
||||
|
||||
# 'SETUP' is a mandatory configuration group.
|
||||
# 'SETUP' is a manditory configuration group.
|
||||
[SETUP]
|
||||
#
|
||||
# Total number of radios requested per network setup. This includes
|
||||
|
@ -578,7 +578,7 @@ static int analyze_pcap(const char *pathname)
|
||||
printf("\n");
|
||||
printf(" Number of packets: %lu\n", pkt_count);
|
||||
printf(" Short packets: %lu\n", pkt_short);
|
||||
printf(" Truncated packets: %lu\n", pkt_trunc);
|
||||
printf(" Tuncated packets: %lu\n", pkt_trunc);
|
||||
printf("\n");
|
||||
printf(" Ethernet packets: %lu\n", pkt_ether);
|
||||
printf(" PAE packets: %lu\n", pkt_pae);
|
||||
@ -718,36 +718,29 @@ static void usage(void)
|
||||
"Usage:\n");
|
||||
printf("\tiwmon [options]\n");
|
||||
printf("Options:\n"
|
||||
"\t-r, --read <file> Read netlink PCAP trace file\n"
|
||||
"\t-w, --write <file> Write netlink PCAP trace file\n"
|
||||
"\t-a, --analyze <file> Analyze netlink PCAP trace file\n"
|
||||
"\t-i, --interface <dev> Use specified netlink monitor\n"
|
||||
"\t-n, --nortnl Don't show RTNL output\n"
|
||||
"\t-y, --nowiphy Don't show 'New Wiphy' output\n"
|
||||
"\t-s, --noscan Don't show scan result output\n"
|
||||
"\t-e, --noies Don't show IEs except SSID\n"
|
||||
"\t-t, --time-format <format> Time format to display. Either\n"
|
||||
"\t\t\t\t 'delta' or 'utc'.\n"
|
||||
"\t-W,--pcap-count Maximum number of PCAP files\n"
|
||||
"\t-C,--pcap-size Maximum size (MB) of PCAP files\n"
|
||||
"\t-h, --help Show help options\n");
|
||||
"\t-r, --read <file> Read netlink PCAP trace file\n"
|
||||
"\t-w, --write <file> Write netlink PCAP trace file\n"
|
||||
"\t-a, --analyze <file> Analyze netlink PCAP trace file\n"
|
||||
"\t-i, --interface <dev> Use specified netlink monitor\n"
|
||||
"\t-n, --nortnl Don't show RTNL output\n"
|
||||
"\t-y, --nowiphy Don't show 'New Wiphy' output\n"
|
||||
"\t-s, --noscan Don't show scan result output\n"
|
||||
"\t-e, --noies Don't show IEs except SSID\n"
|
||||
"\t-h, --help Show help options\n");
|
||||
}
|
||||
|
||||
static const struct option main_options[] = {
|
||||
{ "read", required_argument, NULL, 'r' },
|
||||
{ "write", required_argument, NULL, 'w' },
|
||||
{ "analyze", required_argument, NULL, 'a' },
|
||||
{ "nl80211", required_argument, NULL, 'F' },
|
||||
{ "interface", required_argument, NULL, 'i' },
|
||||
{ "nortnl", no_argument, NULL, 'n' },
|
||||
{ "nowiphy", no_argument, NULL, 'y' },
|
||||
{ "noscan", no_argument, NULL, 's' },
|
||||
{ "noies", no_argument, NULL, 'e' },
|
||||
{ "time-format", required_argument, NULL, 't' },
|
||||
{ "pcap-count", required_argument, NULL, 'W' },
|
||||
{ "pcap-size", required_argument, NULL, 'C' },
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "read", required_argument, NULL, 'r' },
|
||||
{ "write", required_argument, NULL, 'w' },
|
||||
{ "analyze", required_argument, NULL, 'a' },
|
||||
{ "nl80211", required_argument, NULL, 'F' },
|
||||
{ "interface", required_argument, NULL, 'i' },
|
||||
{ "nortnl", no_argument, NULL, 'n' },
|
||||
{ "nowiphy", no_argument, NULL, 'y' },
|
||||
{ "noscan", no_argument, NULL, 's' },
|
||||
{ "noies", no_argument, NULL, 'e' },
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -761,7 +754,7 @@ int main(int argc, char *argv[])
|
||||
for (;;) {
|
||||
int opt;
|
||||
|
||||
opt = getopt_long(argc, argv, "r:w:a:i:t:W:C:nvhyse",
|
||||
opt = getopt_long(argc, argv, "r:w:a:i:nvhyse",
|
||||
main_options, NULL);
|
||||
if (opt < 0)
|
||||
break;
|
||||
@ -791,35 +784,6 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
case 'e':
|
||||
config.noies = true;
|
||||
break;
|
||||
case 't':
|
||||
if (!strcmp(optarg, "delta"))
|
||||
config.time_format = TIME_FORMAT_DELTA;
|
||||
else if (!strcmp(optarg, "utc"))
|
||||
config.time_format = TIME_FORMAT_UTC;
|
||||
else {
|
||||
printf("Invalid time format '%s'", optarg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'W':
|
||||
if (l_safe_atou32(optarg,
|
||||
&config.pcap_file_count) < 0 ||
|
||||
config.pcap_file_count == 0) {
|
||||
printf("Invalid file count '%s'\n", optarg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'C':
|
||||
if (l_safe_atou32(optarg,
|
||||
&config.pcap_file_size) < 0 ||
|
||||
config.pcap_file_size == 0) {
|
||||
printf("Invalid file size '%s'\n", optarg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'v':
|
||||
printf("%s\n", VERSION);
|
||||
|
165
monitor/nlmon.c
165
monitor/nlmon.c
@ -29,7 +29,6 @@
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
@ -43,21 +42,12 @@
|
||||
#include <linux/genetlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/limits.h>
|
||||
#include <ell/ell.h>
|
||||
|
||||
#ifndef ARPHRD_NETLINK
|
||||
#define ARPHRD_NETLINK 824
|
||||
#endif
|
||||
|
||||
#ifndef RMNET_FLAGS_INGRESS_MAP_CKSUMV5
|
||||
#define RMNET_FLAGS_INGRESS_MAP_CKSUMV5 (1U << 4)
|
||||
#endif
|
||||
|
||||
#ifndef RMNET_FLAGS_EGRESS_MAP_CKSUMV5
|
||||
#define RMNET_FLAGS_EGRESS_MAP_CKSUMV5 (1U << 5)
|
||||
#endif
|
||||
|
||||
#include "linux/nl80211.h"
|
||||
|
||||
#include "ell/useful.h"
|
||||
@ -95,8 +85,6 @@
|
||||
#define BSS_CAPABILITY_APSD (1<<11)
|
||||
#define BSS_CAPABILITY_DSSS_OFDM (1<<13)
|
||||
|
||||
#define BYTES_PER_MB 1000000
|
||||
|
||||
struct nlmon *cur_nlmon;
|
||||
|
||||
enum msg_type {
|
||||
@ -117,12 +105,6 @@ struct nlmon {
|
||||
bool noscan;
|
||||
bool noies;
|
||||
bool read;
|
||||
enum time_format time_format;
|
||||
|
||||
char *file_prefix;
|
||||
unsigned int file_idx;
|
||||
unsigned int max_files;
|
||||
unsigned int max_size;
|
||||
};
|
||||
|
||||
struct nlmon_req {
|
||||
@ -195,15 +177,11 @@ static void nlmon_req_free(void *data)
|
||||
}
|
||||
|
||||
static time_t time_offset = ((time_t) -1);
|
||||
static enum time_format time_format;
|
||||
|
||||
static inline void update_time_offset(const struct timeval *tv,
|
||||
enum time_format tf)
|
||||
static inline void update_time_offset(const struct timeval *tv)
|
||||
{
|
||||
if (tv && time_offset == ((time_t) -1)) {
|
||||
if (tv && time_offset == ((time_t) -1))
|
||||
time_offset = tv->tv_sec;
|
||||
time_format = tf;
|
||||
}
|
||||
}
|
||||
|
||||
#define print_indent(indent, color1, prefix, title, color2, fmt, args...) \
|
||||
@ -239,38 +217,15 @@ static void print_packet(const struct timeval *tv, char ident,
|
||||
int n, ts_len = 0, ts_pos = 0, len = 0, pos = 0;
|
||||
|
||||
if (tv) {
|
||||
struct tm *tm;
|
||||
|
||||
if (use_color()) {
|
||||
n = sprintf(ts_str + ts_pos, "%s", COLOR_TIMESTAMP);
|
||||
if (n > 0)
|
||||
ts_pos += n;
|
||||
}
|
||||
|
||||
switch (time_format) {
|
||||
case TIME_FORMAT_DELTA:
|
||||
n = sprintf(ts_str + ts_pos, " %" PRId64 ".%06" PRId64,
|
||||
n = sprintf(ts_str + ts_pos, " %" PRId64 ".%06" PRId64,
|
||||
(int64_t)tv->tv_sec - time_offset,
|
||||
(int64_t)tv->tv_usec);
|
||||
break;
|
||||
case TIME_FORMAT_UTC:
|
||||
tm = gmtime(&tv->tv_sec);
|
||||
if (!tm) {
|
||||
n = sprintf(ts_str + ts_pos, "%s",
|
||||
"Time error");
|
||||
break;
|
||||
}
|
||||
|
||||
n = strftime(ts_str + ts_pos, sizeof(ts_str) - ts_pos,
|
||||
"%b %d %H:%M:%S", tm);
|
||||
break;
|
||||
default:
|
||||
/* Should never happen */
|
||||
printf("Unknown time format");
|
||||
l_main_quit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
ts_pos += n;
|
||||
ts_len += n;
|
||||
@ -528,30 +483,7 @@ static void print_ie_country(unsigned int level, const char *label,
|
||||
return;
|
||||
}
|
||||
|
||||
print_attr(level, "%s: %c%c", label, code[0], code[1]);
|
||||
|
||||
switch (code[2]) {
|
||||
case ' ':
|
||||
print_attr(level + 1,
|
||||
"3rd octet: 0x%02x: All environments", code[2]);
|
||||
break;
|
||||
case 'O':
|
||||
print_attr(level + 1,
|
||||
"3rd octet: 0x%02x: Outdoor environments", code[2]);
|
||||
break;
|
||||
case 'I':
|
||||
print_attr(level + 1,
|
||||
"3rd octet: 0x%02x: Indoor environments", code[2]);
|
||||
break;
|
||||
case 'X':
|
||||
print_attr(level + 1,
|
||||
"3rd octet: 0x%02x: Non-country entity", code[2]);
|
||||
break;
|
||||
default:
|
||||
print_attr(level + 1,
|
||||
"3rd octet: 0x%02x: Annex E table", code[2]);
|
||||
break;
|
||||
}
|
||||
print_attr(level, "%s: %c%c%c", label, code[0], code[1], code[2]);
|
||||
|
||||
while (i < size) {
|
||||
if (code[i] > 200) {
|
||||
@ -1718,7 +1650,7 @@ static void print_ie_vht_capabilities(unsigned int level,
|
||||
[21] = "TXOP PS",
|
||||
[22] = "+HTC-VHT Capable",
|
||||
[23 ... 25] = "Maximum A-MPDU Length Exponent",
|
||||
[26 ... 27] = "VHT Link Adaptation Capable",
|
||||
[26 ... 27] = "VHT Link Adapation Capable",
|
||||
[28] = "RX Antenna Pattern Consistency",
|
||||
[29] = "TX Antenna Pattern Consistency",
|
||||
[30 ... 31] = "Extended NSS BW Support",
|
||||
@ -1915,7 +1847,7 @@ static void print_ie_interworking(unsigned int level,
|
||||
size--;
|
||||
ptr++;
|
||||
|
||||
if (size < 2)
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -7401,64 +7333,6 @@ static bool nlmon_req_match(const void *a, const void *b)
|
||||
return (req->seq == match->seq && req->pid == match->pid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensures that PCAP names are zero padded when needed. This makes the files
|
||||
* sort correctly.
|
||||
*/
|
||||
static void next_pcap_name(char *buf, size_t size, const char *prefix,
|
||||
unsigned int idx, unsigned int max)
|
||||
{
|
||||
unsigned int ndigits = 1;
|
||||
|
||||
while (max > 9) {
|
||||
max /= 10;
|
||||
ndigits++;
|
||||
}
|
||||
|
||||
snprintf(buf, size, "%s%.*u", prefix, ndigits, idx);
|
||||
}
|
||||
|
||||
static bool check_pcap(struct nlmon *nlmon, size_t next_size)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (!nlmon->pcap)
|
||||
return false;
|
||||
|
||||
if (!nlmon->max_size)
|
||||
return true;
|
||||
|
||||
if (pcap_get_size(nlmon->pcap) + next_size <= nlmon->max_size)
|
||||
return true;
|
||||
|
||||
pcap_close(nlmon->pcap);
|
||||
|
||||
/* Exhausted the single PCAP file */
|
||||
if (nlmon->max_files < 2) {
|
||||
printf("Reached maximum size of PCAP, exiting\n");
|
||||
nlmon->pcap = NULL;
|
||||
l_main_quit();
|
||||
return false;
|
||||
}
|
||||
|
||||
next_pcap_name(path, sizeof(path), nlmon->file_prefix,
|
||||
++nlmon->file_idx, nlmon->max_files);
|
||||
|
||||
nlmon->pcap = pcap_create(path);
|
||||
|
||||
if (nlmon->max_files > nlmon->file_idx)
|
||||
return true;
|
||||
|
||||
/* Remove oldest PCAP file */
|
||||
next_pcap_name(path, sizeof(path), nlmon->file_prefix,
|
||||
nlmon->file_idx - nlmon->max_files, nlmon->max_files);
|
||||
|
||||
if (remove(path) < 0)
|
||||
printf("Failed to remove old PCAP file %s\n", path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void store_packet(struct nlmon *nlmon, const struct timeval *tv,
|
||||
uint16_t pkt_type,
|
||||
uint16_t arphrd_type,
|
||||
@ -7467,7 +7341,7 @@ static void store_packet(struct nlmon *nlmon, const struct timeval *tv,
|
||||
{
|
||||
uint8_t sll_hdr[16], *buf = sll_hdr;
|
||||
|
||||
if (!check_pcap(nlmon, sizeof(sll_hdr) + size))
|
||||
if (!nlmon->pcap)
|
||||
return;
|
||||
|
||||
memset(sll_hdr, 0, sizeof(sll_hdr));
|
||||
@ -7592,10 +7466,6 @@ struct nlmon *nlmon_create(uint16_t id, const struct nlmon_config *config)
|
||||
nlmon->noscan = config->noscan;
|
||||
nlmon->noies = config->noies;
|
||||
nlmon->read = config->read_only;
|
||||
nlmon->time_format = config->time_format;
|
||||
nlmon->max_files = config->pcap_file_count;
|
||||
/* Command line expects MB, but use bytes internally */
|
||||
nlmon->max_size = config->pcap_file_size * BYTES_PER_MB;
|
||||
|
||||
return nlmon;
|
||||
}
|
||||
@ -8432,10 +8302,7 @@ void nlmon_print_rtnl(struct nlmon *nlmon, const struct timeval *tv,
|
||||
int64_t aligned_size = NLMSG_ALIGN(size);
|
||||
const struct nlmsghdr *nlmsg;
|
||||
|
||||
if (nlmon->nortnl)
|
||||
return;
|
||||
|
||||
update_time_offset(tv, nlmon->time_format);
|
||||
update_time_offset(tv);
|
||||
|
||||
for (nlmsg = data; NLMSG_OK(nlmsg, aligned_size);
|
||||
nlmsg = NLMSG_NEXT(nlmsg, aligned_size)) {
|
||||
@ -8473,7 +8340,7 @@ void nlmon_print_genl(struct nlmon *nlmon, const struct timeval *tv,
|
||||
{
|
||||
const struct nlmsghdr *nlmsg;
|
||||
|
||||
update_time_offset(tv, nlmon->time_format);
|
||||
update_time_offset(tv);
|
||||
|
||||
for (nlmsg = data; NLMSG_OK(nlmsg, size);
|
||||
nlmsg = NLMSG_NEXT(nlmsg, size)) {
|
||||
@ -8496,7 +8363,7 @@ void nlmon_print_pae(struct nlmon *nlmon, const struct timeval *tv,
|
||||
{
|
||||
char extra_str[16];
|
||||
|
||||
update_time_offset(tv, nlmon->time_format);
|
||||
update_time_offset(tv);
|
||||
|
||||
sprintf(extra_str, "len %u", size);
|
||||
|
||||
@ -8623,20 +8490,13 @@ struct nlmon *nlmon_open(uint16_t id, const char *pathname,
|
||||
struct nlmon *nlmon;
|
||||
struct l_io *pae_io;
|
||||
struct pcap *pcap;
|
||||
char path[PATH_MAX];
|
||||
|
||||
pae_io = open_pae();
|
||||
if (!pae_io)
|
||||
return NULL;
|
||||
|
||||
if (pathname) {
|
||||
if (config->pcap_file_count > 1)
|
||||
next_pcap_name(path, sizeof(path), pathname,
|
||||
0, config->pcap_file_count);
|
||||
else
|
||||
snprintf(path, sizeof(path), "%s", pathname);
|
||||
|
||||
pcap = pcap_create(path);
|
||||
pcap = pcap_create(pathname);
|
||||
if (!pcap) {
|
||||
l_io_destroy(pae_io);
|
||||
return NULL;
|
||||
@ -8649,7 +8509,6 @@ struct nlmon *nlmon_open(uint16_t id, const char *pathname,
|
||||
|
||||
nlmon->pae_io = pae_io;
|
||||
nlmon->pcap = pcap;
|
||||
nlmon->file_prefix = l_strdup(pathname);
|
||||
|
||||
l_io_set_read_handler(nlmon->pae_io, pae_receive, nlmon, NULL);
|
||||
|
||||
@ -8672,7 +8531,5 @@ void nlmon_close(struct nlmon *nlmon)
|
||||
if (nlmon->pcap)
|
||||
pcap_close(nlmon->pcap);
|
||||
|
||||
l_free(nlmon->file_prefix);
|
||||
|
||||
l_free(nlmon);
|
||||
}
|
||||
|
@ -25,22 +25,12 @@
|
||||
|
||||
struct nlmon;
|
||||
|
||||
enum time_format {
|
||||
TIME_FORMAT_DELTA,
|
||||
TIME_FORMAT_UTC,
|
||||
};
|
||||
|
||||
struct nlmon_config {
|
||||
bool nortnl;
|
||||
bool nowiphy;
|
||||
bool noscan;
|
||||
bool noies;
|
||||
bool read_only;
|
||||
enum time_format time_format;
|
||||
|
||||
/* File size in MB */
|
||||
uint32_t pcap_file_size;
|
||||
uint32_t pcap_file_count;
|
||||
};
|
||||
|
||||
struct nlmon *nlmon_open(uint16_t id, const char *pathname,
|
||||
|
@ -60,7 +60,6 @@ struct pcap {
|
||||
bool closed;
|
||||
uint32_t type;
|
||||
uint32_t snaplen;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct pcap *pcap_open(const char *pathname)
|
||||
@ -153,8 +152,6 @@ struct pcap *pcap_create(const char *pathname)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
pcap->size += len;
|
||||
|
||||
return pcap;
|
||||
|
||||
failed:
|
||||
@ -191,11 +188,6 @@ uint32_t pcap_get_snaplen(struct pcap *pcap)
|
||||
return pcap->snaplen;
|
||||
}
|
||||
|
||||
size_t pcap_get_size(struct pcap *pcap)
|
||||
{
|
||||
return pcap->size;
|
||||
}
|
||||
|
||||
bool pcap_read(struct pcap *pcap, struct timeval *tv,
|
||||
void *data, uint32_t size, uint32_t *len, uint32_t *real_len)
|
||||
{
|
||||
@ -287,7 +279,5 @@ bool pcap_write(struct pcap *pcap, const struct timeval *tv,
|
||||
return false;
|
||||
}
|
||||
|
||||
pcap->size += written;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ void pcap_close(struct pcap *pcap);
|
||||
|
||||
uint32_t pcap_get_type(struct pcap *pcap);
|
||||
uint32_t pcap_get_snaplen(struct pcap *pcap);
|
||||
size_t pcap_get_size(struct pcap *pcap);
|
||||
|
||||
bool pcap_read(struct pcap *pcap, struct timeval *tv,
|
||||
void *data, uint32_t size, uint32_t *len, uint32_t *real_len);
|
||||
|
@ -94,13 +94,13 @@ static void adhoc_sta_free(void *data)
|
||||
eapol_sm_free(sta->sm);
|
||||
|
||||
if (sta->hs_sta)
|
||||
handshake_state_unref(sta->hs_sta);
|
||||
handshake_state_free(sta->hs_sta);
|
||||
|
||||
if (sta->sm_a)
|
||||
eapol_sm_free(sta->sm_a);
|
||||
|
||||
if (sta->hs_auth)
|
||||
handshake_state_unref(sta->hs_auth);
|
||||
handshake_state_free(sta->hs_auth);
|
||||
|
||||
end:
|
||||
l_free(sta);
|
||||
|
@ -234,7 +234,7 @@ uint32_t anqp_request(uint64_t wdev_id, const uint8_t *addr,
|
||||
request->anqp_cb = cb;
|
||||
request->anqp_destroy = destroy;
|
||||
/*
|
||||
* WPA3 Specification version 3, Section 9.4:
|
||||
* WPA3 Specificiation version 3, Section 9.4:
|
||||
* "A STA shall use a randomized dialog token for every new GAS
|
||||
* exchange."
|
||||
*/
|
||||
|
@ -131,7 +131,7 @@ char **anqp_parse_nai_realms(const unsigned char *anqp, unsigned int len)
|
||||
uint16_t count;
|
||||
|
||||
if (len < 2)
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
count = l_get_le16(anqp);
|
||||
|
||||
|
14
src/ap.c
14
src/ap.c
@ -230,7 +230,7 @@ static void ap_stop_handshake(struct sta_state *sta)
|
||||
}
|
||||
|
||||
if (sta->hs) {
|
||||
handshake_state_unref(sta->hs);
|
||||
handshake_state_free(sta->hs);
|
||||
sta->hs = NULL;
|
||||
}
|
||||
|
||||
@ -3914,34 +3914,34 @@ struct ap_state *ap_start(struct netdev *netdev, struct l_settings *config,
|
||||
|
||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||
(MPDU_MANAGEMENT_SUBTYPE_ASSOCIATION_REQUEST << 4),
|
||||
NULL, 0, false, ap_assoc_req_cb, ap, NULL))
|
||||
NULL, 0, ap_assoc_req_cb, ap, NULL))
|
||||
goto error;
|
||||
|
||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||
(MPDU_MANAGEMENT_SUBTYPE_REASSOCIATION_REQUEST << 4),
|
||||
NULL, 0, false, ap_reassoc_req_cb, ap, NULL))
|
||||
NULL, 0, ap_reassoc_req_cb, ap, NULL))
|
||||
goto error;
|
||||
|
||||
if (!wiphy_supports_probe_resp_offload(wiphy)) {
|
||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||
(MPDU_MANAGEMENT_SUBTYPE_PROBE_REQUEST << 4),
|
||||
NULL, 0, false, ap_probe_req_cb, ap, NULL))
|
||||
NULL, 0, ap_probe_req_cb, ap, NULL))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||
(MPDU_MANAGEMENT_SUBTYPE_DISASSOCIATION << 4),
|
||||
NULL, 0, false, ap_disassoc_cb, ap, NULL))
|
||||
NULL, 0, ap_disassoc_cb, ap, NULL))
|
||||
goto error;
|
||||
|
||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||
(MPDU_MANAGEMENT_SUBTYPE_AUTHENTICATION << 4),
|
||||
NULL, 0, false, ap_auth_cb, ap, NULL))
|
||||
NULL, 0, ap_auth_cb, ap, NULL))
|
||||
goto error;
|
||||
|
||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||
(MPDU_MANAGEMENT_SUBTYPE_DEAUTHENTICATION << 4),
|
||||
NULL, 0, false, ap_deauth_cb, ap, NULL))
|
||||
NULL, 0, ap_deauth_cb, ap, NULL))
|
||||
goto error;
|
||||
|
||||
ap->mlme_watch = l_genl_family_register(ap->nl80211, "mlme",
|
||||
|
2
src/ap.h
2
src/ap.h
@ -79,7 +79,7 @@ struct ap_ops {
|
||||
void *user_data);
|
||||
/*
|
||||
* If not null, writes extra IEs to be added to the outgoing frame of
|
||||
* given type and, if it's not a beacon frame, in response to a given
|
||||
* given type and, if it's not a beacon frame, in reponse to a given
|
||||
* client frame. May also react to the extra IEs in that frame.
|
||||
* Returns the number of bytes written which must be less than or
|
||||
* equal to the number returned by .get_extra_ies_len when called
|
||||
|
@ -54,7 +54,7 @@ void __iwd_backtrace_print(unsigned int offset)
|
||||
int pathlen;
|
||||
pid_t pid;
|
||||
|
||||
if (!program_exec)
|
||||
if (program_exec == NULL)
|
||||
return;
|
||||
|
||||
pathlen = strlen(program_path);
|
||||
@ -186,7 +186,7 @@ void __iwd_backtrace_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (!program_exec)
|
||||
if (program_exec == NULL)
|
||||
return;
|
||||
|
||||
program_path = getcwd(cwd, sizeof(cwd));
|
||||
|
@ -896,7 +896,7 @@ static const struct operating_class_info e4_operating_classes[] = {
|
||||
},
|
||||
{
|
||||
.operating_class = 136,
|
||||
.starting_frequency = 5925,
|
||||
.starting_frequency = 5950,
|
||||
.channel_spacing = 20,
|
||||
.center_frequencies = { 2 },
|
||||
}
|
||||
@ -1352,10 +1352,6 @@ check_e4:
|
||||
const struct operating_class_info *info =
|
||||
&e4_operating_classes[i];
|
||||
|
||||
if (band != band_oper_class_to_band(NULL,
|
||||
info->operating_class))
|
||||
continue;
|
||||
|
||||
if (e4_has_frequency(info, freq) == 0 ||
|
||||
e4_has_ccfi(info, freq) == 0) {
|
||||
if (out_band)
|
||||
@ -1430,7 +1426,7 @@ static const char *const oper_class_eu_codes[] = {
|
||||
"AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
|
||||
"DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
|
||||
"LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
|
||||
"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", "GB"
|
||||
"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK"
|
||||
};
|
||||
|
||||
/* Annex E, table E-1 */
|
||||
|
120
src/blacklist.c
120
src/blacklist.c
@ -45,42 +45,22 @@
|
||||
|
||||
static uint64_t blacklist_multiplier;
|
||||
static uint64_t blacklist_initial_timeout;
|
||||
static uint64_t blacklist_roam_initial_timeout;
|
||||
static uint64_t blacklist_max_timeout;
|
||||
|
||||
struct blacklist_entry {
|
||||
uint8_t addr[6];
|
||||
uint64_t added_time;
|
||||
uint64_t expire_time;
|
||||
enum blacklist_reason reason;
|
||||
};
|
||||
|
||||
struct blacklist_search {
|
||||
const uint8_t *addr;
|
||||
enum blacklist_reason reason;
|
||||
};
|
||||
|
||||
static struct l_queue *blacklist;
|
||||
|
||||
static 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;
|
||||
default:
|
||||
l_warn("Unhandled blacklist reason: %u", reason);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool check_if_expired(void *data, void *user_data)
|
||||
{
|
||||
struct blacklist_entry *entry = data;
|
||||
uint64_t now = l_get_u64(user_data);
|
||||
|
||||
if (l_time_after(now, entry->expire_time)) {
|
||||
if (l_time_diff(now, entry->added_time) > blacklist_max_timeout) {
|
||||
l_debug("Removing entry "MAC" on prune", MAC_STR(entry->addr));
|
||||
l_free(entry);
|
||||
return true;
|
||||
@ -107,53 +87,17 @@ static bool match_addr(const void *a, const void *b)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool match_addr_and_reason(const void *a, const void *b)
|
||||
{
|
||||
const struct blacklist_entry *entry = a;
|
||||
const struct blacklist_search *search = b;
|
||||
|
||||
if (entry->reason != search->reason)
|
||||
return false;
|
||||
|
||||
if (!memcmp(entry->addr, search->addr, 6))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void blacklist_add_bss(const uint8_t *addr, enum blacklist_reason reason)
|
||||
void blacklist_add_bss(const uint8_t *addr)
|
||||
{
|
||||
struct blacklist_entry *entry;
|
||||
uint64_t timeout;
|
||||
|
||||
blacklist_prune();
|
||||
|
||||
timeout = get_reason_timeout(reason);
|
||||
if (!timeout)
|
||||
return;
|
||||
|
||||
entry = l_queue_find(blacklist, match_addr, addr);
|
||||
|
||||
if (entry) {
|
||||
uint64_t offset;
|
||||
|
||||
if (reason < entry->reason) {
|
||||
l_debug("Promoting "MAC" blacklist to reason %u",
|
||||
MAC_STR(addr), reason);
|
||||
/* Reset this to the new timeout and reason */
|
||||
entry->reason = reason;
|
||||
entry->added_time = l_time_now();
|
||||
entry->expire_time = l_time_offset(entry->added_time,
|
||||
timeout);
|
||||
return;
|
||||
} else if (reason > entry->reason) {
|
||||
l_debug("Ignoring blacklist extension of "MAC", "
|
||||
"current blacklist status is more severe!",
|
||||
MAC_STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
offset = l_time_diff(entry->added_time, entry->expire_time);
|
||||
uint64_t offset = l_time_diff(entry->added_time,
|
||||
entry->expire_time);
|
||||
|
||||
offset *= blacklist_multiplier;
|
||||
|
||||
@ -168,36 +112,40 @@ void blacklist_add_bss(const uint8_t *addr, enum blacklist_reason reason)
|
||||
entry = l_new(struct blacklist_entry, 1);
|
||||
|
||||
entry->added_time = l_time_now();
|
||||
entry->expire_time = l_time_offset(entry->added_time, timeout);
|
||||
entry->reason = reason;
|
||||
entry->expire_time = l_time_offset(entry->added_time,
|
||||
blacklist_initial_timeout);
|
||||
memcpy(entry->addr, addr, 6);
|
||||
|
||||
l_queue_push_tail(blacklist, entry);
|
||||
}
|
||||
|
||||
bool blacklist_contains_bss(const uint8_t *addr, enum blacklist_reason reason)
|
||||
bool blacklist_contains_bss(const uint8_t *addr)
|
||||
{
|
||||
struct blacklist_search search = {
|
||||
.addr = addr,
|
||||
.reason = reason
|
||||
};
|
||||
bool ret;
|
||||
uint64_t time_now;
|
||||
struct blacklist_entry *entry;
|
||||
|
||||
blacklist_prune();
|
||||
|
||||
return l_queue_find(blacklist, match_addr_and_reason, &search) != NULL;
|
||||
entry = l_queue_find(blacklist, match_addr, addr);
|
||||
|
||||
if (!entry)
|
||||
return false;
|
||||
|
||||
time_now = l_time_now();
|
||||
|
||||
ret = l_time_after(time_now, entry->expire_time) ? false : true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void blacklist_remove_bss(const uint8_t *addr, enum blacklist_reason reason)
|
||||
void blacklist_remove_bss(const uint8_t *addr)
|
||||
{
|
||||
struct blacklist_entry *entry;
|
||||
struct blacklist_search search = {
|
||||
.addr = addr,
|
||||
.reason = reason
|
||||
};
|
||||
|
||||
blacklist_prune();
|
||||
|
||||
entry = l_queue_remove_if(blacklist, match_addr_and_reason, &search);
|
||||
entry = l_queue_remove_if(blacklist, match_addr, addr);
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
@ -214,39 +162,19 @@ static int blacklist_init(void)
|
||||
blacklist_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT;
|
||||
|
||||
/* For easier user configuration the timeout values are in seconds */
|
||||
blacklist_initial_timeout *= L_USEC_PER_SEC;
|
||||
|
||||
if (!l_settings_get_uint64(config, "Blacklist",
|
||||
"InitialRoamRequestedTimeout",
|
||||
&blacklist_roam_initial_timeout))
|
||||
blacklist_roam_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT;
|
||||
|
||||
/* For easier user configuration the timeout values are in seconds */
|
||||
blacklist_roam_initial_timeout *= L_USEC_PER_SEC;
|
||||
blacklist_initial_timeout *= 1000000;
|
||||
|
||||
if (!l_settings_get_uint64(config, "Blacklist",
|
||||
"Multiplier",
|
||||
&blacklist_multiplier))
|
||||
blacklist_multiplier = BLACKLIST_DEFAULT_MULTIPLIER;
|
||||
|
||||
if (blacklist_multiplier == 0) {
|
||||
l_warn("[Blacklist].Multiplier cannot be zero, setting to 1");
|
||||
blacklist_multiplier = 1;
|
||||
}
|
||||
|
||||
if (!l_settings_get_uint64(config, "Blacklist",
|
||||
"MaximumTimeout",
|
||||
&blacklist_max_timeout))
|
||||
blacklist_max_timeout = BLACKLIST_DEFAULT_MAX_TIMEOUT;
|
||||
|
||||
blacklist_max_timeout *= L_USEC_PER_SEC;
|
||||
|
||||
if (blacklist_initial_timeout > blacklist_max_timeout)
|
||||
l_warn("[Blacklist].InitialTimeout exceeded "
|
||||
"[Blacklist].MaximumTimeout!");
|
||||
|
||||
if (!blacklist_initial_timeout)
|
||||
l_debug("initial timeout was zero, blacklist will be disabled");
|
||||
blacklist_max_timeout *= 1000000;
|
||||
|
||||
blacklist = l_queue_new();
|
||||
|
||||
|
@ -20,21 +20,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
enum blacklist_reason {
|
||||
/*
|
||||
* When a BSS is blacklisted using this reason IWD will refuse to
|
||||
* connect to it via autoconnect
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
BLACKLIST_REASON_ROAM_REQUESTED,
|
||||
};
|
||||
|
||||
void blacklist_add_bss(const uint8_t *addr, enum blacklist_reason reason);
|
||||
bool blacklist_contains_bss(const uint8_t *addr, enum blacklist_reason reason);
|
||||
void blacklist_remove_bss(const uint8_t *addr, enum blacklist_reason reason);
|
||||
void blacklist_add_bss(const uint8_t *addr);
|
||||
bool blacklist_contains_bss(const uint8_t *addr);
|
||||
void blacklist_remove_bss(const uint8_t *addr);
|
||||
|
@ -1212,7 +1212,7 @@ struct l_ecc_point *crypto_derive_sae_pwe_from_pt_ecc(const uint8_t *mac1,
|
||||
struct l_ecc_point *pwe;
|
||||
|
||||
if (!pt || !curve)
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
hash = crypto_sae_hash_from_ecc_prime_len(CRYPTO_SAE_HASH_TO_ELEMENT,
|
||||
l_ecc_curve_get_scalar_bytes(curve));
|
||||
|
@ -134,12 +134,6 @@ struct l_dbus_message *dbus_error_not_hidden(struct l_dbus_message *msg)
|
||||
"Not hidden");
|
||||
}
|
||||
|
||||
struct l_dbus_message *dbus_error_permission_denied(struct l_dbus_message *msg)
|
||||
{
|
||||
return l_dbus_message_new_error(msg, IWD_SERVICE ".PermissionDenied",
|
||||
"Permission Denied");
|
||||
}
|
||||
|
||||
struct l_dbus_message *dbus_error_from_errno(int err,
|
||||
struct l_dbus_message *msg)
|
||||
{
|
||||
|
@ -82,7 +82,6 @@ struct l_dbus_message *dbus_error_service_set_overlap(
|
||||
struct l_dbus_message *dbus_error_already_provisioned(
|
||||
struct l_dbus_message *msg);
|
||||
struct l_dbus_message *dbus_error_not_hidden(struct l_dbus_message *msg);
|
||||
struct l_dbus_message *dbus_error_permission_denied(struct l_dbus_message *msg);
|
||||
|
||||
struct l_dbus_message *dbus_error_from_errno(int err,
|
||||
struct l_dbus_message *msg);
|
||||
|
@ -1166,34 +1166,21 @@ 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;
|
||||
|
176
src/dpp.c
176
src/dpp.c
@ -66,6 +66,7 @@ static struct l_genl_family *nl80211;
|
||||
static uint8_t broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
static struct l_queue *dpp_list;
|
||||
static uint32_t mlme_watch;
|
||||
static uint32_t unicast_watch;
|
||||
|
||||
static uint8_t dpp_prefix[] = { 0x04, 0x09, 0x50, 0x6f, 0x9a, 0x1a, 0x01 };
|
||||
|
||||
@ -551,8 +552,6 @@ static void dpp_reset(struct dpp_sm *dpp)
|
||||
|
||||
dpp_property_changed_notify(dpp);
|
||||
|
||||
frame_watch_group_remove(dpp->wdev_id, FRAME_GROUP_DPP);
|
||||
|
||||
dpp->interface = DPP_INTERFACE_UNBOUND;
|
||||
|
||||
if (station) {
|
||||
@ -1841,7 +1840,7 @@ static void dpp_send_pkex_exchange_request(struct dpp_sm *dpp)
|
||||
|
||||
l_put_le16(l_ecc_curve_get_ike_group(dpp->curve), &group);
|
||||
|
||||
iov[0].iov_len = dpp_build_header(own_mac, dpp->peer_addr,
|
||||
iov[0].iov_len = dpp_build_header(own_mac, broadcast,
|
||||
DPP_FRAME_PKEX_VERSION1_XCHG_REQUEST, hdr);
|
||||
iov[0].iov_base = hdr;
|
||||
|
||||
@ -2001,7 +2000,7 @@ static void dpp_offchannel_timeout(int error, void *user_data)
|
||||
|
||||
/*
|
||||
* We have a pending agent request but it did not arrive in
|
||||
* time, we can't assume the enrollee will be waiting around
|
||||
* time, we cant assume the enrollee will be waiting around
|
||||
* for our response so cancel the request and continue waiting
|
||||
* for another request
|
||||
*/
|
||||
@ -2722,7 +2721,7 @@ static void dpp_handle_pkex_exchange_response(struct dpp_sm *dpp,
|
||||
}
|
||||
|
||||
if (version && version != dpp->pkex_version) {
|
||||
l_debug("PKEX version does not match, ignoring");
|
||||
l_debug("PKEX version does not match, igoring");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2832,12 +2831,6 @@ static bool dpp_pkex_start_authentication(struct dpp_sm *dpp)
|
||||
|
||||
dpp_property_changed_notify(dpp);
|
||||
|
||||
/*
|
||||
* No longer waiting for an arbitrary peer to respond, reduce the
|
||||
* timeout now that we are proceeding to authentication
|
||||
*/
|
||||
dpp_reset_protocol_timer(dpp, DPP_AUTH_PROTO_TIMEOUT);
|
||||
|
||||
if (dpp->role == DPP_CAPABILITY_ENROLLEE) {
|
||||
dpp->new_freq = dpp->current_freq;
|
||||
|
||||
@ -3438,7 +3431,7 @@ static void dpp_handle_pkex_commit_reveal_request(struct dpp_sm *dpp,
|
||||
dpp->peer_boot_public = l_ecc_point_from_data(dpp->curve,
|
||||
L_ECC_POINT_TYPE_FULL, key, key_len);
|
||||
if (!dpp->peer_boot_public) {
|
||||
l_debug("peers bootstrapping key did not validate");
|
||||
l_debug("peers boostrapping key did not validate");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
@ -3476,11 +3469,10 @@ failed:
|
||||
dpp_reset(dpp);
|
||||
}
|
||||
|
||||
static void dpp_handle_frame(const struct mmpdu_header *frame,
|
||||
const void *body, size_t body_len,
|
||||
int rssi, void *user_data)
|
||||
static void dpp_handle_frame(struct dpp_sm *dpp,
|
||||
const struct mmpdu_header *frame,
|
||||
const void *body, size_t body_len)
|
||||
{
|
||||
struct dpp_sm *dpp = user_data;
|
||||
const uint8_t *ptr;
|
||||
|
||||
/*
|
||||
@ -3598,7 +3590,7 @@ static void dpp_mlme_notify(struct l_genl_msg *msg, void *user_data)
|
||||
|
||||
/*
|
||||
* Only want to handle the no-ACK case. Re-transmitting an ACKed
|
||||
* frame likely won't do any good, at least in the case of DPP.
|
||||
* frame likely wont do any good, at least in the case of DPP.
|
||||
*/
|
||||
if (!ack)
|
||||
goto retransmit;
|
||||
@ -3640,6 +3632,99 @@ retransmit:
|
||||
dpp_frame_timeout, dpp, NULL);
|
||||
}
|
||||
|
||||
static void dpp_unicast_notify(struct l_genl_msg *msg, void *user_data)
|
||||
{
|
||||
struct dpp_sm *dpp;
|
||||
const uint64_t *wdev_id = NULL;
|
||||
struct l_genl_attr attr;
|
||||
uint16_t type, len, frame_len;
|
||||
const void *data;
|
||||
const struct mmpdu_header *mpdu = NULL;
|
||||
const uint8_t *body;
|
||||
size_t body_len;
|
||||
|
||||
if (l_genl_msg_get_command(msg) != NL80211_CMD_FRAME)
|
||||
return;
|
||||
|
||||
if (!l_genl_attr_init(&attr, msg))
|
||||
return;
|
||||
|
||||
while (l_genl_attr_next(&attr, &type, &len, &data)) {
|
||||
switch (type) {
|
||||
case NL80211_ATTR_WDEV:
|
||||
if (len != 8)
|
||||
break;
|
||||
|
||||
wdev_id = data;
|
||||
break;
|
||||
|
||||
case NL80211_ATTR_FRAME:
|
||||
mpdu = mpdu_validate(data, len);
|
||||
if (!mpdu) {
|
||||
l_warn("Frame didn't validate as MMPDU");
|
||||
return;
|
||||
}
|
||||
|
||||
frame_len = len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wdev_id) {
|
||||
l_warn("Bad wdev attribute");
|
||||
return;
|
||||
}
|
||||
|
||||
dpp = l_queue_find(dpp_list, match_wdev, wdev_id);
|
||||
if (!dpp)
|
||||
return;
|
||||
|
||||
if (!mpdu) {
|
||||
l_warn("Missing frame data");
|
||||
return;
|
||||
}
|
||||
|
||||
body = mmpdu_body(mpdu);
|
||||
body_len = (const uint8_t *) mpdu + frame_len - body;
|
||||
|
||||
if (body_len < sizeof(dpp_prefix) ||
|
||||
memcmp(body, dpp_prefix, sizeof(dpp_prefix)) != 0)
|
||||
return;
|
||||
|
||||
dpp_handle_frame(dpp, mpdu, body, body_len);
|
||||
}
|
||||
|
||||
static void dpp_frame_watch_cb(struct l_genl_msg *msg, void *user_data)
|
||||
{
|
||||
if (l_genl_msg_get_error(msg) < 0)
|
||||
l_error("Could not register frame watch type %04x: %i",
|
||||
L_PTR_TO_UINT(user_data), l_genl_msg_get_error(msg));
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case the frame watch which includes the presence frames since they
|
||||
* require multicast support. This is only supported by ath9k, so adding
|
||||
* general support to frame-xchg isn't desireable.
|
||||
*/
|
||||
static void dpp_frame_watch(struct dpp_sm *dpp, uint16_t frame_type,
|
||||
const uint8_t *prefix, size_t prefix_len)
|
||||
{
|
||||
struct l_genl_msg *msg;
|
||||
|
||||
msg = l_genl_msg_new_sized(NL80211_CMD_REGISTER_FRAME, 32 + prefix_len);
|
||||
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_WDEV, 8, &dpp->wdev_id);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_FRAME_TYPE, 2, &frame_type);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_FRAME_MATCH,
|
||||
prefix_len, prefix);
|
||||
if (dpp->mcast_support)
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_RECEIVE_MULTICAST,
|
||||
0, NULL);
|
||||
|
||||
l_genl_family_send(nl80211, msg, dpp_frame_watch_cb,
|
||||
L_UINT_TO_PTR(frame_type), NULL);
|
||||
}
|
||||
|
||||
static void dpp_start_enrollee(struct dpp_sm *dpp);
|
||||
static bool dpp_start_pkex_enrollee(struct dpp_sm *dpp);
|
||||
|
||||
@ -3729,6 +3814,8 @@ static void dpp_create(struct netdev *netdev)
|
||||
{
|
||||
struct l_dbus *dbus = dbus_get_bus();
|
||||
struct dpp_sm *dpp = l_new(struct dpp_sm, 1);
|
||||
uint8_t dpp_conf_response_prefix[] = { 0x04, 0x0b };
|
||||
uint8_t dpp_conf_request_prefix[] = { 0x04, 0x0a };
|
||||
uint64_t wdev_id = netdev_get_wdev_id(netdev);
|
||||
|
||||
dpp->netdev = netdev;
|
||||
@ -3739,8 +3826,9 @@ static void dpp_create(struct netdev *netdev)
|
||||
dpp->key_len = l_ecc_curve_get_scalar_bytes(dpp->curve);
|
||||
dpp->nonce_len = dpp_nonce_len_from_key_len(dpp->key_len);
|
||||
dpp->max_roc = wiphy_get_max_roc_duration(wiphy_find_by_wdev(wdev_id));
|
||||
dpp->mcast_support = wiphy_supports_multicast_rx(
|
||||
wiphy_find_by_wdev(dpp->wdev_id));
|
||||
dpp->mcast_support = wiphy_has_ext_feature(
|
||||
wiphy_find_by_wdev(dpp->wdev_id),
|
||||
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS);
|
||||
|
||||
l_ecdh_generate_key_pair(dpp->curve, &dpp->boot_private,
|
||||
&dpp->boot_public);
|
||||
@ -3763,6 +3851,17 @@ static void dpp_create(struct netdev *netdev)
|
||||
*/
|
||||
dpp->refcount = 2;
|
||||
|
||||
dpp_frame_watch(dpp, 0x00d0, dpp_prefix, sizeof(dpp_prefix));
|
||||
|
||||
frame_watch_add(netdev_get_wdev_id(netdev), 0, 0x00d0,
|
||||
dpp_conf_response_prefix,
|
||||
sizeof(dpp_conf_response_prefix),
|
||||
dpp_handle_config_response_frame, dpp, NULL);
|
||||
frame_watch_add(netdev_get_wdev_id(netdev), 0, 0x00d0,
|
||||
dpp_conf_request_prefix,
|
||||
sizeof(dpp_conf_request_prefix),
|
||||
dpp_handle_config_request_frame, dpp, NULL);
|
||||
|
||||
dpp->known_network_watch = known_networks_watch_add(
|
||||
dpp_known_network_watch, dpp, NULL);
|
||||
|
||||
@ -3907,26 +4006,6 @@ done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dpp_add_frame_watches(struct dpp_sm *dpp, bool multicast_rx)
|
||||
{
|
||||
uint8_t dpp_conf_response_prefix[] = { 0x04, 0x0b };
|
||||
uint8_t dpp_conf_request_prefix[] = { 0x04, 0x0a };
|
||||
|
||||
frame_watch_add(dpp->wdev_id, FRAME_GROUP_DPP, 0x00d0,
|
||||
dpp_prefix, sizeof(dpp_prefix), multicast_rx,
|
||||
dpp_handle_frame, dpp, NULL);
|
||||
|
||||
frame_watch_add(dpp->wdev_id, FRAME_GROUP_DPP, 0x00d0,
|
||||
dpp_conf_response_prefix,
|
||||
sizeof(dpp_conf_response_prefix), false,
|
||||
dpp_handle_config_response_frame, dpp, NULL);
|
||||
|
||||
frame_watch_add(dpp->wdev_id, FRAME_GROUP_DPP, 0x00d0,
|
||||
dpp_conf_request_prefix,
|
||||
sizeof(dpp_conf_request_prefix), false,
|
||||
dpp_handle_config_request_frame, dpp, NULL);
|
||||
}
|
||||
|
||||
static void dpp_start_enrollee(struct dpp_sm *dpp)
|
||||
{
|
||||
uint32_t freq = band_channel_to_freq(6, BAND_FREQ_2_4_GHZ);
|
||||
@ -3966,8 +4045,6 @@ static struct l_dbus_message *dpp_dbus_start_enrollee(struct l_dbus *dbus,
|
||||
dpp->role = DPP_CAPABILITY_ENROLLEE;
|
||||
dpp->interface = DPP_INTERFACE_DPP;
|
||||
|
||||
dpp_add_frame_watches(dpp, false);
|
||||
|
||||
ret = dpp_try_disconnect_station(dpp, &wait_for_disconnect);
|
||||
if (ret < 0) {
|
||||
dpp_reset(dpp);
|
||||
@ -4105,8 +4182,6 @@ static struct l_dbus_message *dpp_start_configurator_common(
|
||||
} else
|
||||
dpp->current_freq = bss->frequency;
|
||||
|
||||
dpp_add_frame_watches(dpp, responder && dpp->mcast_support);
|
||||
|
||||
dpp->uri = dpp_generate_uri(dpp->own_asn1, dpp->own_asn1_len, 2,
|
||||
netdev_get_address(dpp->netdev),
|
||||
&bss->frequency, 1, NULL, NULL);
|
||||
@ -4208,11 +4283,10 @@ static uint32_t *dpp_default_freqs(struct dpp_sm *dpp, size_t *out_len)
|
||||
|
||||
static void __dpp_pkex_start_enrollee(struct dpp_sm *dpp)
|
||||
{
|
||||
uint32_t timeout = minsize(DPP_PKEX_PROTO_TIMEOUT,
|
||||
dpp->freqs_len * DPP_PKEX_PROTO_PER_FREQ_TIMEOUT);
|
||||
dpp->current_freq = dpp->freqs[0];
|
||||
|
||||
dpp_reset_protocol_timer(dpp, timeout);
|
||||
dpp_reset_protocol_timer(dpp,
|
||||
dpp->freqs_len * DPP_PKEX_PROTO_PER_FREQ_TIMEOUT);
|
||||
|
||||
l_debug("PKEX start enrollee (id=%s)", dpp->pkex_id ?: "unset");
|
||||
|
||||
@ -4436,8 +4510,6 @@ static struct l_dbus_message *dpp_dbus_pkex_start_enrollee(struct l_dbus *dbus,
|
||||
dpp->state = DPP_STATE_PKEX_EXCHANGE;
|
||||
dpp->interface = DPP_INTERFACE_PKEX;
|
||||
|
||||
dpp_add_frame_watches(dpp, false);
|
||||
|
||||
ret = dpp_try_disconnect_station(dpp, &wait_for_disconnect);
|
||||
if (ret < 0) {
|
||||
dpp_reset(dpp);
|
||||
@ -4534,7 +4606,6 @@ static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp_sm *dpp,
|
||||
dpp->config = dpp_configuration_new(network_get_settings(network),
|
||||
network_get_ssid(network),
|
||||
hs->akm_suite);
|
||||
dpp_add_frame_watches(dpp, dpp->mcast_support);
|
||||
|
||||
dpp_reset_protocol_timer(dpp, DPP_PKEX_PROTO_TIMEOUT);
|
||||
dpp_property_changed_notify(dpp);
|
||||
@ -4663,6 +4734,11 @@ static int dpp_init(void)
|
||||
mlme_watch = l_genl_family_register(nl80211, "mlme", dpp_mlme_notify,
|
||||
NULL, NULL);
|
||||
|
||||
unicast_watch = l_genl_add_unicast_watch(iwd_get_genl(),
|
||||
NL80211_GENL_NAME,
|
||||
dpp_unicast_notify,
|
||||
NULL, NULL);
|
||||
|
||||
dpp_list = l_queue_new();
|
||||
|
||||
return 0;
|
||||
@ -4677,6 +4753,8 @@ static void dpp_exit(void)
|
||||
|
||||
netdev_watch_remove(netdev_watch);
|
||||
|
||||
l_genl_remove_unicast_watch(iwd_get_genl(), unicast_watch);
|
||||
|
||||
l_genl_family_unregister(nl80211, mlme_watch);
|
||||
mlme_watch = 0;
|
||||
|
||||
|
@ -544,8 +544,7 @@ static bool eap_mschapv2_load_settings(struct eap_state *eap,
|
||||
return true;
|
||||
|
||||
error:
|
||||
l_free(state->user);
|
||||
l_free(state);
|
||||
free(state);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ static void __eap_tls_common_state_reset(struct eap_state *eap)
|
||||
*
|
||||
* Drop the cache even if we have no indication that the
|
||||
* method failed but it just didn't succeed, to handle cases like
|
||||
* the server getting stuck and a timeout occurring at a higher
|
||||
* the server getting stuck and a timout occuring at a higher
|
||||
* layer. The risk is that we may occasionally flush the session
|
||||
* data when there was only a momentary radio issue, invalid
|
||||
* phase2 credentials or decision to abort. Those are not hot
|
||||
|
@ -974,7 +974,7 @@ static void __eap_method_enable(struct eap_method_desc *start,
|
||||
|
||||
l_debug("");
|
||||
|
||||
if (!start || !stop)
|
||||
if (start == NULL || stop == NULL)
|
||||
return;
|
||||
|
||||
for (desc = start; desc < stop; desc++) {
|
||||
@ -992,7 +992,7 @@ static void __eap_method_disable(struct eap_method_desc *start,
|
||||
|
||||
l_debug("");
|
||||
|
||||
if (!start || !stop)
|
||||
if (start == NULL || stop == NULL)
|
||||
return;
|
||||
|
||||
for (desc = start; desc < stop; desc++) {
|
||||
|
@ -342,7 +342,8 @@ static bool frame_watch_group_io_read(struct l_io *io, void *user_data)
|
||||
|
||||
nlmsg_len = bytes_read;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
struct nl_pktinfo pktinfo;
|
||||
|
||||
if (cmsg->cmsg_level != SOL_NETLINK)
|
||||
@ -574,7 +575,6 @@ drop:
|
||||
|
||||
bool frame_watch_add(uint64_t wdev_id, uint32_t group_id, uint16_t frame_type,
|
||||
const uint8_t *prefix, size_t prefix_len,
|
||||
bool multicast_rx,
|
||||
frame_watch_cb_t handler, void *user_data,
|
||||
frame_xchg_destroy_func_t destroy)
|
||||
{
|
||||
@ -614,10 +614,6 @@ bool frame_watch_add(uint64_t wdev_id, uint32_t group_id, uint16_t frame_type,
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_FRAME_MATCH,
|
||||
prefix_len, prefix);
|
||||
|
||||
if (multicast_rx)
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_RECEIVE_MULTICAST,
|
||||
0, NULL);
|
||||
|
||||
if (group->id == 0)
|
||||
l_genl_family_send(nl80211, msg, frame_watch_register_cb,
|
||||
L_UINT_TO_PTR(frame_type), NULL);
|
||||
@ -1198,7 +1194,7 @@ uint32_t frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
|
||||
watch->prefix = prefix;
|
||||
watch->cb = va_arg(resp_args, void *);
|
||||
frame_watch_add(wdev_id, group_id, prefix->frame_type,
|
||||
prefix->data, prefix->len, false,
|
||||
prefix->data, prefix->len,
|
||||
frame_xchg_resp_cb, fx, NULL);
|
||||
|
||||
if (!fx->rx_watches)
|
||||
|
@ -41,12 +41,10 @@ enum frame_xchg_group {
|
||||
FRAME_GROUP_DEFAULT = 0,
|
||||
FRAME_GROUP_P2P_LISTEN,
|
||||
FRAME_GROUP_P2P_CONNECT,
|
||||
FRAME_GROUP_DPP,
|
||||
};
|
||||
|
||||
bool frame_watch_add(uint64_t wdev_id, uint32_t group, uint16_t frame_type,
|
||||
const uint8_t *prefix, size_t prefix_len,
|
||||
bool multicast_rx,
|
||||
frame_watch_cb_t handler, void *user_data,
|
||||
frame_xchg_destroy_func_t destroy);
|
||||
bool frame_watch_group_remove(uint64_t wdev_id, uint32_t group);
|
||||
|
107
src/handshake.c
107
src/handshake.c
@ -43,7 +43,6 @@
|
||||
#include "src/handshake.h"
|
||||
#include "src/erp.h"
|
||||
#include "src/band.h"
|
||||
#include "src/pmksa.h"
|
||||
|
||||
static inline unsigned int n_ecc_groups(void)
|
||||
{
|
||||
@ -104,14 +103,7 @@ void __handshake_set_install_ext_tk_func(handshake_install_ext_tk_func_t func)
|
||||
install_ext_tk = func;
|
||||
}
|
||||
|
||||
struct handshake_state *handshake_state_ref(struct handshake_state *s)
|
||||
{
|
||||
__sync_fetch_and_add(&s->refcount, 1);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void handshake_state_unref(struct handshake_state *s)
|
||||
void handshake_state_free(struct handshake_state *s)
|
||||
{
|
||||
__typeof__(s->free) destroy;
|
||||
|
||||
@ -125,9 +117,6 @@ void handshake_state_unref(struct handshake_state *s)
|
||||
return;
|
||||
}
|
||||
|
||||
if (__sync_sub_and_fetch(&s->refcount, 1))
|
||||
return;
|
||||
|
||||
l_free(s->authenticator_ie);
|
||||
l_free(s->supplicant_ie);
|
||||
l_free(s->authenticator_rsnxe);
|
||||
@ -139,9 +128,6 @@ void handshake_state_unref(struct handshake_state *s)
|
||||
l_free(s->fils_ip_resp_ie);
|
||||
l_free(s->vendor_ies);
|
||||
|
||||
if (s->have_pmksa)
|
||||
l_free(s->pmksa);
|
||||
|
||||
if (s->erp_cache)
|
||||
erp_cache_put(s->erp_cache);
|
||||
|
||||
@ -705,11 +691,6 @@ void handshake_state_install_ptk(struct handshake_state *s)
|
||||
{
|
||||
s->ptk_complete = true;
|
||||
|
||||
if (!s->have_pmksa && IE_AKM_IS_SAE(s->akm_suite)) {
|
||||
l_debug("Adding PMKSA expiration");
|
||||
s->expiration = l_time_now() + pmksa_lifetime();
|
||||
}
|
||||
|
||||
if (install_tk) {
|
||||
uint32_t cipher = ie_rsn_cipher_suite_to_cipher(
|
||||
s->pairwise_cipher);
|
||||
@ -1212,89 +1193,3 @@ done:
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool handshake_state_set_pmksa(struct handshake_state *s,
|
||||
struct pmksa *pmksa)
|
||||
{
|
||||
/* checks for both expiration || pmksa being set */
|
||||
if (s->expiration)
|
||||
return false;
|
||||
|
||||
s->pmksa = pmksa;
|
||||
s->have_pmksa = true;
|
||||
|
||||
handshake_state_set_pmkid(s, pmksa->pmkid);
|
||||
handshake_state_set_pmk(s, pmksa->pmk, pmksa->pmk_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct pmksa *handshake_state_steal_pmksa(struct handshake_state *s)
|
||||
{
|
||||
struct pmksa *pmksa;
|
||||
uint64_t now = l_time_now();
|
||||
|
||||
if (s->have_pmksa) {
|
||||
pmksa = l_steal_ptr(s->pmksa);
|
||||
s->have_pmksa = false;
|
||||
|
||||
if (l_time_after(now, pmksa->expiration)) {
|
||||
pmksa_cache_free(pmksa);
|
||||
pmksa = NULL;
|
||||
}
|
||||
|
||||
return pmksa;
|
||||
}
|
||||
|
||||
if (s->expiration && l_time_after(now, s->expiration)) {
|
||||
s->expiration = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!s->have_pmkid)
|
||||
return NULL;
|
||||
|
||||
pmksa = l_new(struct pmksa, 1);
|
||||
pmksa->expiration = s->expiration;
|
||||
memcpy(pmksa->spa, s->spa, sizeof(s->spa));
|
||||
memcpy(pmksa->aa, s->aa, sizeof(s->aa));
|
||||
memcpy(pmksa->ssid, s->ssid, s->ssid_len);
|
||||
pmksa->ssid_len = s->ssid_len;
|
||||
pmksa->akm = s->akm_suite;
|
||||
memcpy(pmksa->pmkid, s->pmkid, sizeof(s->pmkid));
|
||||
pmksa->pmk_len = s->pmk_len;
|
||||
memcpy(pmksa->pmk, s->pmk, s->pmk_len);
|
||||
|
||||
return pmksa;
|
||||
}
|
||||
|
||||
void handshake_state_cache_pmksa(struct handshake_state *s)
|
||||
{
|
||||
struct pmksa *pmksa = handshake_state_steal_pmksa(s);
|
||||
|
||||
if (!pmksa) {
|
||||
l_debug("No PMKSA for "MAC, MAC_STR(s->aa));
|
||||
return;
|
||||
}
|
||||
|
||||
l_debug("Caching PMKSA for "MAC, MAC_STR(s->aa));
|
||||
|
||||
if (L_WARN_ON(pmksa_cache_put(pmksa) < 0))
|
||||
pmksa_cache_free(pmksa);
|
||||
}
|
||||
|
||||
bool handshake_state_remove_pmksa(struct handshake_state *s)
|
||||
{
|
||||
struct pmksa *pmksa;
|
||||
|
||||
if (!s->have_pmksa)
|
||||
return false;
|
||||
|
||||
pmksa = handshake_state_steal_pmksa(s);
|
||||
if (!pmksa)
|
||||
return false;
|
||||
|
||||
pmksa_cache_free(pmksa);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -29,7 +29,6 @@
|
||||
struct handshake_state;
|
||||
enum crypto_cipher;
|
||||
struct eapol_frame;
|
||||
struct pmksa;
|
||||
|
||||
enum handshake_kde {
|
||||
/* 802.11-2020 Table 12-9 in section 12.7.2 */
|
||||
@ -142,11 +141,6 @@ struct handshake_state {
|
||||
bool supplicant_ocvc : 1;
|
||||
bool ext_key_id_capable : 1;
|
||||
bool force_default_ecc_group : 1;
|
||||
bool have_pmksa : 1;
|
||||
union {
|
||||
struct pmksa *pmksa;
|
||||
uint64_t expiration;
|
||||
};
|
||||
uint8_t ssid[SSID_MAX_SIZE];
|
||||
size_t ssid_len;
|
||||
char *passphrase;
|
||||
@ -176,8 +170,6 @@ struct handshake_state {
|
||||
bool in_event;
|
||||
|
||||
handshake_event_func_t event_func;
|
||||
|
||||
int refcount;
|
||||
};
|
||||
|
||||
#define HSID(x) UNIQUE_ID(handshake_, x)
|
||||
@ -194,7 +186,7 @@ struct handshake_state {
|
||||
##__VA_ARGS__); \
|
||||
\
|
||||
if (!HSID(hs)->in_event) { \
|
||||
handshake_state_unref(HSID(hs)); \
|
||||
handshake_state_free(HSID(hs)); \
|
||||
HSID(freed) = true; \
|
||||
} else \
|
||||
HSID(hs)->in_event = false; \
|
||||
@ -202,8 +194,7 @@ struct handshake_state {
|
||||
HSID(freed); \
|
||||
})
|
||||
|
||||
struct handshake_state *handshake_state_ref(struct handshake_state *s);
|
||||
void handshake_state_unref(struct handshake_state *s);
|
||||
void handshake_state_free(struct handshake_state *s);
|
||||
|
||||
void handshake_state_set_supplicant_address(struct handshake_state *s,
|
||||
const uint8_t *spa);
|
||||
@ -308,10 +299,6 @@ void handshake_state_set_chandef(struct handshake_state *s,
|
||||
int handshake_state_verify_oci(struct handshake_state *s, const uint8_t *oci,
|
||||
size_t oci_len);
|
||||
|
||||
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,
|
||||
const uint8_t *scan_ie, bool is_wpa);
|
||||
|
||||
@ -329,4 +316,4 @@ void handshake_util_build_gtk_kde(enum crypto_cipher cipher, const uint8_t *key,
|
||||
void handshake_util_build_igtk_kde(enum crypto_cipher cipher, const uint8_t *key,
|
||||
unsigned int key_index, uint8_t *to);
|
||||
|
||||
DEFINE_CLEANUP_FUNC(handshake_state_unref);
|
||||
DEFINE_CLEANUP_FUNC(handshake_state_free);
|
||||
|
17
src/ie.h
17
src/ie.h
@ -598,23 +598,6 @@ static inline const unsigned char *ie_tlv_iter_get_data(
|
||||
return iter->data;
|
||||
}
|
||||
|
||||
static inline bool ie_tlv_iter_data_eq(struct ie_tlv_iter *a,
|
||||
struct ie_tlv_iter *b)
|
||||
{
|
||||
if (a == b)
|
||||
return true;
|
||||
|
||||
if (a == NULL || b == NULL)
|
||||
return false;
|
||||
|
||||
if (ie_tlv_iter_get_length(a) != ie_tlv_iter_get_length(b))
|
||||
return false;
|
||||
|
||||
return memcmp(ie_tlv_iter_get_data(a),
|
||||
ie_tlv_iter_get_data(b),
|
||||
ie_tlv_iter_get_length(a)) == 0;
|
||||
}
|
||||
|
||||
void *ie_tlv_extract_wsc_payload(const uint8_t *ies, size_t len,
|
||||
ssize_t *out_len);
|
||||
void *ie_tlv_encapsulate_wsc_payload(const uint8_t *data, size_t len,
|
||||
|
@ -133,22 +133,6 @@ The group ``[General]`` contains general settings.
|
||||
This value can be used to control how aggressively **iwd** roams when
|
||||
connected to a 5GHz access point.
|
||||
|
||||
* - CriticalRoamThreshold
|
||||
- Value: rssi dBm value, from -100 to -1, default: **-80**
|
||||
|
||||
The threshold (for 2.4GHz) at which IWD will roam regardless of the
|
||||
affinity set to the current BSS. If the connected BSS has affinity
|
||||
(set in Station's Affinities list) the roam threshold will be lowed to
|
||||
this value and IWD will not attempt to roam (or roam scan) until either
|
||||
the affinity is cleared, or the signal drops below this threshold.
|
||||
|
||||
|
||||
* - CriticalRoamThreshold5G
|
||||
- Value: rssi dBm value, from -100 to -1, default: **-82**
|
||||
|
||||
This has the same effect as ``CriticalRoamThreshold``, but for the 5GHz
|
||||
band.
|
||||
|
||||
* - RoamRetryInterval
|
||||
- Value: unsigned int value in seconds (default: **60**)
|
||||
|
||||
@ -225,11 +209,6 @@ The group ``[General]`` contains general settings.
|
||||
request is just a 'hint' and ultimately left up to the kernel to set the
|
||||
country.
|
||||
|
||||
* - DisablePMKSA
|
||||
- Value: **false**, true
|
||||
|
||||
Disable PMKSA support in IWD
|
||||
|
||||
Network
|
||||
-------
|
||||
|
||||
@ -290,17 +269,9 @@ control how long a misbehaved BSS spends on the blacklist.
|
||||
* - InitialTimeout
|
||||
- Values: uint64 value in seconds (default: **60**)
|
||||
|
||||
The initial time that a BSS spends on the blacklist. Setting this to zero
|
||||
will disable blacklisting functionality in IWD.
|
||||
* - InitialRoamRequestedTimeout
|
||||
- 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.
|
||||
The initial time that a BSS spends on the blacklist.
|
||||
* - Multiplier
|
||||
- Values: unsigned int value greater than zero, in seconds
|
||||
(default: **30**)
|
||||
- Values: unsigned int value in seconds (default: **30**)
|
||||
|
||||
If the BSS was blacklisted previously and another connection attempt
|
||||
has failed after the initial timeout has expired, then the BSS blacklist
|
||||
@ -354,28 +325,6 @@ autoconnect purposes.
|
||||
A value of 0.0 will disable the 6GHz band and prevent scanning or
|
||||
connecting on those frequencies.
|
||||
|
||||
* - HighUtilizationThreshold
|
||||
- Values: unsigned integer value 0 - 255 (default: **0**, disabled)
|
||||
|
||||
**Warning: This is an experimental feature**
|
||||
|
||||
The BSS utilization threshold at which a negative rank factor begins to
|
||||
be applied to the BSS. As the load increases for a BSS the ranking factor
|
||||
decays exponentially, meaning the ranking factor will decrease
|
||||
exponentially. Setting this can have very drastic effects on the BSS rank
|
||||
if its utilization is high, use with care.
|
||||
|
||||
* - HighStationCountThreshold
|
||||
- Values: unsigned integer value 0 - 255 (default: **0**, disabled)
|
||||
|
||||
**Warning: This is an experimental feature**
|
||||
|
||||
The BSS station count threshold at which a negative rank factor begins to
|
||||
be applied to the BSS. As the station count increases for a BSS the
|
||||
ranking factor decays exponentially, meaning the ranking factor will
|
||||
decrease exponentially. Setting this can have very drastic effects on the
|
||||
BSS rank if its station count is high, use with care.
|
||||
|
||||
Scan
|
||||
----
|
||||
|
||||
@ -467,20 +416,6 @@ are buggy or just don't behave similar enough to the majority of other drivers.
|
||||
|
||||
If a driver in user matches one in this list power save will be disabled.
|
||||
|
||||
* - MulticastRxDisable
|
||||
- Values: comma-separated list of drivers or glob matches
|
||||
|
||||
If a driver in use matches one in this list, multicast RX will be
|
||||
disabled.
|
||||
|
||||
* - SaeDisable
|
||||
- Values: comma-separated list of drivers or glob matches
|
||||
|
||||
If a driver in use matches one in this list, SAE/WPA3 will be disabled
|
||||
for connections. This will prevent connections to WPA3-only networks, but
|
||||
will allow for connections to WPA3/WPA2 hybrid networks by utilizing
|
||||
WPA2.
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
|
||||
|
@ -209,7 +209,7 @@ connect to that network.
|
||||
* - PasswordIdentifier
|
||||
- string
|
||||
|
||||
An identifier string to be used with the passphrase. This is used for
|
||||
An identifer string to be used with the passphrase. This is used for
|
||||
WPA3-Personal (SAE) networks if the security has enabled password
|
||||
identifiers for clients.
|
||||
* - PreSharedKey
|
||||
|
@ -894,11 +894,11 @@ static int manager_init(void)
|
||||
}
|
||||
|
||||
if (!l_settings_get_bool(config, "General",
|
||||
"UseDefaultInterface", &use_default))
|
||||
use_default = false;
|
||||
else
|
||||
"UseDefaultInterface", &use_default)) {
|
||||
l_warn("[General].UseDefaultInterface is deprecated, please "
|
||||
"use [DriverQuirks].DefaultInterface instead");
|
||||
use_default = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -398,16 +398,9 @@ static bool validate_mgmt_ies(const uint8_t *ies, size_t ies_len,
|
||||
|
||||
memcpy(&clone, &iter, sizeof(clone));
|
||||
|
||||
/*
|
||||
* Some APs send completely identical duplicate IEs:
|
||||
* Since these are harmless (and ignored by us) we're
|
||||
* going to allow them here for interoperability.
|
||||
*/
|
||||
while (ie_tlv_iter_next(&clone)) {
|
||||
if (ie_tlv_iter_get_tag(&clone) != tag)
|
||||
continue;
|
||||
else if (ie_tlv_iter_data_eq(&iter, &clone))
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ bool mschap_challenge_response(const uint8_t *challenge,
|
||||
|
||||
/**
|
||||
* Hash the utf8 encoded nt password.
|
||||
* It is assumed, that the password is valid utf8!
|
||||
* It is asumed, that the password is valid utf8!
|
||||
* The rfc says "unicode-char", but never specifies which encoding.
|
||||
* This function converts the password to ucs-2.
|
||||
* The example in the code uses LE for the unicode chars, so it is forced here.
|
||||
|
@ -622,7 +622,7 @@ bool netconfig_get_fils_ip_req(struct netconfig *netconfig,
|
||||
struct ie_fils_ip_addr_request_info *info)
|
||||
{
|
||||
/*
|
||||
* Fill in the fields used for building the FILS IP Address Assignment
|
||||
* Fill in the fields used for building the FILS IP Address Assigment
|
||||
* IE during connection if we're configured to do automatic network
|
||||
* configuration (usually DHCP). If we're configured with static
|
||||
* values return false to mean the IE should not be sent.
|
||||
@ -710,7 +710,7 @@ struct netconfig *netconfig_new(uint32_t ifindex)
|
||||
netconfig_commit_init(netconfig);
|
||||
|
||||
debug_level = getenv("IWD_DHCP_DEBUG");
|
||||
if (debug_level) {
|
||||
if (debug_level != NULL) {
|
||||
if (!strcmp("debug", debug_level))
|
||||
dhcp_priority = L_LOG_DEBUG;
|
||||
else if (!strcmp("info", debug_level))
|
||||
|
616
src/netdev.c
616
src/netdev.c
@ -65,7 +65,6 @@
|
||||
#include "src/frame-xchg.h"
|
||||
#include "src/diagnostic.h"
|
||||
#include "src/band.h"
|
||||
#include "src/pmksa.h"
|
||||
|
||||
#ifndef ENOTSUPP
|
||||
#define ENOTSUPP 524
|
||||
@ -134,7 +133,6 @@ struct netdev {
|
||||
uint32_t get_oci_cmd_id;
|
||||
uint32_t get_link_cmd_id;
|
||||
uint32_t power_save_cmd_id;
|
||||
uint32_t set_cqm_cmd_id;
|
||||
enum netdev_result result;
|
||||
uint16_t last_code; /* reason or status, depending on result */
|
||||
struct l_timeout *neighbor_report_timeout;
|
||||
@ -192,8 +190,6 @@ struct netdev {
|
||||
bool retry_auth : 1;
|
||||
bool in_reassoc : 1;
|
||||
bool privacy : 1;
|
||||
bool cqm_poll_fallback : 1;
|
||||
bool external_auth : 1;
|
||||
};
|
||||
|
||||
struct netdev_preauth_state {
|
||||
@ -377,7 +373,6 @@ struct handshake_state *netdev_handshake_state_new(struct netdev *netdev)
|
||||
|
||||
nhs->super.ifindex = netdev->index;
|
||||
nhs->super.free = netdev_handshake_state_free;
|
||||
nhs->super.refcount = 1;
|
||||
|
||||
nhs->netdev = netdev;
|
||||
/*
|
||||
@ -463,14 +458,6 @@ uint8_t netdev_get_rssi_level_idx(struct netdev *netdev)
|
||||
return netdev->cur_rssi_level_idx;
|
||||
}
|
||||
|
||||
int netdev_get_low_signal_threshold(uint32_t frequency)
|
||||
{
|
||||
if (frequency > 4000)
|
||||
return LOW_SIGNAL_THRESHOLD_5GHZ;
|
||||
|
||||
return LOW_SIGNAL_THRESHOLD;
|
||||
}
|
||||
|
||||
static void netdev_set_powered_result(int error, uint16_t type,
|
||||
const void *data,
|
||||
uint32_t len, void *user_data)
|
||||
@ -613,7 +600,7 @@ static bool netdev_parse_sta_info(struct l_genl_attr *attr,
|
||||
if (!netdev_parse_bitrate(&nested, &info->rx_mcs_type,
|
||||
&info->rx_bitrate,
|
||||
&info->rx_mcs))
|
||||
continue;
|
||||
return false;
|
||||
|
||||
info->have_rx_bitrate = true;
|
||||
|
||||
@ -629,7 +616,7 @@ static bool netdev_parse_sta_info(struct l_genl_attr *attr,
|
||||
if (!netdev_parse_bitrate(&nested, &info->tx_mcs_type,
|
||||
&info->tx_bitrate,
|
||||
&info->tx_mcs))
|
||||
continue;
|
||||
return false;
|
||||
|
||||
info->have_tx_bitrate = true;
|
||||
|
||||
@ -663,47 +650,6 @@ static void netdev_set_rssi_level_idx(struct netdev *netdev)
|
||||
netdev->cur_rssi_level_idx = new_level;
|
||||
}
|
||||
|
||||
static void netdev_cqm_event_rssi_value(struct netdev *netdev, int rssi_val)
|
||||
{
|
||||
bool new_rssi_low;
|
||||
uint8_t prev_rssi_level_idx = netdev->cur_rssi_level_idx;
|
||||
int threshold = netdev->frequency > 4000 ?
|
||||
netdev->low_signal_threshold_5ghz :
|
||||
netdev->low_signal_threshold;
|
||||
|
||||
if (!netdev->connected)
|
||||
return;
|
||||
|
||||
if (rssi_val > 127)
|
||||
rssi_val = 127;
|
||||
else if (rssi_val < -127)
|
||||
rssi_val = -127;
|
||||
|
||||
netdev->cur_rssi = rssi_val;
|
||||
|
||||
if (!netdev->event_filter)
|
||||
return;
|
||||
|
||||
new_rssi_low = rssi_val < threshold;
|
||||
if (netdev->cur_rssi_low != new_rssi_low) {
|
||||
int event = new_rssi_low ?
|
||||
NETDEV_EVENT_RSSI_THRESHOLD_LOW :
|
||||
NETDEV_EVENT_RSSI_THRESHOLD_HIGH;
|
||||
|
||||
netdev->cur_rssi_low = new_rssi_low;
|
||||
netdev->event_filter(netdev, event, NULL, netdev->user_data);
|
||||
}
|
||||
|
||||
if (!netdev->rssi_levels_num)
|
||||
return;
|
||||
|
||||
netdev_set_rssi_level_idx(netdev);
|
||||
if (netdev->cur_rssi_level_idx != prev_rssi_level_idx)
|
||||
netdev->event_filter(netdev, NETDEV_EVENT_RSSI_LEVEL_NOTIFY,
|
||||
&netdev->cur_rssi_level_idx,
|
||||
netdev->user_data);
|
||||
}
|
||||
|
||||
static void netdev_rssi_poll_cb(struct l_genl_msg *msg, void *user_data)
|
||||
{
|
||||
struct netdev *netdev = user_data;
|
||||
@ -740,16 +686,11 @@ static void netdev_rssi_poll_cb(struct l_genl_msg *msg, void *user_data)
|
||||
netdev->cur_rssi = info.cur_rssi;
|
||||
|
||||
/*
|
||||
* If the CMD_SET_CQM call failed RSSI polling was started. In this case
|
||||
* we should behave just like its a CQM event and check both the RSSI
|
||||
* level indexes and the HIGH/LOW thresholds.
|
||||
* Note we don't have to handle LOW_SIGNAL_THRESHOLD here. The
|
||||
* CQM single threshold RSSI monitoring should work even if the
|
||||
* kernel driver doesn't support multiple thresholds. So the
|
||||
* polling only handles the client-supplied threshold list.
|
||||
*/
|
||||
if (netdev->cqm_poll_fallback) {
|
||||
netdev_cqm_event_rssi_value(netdev, info.cur_rssi);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Otherwise just update the level notifications, CQM events work */
|
||||
netdev_set_rssi_level_idx(netdev);
|
||||
if (netdev->cur_rssi_level_idx != prev_rssi_level_idx)
|
||||
netdev->event_filter(netdev, NETDEV_EVENT_RSSI_LEVEL_NOTIFY,
|
||||
@ -779,12 +720,11 @@ static void netdev_rssi_poll(struct l_timeout *timeout, void *user_data)
|
||||
/* To be called whenever operational or rssi_levels_num are updated */
|
||||
static void netdev_rssi_polling_update(struct netdev *netdev)
|
||||
{
|
||||
if (!netdev->cqm_poll_fallback && wiphy_has_ext_feature(netdev->wiphy,
|
||||
if (wiphy_has_ext_feature(netdev->wiphy,
|
||||
NL80211_EXT_FEATURE_CQM_RSSI_LIST))
|
||||
return;
|
||||
|
||||
if (netdev->operational && (netdev->rssi_levels_num > 0 ||
|
||||
netdev->cqm_poll_fallback)) {
|
||||
if (netdev->operational && netdev->rssi_levels_num > 0) {
|
||||
if (netdev->rssi_poll_timeout)
|
||||
return;
|
||||
|
||||
@ -838,7 +778,7 @@ static void netdev_connect_free(struct netdev *netdev)
|
||||
eapol_preauth_cancel(netdev->index);
|
||||
|
||||
if (netdev->handshake) {
|
||||
handshake_state_unref(netdev->handshake);
|
||||
handshake_state_free(netdev->handshake);
|
||||
netdev->handshake = NULL;
|
||||
}
|
||||
|
||||
@ -883,7 +823,6 @@ static void netdev_connect_free(struct netdev *netdev)
|
||||
netdev->expect_connect_failure = false;
|
||||
netdev->cur_rssi_low = false;
|
||||
netdev->privacy = false;
|
||||
netdev->external_auth = false;
|
||||
|
||||
if (netdev->connect_cmd) {
|
||||
l_genl_msg_unref(netdev->connect_cmd);
|
||||
@ -1092,11 +1031,6 @@ static void netdev_free(void *data)
|
||||
netdev->get_station_cmd_id = 0;
|
||||
}
|
||||
|
||||
if (netdev->set_cqm_cmd_id) {
|
||||
l_genl_family_cancel(nl80211, netdev->set_cqm_cmd_id);
|
||||
netdev->set_cqm_cmd_id = 0;
|
||||
}
|
||||
|
||||
if (netdev->fw_roam_bss)
|
||||
scan_bss_free(netdev->fw_roam_bss);
|
||||
|
||||
@ -1105,11 +1039,7 @@ static void netdev_free(void *data)
|
||||
netdev->get_link_cmd_id = 0;
|
||||
}
|
||||
|
||||
if (netdev->rssi_poll_timeout)
|
||||
l_timeout_remove(netdev->rssi_poll_timeout);
|
||||
|
||||
scan_wdev_remove(netdev->wdev_id);
|
||||
frame_watch_wdev_remove(netdev->wdev_id);
|
||||
|
||||
watchlist_destroy(&netdev->station_watches);
|
||||
|
||||
@ -1163,6 +1093,47 @@ static void netdev_cqm_event_rssi_threshold(struct netdev *netdev,
|
||||
netdev->event_filter(netdev, event, NULL, netdev->user_data);
|
||||
}
|
||||
|
||||
static void netdev_cqm_event_rssi_value(struct netdev *netdev, int rssi_val)
|
||||
{
|
||||
bool new_rssi_low;
|
||||
uint8_t prev_rssi_level_idx = netdev->cur_rssi_level_idx;
|
||||
int threshold = netdev->frequency > 4000 ?
|
||||
netdev->low_signal_threshold_5ghz :
|
||||
netdev->low_signal_threshold;
|
||||
|
||||
if (!netdev->connected)
|
||||
return;
|
||||
|
||||
if (rssi_val > 127)
|
||||
rssi_val = 127;
|
||||
else if (rssi_val < -127)
|
||||
rssi_val = -127;
|
||||
|
||||
netdev->cur_rssi = rssi_val;
|
||||
|
||||
if (!netdev->event_filter)
|
||||
return;
|
||||
|
||||
new_rssi_low = rssi_val < threshold;
|
||||
if (netdev->cur_rssi_low != new_rssi_low) {
|
||||
int event = new_rssi_low ?
|
||||
NETDEV_EVENT_RSSI_THRESHOLD_LOW :
|
||||
NETDEV_EVENT_RSSI_THRESHOLD_HIGH;
|
||||
|
||||
netdev->cur_rssi_low = new_rssi_low;
|
||||
netdev->event_filter(netdev, event, NULL, netdev->user_data);
|
||||
}
|
||||
|
||||
if (!netdev->rssi_levels_num)
|
||||
return;
|
||||
|
||||
netdev_set_rssi_level_idx(netdev);
|
||||
if (netdev->cur_rssi_level_idx != prev_rssi_level_idx)
|
||||
netdev->event_filter(netdev, NETDEV_EVENT_RSSI_LEVEL_NOTIFY,
|
||||
&netdev->cur_rssi_level_idx,
|
||||
netdev->user_data);
|
||||
}
|
||||
|
||||
static void netdev_cqm_event(struct l_genl_msg *msg, struct netdev *netdev)
|
||||
{
|
||||
struct l_genl_attr attr;
|
||||
@ -1507,105 +1478,6 @@ static void netdev_setting_keys_failed(struct netdev_handshake_state *nhs,
|
||||
handshake_event(&nhs->super, HANDSHAKE_EVENT_SETTING_KEYS_FAILED, &err);
|
||||
}
|
||||
|
||||
static bool netdev_match_addr(const void *a, const void *b)
|
||||
{
|
||||
const struct netdev *netdev = a;
|
||||
const uint8_t *addr = b;
|
||||
|
||||
return memcmp(netdev->addr, addr, ETH_ALEN) == 0;
|
||||
}
|
||||
|
||||
static struct netdev *netdev_find_by_address(const uint8_t *addr)
|
||||
{
|
||||
return l_queue_find(netdev_list, netdev_match_addr, addr);
|
||||
}
|
||||
|
||||
static void netdev_pmksa_driver_add(const struct pmksa *pmksa)
|
||||
{
|
||||
struct l_genl_msg *msg;
|
||||
struct netdev *netdev = netdev_find_by_address(pmksa->spa);
|
||||
uint32_t expiration = (uint32_t)pmksa->expiration;
|
||||
|
||||
if (!netdev)
|
||||
return;
|
||||
|
||||
/* Only need to set the PMKSA into the kernel for fullmac drivers */
|
||||
if (wiphy_supports_cmds_auth_assoc(netdev->wiphy))
|
||||
return;
|
||||
|
||||
l_debug("Adding PMKSA to kernel");
|
||||
|
||||
msg = l_genl_msg_new(NL80211_CMD_SET_PMKSA);
|
||||
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_PMKID, 16, pmksa->pmkid);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, pmksa->aa);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_SSID,
|
||||
pmksa->ssid_len, pmksa->ssid);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_PMK_LIFETIME, 4, &expiration);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_PMK,
|
||||
pmksa->pmk_len, pmksa->pmk);
|
||||
|
||||
if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
|
||||
l_error("error sending SET_PMKSA");
|
||||
}
|
||||
|
||||
static void netdev_pmksa_driver_remove(const struct pmksa *pmksa)
|
||||
{
|
||||
struct l_genl_msg *msg;
|
||||
struct netdev *netdev = netdev_find_by_address(pmksa->spa);
|
||||
|
||||
if (!netdev)
|
||||
return;
|
||||
|
||||
/* Only need to set the PMKSA into the kernel for fullmac drivers */
|
||||
if (wiphy_supports_cmds_auth_assoc(netdev->wiphy))
|
||||
return;
|
||||
|
||||
l_debug("Removing PMKSA from kernel");
|
||||
|
||||
msg = l_genl_msg_new(NL80211_CMD_DEL_PMKSA);
|
||||
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_PMKID, 16, pmksa->pmkid);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, pmksa->aa);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_SSID,
|
||||
pmksa->ssid_len, pmksa->ssid);
|
||||
|
||||
if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
|
||||
l_error("error sending DEL_PMKSA");
|
||||
}
|
||||
|
||||
static void netdev_flush_pmksa(struct netdev *netdev)
|
||||
{
|
||||
struct l_genl_msg *msg;
|
||||
|
||||
/*
|
||||
* We only utilize the kernel's PMKSA cache for fullmac cards,
|
||||
* so no need to flush if this is a softmac.
|
||||
*/
|
||||
if (wiphy_supports_cmds_auth_assoc(netdev->wiphy))
|
||||
return;
|
||||
|
||||
msg = l_genl_msg_new(NL80211_CMD_FLUSH_PMKSA);
|
||||
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
|
||||
|
||||
if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
|
||||
l_error("Failed to flush PMKSA for %u", netdev->index);
|
||||
}
|
||||
|
||||
static void netdev_pmksa_driver_flush(void)
|
||||
{
|
||||
const struct l_queue_entry *e;
|
||||
|
||||
for (e = l_queue_get_entries(netdev_list); e; e = e->next) {
|
||||
struct netdev *netdev = e->data;
|
||||
|
||||
netdev_flush_pmksa(netdev);
|
||||
}
|
||||
}
|
||||
|
||||
static void try_handshake_complete(struct netdev_handshake_state *nhs)
|
||||
{
|
||||
l_debug("ptk_installed: %u, gtk_installed: %u, igtk_installed: %u",
|
||||
@ -1626,8 +1498,6 @@ static void try_handshake_complete(struct netdev_handshake_state *nhs)
|
||||
|
||||
l_debug("Invoking handshake_event()");
|
||||
|
||||
handshake_state_cache_pmksa(&nhs->super);
|
||||
|
||||
if (handshake_event(&nhs->super, HANDSHAKE_EVENT_COMPLETE))
|
||||
return;
|
||||
|
||||
@ -2281,7 +2151,7 @@ static void netdev_set_pmk(struct handshake_state *hs, const uint8_t *pmk,
|
||||
struct netdev_handshake_state, super);
|
||||
struct netdev *netdev = nhs->netdev;
|
||||
|
||||
/* Only relevant for 8021x offload */
|
||||
/* Only relevent for 8021x offload */
|
||||
if (nhs->type != CONNECTION_TYPE_8021X_OFFLOAD)
|
||||
return;
|
||||
|
||||
@ -2393,7 +2263,7 @@ static void netdev_qos_map_cb(struct l_genl_msg *msg, void *user_data)
|
||||
return;
|
||||
|
||||
ext_error = l_genl_msg_get_extended_error(msg);
|
||||
l_error("Could not set QoS Map in kernel: %s",
|
||||
l_error("Couuld not set QoS Map in kernel: %s",
|
||||
ext_error ? ext_error : strerror(-err));
|
||||
}
|
||||
|
||||
@ -2466,7 +2336,7 @@ static void netdev_get_oci_cb(struct l_genl_msg *msg, void *user_data)
|
||||
done:
|
||||
if (netdev->ap) {
|
||||
/*
|
||||
* Can't do much here. IWD assumes every kernel/driver supports
|
||||
* Cant do much here. IWD assumes every kernel/driver supports
|
||||
* this. There is no way of detecting support either.
|
||||
*/
|
||||
if (L_WARN_ON(err < 0))
|
||||
@ -2569,19 +2439,7 @@ static struct l_genl_msg *netdev_build_cmd_connect(struct netdev *netdev,
|
||||
{
|
||||
struct netdev_handshake_state *nhs =
|
||||
l_container_of(hs, struct netdev_handshake_state, super);
|
||||
/*
|
||||
* Choose Open system auth type if PMKSA caching is used for an SAE AKM:
|
||||
*
|
||||
* IEEE 802.11-2020 Table 9-151
|
||||
* - SAE authentication:
|
||||
* 3 (SAE) for SAE Authentication
|
||||
* 0 (open) for PMKSA caching
|
||||
* - FT authentication over SAE:
|
||||
* 3 (SAE) for FT Initial Mobility Domain Association
|
||||
* 0 (open) for FT Initial Mobility Domain Association over
|
||||
* PMKSA caching
|
||||
*/
|
||||
uint32_t auth_type = IE_AKM_IS_SAE(hs->akm_suite) && !hs->have_pmksa ?
|
||||
uint32_t auth_type = IE_AKM_IS_SAE(hs->akm_suite) ?
|
||||
NL80211_AUTHTYPE_SAE :
|
||||
NL80211_AUTHTYPE_OPEN_SYSTEM;
|
||||
enum mpdu_management_subtype subtype = prev_bssid ?
|
||||
@ -2605,10 +2463,7 @@ static struct l_genl_msg *netdev_build_cmd_connect(struct netdev *netdev,
|
||||
|
||||
switch (nhs->type) {
|
||||
case CONNECTION_TYPE_SOFTMAC:
|
||||
break;
|
||||
case CONNECTION_TYPE_FULLMAC:
|
||||
l_genl_msg_append_attr(msg,
|
||||
NL80211_ATTR_EXTERNAL_AUTH_SUPPORT, 0, NULL);
|
||||
break;
|
||||
case CONNECTION_TYPE_SAE_OFFLOAD:
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_SAE_PASSWORD,
|
||||
@ -3522,84 +3377,6 @@ static void netdev_fils_tx_associate(struct iovec *fils_iov, size_t n_fils_iov,
|
||||
}
|
||||
}
|
||||
|
||||
static void netdev_external_auth_frame_cb(struct l_genl_msg *msg,
|
||||
void *user_data)
|
||||
{
|
||||
int error = l_genl_msg_get_error(msg);
|
||||
|
||||
if (error < 0)
|
||||
l_debug("Failed to send External Auth Frame: %s(%d)",
|
||||
strerror(-error), -error);
|
||||
}
|
||||
|
||||
static void netdev_external_auth_sae_tx_authenticate(const uint8_t *body,
|
||||
size_t body_len, void *user_data)
|
||||
{
|
||||
struct netdev *netdev = user_data;
|
||||
struct handshake_state *hs = netdev->handshake;
|
||||
uint16_t frame_type = MPDU_MANAGEMENT_SUBTYPE_AUTHENTICATION << 4;
|
||||
struct iovec iov[2];
|
||||
struct l_genl_msg *msg;
|
||||
uint8_t algorithm[2] = { 0x03, 0x00 };
|
||||
|
||||
l_debug("");
|
||||
|
||||
iov[0].iov_base = &algorithm;
|
||||
iov[0].iov_len = sizeof(algorithm);
|
||||
iov[1].iov_base = (void *) body;
|
||||
iov[1].iov_len = body_len;
|
||||
|
||||
msg = nl80211_build_cmd_frame(netdev->index, frame_type,
|
||||
hs->spa, hs->aa, 0, iov, 2);
|
||||
|
||||
if (l_genl_family_send(nl80211, msg, netdev_external_auth_frame_cb,
|
||||
netdev, NULL) > 0)
|
||||
return;
|
||||
|
||||
l_genl_msg_unref(msg);
|
||||
}
|
||||
|
||||
static void netdev_external_auth_cb(struct l_genl_msg *msg, void *user_data)
|
||||
{
|
||||
int error = l_genl_msg_get_error(msg);
|
||||
|
||||
if (error < 0)
|
||||
l_debug("Failed to send External Auth: %s(%d)",
|
||||
strerror(-error), -error);
|
||||
}
|
||||
|
||||
static void netdev_send_external_auth(struct netdev *netdev,
|
||||
uint16_t status_code)
|
||||
{
|
||||
struct handshake_state *hs = netdev->handshake;
|
||||
struct l_genl_msg *msg =
|
||||
nl80211_build_external_auth(netdev->index, status_code,
|
||||
hs->ssid, hs->ssid_len, hs->aa);
|
||||
|
||||
if (l_genl_family_send(nl80211, msg, netdev_external_auth_cb,
|
||||
netdev, NULL) > 0)
|
||||
return;
|
||||
|
||||
l_genl_msg_unref(msg);
|
||||
}
|
||||
|
||||
static void netdev_external_auth_sae_tx_associate(void *user_data)
|
||||
{
|
||||
struct netdev *netdev = user_data;
|
||||
|
||||
l_debug("");
|
||||
|
||||
netdev_send_external_auth(netdev, MMPDU_STATUS_CODE_SUCCESS);
|
||||
netdev_ensure_eapol_registered(netdev);
|
||||
|
||||
/*
|
||||
* Free the auth proto now. With external auth there is no associate
|
||||
* event which is where this normally gets cleaned up.
|
||||
*/
|
||||
auth_proto_free(netdev->ap);
|
||||
netdev->ap = NULL;
|
||||
}
|
||||
|
||||
struct rtnl_data {
|
||||
struct netdev *netdev;
|
||||
uint8_t addr[ETH_ALEN];
|
||||
@ -3608,10 +3385,6 @@ struct rtnl_data {
|
||||
|
||||
static int netdev_begin_connection(struct netdev *netdev)
|
||||
{
|
||||
struct netdev_handshake_state *nhs =
|
||||
l_container_of(netdev->handshake,
|
||||
struct netdev_handshake_state, super);
|
||||
|
||||
if (netdev->connect_cmd) {
|
||||
netdev->connect_cmd_id = l_genl_family_send(nl80211,
|
||||
netdev->connect_cmd,
|
||||
@ -3631,7 +3404,7 @@ static int netdev_begin_connection(struct netdev *netdev)
|
||||
*/
|
||||
handshake_state_set_supplicant_address(netdev->handshake, netdev->addr);
|
||||
|
||||
if (netdev->ap && nhs->type == CONNECTION_TYPE_SOFTMAC) {
|
||||
if (netdev->ap) {
|
||||
if (!auth_proto_start(netdev->ap))
|
||||
goto failed;
|
||||
|
||||
@ -3871,50 +3644,11 @@ static struct l_genl_msg *netdev_build_cmd_cqm_rssi_update(
|
||||
|
||||
static void netdev_cmd_set_cqm_cb(struct l_genl_msg *msg, void *user_data)
|
||||
{
|
||||
struct netdev *netdev = user_data;
|
||||
int err = l_genl_msg_get_error(msg);
|
||||
const char *ext_error;
|
||||
|
||||
netdev->set_cqm_cmd_id = 0;
|
||||
|
||||
if (err >= 0) {
|
||||
/*
|
||||
* Looking at some driver code it appears that the -ENOTSUP CQM
|
||||
* failure could be transient. Just in case, reset the fallback
|
||||
* flag if CQM happens to start working again.
|
||||
*/
|
||||
if (netdev->cqm_poll_fallback) {
|
||||
l_debug("CMD_SET_CQM succeeded, stop polling fallback");
|
||||
|
||||
if (netdev->rssi_poll_timeout) {
|
||||
l_timeout_remove(netdev->rssi_poll_timeout);
|
||||
netdev->rssi_poll_timeout = NULL;
|
||||
}
|
||||
|
||||
netdev->cqm_poll_fallback = false;
|
||||
}
|
||||
|
||||
if (err >= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some drivers enable beacon filtering but also use software CQM which
|
||||
* mac80211 detects and returns -ENOTSUP. There is no way to check this
|
||||
* ahead of time so if we see this start polling in order to get RSSI
|
||||
* updates.
|
||||
*/
|
||||
if (err == -ENOTSUP) {
|
||||
l_debug("CMD_SET_CQM not supported, falling back to polling");
|
||||
netdev->cqm_poll_fallback = true;
|
||||
|
||||
if (netdev->rssi_poll_timeout)
|
||||
return;
|
||||
|
||||
netdev->rssi_poll_timeout = l_timeout_create(1,
|
||||
netdev_rssi_poll, netdev, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ext_error = l_genl_msg_get_extended_error(msg);
|
||||
l_error("CMD_SET_CQM failed: %s",
|
||||
@ -3924,21 +3658,9 @@ static void netdev_cmd_set_cqm_cb(struct l_genl_msg *msg, void *user_data)
|
||||
static int netdev_cqm_rssi_update(struct netdev *netdev)
|
||||
{
|
||||
struct l_genl_msg *msg;
|
||||
struct netdev_handshake_state *nhs = l_container_of(netdev->handshake,
|
||||
struct netdev_handshake_state, super);
|
||||
|
||||
/*
|
||||
* Fullmac cards handle roaming in firmware, there is no need to set
|
||||
* CQM thresholds
|
||||
*/
|
||||
if (nhs->type == CONNECTION_TYPE_FULLMAC)
|
||||
return 0;
|
||||
|
||||
l_debug("");
|
||||
|
||||
if (netdev->set_cqm_cmd_id)
|
||||
return -EBUSY;
|
||||
|
||||
if (!wiphy_has_ext_feature(netdev->wiphy,
|
||||
NL80211_EXT_FEATURE_CQM_RSSI_LIST))
|
||||
msg = netdev_build_cmd_cqm_rssi_update(netdev, NULL, 0);
|
||||
@ -3949,10 +3671,8 @@ static int netdev_cqm_rssi_update(struct netdev *netdev)
|
||||
if (!msg)
|
||||
return -EINVAL;
|
||||
|
||||
netdev->set_cqm_cmd_id = l_genl_family_send(nl80211, msg,
|
||||
netdev_cmd_set_cqm_cb,
|
||||
netdev, NULL);
|
||||
if (!netdev->set_cqm_cmd_id) {
|
||||
if (!l_genl_family_send(nl80211, msg, netdev_cmd_set_cqm_cb,
|
||||
NULL, NULL)) {
|
||||
l_genl_msg_unref(msg);
|
||||
return -EIO;
|
||||
}
|
||||
@ -3976,7 +3696,9 @@ static int netdev_set_signal_thresholds(struct netdev *netdev, int threshold,
|
||||
netdev->low_signal_threshold = threshold;
|
||||
netdev->low_signal_threshold_5ghz = threshold_5ghz;
|
||||
|
||||
return netdev_cqm_rssi_update(netdev);
|
||||
netdev_cqm_rssi_update(netdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_lower_signal_threshold(struct netdev *netdev)
|
||||
@ -4091,11 +3813,7 @@ static int netdev_handshake_state_setup_connection_type(
|
||||
if (softmac && wiphy_has_feature(wiphy, NL80211_FEATURE_SAE))
|
||||
goto softmac;
|
||||
|
||||
/* FullMAC uses EXTERNAL_AUTH and reuses this feature bit */
|
||||
if (wiphy_has_feature(wiphy, NL80211_FEATURE_SAE))
|
||||
goto fullmac;
|
||||
|
||||
return -ENOTSUP;
|
||||
return -EINVAL;
|
||||
case IE_RSN_AKM_SUITE_FILS_SHA256:
|
||||
case IE_RSN_AKM_SUITE_FILS_SHA384:
|
||||
case IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA256:
|
||||
@ -4166,55 +3884,40 @@ static void netdev_connect_common(struct netdev *netdev,
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* If SAE, and we have a valid PMKSA cache we can skip the entire SAE
|
||||
* protocol and authenticate using the cached keys.
|
||||
*/
|
||||
if (IE_AKM_IS_SAE(hs->akm_suite) && hs->have_pmksa) {
|
||||
l_debug("Skipping SAE by using PMKSA cache");
|
||||
goto build_cmd_connect;
|
||||
}
|
||||
|
||||
if (!IE_AKM_IS_SAE(hs->akm_suite) ||
|
||||
nhs->type == CONNECTION_TYPE_SAE_OFFLOAD)
|
||||
if (nhs->type != CONNECTION_TYPE_SOFTMAC)
|
||||
goto build_cmd_connect;
|
||||
|
||||
if (nhs->type == CONNECTION_TYPE_SOFTMAC)
|
||||
switch (hs->akm_suite) {
|
||||
case IE_RSN_AKM_SUITE_SAE_SHA256:
|
||||
case IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256:
|
||||
netdev->ap = sae_sm_new(hs, netdev_sae_tx_authenticate,
|
||||
netdev_sae_tx_associate,
|
||||
netdev);
|
||||
else {
|
||||
netdev->ap =
|
||||
sae_sm_new(hs, netdev_external_auth_sae_tx_authenticate,
|
||||
netdev_external_auth_sae_tx_associate,
|
||||
netdev);
|
||||
sae_sm_force_default_group(netdev->ap);
|
||||
sae_sm_force_hunt_and_peck(netdev->ap);
|
||||
}
|
||||
netdev_sae_tx_associate,
|
||||
netdev);
|
||||
|
||||
if (sae_sm_is_h2e(netdev->ap)) {
|
||||
uint8_t own_rsnxe[20];
|
||||
if (sae_sm_is_h2e(netdev->ap)) {
|
||||
uint8_t own_rsnxe[20];
|
||||
|
||||
if (wiphy_get_rsnxe(netdev->wiphy,
|
||||
own_rsnxe, sizeof(own_rsnxe))) {
|
||||
set_bit(own_rsnxe + 2, IE_RSNX_SAE_H2E);
|
||||
handshake_state_set_supplicant_rsnxe(hs,
|
||||
own_rsnxe);
|
||||
if (wiphy_get_rsnxe(netdev->wiphy,
|
||||
own_rsnxe, sizeof(own_rsnxe))) {
|
||||
set_bit(own_rsnxe + 2, IE_RSNX_SAE_H2E);
|
||||
handshake_state_set_supplicant_rsnxe(hs,
|
||||
own_rsnxe);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
build_cmd_connect:
|
||||
cmd_connect = netdev_build_cmd_connect(netdev, hs, prev_bssid);
|
||||
|
||||
if (!is_offload(hs) && (is_rsn || hs->settings_8021x)) {
|
||||
sm = eapol_sm_new(hs);
|
||||
|
||||
if (nhs->type == CONNECTION_TYPE_8021X_OFFLOAD)
|
||||
eapol_sm_set_require_handshake(sm, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (nhs->type == CONNECTION_TYPE_SOFTMAC)
|
||||
goto done;
|
||||
|
||||
build_cmd_connect:
|
||||
cmd_connect = netdev_build_cmd_connect(netdev, hs, prev_bssid);
|
||||
|
||||
if (!is_offload(hs) && (is_rsn || hs->settings_8021x)) {
|
||||
sm = eapol_sm_new(hs);
|
||||
|
||||
if (nhs->type == CONNECTION_TYPE_8021X_OFFLOAD)
|
||||
eapol_sm_set_require_handshake(sm, false);
|
||||
}
|
||||
done:
|
||||
netdev->connect_cmd = cmd_connect;
|
||||
netdev->event_filter = event_filter;
|
||||
@ -4388,7 +4091,7 @@ int netdev_reassociate(struct netdev *netdev, const struct scan_bss *target_bss,
|
||||
eapol_sm_free(old_sm);
|
||||
|
||||
if (old_hs)
|
||||
handshake_state_unref(old_hs);
|
||||
handshake_state_free(old_hs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4723,52 +4426,6 @@ static void netdev_qos_map_frame_event(const struct mmpdu_header *hdr,
|
||||
netdev_send_qos_map_set(netdev, body + 4, body_len - 4);
|
||||
}
|
||||
|
||||
static void netdev_sae_external_auth_frame_event(const struct mmpdu_header *hdr,
|
||||
const void *body, size_t body_len,
|
||||
int rssi, void *user_data)
|
||||
{
|
||||
struct netdev *netdev = user_data;
|
||||
const struct mmpdu_authentication *auth;
|
||||
uint16_t status_code = MMPDU_STATUS_CODE_UNSPECIFIED;
|
||||
int ret;
|
||||
|
||||
if (!netdev->external_auth)
|
||||
return;
|
||||
|
||||
if (!netdev->ap)
|
||||
return;
|
||||
|
||||
auth = mmpdu_body(hdr);
|
||||
/*
|
||||
* Allows station to persist settings so it does not retry
|
||||
* the higher order ECC group again
|
||||
*/
|
||||
if (L_CPU_TO_LE16(auth->status) ==
|
||||
MMPDU_STATUS_CODE_UNSUPP_FINITE_CYCLIC_GROUP &&
|
||||
netdev->event_filter)
|
||||
netdev->event_filter(netdev, NETDEV_EVENT_ECC_GROUP_RETRY,
|
||||
NULL, netdev->user_data);
|
||||
|
||||
ret = auth_proto_rx_authenticate(netdev->ap, (const void *) hdr,
|
||||
mmpdu_header_len(hdr) + body_len);
|
||||
|
||||
switch (ret) {
|
||||
case 0:
|
||||
case -EAGAIN:
|
||||
return;
|
||||
case -ENOMSG:
|
||||
case -EBADMSG:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
status_code = (uint16_t)ret;
|
||||
|
||||
netdev_send_external_auth(netdev, status_code);
|
||||
}
|
||||
|
||||
static void netdev_preauth_cb(const uint8_t *pmk, void *user_data)
|
||||
{
|
||||
struct netdev_preauth_state *preauth = user_data;
|
||||
@ -5593,58 +5250,6 @@ static void netdev_control_port_frame_event(struct l_genl_msg *msg,
|
||||
frame, frame_len, unencrypted);
|
||||
}
|
||||
|
||||
static void netdev_external_auth_event(struct l_genl_msg *msg,
|
||||
struct netdev *netdev)
|
||||
{
|
||||
const uint8_t *bssid;
|
||||
struct iovec ssid;
|
||||
uint32_t akm;
|
||||
uint32_t action;
|
||||
struct handshake_state *hs = netdev->handshake;
|
||||
|
||||
if (L_WARN_ON(nl80211_parse_attrs(msg, NL80211_ATTR_AKM_SUITES, &akm,
|
||||
NL80211_ATTR_EXTERNAL_AUTH_ACTION, &action,
|
||||
NL80211_ATTR_BSSID, &bssid,
|
||||
NL80211_ATTR_SSID, &ssid,
|
||||
NL80211_ATTR_UNSPEC) < 0))
|
||||
return;
|
||||
|
||||
if (!L_IN_SET(action, NL80211_EXTERNAL_AUTH_START,
|
||||
NL80211_EXTERNAL_AUTH_ABORT))
|
||||
return;
|
||||
|
||||
/* kernel sends SAE_SHA256 AKM in BE order for legacy reasons */
|
||||
if (!L_IN_SET(akm, CRYPTO_AKM_SAE_SHA256, CRYPTO_AKM_FT_OVER_SAE_SHA256,
|
||||
L_CPU_TO_BE32(CRYPTO_AKM_SAE_SHA256))) {
|
||||
l_warn("Unknown AKM: %08x", akm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action == NL80211_EXTERNAL_AUTH_ABORT) {
|
||||
l_warn("External Auth Aborted");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (hs->ssid_len != ssid.iov_len ||
|
||||
memcmp(hs->ssid, ssid.iov_base, hs->ssid_len)) {
|
||||
l_warn("Target SSID mismatch");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (memcmp(hs->aa, bssid, ETH_ALEN)) {
|
||||
l_warn("Target BSSID mismatch");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (auth_proto_start(netdev->ap)) {
|
||||
netdev->external_auth = true;
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
netdev_send_external_auth(netdev, MMPDU_STATUS_CODE_UNSPECIFIED);
|
||||
}
|
||||
|
||||
static void netdev_unicast_notify(struct l_genl_msg *msg, void *user_data)
|
||||
{
|
||||
struct netdev *netdev = NULL;
|
||||
@ -5682,9 +5287,6 @@ static void netdev_unicast_notify(struct l_genl_msg *msg, void *user_data)
|
||||
case NL80211_CMD_CONTROL_PORT_FRAME:
|
||||
netdev_control_port_frame_event(msg, netdev);
|
||||
break;
|
||||
case NL80211_CMD_EXTERNAL_AUTH:
|
||||
netdev_external_auth_event(msg, netdev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5707,10 +5309,8 @@ int netdev_set_rssi_report_levels(struct netdev *netdev, const int8_t *levels,
|
||||
if (!cmd_set_cqm)
|
||||
return -EINVAL;
|
||||
|
||||
netdev->set_cqm_cmd_id = l_genl_family_send(nl80211, cmd_set_cqm,
|
||||
netdev_cmd_set_cqm_cb,
|
||||
netdev, NULL);
|
||||
if (!netdev->set_cqm_cmd_id) {
|
||||
if (!l_genl_family_send(nl80211, cmd_set_cqm, netdev_cmd_set_cqm_cb,
|
||||
NULL, NULL)) {
|
||||
l_genl_msg_unref(cmd_set_cqm);
|
||||
return -EIO;
|
||||
}
|
||||
@ -5859,41 +5459,33 @@ static void netdev_add_station_frame_watches(struct netdev *netdev)
|
||||
static const uint8_t action_ft_response_prefix[] = { 0x06, 0x02 };
|
||||
static const uint8_t auth_ft_response_prefix[] = { 0x02, 0x00 };
|
||||
static const uint8_t action_qos_map_prefix[] = { 0x01, 0x04 };
|
||||
static const uint8_t auth_sae_prefix[] = { 0x03, 0x00 };
|
||||
uint64_t wdev = netdev->wdev_id;
|
||||
|
||||
/* Subscribe to Management -> Action -> RM -> Neighbor Report frames */
|
||||
frame_watch_add(wdev, 0, 0x00d0, action_neighbor_report_prefix,
|
||||
sizeof(action_neighbor_report_prefix), false,
|
||||
sizeof(action_neighbor_report_prefix),
|
||||
netdev_neighbor_report_frame_event, netdev, NULL);
|
||||
|
||||
frame_watch_add(wdev, 0, 0x00d0, action_sa_query_resp_prefix,
|
||||
sizeof(action_sa_query_resp_prefix), false,
|
||||
sizeof(action_sa_query_resp_prefix),
|
||||
netdev_sa_query_resp_frame_event, netdev, NULL);
|
||||
|
||||
frame_watch_add(wdev, 0, 0x00d0, action_sa_query_req_prefix,
|
||||
sizeof(action_sa_query_req_prefix), false,
|
||||
sizeof(action_sa_query_req_prefix),
|
||||
netdev_sa_query_req_frame_event, netdev, NULL);
|
||||
|
||||
frame_watch_add(wdev, 0, 0x00d0, action_ft_response_prefix,
|
||||
sizeof(action_ft_response_prefix), false,
|
||||
sizeof(action_ft_response_prefix),
|
||||
netdev_ft_response_frame_event, netdev, NULL);
|
||||
|
||||
frame_watch_add(wdev, 0, 0x00b0, auth_ft_response_prefix,
|
||||
sizeof(auth_ft_response_prefix), false,
|
||||
sizeof(auth_ft_response_prefix),
|
||||
netdev_ft_auth_response_frame_event, netdev, NULL);
|
||||
|
||||
if (wiphy_supports_qos_set_map(netdev->wiphy))
|
||||
frame_watch_add(wdev, 0, 0x00d0, action_qos_map_prefix,
|
||||
sizeof(action_qos_map_prefix), false,
|
||||
sizeof(action_qos_map_prefix),
|
||||
netdev_qos_map_frame_event, netdev, NULL);
|
||||
|
||||
if (!wiphy_supports_cmds_auth_assoc(netdev->wiphy) &&
|
||||
wiphy_has_feature(netdev->wiphy, NL80211_FEATURE_SAE))
|
||||
frame_watch_add(wdev, 0, 0x00b0,
|
||||
auth_sae_prefix, sizeof(auth_sae_prefix),
|
||||
false, netdev_sae_external_auth_frame_event,
|
||||
netdev, NULL);
|
||||
}
|
||||
|
||||
static void netdev_setup_interface(struct netdev *netdev)
|
||||
@ -6641,16 +6233,6 @@ struct netdev *netdev_create_from_genl(struct l_genl_msg *msg,
|
||||
|
||||
netdev_get_link(netdev);
|
||||
|
||||
/*
|
||||
* Call the netdev-specific variant to flush only this devices PMKSA
|
||||
* cache in the kernel. This will make IWD's cache and the kernel's
|
||||
* cache consistent, i.e. no entries
|
||||
*
|
||||
* TODO: If we ever are storing PMKSA's on disk we would first need to
|
||||
* flush, then add all the PMKSA entries at this time.
|
||||
*/
|
||||
netdev_flush_pmksa(netdev);
|
||||
|
||||
return netdev;
|
||||
}
|
||||
|
||||
@ -6766,10 +6348,6 @@ static int netdev_init(void)
|
||||
|
||||
__ft_set_tx_frame_func(netdev_tx_ft_frame);
|
||||
|
||||
__pmksa_set_driver_callbacks(netdev_pmksa_driver_add,
|
||||
netdev_pmksa_driver_remove,
|
||||
netdev_pmksa_driver_flush);
|
||||
|
||||
unicast_watch = l_genl_add_unicast_watch(genl, NL80211_GENL_NAME,
|
||||
netdev_unicast_notify,
|
||||
NULL, NULL);
|
||||
|
@ -158,7 +158,6 @@ const char *netdev_get_name(struct netdev *netdev);
|
||||
bool netdev_get_is_up(struct netdev *netdev);
|
||||
const char *netdev_get_path(struct netdev *netdev);
|
||||
uint8_t netdev_get_rssi_level_idx(struct netdev *netdev);
|
||||
int netdev_get_low_signal_threshold(uint32_t frequency);
|
||||
|
||||
struct handshake_state *netdev_handshake_state_new(struct netdev *netdev);
|
||||
struct handshake_state *netdev_get_handshake(struct netdev *netdev);
|
||||
|
@ -56,7 +56,6 @@
|
||||
#include "src/erp.h"
|
||||
#include "src/handshake.h"
|
||||
#include "src/band.h"
|
||||
#include "src/util.h"
|
||||
|
||||
#define SAE_PT_SETTING "SAE-PT-Group%u"
|
||||
|
||||
@ -213,10 +212,31 @@ void network_disconnected(struct network *network)
|
||||
station_hide_network(network->station, network);
|
||||
}
|
||||
|
||||
/* First 64 entries calculated by 1 / pow(n, 0.3) for n >= 1 */
|
||||
static const double rankmod_table[] = {
|
||||
1.0000000000, 0.8122523964, 0.7192230933, 0.6597539554,
|
||||
0.6170338627, 0.5841906811, 0.5577898253, 0.5358867313,
|
||||
0.5172818580, 0.5011872336, 0.4870596972, 0.4745102806,
|
||||
0.4632516708, 0.4530661223, 0.4437850034, 0.4352752816,
|
||||
0.4274303178, 0.4201634287, 0.4134032816, 0.4070905315,
|
||||
0.4011753236, 0.3956154062, 0.3903746872, 0.3854221125,
|
||||
0.3807307877, 0.3762772797, 0.3720410580, 0.3680040435,
|
||||
0.3641502401, 0.3604654325, 0.3569369365, 0.3535533906,
|
||||
0.3503045821, 0.3471812999, 0.3441752105, 0.3412787518,
|
||||
0.3384850430, 0.3357878061, 0.3331812996, 0.3306602598,
|
||||
0.3282198502, 0.3258556179, 0.3235634544, 0.3213395618,
|
||||
0.3191804229, 0.3170827751, 0.3150435863, 0.3130600345,
|
||||
0.3111294892, 0.3092494947, 0.3074177553, 0.3056321221,
|
||||
0.3038905808, 0.3021912409, 0.3005323264, 0.2989121662,
|
||||
0.2973291870, 0.2957819051, 0.2942689208, 0.2927889114,
|
||||
0.2913406263, 0.2899228820, 0.2885345572, 0.2871745887,
|
||||
};
|
||||
|
||||
bool network_rankmod(const struct network *network, double *rankmod)
|
||||
{
|
||||
struct network_info *info = network->info;
|
||||
int n;
|
||||
int nmax;
|
||||
|
||||
/*
|
||||
* Current policy is that only networks successfully connected
|
||||
@ -230,7 +250,12 @@ bool network_rankmod(const struct network *network, double *rankmod)
|
||||
if (n < 0)
|
||||
return false;
|
||||
|
||||
*rankmod = util_exponential_decay(n);
|
||||
nmax = L_ARRAY_SIZE(rankmod_table);
|
||||
|
||||
if (n >= nmax)
|
||||
n = nmax - 1;
|
||||
|
||||
*rankmod = rankmod_table[n];
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -886,9 +911,6 @@ int network_can_connect_bss(struct network *network, const struct scan_bss *bss)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (IE_AKM_IS_OWE(rsn.akm_suites) && wiphy_owe_disabled(wiphy))
|
||||
return -EPERM;
|
||||
|
||||
if (!config || !config->have_transition_disable) {
|
||||
if (band == BAND_FREQ_6_GHZ)
|
||||
goto mfp_no_tkip;
|
||||
@ -1256,7 +1278,6 @@ struct scan_bss *network_bss_select(struct network *network,
|
||||
struct l_queue *bss_list = network->bss_list;
|
||||
const struct l_queue_entry *bss_entry;
|
||||
struct scan_bss *candidate = NULL;
|
||||
bool skipped_open = false;
|
||||
|
||||
for (bss_entry = l_queue_get_entries(bss_list); bss_entry;
|
||||
bss_entry = bss_entry->next) {
|
||||
@ -1276,35 +1297,30 @@ struct scan_bss *network_bss_select(struct network *network,
|
||||
if (!candidate)
|
||||
candidate = bss;
|
||||
|
||||
/* check if temporarily blacklisted */
|
||||
if (l_queue_find(network->blacklist, match_bss, bss))
|
||||
continue;
|
||||
|
||||
if (blacklist_contains_bss(bss->addr,
|
||||
BLACKLIST_REASON_CONNECT_FAILED))
|
||||
continue;
|
||||
|
||||
/* OWE Transition BSS */
|
||||
if (bss->owe_trans) {
|
||||
/* Don't want to connect to the Open BSS if possible */
|
||||
if (!bss->rsne) {
|
||||
skipped_open = true;
|
||||
if (!bss->rsne)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Candidate is not OWE, set this as new candidate */
|
||||
if (!(candidate->owe_trans && candidate->rsne))
|
||||
candidate = bss;
|
||||
}
|
||||
|
||||
return bss;
|
||||
/* check if temporarily blacklisted */
|
||||
if (l_queue_find(network->blacklist, match_bss, bss))
|
||||
continue;
|
||||
|
||||
if (!blacklist_contains_bss(bss->addr))
|
||||
return bss;
|
||||
}
|
||||
|
||||
/*
|
||||
* No BSS was found, but if we are falling back to blacklisted BSS's we
|
||||
* can just use the first connectable candidate found above.
|
||||
*/
|
||||
if (fallback_to_blacklist || skipped_open)
|
||||
if (fallback_to_blacklist)
|
||||
return candidate;
|
||||
|
||||
return NULL;
|
||||
@ -1994,8 +2010,10 @@ void network_rank_update(struct network *network, bool connected)
|
||||
|
||||
L_WARN_ON(n < 0);
|
||||
|
||||
network->rank =
|
||||
util_exponential_decay(n) * best_bss->rank + USHRT_MAX;
|
||||
if (n >= (int) L_ARRAY_SIZE(rankmod_table))
|
||||
n = L_ARRAY_SIZE(rankmod_table) - 1;
|
||||
|
||||
network->rank = rankmod_table[n] * best_bss->rank + USHRT_MAX;
|
||||
} else
|
||||
network->rank = best_bss->rank;
|
||||
|
||||
|
@ -648,9 +648,7 @@ struct l_genl_msg *nl80211_build_cmd_frame(uint32_t ifindex,
|
||||
msg = l_genl_msg_new_sized(NL80211_CMD_FRAME, 128 + 512);
|
||||
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
|
||||
|
||||
if (freq)
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY_FREQ, 4, &freq);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY_FREQ, 4, &freq);
|
||||
l_genl_msg_append_attrv(msg, NL80211_ATTR_FRAME, iovs, iov_len + 1);
|
||||
|
||||
return msg;
|
||||
@ -697,7 +695,8 @@ int nl80211_parse_chandef(struct l_genl_msg *msg, struct band_chandef *out)
|
||||
|
||||
int nl80211_parse_supported_frequencies(struct l_genl_attr *band_freqs,
|
||||
struct scan_freq_set *supported_list,
|
||||
struct band *band)
|
||||
struct band_freq_attrs *list,
|
||||
size_t num_channels)
|
||||
{
|
||||
uint16_t type, len;
|
||||
const void *data;
|
||||
@ -711,7 +710,6 @@ int nl80211_parse_supported_frequencies(struct l_genl_attr *band_freqs,
|
||||
while (l_genl_attr_next(&nested, NULL, NULL, NULL)) {
|
||||
uint32_t freq = 0;
|
||||
struct band_freq_attrs freq_attr = { 0 };
|
||||
enum band_freq out_band;
|
||||
|
||||
if (!l_genl_attr_recurse(&nested, &attr))
|
||||
continue;
|
||||
@ -752,20 +750,17 @@ int nl80211_parse_supported_frequencies(struct l_genl_attr *band_freqs,
|
||||
if (!freq)
|
||||
continue;
|
||||
|
||||
channel = band_freq_to_channel(freq, &out_band);
|
||||
channel = band_freq_to_channel(freq, NULL);
|
||||
if (!channel)
|
||||
continue;
|
||||
|
||||
if (L_WARN_ON(out_band != band->freq))
|
||||
continue;
|
||||
|
||||
if (L_WARN_ON(channel > band->freqs_len))
|
||||
if (L_WARN_ON(channel > num_channels))
|
||||
continue;
|
||||
|
||||
if (supported_list)
|
||||
scan_freq_set_add(supported_list, freq);
|
||||
|
||||
band->freq_attrs[channel] = freq_attr;
|
||||
list[channel] = freq_attr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -26,7 +26,6 @@ struct band_chandef;
|
||||
struct scan_freq_set;
|
||||
struct band_freq_attrs;
|
||||
struct handshake_state;
|
||||
struct band;
|
||||
|
||||
int nl80211_parse_attrs(struct l_genl_msg *msg, int tag, ...);
|
||||
int nl80211_parse_nested(struct l_genl_attr *attr, int type, int tag, ...);
|
||||
@ -96,7 +95,8 @@ struct l_genl_msg *nl80211_build_external_auth(uint32_t ifindex,
|
||||
int nl80211_parse_chandef(struct l_genl_msg *msg, struct band_chandef *out);
|
||||
int nl80211_parse_supported_frequencies(struct l_genl_attr *band_freqs,
|
||||
struct scan_freq_set *supported_list,
|
||||
struct band *band);
|
||||
struct band_freq_attrs *list,
|
||||
size_t num_channels);
|
||||
|
||||
void nl80211_append_rsn_attributes(struct l_genl_msg *msg,
|
||||
struct handshake_state *hs);
|
||||
|
@ -293,7 +293,7 @@ static void offchannel_mlme_notify(struct l_genl_msg *msg, void *user_data)
|
||||
* - an event coming from an external ROC request (we just
|
||||
* happened to have also sent an ROC request).
|
||||
*
|
||||
* We can't tell where the event originated until we receive our
|
||||
* We can't tell where the event originated until we recieve our
|
||||
* ACK so set early_cookie to track it.
|
||||
*/
|
||||
if (i->roc_cmd_id != 0 && l_genl_family_request_sent(nl80211,
|
||||
|
13
src/p2p.c
13
src/p2p.c
@ -1497,7 +1497,7 @@ static void p2p_handshake_event(struct handshake_state *hs,
|
||||
static void p2p_try_connect_group(struct p2p_device *dev)
|
||||
{
|
||||
struct scan_bss *bss = dev->conn_wsc_bss;
|
||||
_auto_(handshake_state_unref) struct handshake_state *hs = NULL;
|
||||
_auto_(handshake_state_free) struct handshake_state *hs = NULL;
|
||||
struct iovec ie_iov[16];
|
||||
int ie_num = 0;
|
||||
int r;
|
||||
@ -2217,7 +2217,7 @@ static bool p2p_go_negotiation_confirm_cb(const struct mmpdu_header *mpdu,
|
||||
|
||||
/*
|
||||
* Start setting the group up right away and we'll add the
|
||||
* client's Configuration Timeout to the WSC start timeout's
|
||||
* client's Configuation Timeout to the WSC start timeout's
|
||||
* value.
|
||||
*/
|
||||
p2p_device_interface_create(dev);
|
||||
@ -2549,7 +2549,7 @@ static void p2p_go_negotiation_confirm_done(int error, void *user_data)
|
||||
|
||||
/*
|
||||
* Frame was ACKed. On the GO start setting the group up right
|
||||
* away and we'll add the client's Configuration Timeout to the
|
||||
* away and we'll add the client's Configuation Timeout to the
|
||||
* WSC start timeout's value. On the client wait idly the
|
||||
* maximum amount of time indicated by the peer in the GO
|
||||
* Negotiation Response's Configuration Timeout attribute and
|
||||
@ -2951,7 +2951,7 @@ static bool p2p_provision_disc_resp_cb(const struct mmpdu_header *mpdu,
|
||||
}
|
||||
|
||||
/*
|
||||
* Intended P2P Interface address is optional, we don't have the
|
||||
* Indended P2P Interface address is optional, we don't have the
|
||||
* BSSID of the group here.
|
||||
*
|
||||
* We might want to make sure that Group Formation is false but the
|
||||
@ -4163,11 +4163,10 @@ static void p2p_device_discovery_start(struct p2p_device *dev)
|
||||
L_ARRAY_SIZE(channels_social)];
|
||||
|
||||
frame_watch_add(dev->wdev_id, FRAME_GROUP_P2P_LISTEN, 0x0040,
|
||||
(uint8_t *) "", 0, false,
|
||||
p2p_device_probe_cb, dev, NULL);
|
||||
(uint8_t *) "", 0, p2p_device_probe_cb, dev, NULL);
|
||||
frame_watch_add(dev->wdev_id, FRAME_GROUP_P2P_LISTEN, 0x00d0,
|
||||
p2p_frame_go_neg_req.data, p2p_frame_go_neg_req.len,
|
||||
false, p2p_device_go_negotiation_req_cb, dev, NULL);
|
||||
p2p_device_go_negotiation_req_cb, dev, NULL);
|
||||
|
||||
p2p_device_scan_start(dev);
|
||||
}
|
||||
|
269
src/pmksa.c
269
src/pmksa.c
@ -1,269 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Wireless daemon for Linux
|
||||
*
|
||||
* Copyright (C) 2023 Cruise LLC. 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
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <ell/ell.h>
|
||||
#include "ell/useful.h"
|
||||
|
||||
#include "src/module.h"
|
||||
#include "src/pmksa.h"
|
||||
|
||||
#define PMKID "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
|
||||
#define PMKID_STR(x) x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], \
|
||||
x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
|
||||
|
||||
static uint64_t dot11RSNAConfigPMKLifetime = 43200ULL * L_USEC_PER_SEC;
|
||||
static uint32_t pmksa_cache_capacity = 255;
|
||||
static pmksa_cache_add_func_t driver_add;
|
||||
static pmksa_cache_remove_func_t driver_remove;
|
||||
static pmksa_cache_flush_func_t driver_flush;
|
||||
|
||||
struct min_heap {
|
||||
struct pmksa **data;
|
||||
uint32_t capacity;
|
||||
uint32_t used;
|
||||
};
|
||||
|
||||
static struct min_heap cache;
|
||||
|
||||
static __always_inline void swap_ptr(void *l, void *r)
|
||||
{
|
||||
struct pmksa **lp = l;
|
||||
struct pmksa **rp = r;
|
||||
|
||||
SWAP(*lp, *rp);
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
bool pmksa_compare_expiration(const void *l, const void *r)
|
||||
{
|
||||
const struct pmksa * const *lp = l;
|
||||
const struct pmksa * const *rp = r;
|
||||
|
||||
return (*lp)->expiration < (*rp)->expiration;
|
||||
}
|
||||
|
||||
static struct l_minheap_ops ops = {
|
||||
.elem_size = sizeof(struct pmksa *),
|
||||
.swap = swap_ptr,
|
||||
.less = pmksa_compare_expiration,
|
||||
};
|
||||
|
||||
static int pmksa_cache_find(const uint8_t spa[static 6],
|
||||
const uint8_t aa[static 6],
|
||||
const uint8_t *ssid, size_t ssid_len,
|
||||
uint32_t akm)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < cache.used; i++) {
|
||||
struct pmksa *pmksa = cache.data[i];
|
||||
|
||||
if (memcmp(pmksa->spa, spa, sizeof(pmksa->spa)))
|
||||
continue;
|
||||
|
||||
if (memcmp(pmksa->aa, aa, sizeof(pmksa->aa)))
|
||||
continue;
|
||||
|
||||
if (ssid_len != pmksa->ssid_len)
|
||||
continue;
|
||||
|
||||
if (memcmp(pmksa->ssid, ssid, ssid_len))
|
||||
continue;
|
||||
|
||||
if (akm & pmksa->akm)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to obtain a PMKSA entry from the cache. If the the entry matching
|
||||
* the parameters is found, it is removed from the cache and returned to the
|
||||
* caller. The caller is responsible for managing the returned pmksa
|
||||
* structure
|
||||
*/
|
||||
struct pmksa *pmksa_cache_get(const uint8_t spa[static 6],
|
||||
const uint8_t aa[static 6],
|
||||
const uint8_t *ssid, size_t ssid_len,
|
||||
uint32_t akm)
|
||||
{
|
||||
struct pmksa *pmksa;
|
||||
int r = pmksa_cache_find(spa, aa, ssid, ssid_len, akm);
|
||||
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
cache.used -= 1;
|
||||
if ((uint32_t) r == cache.used)
|
||||
goto done;
|
||||
|
||||
SWAP(cache.data[r], cache.data[cache.used]);
|
||||
__minheap_sift_down(cache.data, cache.used, r, &ops);
|
||||
|
||||
done:
|
||||
pmksa = cache.data[cache.used];
|
||||
|
||||
l_debug("Returning entry with PMKID: "PMKID, PMKID_STR(pmksa->pmkid));
|
||||
|
||||
return pmksa;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a PMKSA into the cache. It will be sorted in soonest-to-expire order.
|
||||
* If the cache is full, then soonest-to-expire entry is removed first.
|
||||
*/
|
||||
int pmksa_cache_put(struct pmksa *pmksa)
|
||||
{
|
||||
l_debug("Adding entry with PMKID: "PMKID, PMKID_STR(pmksa->pmkid));
|
||||
|
||||
if (cache.used == cache.capacity) {
|
||||
pmksa_cache_free(cache.data[0]);
|
||||
cache.data[0] = pmksa;
|
||||
__minheap_sift_down(cache.data, cache.used, 0, &ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cache.data[cache.used] = pmksa;
|
||||
__minheap_sift_up(cache.data, cache.used, &ops);
|
||||
cache.used += 1;
|
||||
|
||||
if (driver_add)
|
||||
driver_add(pmksa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expire all PMKSA entries with expiration time smaller or equal to the cutoff
|
||||
* time.
|
||||
*/
|
||||
int pmksa_cache_expire(uint64_t cutoff)
|
||||
{
|
||||
int i;
|
||||
int used = cache.used;
|
||||
int remaining = 0;
|
||||
|
||||
for (i = 0; i < used; i++) {
|
||||
if (cache.data[i]->expiration <= cutoff) {
|
||||
pmksa_cache_free(cache.data[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
cache.data[remaining] = cache.data[i];
|
||||
remaining += 1;
|
||||
}
|
||||
|
||||
cache.used = remaining;
|
||||
|
||||
for (i = cache.used >> 1; i >= 0; i--)
|
||||
__minheap_sift_down(cache.data, cache.used, i, &ops);
|
||||
|
||||
return used - remaining;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush all PMKSA entries from the cache, regardless of expiration time.
|
||||
*/
|
||||
int pmksa_cache_flush(void)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
/*
|
||||
* The driver flush operation is done via a single kernel API call which
|
||||
* is why below we use l_free instead of pmksa_cache_free as to not
|
||||
* induce a DEL_PMKSA kernel call for each entry.
|
||||
*/
|
||||
if (driver_flush)
|
||||
driver_flush();
|
||||
|
||||
for (i = 0; i < cache.used; i++)
|
||||
l_free(cache.data[i]);
|
||||
|
||||
memset(cache.data, 0, cache.capacity * sizeof(struct pmksa *));
|
||||
cache.used = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pmksa_cache_free(struct pmksa *pmksa)
|
||||
{
|
||||
if (driver_remove)
|
||||
driver_remove(pmksa);
|
||||
|
||||
l_free(pmksa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pmksa **__pmksa_cache_get_all(uint32_t *out_n_entries)
|
||||
{
|
||||
if (out_n_entries)
|
||||
*out_n_entries = cache.used;
|
||||
|
||||
return cache.data;
|
||||
}
|
||||
|
||||
uint64_t pmksa_lifetime(void)
|
||||
{
|
||||
return dot11RSNAConfigPMKLifetime;
|
||||
}
|
||||
|
||||
void __pmksa_set_config(const struct l_settings *config)
|
||||
{
|
||||
l_settings_get_uint(config, "PMKSA", "Capacity",
|
||||
&pmksa_cache_capacity);
|
||||
}
|
||||
|
||||
void __pmksa_set_driver_callbacks(pmksa_cache_add_func_t add,
|
||||
pmksa_cache_remove_func_t remove,
|
||||
pmksa_cache_flush_func_t flush)
|
||||
{
|
||||
driver_add = add;
|
||||
driver_remove = remove;
|
||||
driver_flush = flush;
|
||||
}
|
||||
|
||||
static int pmksa_init(void)
|
||||
{
|
||||
cache.capacity = pmksa_cache_capacity;
|
||||
cache.used = 0;
|
||||
cache.data = l_new(struct pmksa *, cache.capacity);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pmksa_exit(void)
|
||||
{
|
||||
pmksa_cache_flush();
|
||||
l_free(cache.data);
|
||||
}
|
||||
|
||||
IWD_MODULE(pmksa, pmksa_init, pmksa_exit);
|
55
src/pmksa.h
55
src/pmksa.h
@ -1,55 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Wireless daemon for Linux
|
||||
*
|
||||
* Copyright (C) 2023 Cruise, LLC. 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
|
||||
*
|
||||
*/
|
||||
|
||||
struct pmksa {
|
||||
uint64_t expiration;
|
||||
uint8_t spa[6];
|
||||
uint8_t aa[6];
|
||||
uint8_t ssid[32];
|
||||
size_t ssid_len;
|
||||
uint32_t akm;
|
||||
uint8_t pmkid[16];
|
||||
uint8_t pmk[64];
|
||||
size_t pmk_len;
|
||||
};
|
||||
|
||||
typedef void (*pmksa_cache_add_func_t)(const struct pmksa *pmksa);
|
||||
typedef void (*pmksa_cache_remove_func_t)(const struct pmksa *pmksa);
|
||||
typedef void (*pmksa_cache_flush_func_t)(void);
|
||||
|
||||
struct pmksa **__pmksa_cache_get_all(uint32_t *out_n_entries);
|
||||
|
||||
struct pmksa *pmksa_cache_get(const uint8_t spa[static 6],
|
||||
const uint8_t aa[static 6],
|
||||
const uint8_t *ssid, size_t ssid_len,
|
||||
uint32_t akm);
|
||||
int pmksa_cache_put(struct pmksa *pmksa);
|
||||
int pmksa_cache_expire(uint64_t cutoff);
|
||||
int pmksa_cache_flush(void);
|
||||
int pmksa_cache_free(struct pmksa *pmksa);
|
||||
|
||||
uint64_t pmksa_lifetime(void);
|
||||
void __pmksa_set_config(const struct l_settings *config);
|
||||
|
||||
void __pmksa_set_driver_callbacks(pmksa_cache_add_func_t add,
|
||||
pmksa_cache_remove_func_t remove,
|
||||
pmksa_cache_flush_func_t flush);
|
@ -798,7 +798,7 @@ static void rrm_add_frame_watches(struct rrm_state *rrm)
|
||||
l_debug("");
|
||||
|
||||
frame_watch_add(rrm->wdev_id, 0, frame_type, prefix, sizeof(prefix),
|
||||
false, rrm_frame_watch_cb, rrm, NULL);
|
||||
rrm_frame_watch_cb, rrm, NULL);
|
||||
}
|
||||
|
||||
static struct rrm_state *rrm_new_state(struct netdev *netdev)
|
||||
|
22
src/sae.c
22
src/sae.c
@ -258,7 +258,7 @@ static struct l_ecc_scalar *sae_pwd_value(const struct l_ecc_curve *curve,
|
||||
is_in_range = util_secure_fill_with_msb(is_in_range);
|
||||
|
||||
/*
|
||||
* ELL has public Legendre symbol only for l_ecc_scalar, but they
|
||||
* libell has public Legendre symbol only for l_ecc_scalar, but they
|
||||
* cannot be created if the coordinate is greater than the p. Hence,
|
||||
* to avoid control flow dependencies, we replace pwd_value by a dummy
|
||||
* quadratic non residue if we generate a value >= prime.
|
||||
@ -1550,26 +1550,6 @@ struct auth_proto *sae_sm_new(struct handshake_state *hs,
|
||||
return &sm->ap;
|
||||
}
|
||||
|
||||
bool sae_sm_force_hunt_and_peck(struct auth_proto *ap)
|
||||
{
|
||||
struct sae_sm *sm = l_container_of(ap, struct sae_sm, ap);
|
||||
|
||||
sae_debug("Forcing SAE Hunting and Pecking");
|
||||
sm->sae_type = CRYPTO_SAE_LOOPING;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sae_sm_force_default_group(struct auth_proto *ap)
|
||||
{
|
||||
struct sae_sm *sm = l_container_of(ap, struct sae_sm, ap);
|
||||
|
||||
sae_debug("Forcing Default Group");
|
||||
sm->force_default_group = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int sae_init(void)
|
||||
{
|
||||
if (getenv("IWD_SAE_DEBUG"))
|
||||
|
@ -34,6 +34,3 @@ struct auth_proto *sae_sm_new(struct handshake_state *hs,
|
||||
sae_tx_authenticate_func_t tx_auth,
|
||||
sae_tx_associate_func_t tx_assoc,
|
||||
void *user_data);
|
||||
|
||||
bool sae_sm_force_hunt_and_peck(struct auth_proto *ap);
|
||||
bool sae_sm_force_default_group(struct auth_proto *ap);
|
||||
|
124
src/scan.c
124
src/scan.c
@ -56,8 +56,6 @@
|
||||
static double RANK_2G_FACTOR;
|
||||
static double RANK_5G_FACTOR;
|
||||
static double RANK_6G_FACTOR;
|
||||
static uint32_t RANK_HIGH_UTILIZATION;
|
||||
static uint32_t RANK_HIGH_STATION_COUNT;
|
||||
static uint32_t SCAN_MAX_INTERVAL;
|
||||
static uint32_t SCAN_INIT_INTERVAL;
|
||||
|
||||
@ -143,9 +141,9 @@ struct scan_survey {
|
||||
};
|
||||
|
||||
struct scan_survey_results {
|
||||
struct scan_survey survey_2_4[15];
|
||||
struct scan_survey survey_5[197];
|
||||
struct scan_survey survey_6[234];
|
||||
struct scan_survey survey_2_4[14];
|
||||
struct scan_survey survey_5[196];
|
||||
struct scan_survey survey_6[233];
|
||||
};
|
||||
|
||||
struct scan_results {
|
||||
@ -1345,8 +1343,8 @@ static bool scan_parse_bss_information_elements(struct scan_bss *bss,
|
||||
iter.len + 2);
|
||||
break;
|
||||
case IE_TYPE_BSS_LOAD:
|
||||
if (ie_parse_bss_load(&iter, &bss->sta_count,
|
||||
&bss->utilization, NULL) < 0)
|
||||
if (ie_parse_bss_load(&iter, NULL, &bss->utilization,
|
||||
NULL) < 0)
|
||||
l_warn("Unable to parse BSS Load IE for "
|
||||
MAC, MAC_STR(bss->addr));
|
||||
else
|
||||
@ -1683,77 +1681,10 @@ static struct scan_bss *scan_parse_result(struct l_genl_msg *msg,
|
||||
return bss;
|
||||
}
|
||||
|
||||
static double scan_legacy_utilization_factor(uint8_t utilization)
|
||||
static void scan_bss_compute_rank(struct scan_bss *bss)
|
||||
{
|
||||
static const double RANK_HIGH_UTILIZATION_FACTOR = 0.8;
|
||||
static const double RANK_LOW_UTILIZATION_FACTOR = 1.2;
|
||||
|
||||
if (utilization >= 192)
|
||||
return RANK_HIGH_UTILIZATION_FACTOR;
|
||||
else if (utilization <= 63)
|
||||
return RANK_LOW_UTILIZATION_FACTOR;
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
static double scan_get_load_factors(uint8_t utilization, uint16_t sta_count)
|
||||
{
|
||||
double n;
|
||||
double factor = 1.0;
|
||||
/*
|
||||
* The exponential decay table has 64 entries (0 <= n <= 63) which range
|
||||
* from 1.0 to 0.28. For the utilization and station count factors we
|
||||
* likely don't want to adjust the rank so drastically (potentially a
|
||||
* 78% reduction in the worse case) so cap the index at 30 which equates
|
||||
* to ~64% at the worst case.
|
||||
*/
|
||||
static const uint8_t LOAD_DECAY_OFFSET = 30;
|
||||
|
||||
if (!RANK_HIGH_UTILIZATION) {
|
||||
/*
|
||||
* To maintain existing behavior, if the utilization factor is
|
||||
* unset (default) fall back to the static thresholds and
|
||||
* factor weights.
|
||||
*/
|
||||
factor = scan_legacy_utilization_factor(utilization);
|
||||
goto sta_count;
|
||||
} else if (utilization < RANK_HIGH_UTILIZATION)
|
||||
goto sta_count;
|
||||
|
||||
/* Map the utilization threshold -> 255 to rankmod_table indexes */
|
||||
if (L_WARN_ON(!util_linear_map(utilization, RANK_HIGH_UTILIZATION,
|
||||
255, 0, LOAD_DECAY_OFFSET, &n)))
|
||||
goto sta_count;
|
||||
|
||||
factor = util_exponential_decay(n);
|
||||
|
||||
sta_count:
|
||||
if (!RANK_HIGH_STATION_COUNT || sta_count < RANK_HIGH_STATION_COUNT)
|
||||
return factor;
|
||||
|
||||
/*
|
||||
* The station count is a uint16 so in theory it could be excessively
|
||||
* large. In practice APs generally can't handle anywhere near this so
|
||||
* put a cap at 255. If at some time in the future APs begin to handle
|
||||
* this level of capacity we could increase this.
|
||||
*
|
||||
* TODO: A warning is used here to make this visible. If we see cases
|
||||
* where this is happening we may need to give this another look.
|
||||
*/
|
||||
if (L_WARN_ON(sta_count > 255))
|
||||
sta_count = 255;
|
||||
|
||||
if (L_WARN_ON(!util_linear_map(sta_count, RANK_HIGH_STATION_COUNT,
|
||||
255, 0, LOAD_DECAY_OFFSET, &n)))
|
||||
return factor;
|
||||
|
||||
factor *= util_exponential_decay(n);
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
static void scan_bss_compute_rank(struct scan_bss *bss)
|
||||
{
|
||||
static const double RANK_HIGH_SNR_FACTOR = 1.2;
|
||||
static const double RANK_LOW_SNR_FACTOR = 0.8;
|
||||
double rank;
|
||||
@ -1777,8 +1708,12 @@ static void scan_bss_compute_rank(struct scan_bss *bss)
|
||||
rank *= RANK_6G_FACTOR;
|
||||
|
||||
/* Rank loaded APs lower and lightly loaded APs higher */
|
||||
if (bss->have_utilization)
|
||||
rank *= scan_get_load_factors(bss->utilization, bss->sta_count);
|
||||
if (bss->have_utilization) {
|
||||
if (bss->utilization >= 192)
|
||||
rank *= RANK_HIGH_UTILIZATION_FACTOR;
|
||||
else if (bss->utilization <= 63)
|
||||
rank *= RANK_LOW_UTILIZATION_FACTOR;
|
||||
}
|
||||
|
||||
if (bss->have_snr) {
|
||||
if (bss->snr <= 15)
|
||||
@ -2154,10 +2089,9 @@ static void scan_get_results(struct scan_context *sc, struct scan_request *sr,
|
||||
results->bss_list = l_queue_new();
|
||||
results->freqs = freqs;
|
||||
|
||||
/* If there is no scan request (external scan), just get the results */
|
||||
if (sr && scan_survey(results))
|
||||
if (scan_survey(results))
|
||||
return;
|
||||
else if (sr)
|
||||
else
|
||||
l_warn("failed to start a scan survey");
|
||||
|
||||
get_results(results);
|
||||
@ -2186,22 +2120,6 @@ static void scan_wiphy_watch(struct wiphy *wiphy,
|
||||
if (!sr)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If the regdom update finished with GET_SCAN/GET_SURVEY in flight
|
||||
* don't try and get the results again and allow those calls to finish.
|
||||
* For the non-6ghz case this has no downside as the results should not
|
||||
* differ.
|
||||
*
|
||||
* If 6ghz was enabled by this regdom update there is still not much we
|
||||
* can do since the scan itself is already completed. Appending to the
|
||||
* command list won't do anything.
|
||||
*
|
||||
* TODO: Handle the 6ghz case by checking for this case in get_scan_done
|
||||
* and continuing to iterate the sr->cmds array.
|
||||
*/
|
||||
if (sc->get_scan_cmd_id || sc->get_survey_cmd_id)
|
||||
return;
|
||||
|
||||
/*
|
||||
* This update did not allow 6GHz, or the original request was
|
||||
* not expecting 6GHz. The periodic scan should now be ended.
|
||||
@ -2664,20 +2582,6 @@ static int scan_init(void)
|
||||
if (SCAN_MAX_INTERVAL > UINT16_MAX)
|
||||
SCAN_MAX_INTERVAL = UINT16_MAX;
|
||||
|
||||
if (!l_settings_get_uint(config, "Rank", "HighUtilizationThreshold",
|
||||
&RANK_HIGH_UTILIZATION))
|
||||
RANK_HIGH_UTILIZATION = 0;
|
||||
|
||||
if (L_WARN_ON(RANK_HIGH_UTILIZATION > 255))
|
||||
RANK_HIGH_UTILIZATION = 255;
|
||||
|
||||
if (!l_settings_get_uint(config, "Rank", "HighStationCountThreshold",
|
||||
&RANK_HIGH_STATION_COUNT))
|
||||
RANK_HIGH_STATION_COUNT = 0;
|
||||
|
||||
if (L_WARN_ON(RANK_HIGH_STATION_COUNT > 255))
|
||||
RANK_HIGH_STATION_COUNT = 255;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,6 @@ struct scan_bss {
|
||||
uint8_t ssid[SSID_MAX_SIZE];
|
||||
uint8_t ssid_len;
|
||||
uint8_t utilization;
|
||||
uint16_t sta_count;
|
||||
uint8_t cc[3];
|
||||
uint16_t rank;
|
||||
uint64_t time_stamp;
|
||||
|
524
src/station.c
524
src/station.c
@ -63,7 +63,6 @@
|
||||
#include "src/eap.h"
|
||||
#include "src/eap-tls-common.h"
|
||||
#include "src/storage.h"
|
||||
#include "src/pmksa.h"
|
||||
|
||||
#define STATION_RECENT_NETWORK_LIMIT 5
|
||||
#define STATION_RECENT_FREQS_LIMIT 5
|
||||
@ -75,11 +74,6 @@ static uint32_t roam_retry_interval;
|
||||
static bool anqp_disabled;
|
||||
static bool supports_arp_evict_nocarrier;
|
||||
static bool supports_ndisc_evict_nocarrier;
|
||||
static bool supports_drop_gratuitous_arp;
|
||||
static bool supports_drop_unsolicited_na;
|
||||
static bool supports_ipv4_drop_unicast_in_l2_multicast;
|
||||
static bool supports_ipv6_drop_unicast_in_l2_multicast;
|
||||
static bool pmksa_disabled;
|
||||
static struct watchlist event_watches;
|
||||
static uint32_t known_networks_watch;
|
||||
static uint32_t allowed_bands;
|
||||
@ -108,6 +102,7 @@ struct station {
|
||||
struct l_queue *owe_hidden_scan_ids;
|
||||
|
||||
/* Roaming related members */
|
||||
struct timespec roam_min_time;
|
||||
struct l_timeout *roam_trigger_timeout;
|
||||
uint32_t roam_scan_id;
|
||||
uint8_t preauth_bssid[6];
|
||||
@ -133,12 +128,6 @@ struct station {
|
||||
|
||||
uint64_t last_roam_scan;
|
||||
|
||||
struct l_queue *affinities;
|
||||
unsigned int affinity_watch;
|
||||
char *affinity_client;
|
||||
|
||||
struct handshake_state *hs;
|
||||
|
||||
bool preparing_roam : 1;
|
||||
bool roam_scan_full : 1;
|
||||
bool signal_low : 1;
|
||||
@ -155,55 +144,6 @@ struct anqp_entry {
|
||||
uint32_t pending;
|
||||
};
|
||||
|
||||
/*
|
||||
* Rather than sorting BSS's purely based on ranking a higher level grouping
|
||||
* is used. The purpose of this higher order grouping is the consider the BSS's
|
||||
* roam blacklist status. The roam blacklist is a "soft" blacklist in that we
|
||||
* still should connect to these BSS's if they are the only "good" option.
|
||||
* The question here is: what makes a BSS "good" vs "bad".
|
||||
*
|
||||
* For an initial (probably naive) approach here we can use the
|
||||
* RoamThreshold[5G] which indicates the signal level that would not
|
||||
* be of an acceptable connection quality. BSS can then be sorted either
|
||||
* above or below this threshold. Within each of these groups a BSS may be
|
||||
* blacklisted, meaning it should get sorted lower on the list compared to
|
||||
* others within the same group.
|
||||
*
|
||||
* This sorting is achieved by extending rank to a uint32_t where the first 16
|
||||
* bits are the standard rank calculated by scan.c. Above that bits can be
|
||||
* reserved for this higher level grouping:
|
||||
*
|
||||
* Bit 16 indicates the BSS is not blacklisted
|
||||
* Bit 17 indicates the BSS is above the critical signal threshold
|
||||
*/
|
||||
|
||||
#define ABOVE_THRESHOLD_BIT 17
|
||||
#define NOT_BLACKLISTED_BIT 16
|
||||
|
||||
static uint32_t evaluate_bss_group_rank(const uint8_t *addr, uint32_t freq,
|
||||
int16_t signal_strength, uint16_t rank)
|
||||
{
|
||||
int signal = signal_strength / 100;
|
||||
bool roam_blacklist;
|
||||
bool good_signal;
|
||||
uint32_t rank_out = (uint32_t) rank;
|
||||
|
||||
if (blacklist_contains_bss(addr, BLACKLIST_REASON_CONNECT_FAILED))
|
||||
return 0;
|
||||
|
||||
roam_blacklist = blacklist_contains_bss(addr,
|
||||
BLACKLIST_REASON_ROAM_REQUESTED);
|
||||
good_signal = signal >= netdev_get_low_signal_threshold(freq);
|
||||
|
||||
if (good_signal)
|
||||
set_bit(&rank_out, ABOVE_THRESHOLD_BIT);
|
||||
|
||||
if (!roam_blacklist)
|
||||
set_bit(&rank_out, NOT_BLACKLISTED_BIT);
|
||||
|
||||
return rank_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used as entries for the roam list since holding scan_bss pointers directly
|
||||
* from station->bss_list is not 100% safe due to the possibility of the
|
||||
@ -211,13 +151,13 @@ static uint32_t evaluate_bss_group_rank(const uint8_t *addr, uint32_t freq,
|
||||
*/
|
||||
struct roam_bss {
|
||||
uint8_t addr[6];
|
||||
uint32_t rank;
|
||||
uint16_t rank;
|
||||
int32_t signal_strength;
|
||||
bool ft_failed: 1;
|
||||
};
|
||||
|
||||
static struct roam_bss *roam_bss_from_scan_bss(const struct scan_bss *bss,
|
||||
uint32_t rank)
|
||||
uint16_t rank)
|
||||
{
|
||||
struct roam_bss *rbss = l_new(struct roam_bss, 1);
|
||||
|
||||
@ -478,8 +418,7 @@ static void station_print_scan_bss(const struct scan_bss *bss)
|
||||
ptr += sprintf(ptr, ", snr: %d", bss->snr);
|
||||
|
||||
if (bss->have_utilization)
|
||||
ptr += sprintf(ptr, ", load: %u/255, clients: %u",
|
||||
bss->utilization, bss->sta_count);
|
||||
ptr += sprintf(ptr, ", load: %u/255", bss->utilization);
|
||||
|
||||
l_debug("Processing BSS '%s' with SSID: %s, freq: %u, rank: %u, "
|
||||
"strength: %i, data_rate: %u.%u%s",
|
||||
@ -510,14 +449,6 @@ static const char *station_get_bss_path(struct station *station,
|
||||
return __network_path_append_bss(network_path, bss);
|
||||
}
|
||||
|
||||
static bool match_bss_path(const void *data, const void *user_data)
|
||||
{
|
||||
const char *path1 = data;
|
||||
const char *path2 = user_data;
|
||||
|
||||
return !strcmp(path1, path2);
|
||||
}
|
||||
|
||||
static bool station_unregister_bss(struct station *station,
|
||||
struct scan_bss *bss)
|
||||
{
|
||||
@ -526,8 +457,6 @@ static bool station_unregister_bss(struct station *station,
|
||||
if (L_WARN_ON(!path))
|
||||
return false;
|
||||
|
||||
l_queue_remove_if(station->affinities, match_bss_path, path);
|
||||
|
||||
return l_dbus_unregister_object(dbus_get_bus(), path);
|
||||
}
|
||||
|
||||
@ -1208,7 +1137,6 @@ static int station_build_handshake_rsn(struct handshake_state *hs,
|
||||
struct network *network,
|
||||
struct scan_bss *bss)
|
||||
{
|
||||
struct netdev *netdev = netdev_find(hs->ifindex);
|
||||
const struct l_settings *settings = iwd_get_config();
|
||||
enum security security = network_get_security(network);
|
||||
bool add_mde = false;
|
||||
@ -1219,7 +1147,6 @@ static int station_build_handshake_rsn(struct handshake_state *hs,
|
||||
uint8_t *ap_ie;
|
||||
bool disable_ocv;
|
||||
enum band_freq band;
|
||||
struct pmksa *pmksa;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
@ -1353,17 +1280,6 @@ build_ie:
|
||||
IE_CIPHER_IS_GCMP_CCMP(info.pairwise_ciphers))
|
||||
info.extended_key_id = true;
|
||||
|
||||
if (IE_AKM_IS_SAE(info.akm_suites) && !pmksa_disabled) {
|
||||
pmksa = pmksa_cache_get(netdev_get_address(netdev), bss->addr,
|
||||
bss->ssid, bss->ssid_len,
|
||||
info.akm_suites);
|
||||
if (pmksa) {
|
||||
handshake_state_set_pmksa(hs, pmksa);
|
||||
info.num_pmkids = 1;
|
||||
info.pmkids = hs->pmksa->pmkid;
|
||||
}
|
||||
}
|
||||
|
||||
/* RSN takes priority */
|
||||
if (bss->rsne) {
|
||||
ap_ie = bss->rsne;
|
||||
@ -1448,7 +1364,7 @@ static struct handshake_state *station_handshake_setup(struct station *station,
|
||||
handshake_state_set_vendor_ies(hs, vendor_ies, iov_elems);
|
||||
|
||||
/*
|
||||
* It can't hurt to try the FILS IP Address Assignment independent of
|
||||
* It can't hurt to try the FILS IP Address Assigment independent of
|
||||
* which auth-proto is actually used.
|
||||
*/
|
||||
if (station->netconfig && netconfig_get_fils_ip_req(station->netconfig,
|
||||
@ -1460,7 +1376,7 @@ static struct handshake_state *station_handshake_setup(struct station *station,
|
||||
return hs;
|
||||
|
||||
not_supported:
|
||||
handshake_state_unref(hs);
|
||||
handshake_state_free(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1712,13 +1628,10 @@ static void station_set_drop_neighbor_discovery(struct station *station,
|
||||
{
|
||||
char *v = value ? "1" : "0";
|
||||
|
||||
if (supports_drop_gratuitous_arp)
|
||||
sysfs_write_ipv4_setting(netdev_get_name(station->netdev),
|
||||
"drop_gratuitous_arp", v);
|
||||
|
||||
if (supports_drop_unsolicited_na)
|
||||
sysfs_write_ipv6_setting(netdev_get_name(station->netdev),
|
||||
"drop_unsolicited_na", v);
|
||||
sysfs_write_ipv4_setting(netdev_get_name(station->netdev),
|
||||
"drop_gratuitous_arp", v);
|
||||
sysfs_write_ipv6_setting(netdev_get_name(station->netdev),
|
||||
"drop_unsolicited_na", v);
|
||||
}
|
||||
|
||||
static void station_set_drop_unicast_l2_multicast(struct station *station,
|
||||
@ -1726,13 +1639,10 @@ static void station_set_drop_unicast_l2_multicast(struct station *station,
|
||||
{
|
||||
char *v = value ? "1" : "0";
|
||||
|
||||
if (supports_ipv4_drop_unicast_in_l2_multicast)
|
||||
sysfs_write_ipv4_setting(netdev_get_name(station->netdev),
|
||||
"drop_unicast_in_l2_multicast", v);
|
||||
|
||||
if (supports_ipv6_drop_unicast_in_l2_multicast)
|
||||
sysfs_write_ipv6_setting(netdev_get_name(station->netdev),
|
||||
"drop_unicast_in_l2_multicast", v);
|
||||
sysfs_write_ipv4_setting(netdev_get_name(station->netdev),
|
||||
"drop_unicast_in_l2_multicast", v);
|
||||
sysfs_write_ipv6_setting(netdev_get_name(station->netdev),
|
||||
"drop_unicast_in_l2_multicast", v);
|
||||
}
|
||||
|
||||
static void station_signal_agent_notify(struct station *station);
|
||||
@ -1830,18 +1740,6 @@ static void station_enter_state(struct station *station,
|
||||
station_set_evict_nocarrier(station, true);
|
||||
station_set_drop_neighbor_discovery(station, false);
|
||||
station_set_drop_unicast_l2_multicast(station, false);
|
||||
|
||||
if (station->affinity_watch) {
|
||||
l_dbus_remove_watch(dbus_get_bus(),
|
||||
station->affinity_watch);
|
||||
station->affinity_watch = 0;
|
||||
}
|
||||
|
||||
if (station->hs) {
|
||||
handshake_state_unref(station->hs);
|
||||
station->hs = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
case STATION_STATE_DISCONNECTING:
|
||||
case STATION_STATE_NETCONFIG:
|
||||
@ -1849,15 +1747,6 @@ static void station_enter_state(struct station *station,
|
||||
case STATION_STATE_ROAMING:
|
||||
case STATION_STATE_FT_ROAMING:
|
||||
case STATION_STATE_FW_ROAMING:
|
||||
l_dbus_property_changed(dbus, netdev_get_path(station->netdev),
|
||||
IWD_STATION_INTERFACE, "ConnectedAccessPoint");
|
||||
|
||||
if (station->affinity_watch) {
|
||||
l_dbus_remove_watch(dbus_get_bus(),
|
||||
station->affinity_watch);
|
||||
station->affinity_watch = 0;
|
||||
}
|
||||
|
||||
station_set_evict_nocarrier(station, false);
|
||||
break;
|
||||
}
|
||||
@ -1931,6 +1820,7 @@ static void station_roam_state_clear(struct station *station)
|
||||
station->preparing_roam = false;
|
||||
station->roam_scan_full = false;
|
||||
station->signal_low = false;
|
||||
station->roam_min_time.tv_sec = 0;
|
||||
station->netconfig_after_roam = false;
|
||||
station->last_roam_scan = 0;
|
||||
|
||||
@ -1987,7 +1877,7 @@ static void station_reset_connection_state(struct station *station)
|
||||
/*
|
||||
* Perform this step last since calling network_disconnected() might
|
||||
* result in the removal of the network (for example if provisioning
|
||||
* a new hidden network fails with an incorrect password).
|
||||
* a new hidden network fails with an incorrect pasword).
|
||||
*/
|
||||
if (station->state == STATION_STATE_CONNECTED ||
|
||||
station->state == STATION_STATE_CONNECTING ||
|
||||
@ -2215,8 +2105,7 @@ static void station_early_neighbor_report_cb(struct netdev *netdev, int err,
|
||||
&station->roam_freqs);
|
||||
}
|
||||
|
||||
static bool station_can_fast_transition(struct station *station,
|
||||
struct handshake_state *hs,
|
||||
static bool station_can_fast_transition(struct handshake_state *hs,
|
||||
struct scan_bss *bss)
|
||||
{
|
||||
uint16_t mdid;
|
||||
@ -2244,16 +2133,6 @@ static bool station_can_fast_transition(struct station *station,
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* FT-over-Air in its current form relies on CMD_REMAIN_ON_CHANNEL. Some
|
||||
* drivers do not support this so only allow over-DS if this is the case
|
||||
*/
|
||||
if (!(hs->mde[4] & 1) &&
|
||||
!wiphy_supports_cmd_offchannel(station->wiphy)) {
|
||||
l_debug("FT-over-Air needs offchannel, using reassociation");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2555,12 +2434,9 @@ static void station_preauthenticate_cb(struct netdev *netdev,
|
||||
}
|
||||
|
||||
if (station_transition_reassociate(station, bss, new_hs) < 0) {
|
||||
handshake_state_unref(new_hs);
|
||||
handshake_state_free(new_hs);
|
||||
station_roam_failed(station);
|
||||
}
|
||||
|
||||
handshake_state_unref(station->hs);
|
||||
station->hs = handshake_state_ref(new_hs);
|
||||
}
|
||||
|
||||
static void station_transition_start(struct station *station);
|
||||
@ -2720,7 +2596,7 @@ static bool station_try_next_transition(struct station *station,
|
||||
station->ap_directed_roaming = false;
|
||||
|
||||
/* Can we use Fast Transition? */
|
||||
if (station_can_fast_transition(station, hs, bss) && !no_ft)
|
||||
if (station_can_fast_transition(hs, bss) && !no_ft)
|
||||
return station_fast_transition(station, bss);
|
||||
|
||||
/* Non-FT transition */
|
||||
@ -2761,13 +2637,10 @@ static bool station_try_next_transition(struct station *station,
|
||||
}
|
||||
|
||||
if (station_transition_reassociate(station, bss, new_hs) < 0) {
|
||||
handshake_state_unref(new_hs);
|
||||
handshake_state_free(new_hs);
|
||||
return false;
|
||||
}
|
||||
|
||||
handshake_state_unref(station->hs);
|
||||
station->hs = handshake_state_ref(new_hs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2854,7 +2727,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
|
||||
struct handshake_state *hs = netdev_get_handshake(station->netdev);
|
||||
struct scan_bss *current_bss = station->connected_bss;
|
||||
struct scan_bss *bss;
|
||||
uint32_t cur_bss_group_rank = 0;
|
||||
double cur_bss_rank = 0.0;
|
||||
static const double RANK_FT_FACTOR = 1.3;
|
||||
uint16_t mdid;
|
||||
enum security orig_security, security;
|
||||
@ -2883,15 +2756,10 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
|
||||
*/
|
||||
bss = l_queue_find(bss_list, bss_match_bssid, current_bss->addr);
|
||||
if (bss && !station->ap_directed_roaming) {
|
||||
double cur_bss_rank = bss->rank;
|
||||
cur_bss_rank = bss->rank;
|
||||
|
||||
if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid)
|
||||
cur_bss_rank *= RANK_FT_FACTOR;
|
||||
|
||||
cur_bss_group_rank = evaluate_bss_group_rank(bss->addr,
|
||||
bss->frequency,
|
||||
bss->signal_strength,
|
||||
(uint16_t) cur_bss_rank);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2913,7 +2781,6 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
|
||||
while ((bss = l_queue_pop_head(bss_list))) {
|
||||
double rank;
|
||||
struct roam_bss *rbss;
|
||||
uint32_t group_rank;
|
||||
|
||||
station_print_scan_bss(bss);
|
||||
|
||||
@ -2935,8 +2802,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
|
||||
if (network_can_connect_bss(network, bss) < 0)
|
||||
goto next;
|
||||
|
||||
if (blacklist_contains_bss(bss->addr,
|
||||
BLACKLIST_REASON_CONNECT_FAILED))
|
||||
if (blacklist_contains_bss(bss->addr))
|
||||
goto next;
|
||||
|
||||
rank = bss->rank;
|
||||
@ -2944,11 +2810,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
|
||||
if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid)
|
||||
rank *= RANK_FT_FACTOR;
|
||||
|
||||
group_rank = evaluate_bss_group_rank(bss->addr, bss->frequency,
|
||||
bss->signal_strength,
|
||||
(uint16_t) rank);
|
||||
|
||||
if (group_rank <= cur_bss_group_rank)
|
||||
if (rank <= cur_bss_rank)
|
||||
goto next;
|
||||
|
||||
/*
|
||||
@ -2957,7 +2819,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
|
||||
*/
|
||||
station_update_roam_bss(station, bss);
|
||||
|
||||
rbss = roam_bss_from_scan_bss(bss, group_rank);
|
||||
rbss = roam_bss_from_scan_bss(bss, rank);
|
||||
|
||||
l_queue_insert(station->roam_bss_list, rbss,
|
||||
roam_bss_rank_compare, NULL);
|
||||
@ -3179,33 +3041,20 @@ static void station_roam_trigger_cb(struct l_timeout *timeout, void *user_data)
|
||||
|
||||
static void station_roam_timeout_rearm(struct station *station, int seconds)
|
||||
{
|
||||
uint64_t remaining;
|
||||
struct timespec now, min_timeout;
|
||||
|
||||
if (!station->roam_trigger_timeout)
|
||||
goto new_timeout;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
/* If we can't get the remaining time just create a new timer */
|
||||
if (L_WARN_ON(!l_timeout_remaining(station->roam_trigger_timeout,
|
||||
&remaining))) {
|
||||
l_timeout_remove(station->roam_trigger_timeout);
|
||||
goto new_timeout;
|
||||
}
|
||||
min_timeout = now;
|
||||
min_timeout.tv_sec += seconds;
|
||||
|
||||
/* Our current timeout is less than the rearm, keep current */
|
||||
if (l_time_before(remaining, seconds * L_USEC_PER_SEC)) {
|
||||
l_debug("Keeping current roam timeout of %" PRIx64 " seconds",
|
||||
l_time_to_secs(remaining));
|
||||
return;
|
||||
}
|
||||
if (station->roam_min_time.tv_sec < min_timeout.tv_sec ||
|
||||
(station->roam_min_time.tv_sec == min_timeout.tv_sec &&
|
||||
station->roam_min_time.tv_nsec < min_timeout.tv_nsec))
|
||||
station->roam_min_time = min_timeout;
|
||||
|
||||
l_debug("Rescheduling roam timeout from %" PRIx64" to %d seconds",
|
||||
l_time_to_secs(remaining), seconds);
|
||||
l_timeout_modify(station->roam_trigger_timeout, seconds);
|
||||
|
||||
return;
|
||||
|
||||
new_timeout:
|
||||
l_debug("Arming new roam timer for %d seconds", seconds);
|
||||
seconds = station->roam_min_time.tv_sec - now.tv_sec +
|
||||
(station->roam_min_time.tv_nsec > now.tv_nsec ? 1 : 0);
|
||||
|
||||
station->roam_trigger_timeout =
|
||||
l_timeout_create(seconds, station_roam_trigger_cb,
|
||||
@ -3225,10 +3074,12 @@ static void station_ap_directed_roam(struct station *station,
|
||||
uint8_t req_mode;
|
||||
uint16_t dtimer;
|
||||
uint8_t valid_interval;
|
||||
bool can_roam = !station_cannot_roam(station);
|
||||
|
||||
l_debug("ifindex: %u", netdev_get_ifindex(station->netdev));
|
||||
|
||||
if (station_cannot_roam(station))
|
||||
return;
|
||||
|
||||
if (station->state != STATION_STATE_CONNECTED) {
|
||||
l_debug("roam: unexpected AP directed roam -- ignore");
|
||||
return;
|
||||
@ -3292,13 +3143,8 @@ static void station_ap_directed_roam(struct station *station,
|
||||
* disassociating us. If either of these bits are set, set the
|
||||
* ap_directed_roaming flag. Otherwise still try roaming but don't
|
||||
* treat it any different than a normal roam.
|
||||
*
|
||||
* The only exception here is if we are in the middle of roaming
|
||||
* (can_roam == false) since we cannot reliably know if the roam scan
|
||||
* included frequencies from potential candidates in this request,
|
||||
* forcing a roam in this case might result in unintended behavior.
|
||||
*/
|
||||
if (can_roam && req_mode & (WNM_REQUEST_MODE_DISASSOCIATION_IMMINENT |
|
||||
if (req_mode & (WNM_REQUEST_MODE_DISASSOCIATION_IMMINENT |
|
||||
WNM_REQUEST_MODE_TERMINATION_IMMINENT |
|
||||
WNM_REQUEST_MODE_ESS_DISASSOCIATION_IMMINENT))
|
||||
station->ap_directed_roaming = true;
|
||||
@ -3325,19 +3171,6 @@ static void station_ap_directed_roam(struct station *station,
|
||||
pos += url_len;
|
||||
}
|
||||
|
||||
blacklist_add_bss(station->connected_bss->addr,
|
||||
BLACKLIST_REASON_ROAM_REQUESTED);
|
||||
station_debug_event(station, "ap-roam-blacklist-added");
|
||||
|
||||
/*
|
||||
* Validating the frame and blacklisting should still be done even if
|
||||
* we are mid-roam. Its important to track the BSS requesting the
|
||||
* transition so when the current roam completes IWD will be less likely
|
||||
* to roam back to the current BSS.
|
||||
*/
|
||||
if (!can_roam)
|
||||
return;
|
||||
|
||||
station->preparing_roam = true;
|
||||
|
||||
l_timeout_remove(station->roam_trigger_timeout);
|
||||
@ -3379,6 +3212,7 @@ static void station_ok_rssi(struct station *station)
|
||||
station->roam_trigger_timeout = NULL;
|
||||
|
||||
station->signal_low = false;
|
||||
station->roam_min_time.tv_sec = 0;
|
||||
}
|
||||
|
||||
static void station_event_roamed(struct station *station, struct scan_bss *new)
|
||||
@ -3476,53 +3310,12 @@ static bool station_retry_with_reason(struct station *station,
|
||||
break;
|
||||
}
|
||||
|
||||
blacklist_add_bss(station->connected_bss->addr,
|
||||
BLACKLIST_REASON_CONNECT_FAILED);
|
||||
|
||||
/*
|
||||
* Network blacklist the BSS as well, since the timeout blacklist could
|
||||
* be disabled
|
||||
*/
|
||||
network_blacklist_add(station->connected_network,
|
||||
station->connected_bss);
|
||||
blacklist_add_bss(station->connected_bss->addr);
|
||||
|
||||
try_next:
|
||||
return station_try_next_bss(station);
|
||||
}
|
||||
|
||||
static bool station_pmksa_fallback(struct station *station, uint16_t status)
|
||||
{
|
||||
/*
|
||||
* IEEE 802.11-2020 12.6.10.3 Cached PMKSAs and RSNA key management
|
||||
*
|
||||
* "If the Authenticator does not have a PMKSA for the PMKIDs in the
|
||||
* (re)association request or the AKM does not match, its behavior
|
||||
* depends on how the PMKSA was established. If SAE authentication was
|
||||
* used to establish the PMKSA, then the AP shall reject (re)association
|
||||
* by sending a (Re)Association Response frame with status code
|
||||
* STATUS_INVALID_PMKID. Note that this allows the non-AP STA to fall
|
||||
* back to full SAE authentication to establish another PMKSA"
|
||||
*/
|
||||
if (status != MMPDU_STATUS_CODE_INVALID_PMKID)
|
||||
return false;
|
||||
|
||||
if (L_WARN_ON(!station->hs))
|
||||
return false;
|
||||
|
||||
if (!IE_AKM_IS_SAE(station->hs->akm_suite) || !station->hs->have_pmksa)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Remove the PMKSA from the handshake and return true to re-try the
|
||||
* same BSS without PMKSA.
|
||||
*/
|
||||
handshake_state_remove_pmksa(station->hs);
|
||||
|
||||
station_debug_event(station, "pmksa-invalid-pmkid");
|
||||
|
||||
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 || \
|
||||
@ -3533,10 +3326,6 @@ static bool station_pmksa_fallback(struct station *station, uint16_t status)
|
||||
static bool station_retry_with_status(struct station *station,
|
||||
uint16_t status_code)
|
||||
{
|
||||
/* If PMKSA failed don't blacklist so we can retry this BSS */
|
||||
if (station_pmksa_fallback(station, status_code))
|
||||
goto try_next;
|
||||
|
||||
/*
|
||||
* Certain Auth/Assoc failures should not cause a timeout blacklist.
|
||||
* In these cases we want to only temporarily blacklist the BSS until
|
||||
@ -3547,19 +3336,12 @@ static bool station_retry_with_status(struct station *station,
|
||||
* specific BSS on our next attempt. There is currently no way to
|
||||
* obtain that IE, but this should be done in the future.
|
||||
*/
|
||||
if (!IS_TEMPORARY_STATUS(status_code))
|
||||
blacklist_add_bss(station->connected_bss->addr,
|
||||
BLACKLIST_REASON_CONNECT_FAILED);
|
||||
if (IS_TEMPORARY_STATUS(status_code))
|
||||
network_blacklist_add(station->connected_network,
|
||||
station->connected_bss);
|
||||
else
|
||||
blacklist_add_bss(station->connected_bss->addr);
|
||||
|
||||
/*
|
||||
* Unconditionally network blacklist the BSS if we are retrying. This
|
||||
* will allow network_bss_select to traverse the BSS list and ignore
|
||||
* BSS's which have previously failed
|
||||
*/
|
||||
network_blacklist_add(station->connected_network,
|
||||
station->connected_bss);
|
||||
|
||||
try_next:
|
||||
iwd_notice(IWD_NOTICE_CONNECT_FAILED, "status: %u", status_code);
|
||||
|
||||
return station_try_next_bss(station);
|
||||
@ -3644,8 +3426,7 @@ static void station_connect_cb(struct netdev *netdev, enum netdev_result result,
|
||||
|
||||
switch (result) {
|
||||
case NETDEV_RESULT_OK:
|
||||
blacklist_remove_bss(station->connected_bss->addr,
|
||||
BLACKLIST_REASON_CONNECT_FAILED);
|
||||
blacklist_remove_bss(station->connected_bss->addr);
|
||||
station_connect_ok(station);
|
||||
return;
|
||||
case NETDEV_RESULT_DISCONNECTED:
|
||||
@ -3777,17 +3558,14 @@ static void station_packets_lost(struct station *station, uint32_t num_pkts)
|
||||
l_debug("Too many roam attempts in %u second timeframe, "
|
||||
"delaying roam", LOSS_ROAM_RATE_LIMIT);
|
||||
|
||||
if (station->roam_trigger_timeout)
|
||||
return;
|
||||
|
||||
station_roam_timeout_rearm(station, LOSS_ROAM_RATE_LIMIT);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (station->roam_trigger_timeout) {
|
||||
l_debug("canceling roam timer to roam immediately");
|
||||
l_timeout_remove(station->roam_trigger_timeout);
|
||||
station->roam_trigger_timeout = NULL;
|
||||
}
|
||||
|
||||
station_start_roam(station);
|
||||
}
|
||||
|
||||
@ -3800,6 +3578,9 @@ static void station_beacon_lost(struct station *station)
|
||||
|
||||
station_debug_event(station, "beacon-loss-roam");
|
||||
|
||||
if (station->roam_trigger_timeout)
|
||||
return;
|
||||
|
||||
station_roam_timeout_rearm(station, LOSS_ROAM_RATE_LIMIT);
|
||||
}
|
||||
|
||||
@ -3878,15 +3659,6 @@ int __station_connect_network(struct station *station, struct network *network,
|
||||
struct handshake_state *hs;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* If we already have a handshake_state ref this is due to a retry,
|
||||
* unref that now
|
||||
*/
|
||||
if (station->hs) {
|
||||
handshake_state_unref(station->hs);
|
||||
station->hs = NULL;
|
||||
}
|
||||
|
||||
if (station->netconfig && !netconfig_load_settings(
|
||||
station->netconfig,
|
||||
network_get_settings(network)))
|
||||
@ -3900,7 +3672,7 @@ int __station_connect_network(struct station *station, struct network *network,
|
||||
station_netdev_event,
|
||||
station_connect_cb, station);
|
||||
if (r < 0) {
|
||||
handshake_state_unref(hs);
|
||||
handshake_state_free(hs);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -3913,7 +3685,6 @@ int __station_connect_network(struct station *station, struct network *network,
|
||||
|
||||
station->connected_bss = bss;
|
||||
station->connected_network = network;
|
||||
station->hs = handshake_state_ref(hs);
|
||||
|
||||
if (station->state != state)
|
||||
station_enter_state(station, state);
|
||||
@ -4749,163 +4520,6 @@ static bool station_property_get_state(struct l_dbus *dbus,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool station_property_get_affinities(struct l_dbus *dbus,
|
||||
struct l_dbus_message *message,
|
||||
struct l_dbus_message_builder *builder,
|
||||
void *user_data)
|
||||
{
|
||||
struct station *station = user_data;
|
||||
const struct l_queue_entry *e;
|
||||
|
||||
if (!station->connected_network)
|
||||
return false;
|
||||
|
||||
l_dbus_message_builder_enter_array(builder, "o");
|
||||
|
||||
for (e = l_queue_get_entries(station->affinities); e; e = e->next) {
|
||||
const char *path = e->data;
|
||||
|
||||
l_dbus_message_builder_append_basic(builder, 'o', path);
|
||||
}
|
||||
|
||||
l_dbus_message_builder_leave_array(builder);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void station_affinity_disconnected_cb(struct l_dbus *dbus,
|
||||
void *user_data)
|
||||
{
|
||||
struct station *station = user_data;
|
||||
|
||||
l_dbus_remove_watch(dbus_get_bus(), station->affinity_watch);
|
||||
|
||||
l_debug("client that set affinity has disconnected");
|
||||
|
||||
/* The client who set the affinity disconnected, raise the threshold */
|
||||
netdev_raise_signal_threshold(station->netdev);
|
||||
}
|
||||
|
||||
static void station_affinity_watch_destroy(void *user_data)
|
||||
{
|
||||
struct station *station = user_data;
|
||||
bool empty = l_queue_length(station->affinities) == 0;
|
||||
|
||||
station->affinity_watch = 0;
|
||||
|
||||
l_free(station->affinity_client);
|
||||
station->affinity_client = NULL;
|
||||
|
||||
l_queue_clear(station->affinities, l_free);
|
||||
|
||||
if (!empty)
|
||||
l_dbus_property_changed(dbus_get_bus(),
|
||||
netdev_get_path(station->netdev),
|
||||
IWD_STATION_INTERFACE, "Affinities");
|
||||
}
|
||||
|
||||
static struct l_dbus_message *station_property_set_affinities(
|
||||
struct l_dbus *dbus,
|
||||
struct l_dbus_message *message,
|
||||
struct l_dbus_message_iter *new_value,
|
||||
l_dbus_property_complete_cb_t complete,
|
||||
void *user_data)
|
||||
{
|
||||
struct station *station = user_data;
|
||||
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;
|
||||
struct scan_bss *new_bss = NULL;
|
||||
struct scan_bss *old_bss = NULL;
|
||||
bool lower_threshold = false;
|
||||
|
||||
if (!station->connected_network)
|
||||
return dbus_error_not_connected(message);
|
||||
|
||||
if (wiphy_supports_firmware_roam(station->wiphy))
|
||||
return dbus_error_not_supported(message);
|
||||
|
||||
if (station->affinity_watch &&
|
||||
strcmp(station->affinity_client, sender)) {
|
||||
l_warn("Only one client may manage Affinities property");
|
||||
return dbus_error_permission_denied(message);
|
||||
}
|
||||
|
||||
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 */
|
||||
if (!l_dbus_message_iter_next_entry(&array, &new_path))
|
||||
return dbus_error_invalid_args(message);
|
||||
|
||||
if (l_dbus_message_iter_next_entry(&array, &new_path))
|
||||
return dbus_error_invalid_args(message);
|
||||
|
||||
old_path = l_queue_peek_head(station->affinities);
|
||||
if (old_path)
|
||||
old_bss = l_dbus_object_get_data(dbus_get_bus(),
|
||||
old_path, IWD_BSS_INTERFACE);
|
||||
if (new_path)
|
||||
new_bss = l_dbus_object_get_data(dbus,
|
||||
new_path, IWD_BSS_INTERFACE);
|
||||
|
||||
/* Either the same path, or both arrays are empty */
|
||||
if (old_bss == new_bss) {
|
||||
complete(dbus, message, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: For now only allow the affinities array to contain a single
|
||||
* value, the connected BSS path. Any other values will be
|
||||
* rejected. This could change in the future.
|
||||
*/
|
||||
if (new_bss && new_bss != station->connected_bss)
|
||||
return dbus_error_invalid_args(message);
|
||||
|
||||
l_queue_clear(station->affinities, l_free);
|
||||
|
||||
/*
|
||||
* Adding a new BSS, create a watch for this DBus client so if it
|
||||
* disconnects we can clear the affinities list
|
||||
*/
|
||||
if (new_path) {
|
||||
l_queue_push_head(station->affinities, l_strdup(new_path));
|
||||
|
||||
lower_threshold = true;
|
||||
|
||||
if (!station->affinity_watch) {
|
||||
station->affinity_client = l_strdup(sender);
|
||||
station->affinity_watch = l_dbus_add_disconnect_watch(
|
||||
dbus, sender,
|
||||
station_affinity_disconnected_cb,
|
||||
station,
|
||||
station_affinity_watch_destroy);
|
||||
}
|
||||
/* The list was cleared, remove the watch */
|
||||
} else if (station->affinity_watch)
|
||||
l_dbus_remove_watch(dbus, station->affinity_watch);
|
||||
|
||||
/*
|
||||
* If affinity was set to the current BSS, lower the roam threshold. If
|
||||
* the connected BSS was not in the list raise the signal threshold.
|
||||
* The threshold may already be raised, in which case netdev will detect
|
||||
* this and do nothing.
|
||||
*/
|
||||
if (lower_threshold)
|
||||
netdev_lower_signal_threshold(station->netdev);
|
||||
else
|
||||
netdev_raise_signal_threshold(station->netdev);
|
||||
|
||||
complete(dbus, message, NULL);
|
||||
|
||||
l_dbus_property_changed(dbus, netdev_get_path(station->netdev),
|
||||
IWD_STATION_INTERFACE, "Affinities");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void station_foreach(station_foreach_func_t func, void *user_data)
|
||||
{
|
||||
const struct l_queue_entry *entry;
|
||||
@ -5136,7 +4750,6 @@ static struct station *station_create(struct netdev *netdev)
|
||||
station_set_autoconnect(station, autoconnect);
|
||||
|
||||
station->roam_bss_list = l_queue_new();
|
||||
station->affinities = l_queue_new();
|
||||
|
||||
return station;
|
||||
}
|
||||
@ -5207,11 +4820,6 @@ static void station_free(struct station *station)
|
||||
l_queue_destroy(station->owe_hidden_scan_ids, NULL);
|
||||
}
|
||||
|
||||
if (station->hs) {
|
||||
handshake_state_unref(station->hs);
|
||||
station->hs = NULL;
|
||||
}
|
||||
|
||||
station_roam_state_clear(station);
|
||||
|
||||
l_queue_destroy(station->networks_sorted, NULL);
|
||||
@ -5234,11 +4842,6 @@ static void station_free(struct station *station)
|
||||
|
||||
l_queue_destroy(station->roam_bss_list, l_free);
|
||||
|
||||
if (station->affinity_watch)
|
||||
l_dbus_remove_watch(dbus_get_bus(), station->affinity_watch);
|
||||
|
||||
l_queue_destroy(station->affinities, l_free);
|
||||
|
||||
l_free(station);
|
||||
}
|
||||
|
||||
@ -5275,9 +4878,6 @@ static void station_setup_interface(struct l_dbus_interface *interface)
|
||||
station_property_get_scanning, NULL);
|
||||
l_dbus_interface_property(interface, "State", 0, "s",
|
||||
station_property_get_state, NULL);
|
||||
l_dbus_interface_property(interface, "Affinities", 0, "ao",
|
||||
station_property_get_affinities,
|
||||
station_property_set_affinities);
|
||||
}
|
||||
|
||||
static void station_destroy_interface(void *user_data)
|
||||
@ -5867,7 +5467,7 @@ static void add_frame_watches(struct netdev *netdev)
|
||||
*/
|
||||
frame_watch_add(netdev_get_wdev_id(netdev), 0, 0x00d0,
|
||||
action_ap_roam_prefix, sizeof(action_ap_roam_prefix),
|
||||
false, ap_roam_frame_event,
|
||||
ap_roam_frame_event,
|
||||
L_UINT_TO_PTR(netdev_get_ifindex(netdev)), NULL);
|
||||
}
|
||||
|
||||
@ -5975,10 +5575,6 @@ static int station_init(void)
|
||||
&anqp_disabled))
|
||||
anqp_disabled = true;
|
||||
|
||||
if (!l_settings_get_bool(iwd_get_config(), "General", "DisablePMKSA",
|
||||
&pmksa_disabled))
|
||||
pmksa_disabled = false;
|
||||
|
||||
if (!netconfig_enabled())
|
||||
l_info("station: Network configuration is disabled.");
|
||||
|
||||
@ -5986,16 +5582,6 @@ static int station_init(void)
|
||||
"arp_evict_nocarrier");
|
||||
supports_ndisc_evict_nocarrier = sysfs_supports_ipv6_setting("all",
|
||||
"ndisc_evict_nocarrier");
|
||||
supports_drop_gratuitous_arp = sysfs_supports_ipv4_setting("all",
|
||||
"drop_gratuitous_arp");
|
||||
supports_drop_unsolicited_na = sysfs_supports_ipv6_setting("all",
|
||||
"drop_unsolicited_na");
|
||||
supports_ipv4_drop_unicast_in_l2_multicast =
|
||||
sysfs_supports_ipv4_setting("all",
|
||||
"drop_unicast_in_l2_multicast");
|
||||
supports_ipv6_drop_unicast_in_l2_multicast =
|
||||
sysfs_supports_ipv6_setting("all",
|
||||
"drop_unicast_in_l2_multicast");
|
||||
|
||||
watchlist_init(&event_watches, NULL);
|
||||
|
||||
|
@ -500,13 +500,6 @@ 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
|
||||
@ -542,7 +535,7 @@ int __storage_decrypt(struct l_settings *settings, const char *ssid,
|
||||
|
||||
/*
|
||||
* Load decrypted data into existing settings. This is not how the API
|
||||
* is intended to be used (since this could result in duplicate groups)
|
||||
* is indended to be used (since this could result in duplicate groups)
|
||||
* but since the Security group was just removed and EncryptedSecurity
|
||||
* should only contain a Security group its safe to use it this way.
|
||||
*/
|
||||
@ -603,7 +596,7 @@ struct l_settings *storage_network_open(enum security type, const char *ssid)
|
||||
struct l_settings *settings;
|
||||
_auto_(l_free) char *path = NULL;
|
||||
|
||||
if (!ssid)
|
||||
if (ssid == NULL)
|
||||
return NULL;
|
||||
|
||||
path = storage_get_network_file_path(type, ssid);
|
||||
@ -630,7 +623,7 @@ int storage_network_touch(enum security type, const char *ssid)
|
||||
char *path;
|
||||
int ret;
|
||||
|
||||
if (!ssid)
|
||||
if (ssid == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
path = storage_get_network_file_path(type, ssid);
|
||||
|
@ -234,7 +234,8 @@ static bool can_read_data(struct l_io *io, void *user_data)
|
||||
if (len < 0)
|
||||
return false;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
struct nl_pktinfo *pktinfo;
|
||||
|
||||
if (cmsg->cmsg_level != SOL_NETLINK)
|
||||
|
65
src/util.c
65
src/util.c
@ -276,7 +276,7 @@ bool util_ip_prefix_tohl(const char *ip, uint8_t *prefix_out,
|
||||
/* 'i' will be at most INET_ADDRSTRLEN - 1 */
|
||||
l_strlcpy(no_prefix, ip, i + 1);
|
||||
|
||||
/* Check if IP preceding prefix is valid */
|
||||
/* Check if IP preceeding prefix is valid */
|
||||
if (inet_pton(AF_INET, no_prefix, &ia) != 1 || ia.s_addr == 0)
|
||||
return false;
|
||||
|
||||
@ -312,36 +312,6 @@ bool util_ip_prefix_tohl(const char *ip, uint8_t *prefix_out,
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Linearly maps @value (expected to be within range @a_start and @a_end) to
|
||||
* a new value between @b_start and @b_end.
|
||||
*
|
||||
* Returns: false if
|
||||
* @value is not between @a_start and @a_end
|
||||
* @a_start/@a_end or @b_start/@b_end are equal.
|
||||
*/
|
||||
bool util_linear_map(double value, double a_start, double a_end,
|
||||
double b_start, double b_end, double *mapped_value)
|
||||
{
|
||||
/* Check value is within a's range */
|
||||
if (a_start < a_end) {
|
||||
if (value < a_start || value > a_end)
|
||||
return false;
|
||||
} else if (a_start > a_end) {
|
||||
if (value > a_start || value < a_end)
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
|
||||
if (b_start == b_end)
|
||||
return false;
|
||||
|
||||
*mapped_value = b_start + (((b_end - b_start) / (a_end - a_start)) *
|
||||
(value - a_start));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct scan_freq_set {
|
||||
uint16_t channels_2ghz;
|
||||
struct l_uintset *channels_5ghz;
|
||||
@ -494,11 +464,6 @@ static void scan_channels_foreach(uint32_t channel, void *user_data)
|
||||
uint32_t freq;
|
||||
|
||||
freq = band_channel_to_freq(channel, channels_data->band);
|
||||
if (!freq) {
|
||||
l_warn("invalid channel %u for band %u", channel,
|
||||
channels_data->band);
|
||||
return;
|
||||
}
|
||||
|
||||
channels_data->func(freq, channels_data->user_data);
|
||||
}
|
||||
@ -636,31 +601,3 @@ struct scan_freq_set *scan_freq_set_clone(const struct scan_freq_set *set,
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/* First 64 entries calculated by 1 / pow(n, 0.3) for n >= 1 */
|
||||
static const double rankmod_table[] = {
|
||||
1.0000000000, 0.8122523964, 0.7192230933, 0.6597539554,
|
||||
0.6170338627, 0.5841906811, 0.5577898253, 0.5358867313,
|
||||
0.5172818580, 0.5011872336, 0.4870596972, 0.4745102806,
|
||||
0.4632516708, 0.4530661223, 0.4437850034, 0.4352752816,
|
||||
0.4274303178, 0.4201634287, 0.4134032816, 0.4070905315,
|
||||
0.4011753236, 0.3956154062, 0.3903746872, 0.3854221125,
|
||||
0.3807307877, 0.3762772797, 0.3720410580, 0.3680040435,
|
||||
0.3641502401, 0.3604654325, 0.3569369365, 0.3535533906,
|
||||
0.3503045821, 0.3471812999, 0.3441752105, 0.3412787518,
|
||||
0.3384850430, 0.3357878061, 0.3331812996, 0.3306602598,
|
||||
0.3282198502, 0.3258556179, 0.3235634544, 0.3213395618,
|
||||
0.3191804229, 0.3170827751, 0.3150435863, 0.3130600345,
|
||||
0.3111294892, 0.3092494947, 0.3074177553, 0.3056321221,
|
||||
0.3038905808, 0.3021912409, 0.3005323264, 0.2989121662,
|
||||
0.2973291870, 0.2957819051, 0.2942689208, 0.2927889114,
|
||||
0.2913406263, 0.2899228820, 0.2885345572, 0.2871745887,
|
||||
};
|
||||
|
||||
double util_exponential_decay(unsigned int n)
|
||||
{
|
||||
if (n >= L_ARRAY_SIZE(rankmod_table))
|
||||
return rankmod_table[L_ARRAY_SIZE(rankmod_table) - 1];
|
||||
|
||||
return rankmod_table[n];
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user