mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2026-02-07 10:47:57 +01:00
Compare commits
No commits in common. "master" and "3.9" have entirely different histories.
@ -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.
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
|
||||||
@ -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
|
|
||||||
@ -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 = {}
|
||||||
|
|||||||
@ -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 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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" },
|
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
10
src/ft.c
10
src/ft.c
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
38
src/main.c
38
src/main.c
@ -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)
|
||||||
|
|||||||
37
src/netdev.c
37
src/netdev.c
@ -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) {
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
@ -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 */
|
|
||||||
35
src/wiphy.c
35
src/wiphy.c
@ -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);
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user