[PATCH 1/7] ap: Don't use L_AUTO_FREE_VAR with l_settings
by Andrew Zaborowski
L_AUTO_FREE_VAR only causes l_free to be called on the variable that is
freed and may leak the rest of the l_settings object's memory.
---
src/ap.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/src/ap.c b/src/ap.c
index fd1a9a6b..f7b1cf9f 100644
--- a/src/ap.c
+++ b/src/ap.c
@@ -2544,8 +2544,8 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
{
uint32_t ifindex = netdev_get_ifindex(ap->netdev);
char *passphrase;
- L_AUTO_FREE_VAR(struct l_settings *, settings) = NULL;
- int err;
+ struct l_settings *settings = NULL;
+ int err = -EINVAL;
/* No profile or DHCP settings */
if (!ap->config->profile && !pool.used)
@@ -2555,7 +2555,7 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
settings = l_settings_new();
if (!l_settings_load_from_file(settings, ap->config->profile))
- return -EINVAL;
+ goto cleanup;
passphrase = l_settings_get_string(settings, "Security",
"Passphrase");
@@ -2564,7 +2564,7 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
l_error("[Security].Passphrase must not exceed "
"63 characters");
l_free(passphrase);
- return -EINVAL;
+ goto cleanup;
}
strcpy(ap->config->passphrase, passphrase);
@@ -2573,7 +2573,8 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
if (!l_settings_has_group(settings, "IPv4")) {
*wait_dhcp = false;
- return 0;
+ err = 0;
+ goto cleanup;
}
}
@@ -2587,21 +2588,22 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
if (!ap->rtnl_add_cmd) {
l_error("Failed to add IPv4 address");
- return -EIO;
+ err = -EIO;
+ goto cleanup;
}
ap->cleanup_ip = true;
*wait_dhcp = true;
-
- return 0;
+ err = 0;
/* Selected address already set, continue normally */
} else if (err == -EALREADY) {
*wait_dhcp = false;
-
- return 0;
+ err = 0;
}
+cleanup:
+ l_settings_free(settings);
return err;
}
--
2.27.0
1 month, 2 weeks
[PATCH 01/17] auto-t: testEAD: stop ead when test finishes
by James Prestwood
---
autotests/testEAD/connection_test.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/autotests/testEAD/connection_test.py b/autotests/testEAD/connection_test.py
index bdf242b6..7f23f0d6 100644
--- a/autotests/testEAD/connection_test.py
+++ b/autotests/testEAD/connection_test.py
@@ -3,6 +3,7 @@
import unittest
import sys
import os
+import shutil
sys.path.append('../util')
from iwd import IWD
@@ -14,7 +15,7 @@ class Test(unittest.TestCase):
def test_connection_success(self):
env = os.environ.copy()
env['STATE_DIRECTORY'] = '/tmp/ead'
- ctx.start_process(['ead', '-i', 'eth1', '-d'], env=env)
+ p = ctx.start_process(['ead', '-i', 'eth1', '-d'], env=env)
ead = EAD()
@@ -26,6 +27,7 @@ class Test(unittest.TestCase):
condition = 'obj.authenticated == True'
ead.wait_for_object_condition(adapter, condition)
+ ctx.stop_process(p)
@classmethod
def setUpClass(cls):
os.mkdir('/tmp/ead')
@@ -36,5 +38,7 @@ class Test(unittest.TestCase):
def tearDownClass(cls):
IWD.clear_storage(storage_dir='/tmp/ead')
+ shutil.rmtree('/tmp/ead')
+
if __name__ == '__main__':
unittest.main(exit=True)
--
2.26.2
1 month, 2 weeks
[PATCH 1/7] ap: Don't use L_AUTO_FREE_VAR with l_settings
by Andrew Zaborowski
L_AUTO_FREE_VAR only causes l_free to be called on the variable that is
freed and may leak the rest of the l_settings object's memory.
---
src/ap.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/src/ap.c b/src/ap.c
index fd1a9a6b..f7b1cf9f 100644
--- a/src/ap.c
+++ b/src/ap.c
@@ -2544,8 +2544,8 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
{
uint32_t ifindex = netdev_get_ifindex(ap->netdev);
char *passphrase;
- L_AUTO_FREE_VAR(struct l_settings *, settings) = NULL;
- int err;
+ struct l_settings *settings = NULL;
+ int err = -EINVAL;
/* No profile or DHCP settings */
if (!ap->config->profile && !pool.used)
@@ -2555,7 +2555,7 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
settings = l_settings_new();
if (!l_settings_load_from_file(settings, ap->config->profile))
- return -EINVAL;
+ goto cleanup;
passphrase = l_settings_get_string(settings, "Security",
"Passphrase");
@@ -2564,7 +2564,7 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
l_error("[Security].Passphrase must not exceed "
"63 characters");
l_free(passphrase);
- return -EINVAL;
+ goto cleanup;
}
strcpy(ap->config->passphrase, passphrase);
@@ -2573,7 +2573,8 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
if (!l_settings_has_group(settings, "IPv4")) {
*wait_dhcp = false;
- return 0;
+ err = 0;
+ goto cleanup;
}
}
@@ -2587,21 +2588,22 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
if (!ap->rtnl_add_cmd) {
l_error("Failed to add IPv4 address");
- return -EIO;
+ err = -EIO;
+ goto cleanup;
}
ap->cleanup_ip = true;
*wait_dhcp = true;
-
- return 0;
+ err = 0;
/* Selected address already set, continue normally */
} else if (err == -EALREADY) {
*wait_dhcp = false;
-
- return 0;
+ err = 0;
}
+cleanup:
+ l_settings_free(settings);
return err;
}
--
2.27.0
1 month, 2 weeks
quick connect path may never update the frequency cache
by iwd@jolan.org
Hi,
I was deploying some new access points and reconfigured all the 5GHz channels on the old access points to spread out the spectrum usage. When I restarted my iwd-using computers, I noticed they all came up on 2.4GHz instead of 5GHz. I quickly realized that this is because the quick path is reducing the scan to only the known frequencies in the cache. I left iwd running and figured it would eventually find the old APs on their new frequencies but it never did. Looking through the code, I see why this is. The quick connect/roam path will only do a full scan if it can't connect at all, so it will happily stay associated at lower bandwidth indefinitely.
I can think of some other situations where this behavior may not be desired:
- AP is using a DFS channel, AP detects radar and falls over to a non-DFS channel
- a new frequency is deployed (Wi-FI 6E)
I tried to find a quick, easy way to forcibly full scan and cache but there really wasn't good place to do so except on start up so I've resorted to deleting the cache on boot-up until I've finalized WLAN configuration.
I haven't been following iwd development much until now so maybe this has already been discussed. Perhaps the cache needs to be a little less naive and take other factors into account like cache creation time, the BSS/frequency of the last connection, or perhaps all BSS/frequencies so a quick scan result could be checked to see how complete it is compared to the fully cached BSS/frequency list and fall back to a full scan if the current network topology varies greatly from the cached result.
Thank you for your work on iwd and your time/consideration,
- Jolan
1 month, 3 weeks
[PATCH 1/7] test-runner: start dmesg process with start_process
by James Prestwood
This avoids the need to pass in the context explicitly.
---
tools/test-runner | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/test-runner b/tools/test-runner
index 965b0a57..70694e47 100755
--- a/tools/test-runner
+++ b/tools/test-runner
@@ -1178,7 +1178,7 @@ def run_auto_tests(ctx, args):
# Write out kernel log
if ctx.args.log:
- Process(["dmesg"], ctx=ctx, wait=True)
+ ctx.start_process(["dmesg"], wait=True)
def run_unit_tests(ctx, args):
os.chdir(args.testhome + '/unit')
--
2.26.2
1 month, 3 weeks
[PATCH 1/2] ap: Clarify settings in iwd.ap(5)
by Andrew Zaborowski
Change some of the wording and add some references, for example the phrase
IP pool was used but it wasn't clear what it referred to.
---
src/iwd.ap.rst | 49 +++++++++++++++++++++++++++----------------------
1 file changed, 27 insertions(+), 22 deletions(-)
diff --git a/src/iwd.ap.rst b/src/iwd.ap.rst
index 52312855..9240f25b 100644
--- a/src/iwd.ap.rst
+++ b/src/iwd.ap.rst
@@ -3,7 +3,7 @@
============
--------------------------------------
-Configuration of IWD access point
+Configuration of IWD access points
--------------------------------------
:Author: James Prestwood <prestwoj(a)gmail.com>
@@ -25,19 +25,21 @@ Description of access point provisioning files.
DESCRIPTION
===========
-An access point provisioning files define the configuration of an IWD access
+An access point provisioning file defines the configuration of an IWD access
point. These files live in *$STATE_DIRECTORY*/ap (/var/lib/iwd/ap by default).
+They are read when the net.connman.iwd.AccessPoint.StartProfile(ssid) DBus
+method is used.
FILE FORMAT
===========
-See *iwd.network* for details on the file format.
+See *iwd.network* for details on the settings file syntax.
SETTINGS
========
The settings are split into several categories. Each category has a group
-associated with it and described in separate tables below.
+associated with it and is described in the corresponding table below.
Network Authentication Settings
-------------------------------
@@ -54,13 +56,14 @@ configuration.
* - Passphrase
- 8..63 character string
- Passphrase to be used with this access point.
+ PSK Passphrase to be used with this access point.
DHCP Server Settings
--------------------
-The group ``[IPv4]`` contains settings for IWD's built in DHCP server. All
-settings are optional.
+The group ``[IPv4]`` contains settings for IWD's built-in DHCP server. All
+settings are optional. They're used if network configuration was enabled as
+described in *iwd.config*(5).
.. list-table::
:header-rows: 0
@@ -68,41 +71,43 @@ settings are optional.
:widths: 20 80
* - Address
- - IP Address of AP
+ - Local IP Address of the AP
- Optional address for the DHCP server/access point. If provided this
- address will be set on the AP interface and any other DHCP server options
- will be derived from this address, unless they are overriden inside the
- AP profile. If [IPv4].Address is not provided and no IP address is set
- on the interface prior to calling StartProfile the IP pool will be used.
+ Optional local address for the access point and the DHCP server. If
+ provided this address will be set on the AP interface and any other DHCP
+ server options will be derived from this address, unless they are
+ overriden by other settings. If [IPv4].Address is not provided and no IP
+ address is set on the interface prior to calling StartProfile the IP
+ pool defined by the global [General].APRanges setting will be used.
* - Gateway
- IP Address of gateway
- IP address of gateway. This will inherit from [IPv4].Address if not
- provided.
+ IP address of the gateway to be advertised by DHCP. This will inherit
+ the value of [IPv4].Address if not provided.
* - Netmask
- - Netmask of DHCP server
+ - Local netmask of the AP
- This will be generated from [IPv4].Address if not provided.
+ Defaults to a 24-bit netmask if not provided.
* - DNSList
- - List of DNS servers
+ - List of DNS servers as a comma-separated IP address list
A list of DNS servers which will be advertised by the DHCP server. If
not provided no DNS servers will be sent by the DHCP server.
* - LeaseTime
- - Time limit for DHCP leases
+ - Time limit for DHCP leases in seconds
Override the default lease time.
* - IPRange
- - Range of IPs to use for the DHCP server
+ - Range of IPs to use for the DHCP server given as two addresses separated
+ by a comma
- If not provided a default range will be chosen which is the DHCP server
- address + 1 to 254.
+ From and to addresses of the range assigned to clients by DHCP. If not
+ provided the range from local address + 1 to .254 will be used.
SEE ALSO
========
--
2.27.0
1 month, 3 weeks
[PATCH 1/4] ap: Pass vendor IEs between frames and the user
by Andrew Zaborowski
Add API for the ap.h users to add extra vendor IEs to outgoing
management frames (beacons, etc.). Pass the string IEs from the
incoming STA association frames to the user in the AP event data.
I drop ap_event_station_added_data.rsn_ie because that probably
wasn't going to ever be useful and the RSN IE is included in the
assoc_ies array in any case.
---
src/ap.c | 233 ++++++++++++++++++++++++++++++++++++++++---------------
src/ap.h | 15 +++-
2 files changed, 186 insertions(+), 62 deletions(-)
diff --git a/src/ap.c b/src/ap.c
index 8ea26a0d..dbc624c2 100644
--- a/src/ap.c
+++ b/src/ap.c
@@ -75,6 +75,8 @@ struct ap_state {
uint16_t wsc_dpid;
uint8_t wsc_uuid_r[16];
+ struct l_queue *vendor_ie_writers;
+
uint16_t last_aid;
struct l_queue *sta_states;
@@ -99,6 +101,8 @@ struct sta_state {
struct l_uintset *rates;
uint32_t assoc_resp_cmd_id;
struct ap_state *ap;
+ uint8_t *assoc_ies;
+ size_t assoc_ies_len;
uint8_t *assoc_rsne;
struct eapol_sm *sm;
struct handshake_state *hs;
@@ -127,6 +131,12 @@ struct ap_ip_pool {
struct l_uintset *used;
};
+struct ap_vendor_ie_writer {
+ ap_get_vendor_ie_len get_len_func;
+ ap_write_vendor_ie write_func;
+ void *user_data;
+};
+
struct ap_ip_pool pool;
static uint32_t netdev_watch;
struct l_netlink *rtnl;
@@ -279,7 +289,7 @@ static void ap_sta_free(void *data)
struct ap_state *ap = sta->ap;
l_uintset_free(sta->rates);
- l_free(sta->assoc_rsne);
+ l_free(sta->assoc_ies);
if (sta->assoc_resp_cmd_id)
l_genl_family_cancel(ap->nl80211, sta->assoc_resp_cmd_id);
@@ -411,7 +421,8 @@ static void ap_new_rsna(struct sta_state *sta)
if (ap->ops->handle_event) {
struct ap_event_station_added_data event_data = {};
event_data.mac = sta->addr;
- event_data.rsn_ie = sta->assoc_rsne;
+ event_data.assoc_ies = sta->assoc_ies;
+ event_data.assoc_ies_len = sta->assoc_ies_len;
ap->ops->handle_event(AP_EVENT_STATION_ADDED, &event_data,
ap->user_data);
}
@@ -463,11 +474,51 @@ static void ap_set_rsn_info(struct ap_state *ap, struct ie_rsn_info *rsn)
rsn->group_cipher = ap->group_cipher;
}
+static size_t ap_get_vendor_ies_len(struct ap_state *ap,
+ enum mpdu_management_subtype type)
+{
+ const struct l_queue_entry *entry;
+ size_t len = 0;
+
+ for (entry = l_queue_get_entries(ap->sta_states); entry;
+ entry = entry->next) {
+ struct ap_vendor_ie_writer *writer = entry->data;
+
+ len += writer->get_len_func(type, writer->user_data);
+ }
+
+ return len;
+}
+
+static size_t ap_write_vendor_ies(struct ap_state *ap,
+ enum mpdu_management_subtype type,
+ uint8_t *out_buf)
+{
+ const struct l_queue_entry *entry;
+ size_t len = 0;
+
+ for (entry = l_queue_get_entries(ap->sta_states); entry;
+ entry = entry->next) {
+ struct ap_vendor_ie_writer *writer = entry->data;
+
+ len += writer->write_func(type, out_buf + len,
+ writer->user_data);
+ }
+
+ return len;
+}
+
/*
* Build a Beacon frame or a Probe Response frame's header and body until
* the TIM IE. Except for the optional TIM IE which is inserted by the
* kernel when needed, our contents for both frames are the same.
* See Beacon format in 8.3.3.2 and Probe Response format in 8.3.3.10.
+ *
+ * 802.11-2016, Section 9.4.2.1:
+ * "The frame body components specified for many management subtypes result
+ * in elements ordered by ascending values of the Element ID field and then
+ * the Element ID Extension field (when present), with the exception of the
+ * MIC Management element (9.4.2.55)."
*/
static size_t ap_build_beacon_pr_head(struct ap_state *ap,
enum mpdu_management_subtype stype,
@@ -533,15 +584,12 @@ static size_t ap_build_beacon_pr_head(struct ap_state *ap,
}
/* Beacon / Probe Response frame portion after the TIM IE */
-static size_t ap_build_beacon_pr_tail(struct ap_state *ap, bool pr,
+static size_t ap_build_beacon_pr_tail(struct ap_state *ap,
+ enum mpdu_management_subtype stype,
uint8_t *out_buf)
{
size_t len;
struct ie_rsn_info rsn;
- uint8_t *wsc_data;
- size_t wsc_data_size;
- uint8_t *wsc_ie;
- size_t wsc_ie_size;
/* TODO: Country IE between TIM IE and RSNE */
@@ -551,8 +599,71 @@ static size_t ap_build_beacon_pr_tail(struct ap_state *ap, bool pr,
return 0;
len = 2 + out_buf[1];
+ len += ap_write_vendor_ies(ap, stype, out_buf + len);
+ return len;
+}
+
+static void ap_set_beacon_cb(struct l_genl_msg *msg, void *user_data)
+{
+ int error = l_genl_msg_get_error(msg);
+
+ if (error < 0)
+ l_error("SET_BEACON failed: %s (%i)", strerror(-error), -error);
+}
+
+static void ap_update_beacon(struct ap_state *ap)
+{
+ struct l_genl_msg *cmd;
+ uint8_t head[256];
+ uint8_t tail[256 + ap_get_vendor_ies_len(ap,
+ MPDU_MANAGEMENT_SUBTYPE_BEACON)];
+ size_t head_len, tail_len;
+ uint64_t wdev_id = netdev_get_wdev_id(ap->netdev);
+ static const uint8_t bcast_addr[6] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ head_len = ap_build_beacon_pr_head(ap, MPDU_MANAGEMENT_SUBTYPE_BEACON,
+ bcast_addr, head, sizeof(head));
+ tail_len = ap_build_beacon_pr_tail(ap, MPDU_MANAGEMENT_SUBTYPE_BEACON,
+ tail);
+ if (L_WARN_ON(!head_len || !tail_len))
+ return;
+
+ cmd = l_genl_msg_new_sized(NL80211_CMD_SET_BEACON,
+ 32 + head_len + tail_len);
+ l_genl_msg_append_attr(cmd, NL80211_ATTR_WDEV, 8, &wdev_id);
+ l_genl_msg_append_attr(cmd, NL80211_ATTR_BEACON_HEAD, head_len, head);
+ l_genl_msg_append_attr(cmd, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
+ l_genl_msg_append_attr(cmd, NL80211_ATTR_IE, 0, "");
+ l_genl_msg_append_attr(cmd, NL80211_ATTR_IE_PROBE_RESP, 0, "");
+ l_genl_msg_append_attr(cmd, NL80211_ATTR_IE_ASSOC_RESP, 0, "");
+
+ if (l_genl_family_send(ap->nl80211, cmd, ap_set_beacon_cb, NULL, NULL))
+ return;
+
+ l_genl_msg_unref(cmd);
+ l_error("Issuing SET_BEACON failed");
+}
+
+static size_t ap_get_wsc_ie_len(enum mpdu_management_subtype type,
+ void *user_data)
+{
+ return 256;
+}
+
+static size_t ap_write_wsc_ie(enum mpdu_management_subtype type,
+ uint8_t *out_buf, void *user_data)
+{
+ struct ap_state *ap = user_data;
+ uint8_t *wsc_data;
+ size_t wsc_data_size;
+ uint8_t *wsc_ie;
+ size_t wsc_ie_size;
+ size_t len = 0;
+
/* WSC IE */
- if (pr) {
+ if (type == MPDU_MANAGEMENT_SUBTYPE_PROBE_RESPONSE) {
struct wsc_probe_response wsc_pr = {};
wsc_pr.version2 = true;
@@ -633,46 +744,6 @@ static size_t ap_build_beacon_pr_tail(struct ap_state *ap, bool pr,
return len;
}
-static void ap_set_beacon_cb(struct l_genl_msg *msg, void *user_data)
-{
- int error = l_genl_msg_get_error(msg);
-
- if (error < 0)
- l_error("SET_BEACON failed: %s (%i)", strerror(-error), -error);
-}
-
-static void ap_update_beacon(struct ap_state *ap)
-{
- struct l_genl_msg *cmd;
- uint8_t head[256], tail[256];
- size_t head_len, tail_len;
- uint64_t wdev_id = netdev_get_wdev_id(ap->netdev);
- static const uint8_t bcast_addr[6] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
-
- head_len = ap_build_beacon_pr_head(ap, MPDU_MANAGEMENT_SUBTYPE_BEACON,
- bcast_addr, head, sizeof(head));
- tail_len = ap_build_beacon_pr_tail(ap, false, tail);
- if (L_WARN_ON(!head_len || !tail_len))
- return;
-
- cmd = l_genl_msg_new_sized(NL80211_CMD_SET_BEACON,
- 32 + head_len + tail_len);
- l_genl_msg_append_attr(cmd, NL80211_ATTR_WDEV, 8, &wdev_id);
- l_genl_msg_append_attr(cmd, NL80211_ATTR_BEACON_HEAD, head_len, head);
- l_genl_msg_append_attr(cmd, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
- l_genl_msg_append_attr(cmd, NL80211_ATTR_IE, 0, "");
- l_genl_msg_append_attr(cmd, NL80211_ATTR_IE_PROBE_RESP, 0, "");
- l_genl_msg_append_attr(cmd, NL80211_ATTR_IE_ASSOC_RESP, 0, "");
-
- if (l_genl_family_send(ap->nl80211, cmd, ap_set_beacon_cb, NULL, NULL))
- return;
-
- l_genl_msg_unref(cmd);
- l_error("Issuing SET_BEACON failed");
-}
-
static void ap_wsc_exit_pbc(struct ap_state *ap)
{
if (!ap->wsc_pbc_timeout)
@@ -1194,7 +1265,10 @@ static uint32_t ap_assoc_resp(struct ap_state *ap, struct sta_state *sta,
bool reassoc, frame_xchg_cb_t callback)
{
const uint8_t *addr = netdev_get_address(ap->netdev);
- uint8_t mpdu_buf[128];
+ enum mpdu_management_subtype stype = reassoc ?
+ MPDU_MANAGEMENT_SUBTYPE_REASSOCIATION_RESPONSE :
+ MPDU_MANAGEMENT_SUBTYPE_ASSOCIATION_RESPONSE;
+ uint8_t mpdu_buf[128 + ap_get_vendor_ies_len(ap, stype)];
struct mmpdu_header *mpdu = (void *) mpdu_buf;
struct mmpdu_association_response *resp;
size_t ies_len = 0;
@@ -1206,9 +1280,7 @@ static uint32_t ap_assoc_resp(struct ap_state *ap, struct sta_state *sta,
/* Header */
mpdu->fc.protocol_version = 0;
mpdu->fc.type = MPDU_TYPE_MANAGEMENT;
- mpdu->fc.subtype = reassoc ?
- MPDU_MANAGEMENT_SUBTYPE_REASSOCIATION_RESPONSE :
- MPDU_MANAGEMENT_SUBTYPE_ASSOCIATION_RESPONSE;
+ mpdu->fc.subtype = stype;
memcpy(mpdu->address_1, dest, 6); /* DA */
memcpy(mpdu->address_2, addr, 6); /* SA */
memcpy(mpdu->address_3, addr, 6); /* BSSID */
@@ -1270,6 +1342,8 @@ static uint32_t ap_assoc_resp(struct ap_state *ap, struct sta_state *sta,
l_free(wsc_ie);
}
+ ies_len += ap_write_vendor_ies(ap, stype, resp->ies + ies_len);
+
send_frame:
return ap_send_mgmt_frame(ap, mpdu, resp->ies + ies_len - mpdu_buf,
callback, sta);
@@ -1471,6 +1545,8 @@ static void ap_assoc_reassoc(struct sta_state *sta, bool reassoc,
sta->wsc_v2 = wsc_req.version2;
event_data.mac = sta->addr;
+ event_data.assoc_ies = ies;
+ event_data.assoc_ies_len = ies_len;
ap->ops->handle_event(AP_EVENT_REGISTRATION_START, &event_data,
ap->user_data);
@@ -1521,13 +1597,16 @@ static void ap_assoc_reassoc(struct sta_state *sta, bool reassoc,
sta->rates = rates;
- if (sta->assoc_rsne)
- l_free(sta->assoc_rsne);
+ l_free(sta->assoc_ies);
- if (rsn)
- sta->assoc_rsne = l_memdup(rsn, rsn[1] + 2);
- else
+ if (rsn) {
+ sta->assoc_ies = l_memdup(ies, ies_len);
+ sta->assoc_ies_len = ies_len;
+ sta->assoc_rsne = sta->assoc_ies + (rsn - ies);
+ } else {
+ sta->assoc_ies = NULL;
sta->assoc_rsne = NULL;
+ }
sta->assoc_resp_cmd_id = ap_assoc_resp(ap, sta, sta->addr, 0, reassoc,
ap_success_assoc_resp_cb);
@@ -1774,7 +1853,8 @@ static void ap_probe_req_cb(const struct mmpdu_header *hdr, const void *body,
struct ie_tlv_iter iter;
const uint8_t *bssid = netdev_get_address(ap->netdev);
bool match = false;
- uint8_t resp[512];
+ uint8_t resp[512 + ap_get_vendor_ies_len(ap,
+ MPDU_MANAGEMENT_SUBTYPE_PROBE_RESPONSE)];
uint8_t *wsc_data;
ssize_t wsc_data_len;
@@ -1864,7 +1944,9 @@ static void ap_probe_req_cb(const struct mmpdu_header *hdr, const void *body,
len = ap_build_beacon_pr_head(ap,
MPDU_MANAGEMENT_SUBTYPE_PROBE_RESPONSE,
hdr->address_2, resp, sizeof(resp));
- len += ap_build_beacon_pr_tail(ap, true, resp + len);
+ len += ap_build_beacon_pr_tail(ap,
+ MPDU_MANAGEMENT_SUBTYPE_PROBE_RESPONSE,
+ resp + len);
ap_send_mgmt_frame(ap, (struct mmpdu_header *) resp, len,
ap_probe_resp_cb, NULL);
@@ -2102,7 +2184,9 @@ static struct l_genl_msg *ap_build_cmd_start_ap(struct ap_state *ap)
{
struct l_genl_msg *cmd;
- uint8_t head[256], tail[256];
+ uint8_t head[256];
+ uint8_t tail[256 + ap_get_vendor_ies_len(ap,
+ MPDU_MANAGEMENT_SUBTYPE_BEACON)];
size_t head_len, tail_len;
uint32_t dtim_period = 3;
@@ -2132,7 +2216,8 @@ static struct l_genl_msg *ap_build_cmd_start_ap(struct ap_state *ap)
head_len = ap_build_beacon_pr_head(ap, MPDU_MANAGEMENT_SUBTYPE_BEACON,
bcast_addr, head, sizeof(head));
- tail_len = ap_build_beacon_pr_tail(ap, false, tail);
+ tail_len = ap_build_beacon_pr_tail(ap, MPDU_MANAGEMENT_SUBTYPE_BEACON,
+ tail);
if (!head_len || !tail_len)
return NULL;
@@ -2697,6 +2782,7 @@ struct ap_state *ap_start(struct netdev *netdev, struct ap_config *config,
}
wsc_uuid_from_addr(netdev_get_address(netdev), ap->wsc_uuid_r);
+ ap_add_vendor_ie_writer(ap, ap_get_wsc_ie_len, ap_write_wsc_ie, ap);
if (config->passphrase[0] &&
crypto_psk_from_passphrase(config->passphrase,
@@ -2876,9 +2962,34 @@ void ap_free(struct ap_state *ap)
l_genl_family_free(ap->nl80211);
if (ap->server)
l_dhcp_server_destroy(ap->server);
+
+ l_queue_destroy(ap->vendor_ie_writers, l_free);
l_free(ap);
}
+void ap_add_vendor_ie_writer(struct ap_state *ap,
+ ap_get_vendor_ie_len get_len_func,
+ ap_write_vendor_ie write_func,
+ void *user_data)
+{
+ struct ap_vendor_ie_writer *writer =
+ l_new(struct ap_vendor_ie_writer, 1);
+
+ writer->get_len_func = get_len_func;
+ writer->write_func = write_func;
+ writer->user_data = user_data;
+
+ if (!ap->vendor_ie_writers)
+ ap->vendor_ie_writers = l_queue_new();
+
+ /*
+ * It doesn't look like vendor IEs need to be ordered in a specific
+ * way so just append at the end, but if needed we can take an OUI
+ * parameter and switch to inserting at the right place in the queue.
+ */
+ l_queue_push_tail(ap->vendor_ie_writers, writer);
+}
+
bool ap_station_disconnect(struct ap_state *ap, const uint8_t *mac,
enum mmpdu_reason_code reason)
{
diff --git a/src/ap.h b/src/ap.h
index dc57a0bb..eb4f96df 100644
--- a/src/ap.h
+++ b/src/ap.h
@@ -22,6 +22,7 @@
struct ap_state;
struct iovec;
+enum mpdu_management_subtype;
enum ap_event_type {
AP_EVENT_START_FAILED,
@@ -36,7 +37,8 @@ enum ap_event_type {
struct ap_event_station_added_data {
const uint8_t *mac;
- const uint8_t *rsn_ie;
+ const uint8_t *assoc_ies;
+ size_t assoc_ies_len;
};
struct ap_event_station_removed_data {
@@ -46,6 +48,8 @@ struct ap_event_station_removed_data {
struct ap_event_registration_start_data {
const uint8_t *mac;
+ const uint8_t *assoc_ies;
+ size_t assoc_ies_len;
};
struct ap_event_registration_success_data {
@@ -53,6 +57,10 @@ struct ap_event_registration_success_data {
};
typedef void (*ap_stopped_func_t)(void *user_data);
+typedef size_t (*ap_get_vendor_ie_len)(enum mpdu_management_subtype type,
+ void *user_data);
+typedef size_t (*ap_write_vendor_ie)(enum mpdu_management_subtype type,
+ uint8_t *out_buf, void *user_data);
struct ap_config {
char *ssid;
@@ -83,6 +91,11 @@ void ap_shutdown(struct ap_state *ap, ap_stopped_func_t stopped_func,
void *user_data);
void ap_free(struct ap_state *ap);
+void ap_add_vendor_ie_writer(struct ap_state *ap,
+ ap_get_vendor_ie_len get_len_func,
+ ap_write_vendor_ie write_func,
+ void *user_data);
+
bool ap_station_disconnect(struct ap_state *ap, const uint8_t *mac,
enum mmpdu_reason_code reason);
--
2.27.0
1 month, 3 weeks
[PATCH 1/4] scan: add MaximumPeriodicScanInterval setting
by Alvin Šipraga
---
src/scan.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/src/scan.c b/src/scan.c
index 3c28eb7d..a4469f0e 100644
--- a/src/scan.c
+++ b/src/scan.c
@@ -50,9 +50,12 @@
#include "src/mpdu.h"
#include "src/scan.h"
-#define SCAN_MAX_INTERVAL 320
#define SCAN_INIT_INTERVAL 10
+/* User configurable options */
+static double RANK_5G_FACTOR;
+static uint32_t SCAN_MAX_INTERVAL;
+
static struct l_queue *scan_contexts;
static struct l_genl_family *nl80211;
@@ -1313,9 +1316,6 @@ static struct scan_bss *scan_parse_result(struct l_genl_msg *msg,
return bss;
}
-/* User configurable options */
-static double RANK_5G_FACTOR;
-
static void scan_bss_compute_rank(struct scan_bss *bss)
{
static const double RANK_RSNE_FACTOR = 1.2;
@@ -2215,6 +2215,13 @@ static int scan_init(void)
&RANK_5G_FACTOR))
RANK_5G_FACTOR = 1.0;
+ if (!l_settings_get_uint(config, "Scan", "MaximumPeriodicScanInterval",
+ &SCAN_MAX_INTERVAL))
+ SCAN_MAX_INTERVAL = 300;
+
+ if (SCAN_MAX_INTERVAL > UINT16_MAX)
+ SCAN_MAX_INTERVAL = UINT16_MAX;
+
return 0;
}
--
2.30.0
2 months
[PATCH] auto-t: fix blacklist test timing issues
by James Prestwood
This test fails randomly, and it appears to be due to excessive
scanning. Historically most autotests start a dbus scan right
away. The problem is that most likely a periodic scan is already
ongoing, meaning the dbus scan gets queued. If a Connect() call
comes in (which it always does), the dbus scan gets delayed and will
trigger once connected, at a time the test is not expecting. This
can cause problems with any assumed timing as well as offchannel
frames.
This patch removes the explicit DBus scanning and instead uses
scan_if_needed with get_ordered_networks. The 'all_blacklisted_test'
was also modified to wait for scanning to complete after failing
to connect to all BSS's. This lets all the networks fully come
up (after being blocked by hwsim) and appear in scan results.
---
.../testBSSBlacklist/all_blacklisted_test.py | 15 ++++++---------
autotests/testBSSBlacklist/bad_pass_test.py | 10 +---------
autotests/testBSSBlacklist/connection_test.py | 10 +---------
autotests/testBSSBlacklist/temp_blacklist_test.py | 10 +---------
4 files changed, 9 insertions(+), 36 deletions(-)
diff --git a/autotests/testBSSBlacklist/all_blacklisted_test.py b/autotests/testBSSBlacklist/all_blacklisted_test.py
index d3ed7acc..b52d0900 100644
--- a/autotests/testBSSBlacklist/all_blacklisted_test.py
+++ b/autotests/testBSSBlacklist/all_blacklisted_test.py
@@ -47,15 +47,7 @@ class Test(unittest.TestCase):
devices = wd.list_devices(1)
device = devices[0]
- condition = 'not obj.scanning'
- wd.wait_for_object_condition(device, condition)
-
- device.scan()
-
- condition = 'not obj.scanning'
- wd.wait_for_object_condition(device, condition)
-
- ordered_network = device.get_ordered_network("TestBlacklist")
+ ordered_network = device.get_ordered_network("TestBlacklist", scan_if_needed=True)
self.assertEqual(ordered_network.type, NetworkType.psk)
@@ -74,6 +66,11 @@ class Test(unittest.TestCase):
rule1.drop = False
rule2.drop = False
+ # Wait for scanning (likely a quick-scan) to finish, otherwise we will
+ # may not have all BSS's in the list.
+ condition = 'not obj.scanning'
+ wd.wait_for_object_condition(device, condition)
+
# This connect should work
ordered_network.network_object.connect()
diff --git a/autotests/testBSSBlacklist/bad_pass_test.py b/autotests/testBSSBlacklist/bad_pass_test.py
index 0aff053a..b0a81991 100644
--- a/autotests/testBSSBlacklist/bad_pass_test.py
+++ b/autotests/testBSSBlacklist/bad_pass_test.py
@@ -47,15 +47,7 @@ class Test(unittest.TestCase):
devices = wd.list_devices(1)
device = devices[0]
- condition = 'not obj.scanning'
- wd.wait_for_object_condition(device, condition)
-
- device.scan()
-
- condition = 'not obj.scanning'
- wd.wait_for_object_condition(device, condition)
-
- ordered_network = device.get_ordered_network("TestBlacklist")
+ ordered_network = device.get_ordered_network("TestBlacklist", scan_if_needed=True)
self.assertEqual(ordered_network.type, NetworkType.psk)
diff --git a/autotests/testBSSBlacklist/connection_test.py b/autotests/testBSSBlacklist/connection_test.py
index 8d7d92e1..111ae582 100644
--- a/autotests/testBSSBlacklist/connection_test.py
+++ b/autotests/testBSSBlacklist/connection_test.py
@@ -51,15 +51,7 @@ class Test(unittest.TestCase):
devices[1].disconnect()
- condition = 'not obj.scanning'
- wd.wait_for_object_condition(device, condition)
-
- device.scan()
-
- condition = 'not obj.scanning'
- wd.wait_for_object_condition(device, condition)
-
- ordered_network = device.get_ordered_network("TestBlacklist")
+ ordered_network = device.get_ordered_network("TestBlacklist", scan_if_needed=True)
self.assertEqual(ordered_network.type, NetworkType.psk)
diff --git a/autotests/testBSSBlacklist/temp_blacklist_test.py b/autotests/testBSSBlacklist/temp_blacklist_test.py
index 2a9590b8..efb848e9 100644
--- a/autotests/testBSSBlacklist/temp_blacklist_test.py
+++ b/autotests/testBSSBlacklist/temp_blacklist_test.py
@@ -46,15 +46,7 @@ class Test(unittest.TestCase):
dev1, dev2 = wd.list_devices(2)
- condition = 'not obj.scanning'
- wd.wait_for_object_condition(dev1, condition)
-
- dev1.scan()
-
- condition = 'not obj.scanning'
- wd.wait_for_object_condition(dev1, condition)
-
- ordered_network = dev1.get_ordered_network("TestBlacklist")
+ ordered_network = dev1.get_ordered_network("TestBlacklist", scan_if_needed=True)
self.assertEqual(ordered_network.type, NetworkType.psk)
--
2.26.2
2 months
[PATCH] src: configure systemd-resolved's MulticastDNS=
setting
by Daniel Lin
When using iwd.conf:[General].EnableNetworkConfiguration=true, it is not
possible to configure systemd.network:[Network].MulticastDNS= as
systemd-networkd considers the link to be unmanaged. This patch allows
iwd to configure that setting on systemd-resolved directly.
---
src/iwd.config.rst | 7 ++++
src/netconfig.c | 6 ++++
src/resolve.c | 83 ++++++++++++++++++++++++++++++++--------------
src/resolve.h | 1 +
4 files changed, 73 insertions(+), 24 deletions(-)
diff --git a/src/iwd.config.rst b/src/iwd.config.rst
index 0064dfd2..73d41cc0 100644
--- a/src/iwd.config.rst
+++ b/src/iwd.config.rst
@@ -212,6 +212,13 @@ The group ``[Network]`` contains network configuration related settings.
If not specified, ``300`` is used as default.
+ * - MulticastDNS
+ - Values: true, false, resolve
+
+ Configures multicast DNS. See ``man 5 systemd.network`` for details.
+
+ Only applies when ``NameResolvingService=systemd``.
+
Blacklist
---------
diff --git a/src/netconfig.c b/src/netconfig.c
index cf092b78..749ba0ad 100644
--- a/src/netconfig.c
+++ b/src/netconfig.c
@@ -963,6 +963,8 @@ bool netconfig_configure(struct netconfig *netconfig,
const uint8_t *mac_address,
netconfig_notify_func_t notify, void *user_data)
{
+ char *mdns;
+
netconfig->dns4_overrides = l_settings_get_string_list(active_settings,
"IPv4", "DNS", ' ');
@@ -1006,6 +1008,10 @@ bool netconfig_configure(struct netconfig *netconfig,
netconfig_ipv6_select_and_install(netconfig);
+ mdns = l_settings_get_string(active_settings, "Network", "MulticastDNS");
+ resolve_set_mdns(netconfig->resolve, mdns);
+ l_free(mdns);
+
return true;
}
diff --git a/src/resolve.c b/src/resolve.c
index d3b483a8..993bbf34 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -40,6 +40,7 @@
struct resolve_ops {
void (*set_dns)(struct resolve *resolve, char **dns_list);
void (*set_domains)(struct resolve *resolve, char **domain_list);
+ void (*set_mdns)(struct resolve *resolve, char *mdns);
void (*revert)(struct resolve *resolve);
void (*destroy)(struct resolve *resolve);
};
@@ -78,6 +79,17 @@ void resolve_set_domains(struct resolve *resolve, char **domain_list)
resolve->ops->set_domains(resolve, domain_list);
}
+void resolve_set_mdns(struct resolve *resolve, char *mdns)
+{
+ if (!mdns)
+ return;
+
+ if (!resolve->ops->set_mdns)
+ return;
+
+ resolve->ops->set_mdns(resolve, mdns);
+}
+
void resolve_revert(struct resolve *resolve)
{
if (!resolve->ops->revert)
@@ -112,9 +124,10 @@ struct systemd {
struct resolve super;
};
-static void systemd_link_dns_reply(struct l_dbus_message *message,
+static void systemd_link_generic_reply(struct l_dbus_message *message,
void *user_data)
{
+ const char *type = user_data;
const char *name;
const char *text;
@@ -123,8 +136,8 @@ static void systemd_link_dns_reply(struct l_dbus_message *message,
l_dbus_message_get_error(message, &name, &text);
- l_error("resolve-systemd: Failed to modify the DNS entries. %s: %s",
- name, text);
+ l_error("resolve-systemd: Failed to modify the %s entries. %s: %s",
+ type, name, text);
}
static bool systemd_builder_add_dns(struct l_dbus_message_builder *builder,
@@ -205,23 +218,8 @@ static void resolve_systemd_set_dns(struct resolve *resolve, char **dns_list)
l_dbus_message_builder_finalize(builder);
l_dbus_message_builder_destroy(builder);
- l_dbus_send_with_reply(dbus_get_bus(), message, systemd_link_dns_reply,
- NULL, NULL);
-}
-
-static void systemd_set_link_domains_reply(struct l_dbus_message *message,
- void *user_data)
-{
- const char *name;
- const char *text;
-
- if (!l_dbus_message_is_error(message))
- return;
-
- l_dbus_message_get_error(message, &name, &text);
-
- l_error("resolve-systemd: Failed to modify the domain entries. %s: %s",
- name, text);
+ l_dbus_send_with_reply(dbus_get_bus(), message, systemd_link_generic_reply,
+ "DNS", NULL);
}
static void resolve_systemd_set_domains(struct resolve *resolve,
@@ -266,8 +264,43 @@ static void resolve_systemd_set_domains(struct resolve *resolve,
l_dbus_message_builder_finalize(builder);
l_dbus_message_builder_destroy(builder);
- l_dbus_send_with_reply(dbus_get_bus(), message,
- systemd_set_link_domains_reply, NULL, NULL);
+ l_dbus_send_with_reply(dbus_get_bus(), message, systemd_link_generic_reply,
+ "domains", NULL);
+}
+
+static void resolve_systemd_set_mdns(struct resolve *resolve, char *mdns)
+{
+ struct l_dbus_message_builder *builder;
+ struct l_dbus_message *message;
+
+ l_debug("ifindex: %u", resolve->ifindex);
+
+ if (L_WARN_ON(!systemd_state.is_ready))
+ return;
+
+ message = l_dbus_message_new_method_call(dbus_get_bus(),
+ SYSTEMD_RESOLVED_SERVICE,
+ SYSTEMD_RESOLVED_MANAGER_PATH,
+ SYSTEMD_RESOLVED_MANAGER_INTERFACE,
+ "SetLinkMulticastDNS");
+
+ if (!message)
+ return;
+
+ builder = l_dbus_message_builder_new(message);
+ if (!builder) {
+ l_dbus_message_unref(message);
+ return;
+ }
+
+ l_dbus_message_builder_append_basic(builder, 'i', &resolve->ifindex);
+ l_dbus_message_builder_append_basic(builder, 's', mdns);
+
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+
+ l_dbus_send_with_reply(dbus_get_bus(), message, systemd_link_generic_reply,
+ "MulticastDNS", NULL);
}
static void resolve_systemd_revert(struct resolve *resolve)
@@ -288,8 +321,8 @@ static void resolve_systemd_revert(struct resolve *resolve)
return;
l_dbus_message_set_arguments(message, "i", resolve->ifindex);
- l_dbus_send_with_reply(dbus_get_bus(), message, systemd_link_dns_reply,
- NULL, NULL);
+ l_dbus_send_with_reply(dbus_get_bus(), message, systemd_link_generic_reply,
+ "DNS", NULL);
}
static void resolve_systemd_destroy(struct resolve *resolve)
@@ -302,6 +335,7 @@ static void resolve_systemd_destroy(struct resolve *resolve)
static const struct resolve_ops systemd_ops = {
.set_dns = resolve_systemd_set_dns,
.set_domains = resolve_systemd_set_domains,
+ .set_mdns = resolve_systemd_set_mdns,
.revert = resolve_systemd_revert,
.destroy = resolve_systemd_destroy,
};
@@ -482,6 +516,7 @@ static void resolve_resolvconf_destroy(struct resolve *resolve)
static struct resolve_ops resolvconf_ops = {
.set_dns = resolve_resolvconf_set_dns,
.set_domains = resolve_resolvconf_set_domains,
+ .set_mdns = NULL,
.revert = resolve_resolvconf_revert,
.destroy = resolve_resolvconf_destroy,
};
diff --git a/src/resolve.h b/src/resolve.h
index 64ed15f3..09cd9ac2 100644
--- a/src/resolve.h
+++ b/src/resolve.h
@@ -23,5 +23,6 @@
struct resolve *resolve_new(uint32_t ifindex);
void resolve_set_dns(struct resolve *resolve, char **dns_list);
void resolve_set_domains(struct resolve *resolve, char **domain_list);
+void resolve_set_mdns(struct resolve *resolve, char *mdns);
void resolve_revert(struct resolve *resolve);
void resolve_free(struct resolve *resolve);
--
2.30.1
2 months