3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2026-02-07 02:28:02 +01:00

Compare commits

..

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

25 changed files with 48 additions and 596 deletions

View File

@ -1,8 +1,3 @@
ver 3.10:
Fix issue with handling neighbor report on BSS TM request.
Fix issue with handling deauth and FT association failure.
Fix issue with handling roaming and old frequencies.
ver 3.9: ver 3.9:
Fix issue with Access Point mode and frequency unlocking. Fix issue with Access Point mode and frequency unlocking.
Fix issue with network configuration and BSS retry logic. Fix issue with network configuration and BSS retry logic.

View File

@ -274,8 +274,6 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h \
src/dpp.c \ src/dpp.c \
src/udev.c \ src/udev.c \
src/pmksa.h src/pmksa.c \ src/pmksa.h src/pmksa.c \
src/vendor_quirks.h \
src/vendor_quirks.c \
$(eap_sources) \ $(eap_sources) \
$(builtin_sources) $(builtin_sources)

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
AC_PREREQ([2.69]) AC_PREREQ([2.69])
AC_INIT([iwd],[3.10]) AC_INIT([iwd],[3.9])
AC_CONFIG_HEADERS(config.h) AC_CONFIG_HEADERS(config.h)
AC_CONFIG_AUX_DIR(build-aux) AC_CONFIG_AUX_DIR(build-aux)

View File

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

View File

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

View File

@ -404,7 +404,6 @@ static const struct {
{ { 0x00, 0x50, 0xf2 }, "Microsoft" }, { { 0x00, 0x50, 0xf2 }, "Microsoft" },
{ { 0x00, 0x90, 0x4c }, "Epigram" }, { { 0x00, 0x90, 0x4c }, "Epigram" },
{ { 0x50, 0x6f, 0x9a }, "Wi-Fi Alliance" }, { { 0x50, 0x6f, 0x9a }, "Wi-Fi Alliance" },
{ { 0x00, 0x18, 0x0a }, "Cisco Meraki" },
{ } { }
}; };

View File

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

View File

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

View File

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

View File

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

View File

@ -368,12 +368,6 @@ void handshake_state_set_vendor_ies(struct handshake_state *s,
} }
} }
void handshake_state_set_vendor_quirks(struct handshake_state *s,
struct vendor_quirk quirks)
{
s->vendor_quirks = quirks;
}
void handshake_state_set_kh_ids(struct handshake_state *s, void handshake_state_set_kh_ids(struct handshake_state *s,
const uint8_t *r0khid, size_t r0khid_len, const uint8_t *r0khid, size_t r0khid_len,
const uint8_t *r1khid) const uint8_t *r1khid)
@ -883,8 +877,7 @@ void handshake_state_set_igtk(struct handshake_state *s, const uint8_t *key,
* results vs the RSN/WPA IE obtained as part of the 4-way handshake. If they * results vs the RSN/WPA IE obtained as part of the 4-way handshake. If they
* don't match, the EAPoL packet must be silently discarded. * don't match, the EAPoL packet must be silently discarded.
*/ */
bool handshake_util_ap_ie_matches(struct handshake_state *s, bool handshake_util_ap_ie_matches(const struct ie_rsn_info *msg_info,
const struct ie_rsn_info *msg_info,
const uint8_t *scan_ie, bool is_wpa) const uint8_t *scan_ie, bool is_wpa)
{ {
struct ie_rsn_info scan_info; struct ie_rsn_info scan_info;
@ -914,15 +907,11 @@ bool handshake_util_ap_ie_matches(struct handshake_state *s,
if (msg_info->no_pairwise != scan_info.no_pairwise) if (msg_info->no_pairwise != scan_info.no_pairwise)
return false; return false;
if (!(s->vendor_quirks.replay_counter_mismatch)) { if (msg_info->ptksa_replay_counter != scan_info.ptksa_replay_counter)
if (msg_info->ptksa_replay_counter != return false;
scan_info.ptksa_replay_counter)
return false;
if (msg_info->gtksa_replay_counter != if (msg_info->gtksa_replay_counter != scan_info.gtksa_replay_counter)
scan_info.gtksa_replay_counter) return false;
return false;
}
if (msg_info->mfpr != scan_info.mfpr) if (msg_info->mfpr != scan_info.mfpr)
return false; return false;

View File

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

View File

@ -197,12 +197,29 @@ static void request_name_callback(struct l_dbus *dbus, bool success,
{ {
if (!success) { if (!success) {
l_error("Name request failed"); l_error("Name request failed");
l_main_quit(); goto fail_exit;
} }
if (!l_dbus_object_manager_enable(dbus, "/"))
l_warn("Unable to register the ObjectManager");
if (!l_dbus_object_add_interface(dbus, IWD_BASE_PATH,
IWD_DAEMON_INTERFACE,
NULL) ||
!l_dbus_object_add_interface(dbus, IWD_BASE_PATH,
L_DBUS_INTERFACE_PROPERTIES,
NULL))
l_info("Unable to add %s and/or %s at %s",
IWD_DAEMON_INTERFACE, L_DBUS_INTERFACE_PROPERTIES,
IWD_BASE_PATH);
/* TODO: Always request nl80211 for now, ignoring auto-loading */ /* TODO: Always request nl80211 for now, ignoring auto-loading */
l_genl_request_family(genl, NL80211_GENL_NAME, nl80211_appeared, l_genl_request_family(genl, NL80211_GENL_NAME, nl80211_appeared,
NULL, NULL); NULL, NULL);
return;
fail_exit:
l_main_quit();
} }
static struct l_dbus_message *iwd_dbus_get_info(struct l_dbus *dbus, static struct l_dbus_message *iwd_dbus_get_info(struct l_dbus *dbus,
@ -232,25 +249,12 @@ static void dbus_ready(void *user_data)
{ {
struct l_dbus *dbus = user_data; struct l_dbus *dbus = user_data;
l_dbus_name_acquire(dbus, "net.connman.iwd", false, false, false,
request_name_callback, NULL);
l_dbus_register_interface(dbus, IWD_DAEMON_INTERFACE, l_dbus_register_interface(dbus, IWD_DAEMON_INTERFACE,
iwd_setup_deamon_interface, iwd_setup_deamon_interface,
NULL, false); NULL, false);
if (!l_dbus_object_manager_enable(dbus, "/"))
l_warn("Unable to register the ObjectManager");
if (!l_dbus_object_add_interface(dbus, IWD_BASE_PATH,
IWD_DAEMON_INTERFACE,
NULL) ||
!l_dbus_object_add_interface(dbus, IWD_BASE_PATH,
L_DBUS_INTERFACE_PROPERTIES,
NULL))
l_info("Unable to add %s and/or %s at %s",
IWD_DAEMON_INTERFACE, L_DBUS_INTERFACE_PROPERTIES,
IWD_BASE_PATH);
l_dbus_name_acquire(dbus, "net.connman.iwd", false, false, false,
request_name_callback, NULL);
} }
static void dbus_disconnected(void *user_data) static void dbus_disconnected(void *user_data)

View File

@ -637,6 +637,7 @@ static bool netdev_parse_sta_info(struct l_genl_attr *attr,
info->have_tx_mcs = true; info->have_tx_mcs = true;
break; break;
case NL80211_STA_INFO_EXPECTED_THROUGHPUT: case NL80211_STA_INFO_EXPECTED_THROUGHPUT:
if (len != 4) if (len != 4)
return false; return false;
@ -644,22 +645,6 @@ static bool netdev_parse_sta_info(struct l_genl_attr *attr,
info->expected_throughput = l_get_u32(data); info->expected_throughput = l_get_u32(data);
info->have_expected_throughput = true; info->have_expected_throughput = true;
break;
case NL80211_STA_INFO_INACTIVE_TIME:
if (len != 4)
return false;
info->inactive_time = l_get_u32(data);
info->have_inactive_time = true;
break;
case NL80211_STA_INFO_CONNECTED_TIME:
if (len != 4)
return false;
info->connected_time = l_get_u32(data);
info->have_connected_time = true;
break; break;
} }
} }
@ -3008,26 +2993,13 @@ static void netdev_cmd_ft_reassociate_cb(struct l_genl_msg *msg,
void *user_data) void *user_data)
{ {
struct netdev *netdev = user_data; struct netdev *netdev = user_data;
int err = l_genl_msg_get_error(msg);
netdev->connect_cmd_id = 0; netdev->connect_cmd_id = 0;
l_debug("%d", err); if (l_genl_msg_get_error(msg) >= 0)
if (err >= 0)
return; return;
/* netdev_deauth_and_fail_connection(netdev,
* TODO: It is possible to not trigger a disconnect here and maintain
* the current connection. The issue is that IWD has already
* modified the handshake and we've lost all reference to the old
* BSS keys.
*
* This could be remedied in the future by creating an entirely
* new handshake_state object for the association and only when
* the ack indicates success do we clear out the old object.
*/
netdev_disconnect_and_fail_connection(netdev,
NETDEV_RESULT_ASSOCIATION_FAILED, NETDEV_RESULT_ASSOCIATION_FAILED,
MMPDU_STATUS_CODE_UNSPECIFIED); MMPDU_STATUS_CODE_UNSPECIFIED);
} }
@ -5430,9 +5402,6 @@ static void netdev_channel_switch_event(struct l_genl_msg *msg,
if (netdev->type != NL80211_IFTYPE_STATION) if (netdev->type != NL80211_IFTYPE_STATION)
return; return;
if (L_WARN_ON(!netdev->connected))
return;
chandef = l_new(struct band_chandef, 1); chandef = l_new(struct band_chandef, 1);
if (nl80211_parse_chandef(msg, chandef) < 0) { if (nl80211_parse_chandef(msg, chandef) < 0) {

View File

@ -51,7 +51,6 @@
#include "src/mpdu.h" #include "src/mpdu.h"
#include "src/band.h" #include "src/band.h"
#include "src/scan.h" #include "src/scan.h"
#include "src/vendor_quirks.h"
/* User configurable options */ /* User configurable options */
static double RANK_2G_FACTOR; static double RANK_2G_FACTOR;
@ -415,8 +414,7 @@ static struct l_genl_msg *scan_build_cmd(struct scan_context *sc,
if (params->ap_scan) if (params->ap_scan)
flags |= NL80211_SCAN_FLAG_AP; flags |= NL80211_SCAN_FLAG_AP;
if (wiphy_supports_colocated_flag(sc->wiphy)) flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
if (flags) if (flags)
l_genl_msg_append_attr(msg, NL80211_ATTR_SCAN_FLAGS, 4, &flags); l_genl_msg_append_attr(msg, NL80211_ATTR_SCAN_FLAGS, 4, &flags);
@ -1222,11 +1220,6 @@ static void scan_parse_vendor_specific(struct scan_bss *bss, const void *data,
uint16_t cost_flags; uint16_t cost_flags;
bool dgaf_disable; bool dgaf_disable;
if (L_WARN_ON(len < 3))
return;
vendor_quirks_append_for_oui(data, &bss->vendor_quirks);
if (!bss->wpa && is_ie_wpa_ie(data, len)) { if (!bss->wpa && is_ie_wpa_ie(data, len)) {
bss->wpa = l_memdup(data - 2, len + 2); bss->wpa = l_memdup(data - 2, len + 2);
return; return;

View File

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

View File

@ -64,7 +64,6 @@
#include "src/eap-tls-common.h" #include "src/eap-tls-common.h"
#include "src/storage.h" #include "src/storage.h"
#include "src/pmksa.h" #include "src/pmksa.h"
#include "src/vendor_quirks.h"
#define STATION_RECENT_NETWORK_LIMIT 5 #define STATION_RECENT_NETWORK_LIMIT 5
#define STATION_RECENT_FREQS_LIMIT 5 #define STATION_RECENT_FREQS_LIMIT 5
@ -1447,8 +1446,6 @@ static struct handshake_state *station_handshake_setup(struct station *station,
vendor_ies = network_info_get_extra_ies(info, bss, &iov_elems); vendor_ies = network_info_get_extra_ies(info, bss, &iov_elems);
handshake_state_set_vendor_ies(hs, vendor_ies, iov_elems); handshake_state_set_vendor_ies(hs, vendor_ies, iov_elems);
handshake_state_set_vendor_quirks(hs, bss->vendor_quirks);
/* /*
* It can't hurt to try the FILS IP Address Assignment independent of * It can't hurt to try the FILS IP Address Assignment independent of
* which auth-proto is actually used. * which auth-proto is actually used.
@ -2407,11 +2404,6 @@ static void station_roam_retry(struct station *station)
station->roam_scan_full = false; station->roam_scan_full = false;
station->ap_directed_roaming = false; station->ap_directed_roaming = false;
if (station->roam_freqs) {
scan_freq_set_free(station->roam_freqs);
station->roam_freqs = NULL;
}
if (station->signal_low) if (station->signal_low)
station_roam_timeout_rearm(station, roam_retry_interval); station_roam_timeout_rearm(station, roam_retry_interval);
} }
@ -2441,16 +2433,8 @@ static void station_roam_failed(struct station *station)
* We were told by the AP to roam, but failed. Try ourselves or * We were told by the AP to roam, but failed. Try ourselves or
* wait for the AP to tell us to roam again * wait for the AP to tell us to roam again
*/ */
if (station->ap_directed_roaming) { if (station->ap_directed_roaming)
/*
* The candidate list from the AP (or neighbor report) found
* no BSS's. Force a full scan
*/
if (!station->roam_scan_full)
goto full_scan;
goto delayed_retry; goto delayed_retry;
}
/* /*
* If we tried a limited scan, failed and the signal is still low, * If we tried a limited scan, failed and the signal is still low,
@ -2462,7 +2446,6 @@ static void station_roam_failed(struct station *station)
* the scan here, so that the destroy callback is not called * the scan here, so that the destroy callback is not called
* after the return of this function * after the return of this function
*/ */
full_scan:
scan_cancel(netdev_get_wdev_id(station->netdev), scan_cancel(netdev_get_wdev_id(station->netdev),
station->roam_scan_id); station->roam_scan_id);
@ -2750,15 +2733,11 @@ static bool station_try_next_transition(struct station *station,
enum security security = network_get_security(connected); enum security security = network_get_security(connected);
struct handshake_state *new_hs; struct handshake_state *new_hs;
struct ie_rsn_info cur_rsne, target_rsne; struct ie_rsn_info cur_rsne, target_rsne;
const char *vendor_quirks = vendor_quirks_to_string(bss->vendor_quirks);
iwd_notice(IWD_NOTICE_ROAM_INFO, "bss: "MAC", signal: %d, load: %d/255", iwd_notice(IWD_NOTICE_ROAM_INFO, "bss: "MAC", signal: %d, load: %d/255",
MAC_STR(bss->addr), MAC_STR(bss->addr),
bss->signal_strength / 100, bss->signal_strength / 100,
bss->utilization); bss->utilization);
if (vendor_quirks)
l_debug("vendor quirks for "MAC": %s",
MAC_STR(bss->addr), vendor_quirks);
/* Reset AP roam flag, at this point the roaming behaves the same */ /* Reset AP roam flag, at this point the roaming behaves the same */
station->ap_directed_roaming = false; station->ap_directed_roaming = false;
@ -3059,7 +3038,6 @@ static int station_roam_scan(struct station *station,
if (!freq_set) { if (!freq_set) {
station->roam_scan_full = true; station->roam_scan_full = true;
params.freqs = allowed; params.freqs = allowed;
station_debug_event(station, "full-roam-scan");
} else } else
scan_freq_set_constrain(freq_set, allowed); scan_freq_set_constrain(freq_set, allowed);
@ -3271,8 +3249,6 @@ static void station_ap_directed_roam(struct station *station,
uint16_t dtimer; uint16_t dtimer;
uint8_t valid_interval; uint8_t valid_interval;
bool can_roam = !station_cannot_roam(station); bool can_roam = !station_cannot_roam(station);
bool ignore_candidates =
station->connected_bss->vendor_quirks.ignore_bss_tm_candidates;
l_debug("ifindex: %u", netdev_get_ifindex(station->netdev)); l_debug("ifindex: %u", netdev_get_ifindex(station->netdev));
@ -3390,21 +3366,12 @@ static void station_ap_directed_roam(struct station *station,
l_timeout_remove(station->roam_trigger_timeout); l_timeout_remove(station->roam_trigger_timeout);
station->roam_trigger_timeout = NULL; station->roam_trigger_timeout = NULL;
if ((req_mode & WNM_REQUEST_MODE_PREFERRED_CANDIDATE_LIST) && if (req_mode & WNM_REQUEST_MODE_PREFERRED_CANDIDATE_LIST) {
!ignore_candidates) {
l_debug("roam: AP sent a preferred candidate list"); l_debug("roam: AP sent a preferred candidate list");
station_neighbor_report_cb(station->netdev, 0, body + pos, station_neighbor_report_cb(station->netdev, 0, body + pos,
body_len - pos, station); body_len - pos, station);
} else { } else {
if (station->connected_bss->cap_rm_neighbor_report) { l_debug("roam: AP did not include a preferred candidate list");
if (!netdev_neighbor_report_req(station->netdev,
station_neighbor_report_cb))
return;
l_warn("failed to request neighbor report!");
}
l_debug("full scan after BSS transition request");
if (station_roam_scan(station, NULL) < 0) if (station_roam_scan(station, NULL) < 0)
station_roam_failed(station); station_roam_failed(station);
} }
@ -3917,7 +3884,6 @@ int __station_connect_network(struct station *station, struct network *network,
{ {
struct handshake_state *hs; struct handshake_state *hs;
int r; int r;
const char *vendor_quirks = vendor_quirks_to_string(bss->vendor_quirks);
/* /*
* If we already have a handshake_state ref this is due to a retry, * If we already have a handshake_state ref this is due to a retry,
@ -3952,10 +3918,6 @@ int __station_connect_network(struct station *station, struct network *network,
bss->signal_strength / 100, bss->signal_strength / 100,
bss->utilization); bss->utilization);
if (vendor_quirks)
l_debug("vendor quirks for "MAC": %s",
MAC_STR(bss->addr), vendor_quirks);
station->connected_bss = bss; station->connected_bss = bss;
station->connected_network = network; station->connected_network = network;
station->hs = handshake_state_ref(hs); station->hs = handshake_state_ref(hs);

View File

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

View File

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

View File

@ -69,26 +69,12 @@ static uint32_t work_ids;
static unsigned int wiphy_dump_id; static unsigned int wiphy_dump_id;
enum driver_flag { enum driver_flag {
/* Force the use of the default interface created by the kernel */
DEFAULT_IF = 0x1, DEFAULT_IF = 0x1,
/*
* Force the use of the PAE socket rather than control port, even if
* control port is supported
*/
FORCE_PAE = 0x2, FORCE_PAE = 0x2,
/* Disable power save on the adapter during initialization */
POWER_SAVE_DISABLE = 0x4, POWER_SAVE_DISABLE = 0x4,
/* Don't use OWE when connecting to open networks */
OWE_DISABLE = 0x8, OWE_DISABLE = 0x8,
/* Disables multicast RX frame registration */
MULTICAST_RX_DISABLE = 0x10, MULTICAST_RX_DISABLE = 0x10,
/*
* Don't use SAE (WPA3) when connecting to hybrid networks. This will
* prevent IWD from connecting to WPA3-only networks
*/
SAE_DISABLE = 0x20, SAE_DISABLE = 0x20,
/* Disables use of the NL80211_SCAN_FLAG_COLOCATED_6GHZ flag in scans */
COLOCATED_SCAN_DISABLE = 0x40,
}; };
struct driver_flag_name { struct driver_flag_name {
@ -117,13 +103,12 @@ static const struct driver_info driver_infos[] = {
}; };
static const struct driver_flag_name driver_flag_names[] = { static const struct driver_flag_name driver_flag_names[] = {
{ "DefaultInterface", DEFAULT_IF }, { "DefaultInterface", DEFAULT_IF },
{ "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 }, { "SaeDisable", SAE_DISABLE },
{ "ColocatedScanDisable", COLOCATED_SCAN_DISABLE },
}; };
struct wiphy { struct wiphy {
@ -978,11 +963,6 @@ bool wiphy_supports_multicast_rx(const struct wiphy *wiphy)
!(wiphy->driver_flags & MULTICAST_RX_DISABLE); !(wiphy->driver_flags & MULTICAST_RX_DISABLE);
} }
bool wiphy_supports_colocated_flag(const struct wiphy *wiphy)
{
return !(wiphy->driver_flags & COLOCATED_SCAN_DISABLE);
}
const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy, const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy,
enum band_freq band, enum band_freq band,
size_t *size) size_t *size)
@ -1402,9 +1382,6 @@ static void wiphy_print_basic_info(struct wiphy *wiphy)
if (wiphy->driver_flags & SAE_DISABLE) if (wiphy->driver_flags & SAE_DISABLE)
flags = l_strv_append(flags, "SaeDisable"); flags = l_strv_append(flags, "SaeDisable");
if (wiphy->driver_flags & COLOCATED_SCAN_DISABLE)
flags = l_strv_append(flags, "ColocatedScanDisable");
joined = l_strjoinv(flags, ' '); joined = l_strjoinv(flags, ' ');
l_info("\tDriver Flags: %s", joined); l_info("\tDriver Flags: %s", joined);

View File

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