3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2025-04-21 12:17:50 +02:00

Compare commits

..

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

32 changed files with 104 additions and 893 deletions

View File

@ -1,15 +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: ver 3.3:
Fix issue with handling External Authentication. Fix issue with handling External Authentication.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1915,7 +1915,7 @@ static void print_ie_interworking(unsigned int level,
size--; size--;
ptr++; ptr++;
if (size < 2) if (!size)
return; return;
/* /*
@ -7433,7 +7433,7 @@ static bool check_pcap(struct nlmon *nlmon, size_t next_size)
pcap_close(nlmon->pcap); pcap_close(nlmon->pcap);
/* Exhausted the single PCAP file */ /* Exausted the single PCAP file */
if (nlmon->max_files < 2) { if (nlmon->max_files < 2) {
printf("Reached maximum size of PCAP, exiting\n"); printf("Reached maximum size of PCAP, exiting\n");
nlmon->pcap = NULL; nlmon->pcap = NULL;

View File

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

View File

@ -20,21 +20,6 @@
* *
*/ */
enum blacklist_reason { void blacklist_add_bss(const uint8_t *addr);
/* bool blacklist_contains_bss(const uint8_t *addr);
* When a BSS is blacklisted using this reason IWD will refuse to void blacklist_remove_bss(const uint8_t *addr);
* connect to it via autoconnect
*/
BLACKLIST_REASON_CONNECT_FAILED,
/*
* This type of blacklist is added when 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);

View File

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

View File

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

View File

@ -1239,7 +1239,7 @@ static struct pmksa *handshake_state_steal_pmksa(struct handshake_state *s)
s->have_pmksa = false; s->have_pmksa = false;
if (l_time_after(now, pmksa->expiration)) { if (l_time_after(now, pmksa->expiration)) {
pmksa_cache_free(pmksa); l_free(pmksa);
pmksa = NULL; pmksa = NULL;
} }
@ -1272,15 +1272,13 @@ void handshake_state_cache_pmksa(struct handshake_state *s)
{ {
struct pmksa *pmksa = handshake_state_steal_pmksa(s); struct pmksa *pmksa = handshake_state_steal_pmksa(s);
if (!pmksa) { l_debug("%p", pmksa);
l_debug("No PMKSA for "MAC, MAC_STR(s->aa));
return;
}
l_debug("Caching PMKSA for "MAC, MAC_STR(s->aa)); if (!pmksa)
return;
if (L_WARN_ON(pmksa_cache_put(pmksa) < 0)) if (L_WARN_ON(pmksa_cache_put(pmksa) < 0))
pmksa_cache_free(pmksa); l_free(pmksa);
} }
bool handshake_state_remove_pmksa(struct handshake_state *s) bool handshake_state_remove_pmksa(struct handshake_state *s)
@ -1294,7 +1292,7 @@ bool handshake_state_remove_pmksa(struct handshake_state *s)
if (!pmksa) if (!pmksa)
return false; return false;
pmksa_cache_free(pmksa); l_free(pmksa);
return true; return true;
} }

View File

@ -290,17 +290,9 @@ control how long a misbehaved BSS spends on the blacklist.
* - InitialTimeout * - InitialTimeout
- Values: uint64 value in seconds (default: **60**) - Values: uint64 value in seconds (default: **60**)
The initial time that a BSS spends on the blacklist. Setting this to zero The initial time that a BSS spends on the blacklist.
will disable blacklisting functionality in IWD.
* - InitialRoamRequestedTimeout
- 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.
* - Multiplier * - Multiplier
- Values: unsigned int value greater than zero, in seconds - Values: unsigned int value in seconds (default: **30**)
(default: **30**)
If the BSS was blacklisted previously and another connection attempt If the BSS was blacklisted previously and another connection attempt
has failed after the initial timeout has expired, then the BSS blacklist has failed after the initial timeout has expired, then the BSS blacklist
@ -473,14 +465,6 @@ are buggy or just don't behave similar enough to the majority of other drivers.
If a driver in use matches one in this list, multicast RX will be If a driver in use matches one in this list, multicast RX will be
disabled. disabled.
* - SaeDisable
- Values: comma-separated list of drivers or glob matches
If a driver in use matches one in this list, SAE/WPA3 will be disabled
for connections. This will prevent connections to WPA3-only networks, but
will allow for connections to WPA3/WPA2 hybrid networks by utilizing
WPA2.
SEE ALSO SEE ALSO
======== ========

View File

@ -463,14 +463,6 @@ uint8_t netdev_get_rssi_level_idx(struct netdev *netdev)
return netdev->cur_rssi_level_idx; return netdev->cur_rssi_level_idx;
} }
int netdev_get_low_signal_threshold(uint32_t frequency)
{
if (frequency > 4000)
return LOW_SIGNAL_THRESHOLD_5GHZ;
return LOW_SIGNAL_THRESHOLD;
}
static void netdev_set_powered_result(int error, uint16_t type, static void netdev_set_powered_result(int error, uint16_t type,
const void *data, const void *data,
uint32_t len, void *user_data) uint32_t len, void *user_data)
@ -1109,7 +1101,6 @@ static void netdev_free(void *data)
l_timeout_remove(netdev->rssi_poll_timeout); l_timeout_remove(netdev->rssi_poll_timeout);
scan_wdev_remove(netdev->wdev_id); scan_wdev_remove(netdev->wdev_id);
frame_watch_wdev_remove(netdev->wdev_id);
watchlist_destroy(&netdev->station_watches); watchlist_destroy(&netdev->station_watches);
@ -1507,105 +1498,6 @@ static void netdev_setting_keys_failed(struct netdev_handshake_state *nhs,
handshake_event(&nhs->super, HANDSHAKE_EVENT_SETTING_KEYS_FAILED, &err); handshake_event(&nhs->super, HANDSHAKE_EVENT_SETTING_KEYS_FAILED, &err);
} }
static bool netdev_match_addr(const void *a, const void *b)
{
const struct netdev *netdev = a;
const uint8_t *addr = b;
return memcmp(netdev->addr, addr, ETH_ALEN) == 0;
}
static struct netdev *netdev_find_by_address(const uint8_t *addr)
{
return l_queue_find(netdev_list, netdev_match_addr, addr);
}
static void netdev_pmksa_driver_add(const struct pmksa *pmksa)
{
struct l_genl_msg *msg;
struct netdev *netdev = netdev_find_by_address(pmksa->spa);
uint32_t expiration = (uint32_t)pmksa->expiration;
if (!netdev)
return;
/* Only need to set the PMKSA into the kernel for fullmac drivers */
if (wiphy_supports_cmds_auth_assoc(netdev->wiphy))
return;
l_debug("Adding PMKSA to kernel");
msg = l_genl_msg_new(NL80211_CMD_SET_PMKSA);
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
l_genl_msg_append_attr(msg, NL80211_ATTR_PMKID, 16, pmksa->pmkid);
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, pmksa->aa);
l_genl_msg_append_attr(msg, NL80211_ATTR_SSID,
pmksa->ssid_len, pmksa->ssid);
l_genl_msg_append_attr(msg, NL80211_ATTR_PMK_LIFETIME, 4, &expiration);
l_genl_msg_append_attr(msg, NL80211_ATTR_PMK,
pmksa->pmk_len, pmksa->pmk);
if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
l_error("error sending SET_PMKSA");
}
static void netdev_pmksa_driver_remove(const struct pmksa *pmksa)
{
struct l_genl_msg *msg;
struct netdev *netdev = netdev_find_by_address(pmksa->spa);
if (!netdev)
return;
/* Only need to set the PMKSA into the kernel for fullmac drivers */
if (wiphy_supports_cmds_auth_assoc(netdev->wiphy))
return;
l_debug("Removing PMKSA from kernel");
msg = l_genl_msg_new(NL80211_CMD_DEL_PMKSA);
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
l_genl_msg_append_attr(msg, NL80211_ATTR_PMKID, 16, pmksa->pmkid);
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, pmksa->aa);
l_genl_msg_append_attr(msg, NL80211_ATTR_SSID,
pmksa->ssid_len, pmksa->ssid);
if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
l_error("error sending DEL_PMKSA");
}
static void netdev_flush_pmksa(struct netdev *netdev)
{
struct l_genl_msg *msg;
/*
* We only utilize the kernel's PMKSA cache for fullmac cards,
* so no need to flush if this is a softmac.
*/
if (wiphy_supports_cmds_auth_assoc(netdev->wiphy))
return;
msg = l_genl_msg_new(NL80211_CMD_FLUSH_PMKSA);
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
l_error("Failed to flush PMKSA for %u", netdev->index);
}
static void netdev_pmksa_driver_flush(void)
{
const struct l_queue_entry *e;
for (e = l_queue_get_entries(netdev_list); e; e = e->next) {
struct netdev *netdev = e->data;
netdev_flush_pmksa(netdev);
}
}
static void try_handshake_complete(struct netdev_handshake_state *nhs) static void try_handshake_complete(struct netdev_handshake_state *nhs)
{ {
l_debug("ptk_installed: %u, gtk_installed: %u, igtk_installed: %u", l_debug("ptk_installed: %u, gtk_installed: %u, igtk_installed: %u",
@ -3924,15 +3816,6 @@ static void netdev_cmd_set_cqm_cb(struct l_genl_msg *msg, void *user_data)
static int netdev_cqm_rssi_update(struct netdev *netdev) static int netdev_cqm_rssi_update(struct netdev *netdev)
{ {
struct l_genl_msg *msg; struct l_genl_msg *msg;
struct netdev_handshake_state *nhs = l_container_of(netdev->handshake,
struct netdev_handshake_state, super);
/*
* Fullmac cards handle roaming in firmware, there is no need to set
* CQM thresholds
*/
if (nhs->type == CONNECTION_TYPE_FULLMAC)
return 0;
l_debug(""); l_debug("");
@ -5621,18 +5504,23 @@ static void netdev_external_auth_event(struct l_genl_msg *msg,
} }
if (action == NL80211_EXTERNAL_AUTH_ABORT) { if (action == NL80211_EXTERNAL_AUTH_ABORT) {
l_warn("External Auth Aborted"); iwd_notice(IWD_NOTICE_CONNECT_INFO, "External Auth Aborted");
goto error; goto error;
} }
iwd_notice(IWD_NOTICE_CONNECT_INFO,
"External Auth to SSID: %s, bssid: "MAC,
util_ssid_to_utf8(ssid.iov_len, ssid.iov_base),
MAC_STR(bssid));
if (hs->ssid_len != ssid.iov_len || if (hs->ssid_len != ssid.iov_len ||
memcmp(hs->ssid, ssid.iov_base, hs->ssid_len)) { memcmp(hs->ssid, ssid.iov_base, hs->ssid_len)) {
l_warn("Target SSID mismatch"); iwd_notice(IWD_NOTICE_CONNECT_INFO, "Target SSID mismatch");
goto error; goto error;
} }
if (memcmp(hs->aa, bssid, ETH_ALEN)) { if (memcmp(hs->aa, bssid, ETH_ALEN)) {
l_warn("Target BSSID mismatch"); iwd_notice(IWD_NOTICE_CONNECT_INFO, "Target BSSID mismatch");
goto error; goto error;
} }
@ -6641,16 +6529,6 @@ struct netdev *netdev_create_from_genl(struct l_genl_msg *msg,
netdev_get_link(netdev); netdev_get_link(netdev);
/*
* Call the netdev-specific variant to flush only this devices PMKSA
* cache in the kernel. This will make IWD's cache and the kernel's
* cache consistent, i.e. no entries
*
* TODO: If we ever are storing PMKSA's on disk we would first need to
* flush, then add all the PMKSA entries at this time.
*/
netdev_flush_pmksa(netdev);
return netdev; return netdev;
} }
@ -6766,10 +6644,6 @@ static int netdev_init(void)
__ft_set_tx_frame_func(netdev_tx_ft_frame); __ft_set_tx_frame_func(netdev_tx_ft_frame);
__pmksa_set_driver_callbacks(netdev_pmksa_driver_add,
netdev_pmksa_driver_remove,
netdev_pmksa_driver_flush);
unicast_watch = l_genl_add_unicast_watch(genl, NL80211_GENL_NAME, unicast_watch = l_genl_add_unicast_watch(genl, NL80211_GENL_NAME,
netdev_unicast_notify, netdev_unicast_notify,
NULL, NULL); NULL, NULL);

View File

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

View File

@ -1280,8 +1280,7 @@ struct scan_bss *network_bss_select(struct network *network,
if (l_queue_find(network->blacklist, match_bss, bss)) if (l_queue_find(network->blacklist, match_bss, bss))
continue; continue;
if (blacklist_contains_bss(bss->addr, if (blacklist_contains_bss(bss->addr))
BLACKLIST_REASON_CONNECT_FAILED))
continue; continue;
/* OWE Transition BSS */ /* OWE Transition BSS */

View File

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

View File

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

View File

@ -143,9 +143,9 @@ struct scan_survey {
}; };
struct scan_survey_results { struct scan_survey_results {
struct scan_survey survey_2_4[15]; struct scan_survey survey_2_4[14];
struct scan_survey survey_5[197]; struct scan_survey survey_5[196];
struct scan_survey survey_6[234]; struct scan_survey survey_6[233];
}; };
struct scan_results { struct scan_results {

View File

@ -155,55 +155,6 @@ struct anqp_entry {
uint32_t pending; uint32_t pending;
}; };
/*
* Rather than sorting BSS's purely based on ranking a higher level grouping
* is used. The purpose of this higher order grouping is the consider the BSS's
* roam blacklist status. The roam blacklist is a "soft" blacklist in that we
* still should connect to these BSS's if they are the only "good" option.
* The question here is: what makes a BSS "good" vs "bad".
*
* For an initial (probably naive) approach here we can use the
* RoamThreshold[5G] which indicates the signal level that would not
* be of an acceptable connection quality. BSS can then be sorted either
* above or below this threshold. Within each of these groups a BSS may be
* blacklisted, meaning it should get sorted lower on the list compared to
* others within the same group.
*
* This sorting is achieved by extending rank to a uint32_t where the first 16
* bits are the standard rank calculated by scan.c. Above that bits can be
* reserved for this higher level grouping:
*
* Bit 16 indicates the BSS is not blacklisted
* Bit 17 indicates the BSS is above the critical signal threshold
*/
#define ABOVE_THRESHOLD_BIT 17
#define NOT_BLACKLISTED_BIT 16
static uint32_t evaluate_bss_group_rank(const uint8_t *addr, uint32_t freq,
int16_t signal_strength, uint16_t rank)
{
int signal = signal_strength / 100;
bool roam_blacklist;
bool good_signal;
uint32_t rank_out = (uint32_t) rank;
if (blacklist_contains_bss(addr, BLACKLIST_REASON_CONNECT_FAILED))
return 0;
roam_blacklist = blacklist_contains_bss(addr,
BLACKLIST_REASON_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 * Used as entries for the roam list since holding scan_bss pointers directly
* from station->bss_list is not 100% safe due to the possibility of the * from station->bss_list is not 100% safe due to the possibility of the
@ -211,13 +162,13 @@ static uint32_t evaluate_bss_group_rank(const uint8_t *addr, uint32_t freq,
*/ */
struct roam_bss { struct roam_bss {
uint8_t addr[6]; uint8_t addr[6];
uint32_t rank; uint16_t rank;
int32_t signal_strength; int32_t signal_strength;
bool ft_failed: 1; bool ft_failed: 1;
}; };
static struct roam_bss *roam_bss_from_scan_bss(const struct scan_bss *bss, static struct roam_bss *roam_bss_from_scan_bss(const struct scan_bss *bss,
uint32_t rank) uint16_t rank)
{ {
struct roam_bss *rbss = l_new(struct roam_bss, 1); struct roam_bss *rbss = l_new(struct roam_bss, 1);
@ -2854,7 +2805,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
struct handshake_state *hs = netdev_get_handshake(station->netdev); struct handshake_state *hs = netdev_get_handshake(station->netdev);
struct scan_bss *current_bss = station->connected_bss; struct scan_bss *current_bss = station->connected_bss;
struct scan_bss *bss; struct scan_bss *bss;
uint32_t cur_bss_group_rank = 0; double cur_bss_rank = 0.0;
static const double RANK_FT_FACTOR = 1.3; static const double RANK_FT_FACTOR = 1.3;
uint16_t mdid; uint16_t mdid;
enum security orig_security, security; enum security orig_security, security;
@ -2883,15 +2834,10 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
*/ */
bss = l_queue_find(bss_list, bss_match_bssid, current_bss->addr); bss = l_queue_find(bss_list, bss_match_bssid, current_bss->addr);
if (bss && !station->ap_directed_roaming) { if (bss && !station->ap_directed_roaming) {
double cur_bss_rank = bss->rank; cur_bss_rank = bss->rank;
if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid) if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid)
cur_bss_rank *= RANK_FT_FACTOR; cur_bss_rank *= RANK_FT_FACTOR;
cur_bss_group_rank = evaluate_bss_group_rank(bss->addr,
bss->frequency,
bss->signal_strength,
(uint16_t) cur_bss_rank);
} }
/* /*
@ -2913,7 +2859,6 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
while ((bss = l_queue_pop_head(bss_list))) { while ((bss = l_queue_pop_head(bss_list))) {
double rank; double rank;
struct roam_bss *rbss; struct roam_bss *rbss;
uint32_t group_rank;
station_print_scan_bss(bss); station_print_scan_bss(bss);
@ -2935,8 +2880,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
if (network_can_connect_bss(network, bss) < 0) if (network_can_connect_bss(network, bss) < 0)
goto next; goto next;
if (blacklist_contains_bss(bss->addr, if (blacklist_contains_bss(bss->addr))
BLACKLIST_REASON_CONNECT_FAILED))
goto next; goto next;
rank = bss->rank; rank = bss->rank;
@ -2944,11 +2888,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid) if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid)
rank *= RANK_FT_FACTOR; rank *= RANK_FT_FACTOR;
group_rank = evaluate_bss_group_rank(bss->addr, bss->frequency, if (rank <= cur_bss_rank)
bss->signal_strength,
(uint16_t) rank);
if (group_rank <= cur_bss_group_rank)
goto next; goto next;
/* /*
@ -2957,7 +2897,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
*/ */
station_update_roam_bss(station, bss); station_update_roam_bss(station, bss);
rbss = roam_bss_from_scan_bss(bss, group_rank); rbss = roam_bss_from_scan_bss(bss, rank);
l_queue_insert(station->roam_bss_list, rbss, l_queue_insert(station->roam_bss_list, rbss,
roam_bss_rank_compare, NULL); roam_bss_rank_compare, NULL);
@ -3225,10 +3165,12 @@ static void station_ap_directed_roam(struct station *station,
uint8_t req_mode; uint8_t req_mode;
uint16_t dtimer; uint16_t dtimer;
uint8_t valid_interval; uint8_t valid_interval;
bool can_roam = !station_cannot_roam(station);
l_debug("ifindex: %u", netdev_get_ifindex(station->netdev)); l_debug("ifindex: %u", netdev_get_ifindex(station->netdev));
if (station_cannot_roam(station))
return;
if (station->state != STATION_STATE_CONNECTED) { if (station->state != STATION_STATE_CONNECTED) {
l_debug("roam: unexpected AP directed roam -- ignore"); l_debug("roam: unexpected AP directed roam -- ignore");
return; return;
@ -3292,13 +3234,8 @@ static void station_ap_directed_roam(struct station *station,
* disassociating us. If either of these bits are set, set the * disassociating us. If either of these bits are set, set the
* ap_directed_roaming flag. Otherwise still try roaming but don't * ap_directed_roaming flag. Otherwise still try roaming but don't
* treat it any different than a normal roam. * treat it any different than a normal roam.
*
* The only exception here is if we are in the middle of roaming
* (can_roam == false) since we cannot reliably know if the roam scan
* included frequencies from potential candidates in this request,
* forcing a roam in this case might result in unintended behavior.
*/ */
if (can_roam && req_mode & (WNM_REQUEST_MODE_DISASSOCIATION_IMMINENT | if (req_mode & (WNM_REQUEST_MODE_DISASSOCIATION_IMMINENT |
WNM_REQUEST_MODE_TERMINATION_IMMINENT | WNM_REQUEST_MODE_TERMINATION_IMMINENT |
WNM_REQUEST_MODE_ESS_DISASSOCIATION_IMMINENT)) WNM_REQUEST_MODE_ESS_DISASSOCIATION_IMMINENT))
station->ap_directed_roaming = true; station->ap_directed_roaming = true;
@ -3325,19 +3262,6 @@ static void station_ap_directed_roam(struct station *station,
pos += url_len; 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; station->preparing_roam = true;
l_timeout_remove(station->roam_trigger_timeout); l_timeout_remove(station->roam_trigger_timeout);
@ -3476,15 +3400,7 @@ static bool station_retry_with_reason(struct station *station,
break; break;
} }
blacklist_add_bss(station->connected_bss->addr, blacklist_add_bss(station->connected_bss->addr);
BLACKLIST_REASON_CONNECT_FAILED);
/*
* Network blacklist the BSS as well, since the timeout blacklist could
* be disabled
*/
network_blacklist_add(station->connected_network,
station->connected_bss);
try_next: try_next:
return station_try_next_bss(station); return station_try_next_bss(station);
@ -3533,10 +3449,6 @@ static bool station_pmksa_fallback(struct station *station, uint16_t status)
static bool station_retry_with_status(struct station *station, static bool station_retry_with_status(struct station *station,
uint16_t status_code) uint16_t status_code)
{ {
/* If PMKSA failed don't blacklist so we can retry this BSS */
if (station_pmksa_fallback(station, status_code))
goto try_next;
/* /*
* Certain Auth/Assoc failures should not cause a timeout blacklist. * Certain Auth/Assoc failures should not cause a timeout blacklist.
* In these cases we want to only temporarily blacklist the BSS until * In these cases we want to only temporarily blacklist the BSS until
@ -3547,19 +3459,12 @@ static bool station_retry_with_status(struct station *station,
* specific BSS on our next attempt. There is currently no way to * specific BSS on our next attempt. There is currently no way to
* obtain that IE, but this should be done in the future. * obtain that IE, but this should be done in the future.
*/ */
if (!IS_TEMPORARY_STATUS(status_code)) if (IS_TEMPORARY_STATUS(status_code))
blacklist_add_bss(station->connected_bss->addr,
BLACKLIST_REASON_CONNECT_FAILED);
/*
* Unconditionally network blacklist the BSS if we are retrying. This
* will allow network_bss_select to traverse the BSS list and ignore
* BSS's which have previously failed
*/
network_blacklist_add(station->connected_network, network_blacklist_add(station->connected_network,
station->connected_bss); station->connected_bss);
else if (!station_pmksa_fallback(station, status_code))
blacklist_add_bss(station->connected_bss->addr);
try_next:
iwd_notice(IWD_NOTICE_CONNECT_FAILED, "status: %u", status_code); iwd_notice(IWD_NOTICE_CONNECT_FAILED, "status: %u", status_code);
return station_try_next_bss(station); return station_try_next_bss(station);
@ -3644,8 +3549,7 @@ static void station_connect_cb(struct netdev *netdev, enum netdev_result result,
switch (result) { switch (result) {
case NETDEV_RESULT_OK: case NETDEV_RESULT_OK:
blacklist_remove_bss(station->connected_bss->addr, blacklist_remove_bss(station->connected_bss->addr);
BLACKLIST_REASON_CONNECT_FAILED);
station_connect_ok(station); station_connect_ok(station);
return; return;
case NETDEV_RESULT_DISCONNECTED: case NETDEV_RESULT_DISCONNECTED:
@ -4836,8 +4740,7 @@ static struct l_dbus_message *station_property_set_affinities(
return dbus_error_invalid_args(message); return dbus_error_invalid_args(message);
/* Get first entry, there should be only one */ /* Get first entry, there should be only one */
if (!l_dbus_message_iter_next_entry(&array, &new_path)) l_dbus_message_iter_next_entry(&array, &new_path);
return dbus_error_invalid_args(message);
if (l_dbus_message_iter_next_entry(&array, &new_path)) if (l_dbus_message_iter_next_entry(&array, &new_path))
return dbus_error_invalid_args(message); return dbus_error_invalid_args(message);

View File

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

View File

@ -74,7 +74,6 @@ enum driver_flag {
POWER_SAVE_DISABLE = 0x4, POWER_SAVE_DISABLE = 0x4,
OWE_DISABLE = 0x8, OWE_DISABLE = 0x8,
MULTICAST_RX_DISABLE = 0x10, MULTICAST_RX_DISABLE = 0x10,
SAE_DISABLE = 0x20,
}; };
struct driver_flag_name { struct driver_flag_name {
@ -107,8 +106,7 @@ static const struct driver_flag_name driver_flag_names[] = {
{ "ForcePae", FORCE_PAE }, { "ForcePae", FORCE_PAE },
{ "PowerSaveDisable", POWER_SAVE_DISABLE }, { "PowerSaveDisable", POWER_SAVE_DISABLE },
{ "OweDisable", OWE_DISABLE }, { "OweDisable", OWE_DISABLE },
{ "MulticastRxDisable", MULTICAST_RX_DISABLE }, { "MulticastRxDisable", MULTICAST_RX_DISABLE }
{ "SaeDisable", SAE_DISABLE },
}; };
struct wiphy { struct wiphy {
@ -204,9 +202,6 @@ uint16_t wiphy_get_supported_ciphers(struct wiphy *wiphy, uint16_t mask)
static bool wiphy_can_connect_sae(struct wiphy *wiphy) static bool wiphy_can_connect_sae(struct wiphy *wiphy)
{ {
if (wiphy->driver_flags & SAE_DISABLE)
return false;
/* /*
* WPA3 Specification version 3, Section 2.2: * WPA3 Specification version 3, Section 2.2:
* A STA shall not enable WEP and TKIP * A STA shall not enable WEP and TKIP
@ -1379,9 +1374,6 @@ static void wiphy_print_basic_info(struct wiphy *wiphy)
if (wiphy->driver_flags & MULTICAST_RX_DISABLE) if (wiphy->driver_flags & MULTICAST_RX_DISABLE)
flags = l_strv_append(flags, "MulticastRxDisable"); flags = l_strv_append(flags, "MulticastRxDisable");
if (wiphy->driver_flags & SAE_DISABLE)
flags = l_strv_append(flags, "SaeDisable");
joined = l_strjoinv(flags, ' '); joined = l_strjoinv(flags, ' ');
l_info("\tDriver Flags: %s", joined); l_info("\tDriver Flags: %s", joined);

View File

@ -116,29 +116,6 @@ struct dpp_test_info bad_channels[] = {
}, },
}; };
struct dpp_test_info duplicates[] = {
/* Duplicate key */
{
.uri = "DPP:K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgADURzxmttZoIRIPWGoQMV00XHWCAQIhXruVWOz0NjlkIA=;K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgADURzxmttZoIRIPWGoQMV00XHWCAQIhXruVWOz0NjlkIA=;;",
.expect_fail = true
},
/* Duplicate frequencies*/
{
.uri = "DPP:C:81/1,115/36;C:81/1,115/36;;",
.expect_fail = true
},
/* Duplicate MACs*/
{
.uri = "DPP:M:5254005828e5;M:5254005828e5;;",
.expect_fail = true
},
/* Duplicate versions */
{
.uri = "DPP:V:2;V:2;;",
.expect_fail = true
},
};
static bool verify_info(const struct dpp_uri_info *parsed, static bool verify_info(const struct dpp_uri_info *parsed,
const struct dpp_test_info *result) const struct dpp_test_info *result)
{ {
@ -181,14 +158,6 @@ static void test_bad_channels(const void *data)
test_uri_parse(&bad_channels[i]); test_uri_parse(&bad_channels[i]);
} }
static void test_duplicate_in_uri(const void *data)
{
unsigned int i;
for (i = 0; i < L_ARRAY_SIZE(duplicates); i++)
test_uri_parse(&duplicates[i]);
}
struct dpp_test_vector { struct dpp_test_vector {
/* Initiator values */ /* Initiator values */
const char *i_proto_public; const char *i_proto_public;
@ -607,7 +576,6 @@ int main(int argc, char *argv[])
l_test_add("DPP URI bad key", test_uri_parse, &bad_key); l_test_add("DPP URI bad key", test_uri_parse, &bad_key);
l_test_add("DPP URI bad channels", test_bad_channels, &bad_channels); l_test_add("DPP URI bad channels", test_bad_channels, &bad_channels);
l_test_add("DPP URI unexpected ID", test_uri_parse, &unexpected_id); l_test_add("DPP URI unexpected ID", test_uri_parse, &unexpected_id);
l_test_add("DPP URI duplicates", test_duplicate_in_uri, &duplicates);
return l_test_run(); return l_test_run();
} }

View File

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

View File

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