Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package iwd for openSUSE:Factory checked in 
at 2024-07-12 17:05:29
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/iwd (Old)
 and      /work/SRC/openSUSE:Factory/.iwd.new.17339 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "iwd"

Fri Jul 12 17:05:29 2024 rev:49 rq:1186995 version:2.19

Changes:
--------
--- /work/SRC/openSUSE:Factory/iwd/iwd.changes  2024-06-09 20:24:52.919586655 
+0200
+++ /work/SRC/openSUSE:Factory/.iwd.new.17339/iwd.changes       2024-07-12 
17:05:43.762513225 +0200
@@ -1,0 +2,7 @@
+Tue Jul  9 12:37:37 UTC 2024 - Dirk Müller <[email protected]>
+
+- update to 2.19:
+  * Fix issue with handling flush flag for external scans.
+  * Fix issue with handling SNR calculation in ranking.
+
+-------------------------------------------------------------------
@@ -21 +28 @@
-- Update to version 2.16
+- Update to version 2.16 (bsc#1221018, CVE-2024-28084):

Old:
----
  iwd-2.18.tar.sign
  iwd-2.18.tar.xz

New:
----
  iwd-2.19.tar.sign
  iwd-2.19.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ iwd.spec ++++++
--- /var/tmp/diff_new_pack.cz7TCW/_old  2024-07-12 17:05:44.454538650 +0200
+++ /var/tmp/diff_new_pack.cz7TCW/_new  2024-07-12 17:05:44.454538650 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           iwd
-Version:        2.18
+Version:        2.19
 Release:        0
 Summary:        Wireless daemon for Linux
 License:        LGPL-2.1-or-later
@@ -31,7 +31,7 @@
 BuildRequires:  pkg-config
 BuildRequires:  systemd-rpm-macros
 BuildRequires:  pkgconfig(dbus-1)
-BuildRequires:  pkgconfig(ell) >= 0.66
+BuildRequires:  pkgconfig(ell) >= 0.67
 BuildRequires:  pkgconfig(readline)
 BuildRequires:  pkgconfig(systemd)
 %{?systemd_ordering}

++++++ iwd-2.18.tar.xz -> iwd-2.19.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/ChangeLog new/iwd-2.19/ChangeLog
--- old/iwd-2.18/ChangeLog      2024-06-04 15:38:25.000000000 +0200
+++ new/iwd-2.19/ChangeLog      2024-07-08 22:13:39.000000000 +0200
@@ -1,3 +1,7 @@
+ver 2.19:
+       Fix issue with handling flush flag for external scans.
+       Fix issue with handling SNR calculation in ranking.
+
 ver 2.18:
        Fix issue with handling BSS with invalid HE capabilities.
        Fix issue with neighbor reports with invalid country codes.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/Makefile.am new/iwd-2.19/Makefile.am
--- old/iwd-2.18/Makefile.am    2024-06-04 15:38:25.000000000 +0200
+++ new/iwd-2.19/Makefile.am    2024-07-08 22:13:39.000000000 +0200
@@ -433,7 +433,7 @@
                unit/test-ie unit/test-util unit/test-ssid-security \
                unit/test-arc4 unit/test-wsc unit/test-eap-mschapv2 \
                unit/test-eap-sim unit/test-sae unit/test-p2p unit/test-band \
-               unit/test-dpp unit/test-json
+               unit/test-dpp unit/test-json unit/test-nl80211util
 endif
 
 if CLIENT
@@ -582,6 +582,13 @@
 
 unit_test_json_SOURCES = unit/test-json.c src/json.h src/json.c shared/jsmn.h
 unit_test_json_LDADD = $(ell_ldadd)
+
+unit_test_nl80211util_SOURCES = unit/test-nl80211util.c \
+                               src/nl80211util.h src/nl80211util.c \
+                               src/band.h src/band.c \
+                               src/ie.h src/ie.c \
+                               src/util.h src/util.c
+unit_test_nl80211util_LDADD = $(ell_ldadd)
 endif
 
 if CLIENT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/Makefile.in new/iwd-2.19/Makefile.in
--- old/iwd-2.18/Makefile.in    2024-06-04 15:40:47.000000000 +0200
+++ new/iwd-2.19/Makefile.in    2024-07-08 22:29:04.000000000 +0200
@@ -125,7 +125,7 @@
 @DAEMON_TRUE@          unit/test-ie unit/test-util unit/test-ssid-security \
 @DAEMON_TRUE@          unit/test-arc4 unit/test-wsc unit/test-eap-mschapv2 \
 @DAEMON_TRUE@          unit/test-eap-sim unit/test-sae unit/test-p2p 
unit/test-band \
-@DAEMON_TRUE@          unit/test-dpp unit/test-json
+@DAEMON_TRUE@          unit/test-dpp unit/test-json unit/test-nl80211util
 
 @CLIENT_TRUE@am__append_25 = unit/test-client
 @MAINTAINER_MODE_TRUE@am__append_26 = $(unit_tests)
@@ -178,7 +178,8 @@
 @DAEMON_TRUE@  unit/test-eap-mschapv2$(EXEEXT) \
 @DAEMON_TRUE@  unit/test-eap-sim$(EXEEXT) unit/test-sae$(EXEEXT) \
 @DAEMON_TRUE@  unit/test-p2p$(EXEEXT) unit/test-band$(EXEEXT) \
-@DAEMON_TRUE@  unit/test-dpp$(EXEEXT) unit/test-json$(EXEEXT)
+@DAEMON_TRUE@  unit/test-dpp$(EXEEXT) unit/test-json$(EXEEXT) \
+@DAEMON_TRUE@  unit/test-nl80211util$(EXEEXT)
 @CLIENT_TRUE@am__EXEEXT_8 = unit/test-client$(EXEEXT)
 am__EXEEXT_9 = $(am__EXEEXT_7) $(am__EXEEXT_8)
 @MAINTAINER_MODE_TRUE@am__EXEEXT_10 = $(am__EXEEXT_9)
@@ -554,6 +555,16 @@
 @DAEMON_TRUE@  src/mpdu.$(OBJEXT) src/ie.$(OBJEXT)
 unit_test_mpdu_OBJECTS = $(am_unit_test_mpdu_OBJECTS)
 @DAEMON_TRUE@unit_test_mpdu_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__unit_test_nl80211util_SOURCES_DIST = unit/test-nl80211util.c \
+       src/nl80211util.h src/nl80211util.c src/band.h src/band.c \
+       src/ie.h src/ie.c src/util.h src/util.c
+@DAEMON_TRUE@am_unit_test_nl80211util_OBJECTS =  \
+@DAEMON_TRUE@  unit/test-nl80211util.$(OBJEXT) \
+@DAEMON_TRUE@  src/nl80211util.$(OBJEXT) src/band.$(OBJEXT) \
+@DAEMON_TRUE@  src/ie.$(OBJEXT) src/util.$(OBJEXT)
+unit_test_nl80211util_OBJECTS = $(am_unit_test_nl80211util_OBJECTS)
+@DAEMON_TRUE@unit_test_nl80211util_DEPENDENCIES =  \
+@DAEMON_TRUE@  $(am__DEPENDENCIES_1)
 am__unit_test_p2p_SOURCES_DIST = unit/test-p2p.c src/wscutil.h \
        src/wscutil.c src/crypto.h src/crypto.c src/ie.h src/ie.c \
        src/util.h src/util.c src/p2putil.h src/p2putil.c src/band.h \
@@ -737,8 +748,9 @@
        unit/$(DEPDIR)/test-hmac-sha1.Po \
        unit/$(DEPDIR)/test-hmac-sha256.Po unit/$(DEPDIR)/test-ie.Po \
        unit/$(DEPDIR)/test-json.Po unit/$(DEPDIR)/test-kdf-sha256.Po \
-       unit/$(DEPDIR)/test-mpdu.Po unit/$(DEPDIR)/test-p2p.Po \
-       unit/$(DEPDIR)/test-prf-sha1.Po unit/$(DEPDIR)/test-sae.Po \
+       unit/$(DEPDIR)/test-mpdu.Po unit/$(DEPDIR)/test-nl80211util.Po \
+       unit/$(DEPDIR)/test-p2p.Po unit/$(DEPDIR)/test-prf-sha1.Po \
+       unit/$(DEPDIR)/test-sae.Po \
        unit/$(DEPDIR)/test-ssid-security.Po \
        unit/$(DEPDIR)/test-util.Po unit/$(DEPDIR)/test-wsc.Po \
        wired/$(DEPDIR)/dbus.Po wired/$(DEPDIR)/ethdev.Po \
@@ -773,10 +785,11 @@
        $(unit_test_hmac_md5_SOURCES) $(unit_test_hmac_sha1_SOURCES) \
        $(unit_test_hmac_sha256_SOURCES) $(unit_test_ie_SOURCES) \
        $(unit_test_json_SOURCES) $(unit_test_kdf_sha256_SOURCES) \
-       $(unit_test_mpdu_SOURCES) $(unit_test_p2p_SOURCES) \
-       $(unit_test_prf_sha1_SOURCES) $(unit_test_sae_SOURCES) \
-       $(unit_test_ssid_security_SOURCES) $(unit_test_util_SOURCES) \
-       $(unit_test_wsc_SOURCES) $(wired_ead_SOURCES)
+       $(unit_test_mpdu_SOURCES) $(unit_test_nl80211util_SOURCES) \
+       $(unit_test_p2p_SOURCES) $(unit_test_prf_sha1_SOURCES) \
+       $(unit_test_sae_SOURCES) $(unit_test_ssid_security_SOURCES) \
+       $(unit_test_util_SOURCES) $(unit_test_wsc_SOURCES) \
+       $(wired_ead_SOURCES)
 DIST_SOURCES = $(am__ell_libell_internal_la_SOURCES_DIST) \
        $(am__client_iwctl_SOURCES_DIST) \
        $(am__monitor_iwmon_SOURCES_DIST) $(am__src_iwd_SOURCES_DIST) \
@@ -799,6 +812,7 @@
        $(am__unit_test_json_SOURCES_DIST) \
        $(am__unit_test_kdf_sha256_SOURCES_DIST) \
        $(am__unit_test_mpdu_SOURCES_DIST) \
+       $(am__unit_test_nl80211util_SOURCES_DIST) \
        $(am__unit_test_p2p_SOURCES_DIST) \
        $(am__unit_test_prf_sha1_SOURCES_DIST) \
        $(am__unit_test_sae_SOURCES_DIST) \
@@ -1672,6 +1686,13 @@
 @DAEMON_TRUE@unit_test_dpp_LDADD = $(ell_ldadd)
 @DAEMON_TRUE@unit_test_json_SOURCES = unit/test-json.c src/json.h src/json.c 
shared/jsmn.h
 @DAEMON_TRUE@unit_test_json_LDADD = $(ell_ldadd)
+@DAEMON_TRUE@unit_test_nl80211util_SOURCES = unit/test-nl80211util.c \
+@DAEMON_TRUE@                          src/nl80211util.h src/nl80211util.c \
+@DAEMON_TRUE@                          src/band.h src/band.c \
+@DAEMON_TRUE@                          src/ie.h src/ie.c \
+@DAEMON_TRUE@                          src/util.h src/util.c
+
+@DAEMON_TRUE@unit_test_nl80211util_LDADD = $(ell_ldadd)
 @CLIENT_TRUE@unit_test_client_SOURCES = unit/test-client.c \
 @CLIENT_TRUE@                          client/adapter.c \
 @CLIENT_TRUE@                          client/agent.h client/agent.c \
@@ -2284,6 +2305,12 @@
 unit/test-mpdu$(EXEEXT): $(unit_test_mpdu_OBJECTS) 
$(unit_test_mpdu_DEPENDENCIES) $(EXTRA_unit_test_mpdu_DEPENDENCIES) 
unit/$(am__dirstamp)
        @rm -f unit/test-mpdu$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(unit_test_mpdu_OBJECTS) $(unit_test_mpdu_LDADD) 
$(LIBS)
+unit/test-nl80211util.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+
+unit/test-nl80211util$(EXEEXT): $(unit_test_nl80211util_OBJECTS) 
$(unit_test_nl80211util_DEPENDENCIES) 
$(EXTRA_unit_test_nl80211util_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-nl80211util$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_nl80211util_OBJECTS) 
$(unit_test_nl80211util_LDADD) $(LIBS)
 unit/test-p2p.$(OBJEXT): unit/$(am__dirstamp) \
        unit/$(DEPDIR)/$(am__dirstamp)
 
@@ -2530,6 +2557,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-json.Po@am__quote@ # 
am--include-marker
 @AMDEP_TRUE@@am__include@ 
@am__quote@unit/$(DEPDIR)/test-kdf-sha256.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-mpdu.Po@am__quote@ # 
am--include-marker
+@AMDEP_TRUE@@am__include@ 
@am__quote@unit/$(DEPDIR)/test-nl80211util.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-p2p.Po@am__quote@ # 
am--include-marker
 @AMDEP_TRUE@@am__include@ 
@am__quote@unit/$(DEPDIR)/test-prf-sha1.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-sae.Po@am__quote@ # 
am--include-marker
@@ -3211,6 +3239,13 @@
        --log-file $$b.log --trs-file $$b.trs \
        $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) 
-- $(LOG_COMPILE) \
        "$$tst" $(AM_TESTS_FD_REDIRECT)
+unit/test-nl80211util.log: unit/test-nl80211util$(EXEEXT)
+       @p='unit/test-nl80211util$(EXEEXT)'; \
+       b='unit/test-nl80211util'; \
+       $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+       --log-file $$b.log --trs-file $$b.trs \
+       $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) 
-- $(LOG_COMPILE) \
+       "$$tst" $(AM_TESTS_FD_REDIRECT)
 unit/test-client.log: unit/test-client$(EXEEXT)
        @p='unit/test-client$(EXEEXT)'; \
        b='unit/test-client'; \
@@ -3650,6 +3685,7 @@
        -rm -f unit/$(DEPDIR)/test-json.Po
        -rm -f unit/$(DEPDIR)/test-kdf-sha256.Po
        -rm -f unit/$(DEPDIR)/test-mpdu.Po
+       -rm -f unit/$(DEPDIR)/test-nl80211util.Po
        -rm -f unit/$(DEPDIR)/test-p2p.Po
        -rm -f unit/$(DEPDIR)/test-prf-sha1.Po
        -rm -f unit/$(DEPDIR)/test-sae.Po
@@ -3887,6 +3923,7 @@
        -rm -f unit/$(DEPDIR)/test-json.Po
        -rm -f unit/$(DEPDIR)/test-kdf-sha256.Po
        -rm -f unit/$(DEPDIR)/test-mpdu.Po
+       -rm -f unit/$(DEPDIR)/test-nl80211util.Po
        -rm -f unit/$(DEPDIR)/test-p2p.Po
        -rm -f unit/$(DEPDIR)/test-prf-sha1.Po
        -rm -f unit/$(DEPDIR)/test-sae.Po
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/configure new/iwd-2.19/configure
--- old/iwd-2.18/configure      2024-06-04 15:40:42.000000000 +0200
+++ new/iwd-2.19/configure      2024-07-08 22:28:59.000000000 +0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for iwd 2.18.
+# Generated by GNU Autoconf 2.71 for iwd 2.19.
 #
 #
 # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -618,8 +618,8 @@
 # Identity of this package.
 PACKAGE_NAME='iwd'
 PACKAGE_TARNAME='iwd'
-PACKAGE_VERSION='2.18'
-PACKAGE_STRING='iwd 2.18'
+PACKAGE_VERSION='2.19'
+PACKAGE_STRING='iwd 2.19'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1433,7 +1433,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures iwd 2.18 to adapt to many kinds of systems.
+\`configure' configures iwd 2.19 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1504,7 +1504,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of iwd 2.18:";;
+     short | recursive ) echo "Configuration of iwd 2.19:";;
    esac
   cat <<\_ACEOF
 
@@ -1661,7 +1661,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-iwd configure 2.18
+iwd configure 2.19
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1879,7 +1879,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by iwd $as_me 2.18, which was
+It was created by iwd $as_me 2.19, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3154,7 +3154,7 @@
 
 # Define the identity of the package.
  PACKAGE='iwd'
- VERSION='2.18'
+ VERSION='2.19'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -14236,7 +14236,7 @@
                        test "${enable_monitor}" != "no" ||
                        test "${enable_wired}" = "yes" ||
                        test "${enable_hwsim}" = "yes"); then
-               ell_min_version="0.66"
+               ell_min_version="0.67"
        else
                ell_min_version="0.5"
        fi
@@ -14984,7 +14984,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by iwd $as_me 2.18, which was
+This file was extended by iwd $as_me 2.19, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -15052,7 +15052,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-iwd config.status 2.18
+iwd config.status 2.19
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/configure.ac new/iwd-2.19/configure.ac
--- old/iwd-2.18/configure.ac   2024-06-04 15:38:25.000000000 +0200
+++ new/iwd-2.19/configure.ac   2024-07-08 22:13:39.000000000 +0200
@@ -1,5 +1,5 @@
 AC_PREREQ([2.69])
-AC_INIT([iwd],[2.18])
+AC_INIT([iwd],[2.19])
 
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_AUX_DIR(build-aux)
@@ -297,7 +297,7 @@
                        test "${enable_monitor}" != "no" ||
                        test "${enable_wired}" = "yes" ||
                        test "${enable_hwsim}" = "yes"); then
-               ell_min_version="0.66"
+               ell_min_version="0.67"
        else
                ell_min_version="0.5"
        fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/ell/genl.c new/iwd-2.19/ell/genl.c
--- old/iwd-2.18/ell/genl.c     2023-11-19 18:31:06.000000000 +0100
+++ new/iwd-2.19/ell/genl.c     2024-07-08 19:33:06.000000000 +0200
@@ -20,6 +20,7 @@
 #include "io.h"
 #include "private.h"
 #include "netlink-private.h"
+#include "notifylist.h"
 #include "genl.h"
 
 #define MAX_NESTING_LEVEL 4
@@ -33,11 +34,9 @@
 };
 
 struct unicast_watch {
-       uint32_t id;
+       struct l_notifylist_entry super;
        char name[GENL_NAMSIZ];
        l_genl_msg_func_t handler;
-       void *user_data;
-       l_genl_destroy_func_t destroy;
 };
 
 struct family_watch {
@@ -69,7 +68,7 @@
        unsigned int next_notify_id;
        struct genl_discovery *discovery;
        uint32_t next_watch_id;
-       struct l_queue *unicast_watches;
+       struct l_notifylist *unicast_watches;
        struct l_queue *family_watches;
        struct l_queue *family_infos;
        struct l_genl_family *nlctrl;
@@ -449,32 +448,38 @@
        return info->version;
 }
 
-static void unicast_watch_free(void *data)
+static void unicast_watch_free(struct l_notifylist_entry *e)
 {
-       struct unicast_watch *watch = data;
-
-       if (watch->destroy)
-               watch->destroy(watch->user_data);
-
+       struct unicast_watch *watch =
+                       l_container_of(e, struct unicast_watch, super);
        l_free(watch);
 }
 
-static bool unicast_watch_match(const void *a, const void *b)
+static void unicast_watch_notify(const struct l_notifylist_entry *e,
+                                               int type, va_list args)
 {
-       const struct unicast_watch *watch = a;
-       uint32_t id = L_PTR_TO_UINT(b);
+       const struct unicast_watch *watch =
+                       l_container_of(e, struct unicast_watch, super);
 
-       return watch->id == id;
+       if (!watch->handler)
+               return;
+
+       watch->handler(va_arg(args, struct l_genl_msg *),
+                       watch->super.notify_data);
 }
 
-static void unicast_watch_prune(struct l_genl *genl)
+static struct l_notifylist_ops unicast_watch_ops = {
+       .free_entry = unicast_watch_free,
+       .notify = unicast_watch_notify,
+};
+
+static bool unicast_watch_match_name(const struct l_notifylist_entry *e,
+                                       const void *user)
 {
-       struct unicast_watch *watch;
+       struct unicast_watch *watch =
+                       l_container_of(e, struct unicast_watch, super);
 
-       while ((watch = l_queue_remove_if(genl->unicast_watches,
-                                               unicast_watch_match,
-                                               L_UINT_TO_PTR(0))))
-               unicast_watch_free(watch);
+       return !strncmp(watch->name, user, GENL_NAMSIZ);
 }
 
 static void family_watch_free(void *data)
@@ -870,39 +875,6 @@
        return request->seq == seq;
 }
 
-static void dispatch_unicast_watches(struct l_genl *genl, uint16_t id,
-                                                       struct l_genl_msg *msg)
-{
-       const struct l_queue_entry *entry;
-       struct l_genl_family_info *info = l_queue_find(genl->family_infos,
-                                                       family_info_match,
-                                                       L_UINT_TO_PTR(id));
-
-       if (!info)
-               return;
-
-       genl->in_unicast_watch_notify = true;
-
-       for (entry = l_queue_get_entries(genl->unicast_watches);
-                                               entry; entry = entry->next) {
-               struct unicast_watch *watch = entry->data;
-
-               if (!watch->id)
-                       continue;
-
-               if (!watch->handler)
-                       continue;
-
-               if (strncmp(watch->name, info->name, GENL_NAMSIZ))
-                       continue;
-
-               watch->handler(msg, watch->user_data);
-       }
-
-       genl->in_unicast_watch_notify = false;
-       unicast_watch_prune(genl);
-}
-
 static void process_unicast(struct l_genl *genl, const struct nlmsghdr *nlmsg)
 {
        struct l_genl_msg *msg;
@@ -914,8 +886,15 @@
 
        msg = msg_create(nlmsg);
        if (!nlmsg->nlmsg_seq) {
-               if (msg)
-                       dispatch_unicast_watches(genl, nlmsg->nlmsg_type, msg);
+               struct l_genl_family_info *info =
+                       l_queue_find(genl->family_infos, family_info_match,
+                                       L_UINT_TO_PTR(nlmsg->nlmsg_type));
+
+               if (info && msg)
+                       l_notifylist_notify_matches(genl->unicast_watches,
+                                               unicast_watch_match_name,
+                                               info->name, 0, msg);
+
                goto done;
        }
 
@@ -1107,7 +1086,7 @@
        genl->notify_list = l_queue_new();
        genl->family_watches = l_queue_new();
        genl->family_infos = l_queue_new();
-       genl->unicast_watches = l_queue_new();
+       genl->unicast_watches = l_notifylist_new(&unicast_watch_ops);
 
        l_queue_push_head(genl->family_infos, build_nlctrl_info());
 
@@ -1150,7 +1129,7 @@
 
        l_genl_family_free(genl->nlctrl);
 
-       l_queue_destroy(genl->unicast_watches, unicast_watch_free);
+       l_notifylist_free(genl->unicast_watches);
        l_queue_destroy(genl->family_watches, family_watch_free);
        l_queue_destroy(genl->family_infos, family_info_free);
        l_queue_destroy(genl->notify_list, mcast_notify_free);
@@ -1285,12 +1264,10 @@
        watch = l_new(struct unicast_watch, 1);
        l_strlcpy(watch->name, family, GENL_NAMSIZ);
        watch->handler = handler;
-       watch->destroy = destroy;
-       watch->user_data = user_data;
-       watch->id = get_next_id(&genl->next_watch_id);
-       l_queue_push_tail(genl->unicast_watches, watch);
+       watch->super.destroy = destroy;
+       watch->super.notify_data = user_data;
 
-       return watch->id;
+       return l_notifylist_add(genl->unicast_watches, &watch->super);
 }
 
 /**
@@ -1306,29 +1283,10 @@
 LIB_EXPORT bool l_genl_remove_unicast_watch(struct l_genl *genl,
                                                        unsigned int id)
 {
-       struct unicast_watch *watch;
-
        if (unlikely(!genl))
                return false;
 
-       if (genl->in_unicast_watch_notify) {
-               watch = l_queue_find(genl->unicast_watches, unicast_watch_match,
-                                                       L_UINT_TO_PTR(id));
-               if (!watch)
-                       return false;
-
-               watch->id = 0;
-               return true;
-       }
-
-       watch = l_queue_remove_if(genl->unicast_watches, unicast_watch_match,
-                                                       L_UINT_TO_PTR(id));
-       if (!watch)
-               return false;
-
-       unicast_watch_free(watch);
-
-       return true;
+       return l_notifylist_remove(genl->unicast_watches, id);
 }
 
 /**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/ell/sysctl.c new/iwd-2.19/ell/sysctl.c
--- old/iwd-2.18/ell/sysctl.c   2023-09-27 11:03:04.000000000 +0200
+++ new/iwd-2.19/ell/sysctl.c   2024-07-08 19:33:06.000000000 +0200
@@ -95,3 +95,27 @@
 
        return sysctl_write(filename, valuestr, len);
 }
+
+LIB_EXPORT int l_sysctl_get_char(char *out_c, const char *format, ...)
+{
+       _auto_(l_free) char *filename = NULL;
+       va_list ap;
+
+       va_start(ap, format);
+       filename = l_strdup_vprintf(format, ap);
+       va_end(ap);
+
+       return sysctl_read(filename, out_c, sizeof(char));
+}
+
+LIB_EXPORT int l_sysctl_set_char(char c, const char *format, ...)
+{
+       _auto_(l_free) char *filename = NULL;
+       va_list ap;
+
+       va_start(ap, format);
+       filename = l_strdup_vprintf(format, ap);
+       va_end(ap);
+
+       return sysctl_write(filename, &c, sizeof(char));
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/ell/sysctl.h new/iwd-2.19/ell/sysctl.h
--- old/iwd-2.18/ell/sysctl.h   2023-09-27 11:03:04.000000000 +0200
+++ new/iwd-2.19/ell/sysctl.h   2024-07-08 19:33:06.000000000 +0200
@@ -20,6 +20,11 @@
 int l_sysctl_set_u32(uint32_t v, const char *format, ...)
                        __attribute__((format(printf, 2, 3)));
 
+int l_sysctl_get_char(char *out_c, const char *format, ...)
+                       __attribute__((format(printf, 2, 3)));
+int l_sysctl_set_char(char c, const char *format, ...)
+                       __attribute__((format(printf, 2, 3)));
+
 #ifdef __cplusplus
 }
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/src/netdev.c new/iwd-2.19/src/netdev.c
--- old/iwd-2.18/src/netdev.c   2024-03-29 00:27:27.000000000 +0100
+++ new/iwd-2.19/src/netdev.c   2024-07-08 22:13:39.000000000 +0200
@@ -1328,12 +1328,10 @@
 static void netdev_deauthenticate_event(struct l_genl_msg *msg,
                                                        struct netdev *netdev)
 {
-       struct l_genl_attr attr;
-       uint16_t type, len;
-       const void *data;
        const struct mmpdu_header *hdr = NULL;
        const struct mmpdu_deauthentication *deauth;
        uint16_t reason_code;
+       struct iovec iov;
 
        l_debug("");
 
@@ -1349,17 +1347,11 @@
         * deauthenticating immediately afterwards
         */
 
-       if (L_WARN_ON(!l_genl_attr_init(&attr, msg)))
+       if (L_WARN_ON(nl80211_parse_attrs(msg, NL80211_ATTR_FRAME, &iov,
+                                               NL80211_ATTR_UNSPEC) < 0))
                return;
 
-       while (l_genl_attr_next(&attr, &type, &len, &data)) {
-               switch (type) {
-               case NL80211_ATTR_FRAME:
-                       hdr = mpdu_validate(data, len);
-                       break;
-               }
-       }
-
+       hdr = mpdu_validate(iov.iov_base, iov.iov_len);
        if (L_WARN_ON(!hdr))
                return;
 
@@ -2430,10 +2422,6 @@
 {
        netdev->connected = true;
 
-       if (netdev->event_filter)
-               netdev->event_filter(netdev, NETDEV_EVENT_ASSOCIATING, NULL,
-                                       netdev->user_data);
-
        /*
         * We register the eapol state machine here, in case the PAE
         * socket receives EAPoL packets before the nl80211 socket
@@ -2898,7 +2886,7 @@
 
 static void netdev_ensure_eapol_registered(struct netdev *netdev)
 {
-       if (L_WARN_ON(netdev->sm))
+       if (netdev->sm)
                return;
 
        netdev->sm = eapol_sm_new(netdev->handshake);
@@ -2927,6 +2915,10 @@
                return;
        }
 
+       if (netdev->event_filter)
+               netdev->event_filter(netdev, NETDEV_EVENT_AUTHENTICATING,
+                                       NULL, netdev->user_data);
+
        /*
         * During Fast Transition we use the authenticate event to start the
         * reassociation step because the FTE necessary before we can build
@@ -3048,6 +3040,10 @@
        if (!netdev->connected || netdev->aborting)
                return;
 
+       if (netdev->event_filter)
+               netdev->event_filter(netdev, NETDEV_EVENT_ASSOCIATING,
+                                       NULL, netdev->user_data);
+
        if (!netdev->ap && !netdev->in_ft) {
                netdev->associated = true;
                netdev->in_reassoc = false;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/src/nl80211util.c 
new/iwd-2.19/src/nl80211util.c
--- old/iwd-2.18/src/nl80211util.c      2024-03-04 08:53:21.000000000 +0100
+++ new/iwd-2.19/src/nl80211util.c      2024-07-08 22:13:39.000000000 +0200
@@ -37,6 +37,7 @@
 #include "src/util.h"
 
 typedef bool (*attr_handler)(const void *data, uint16_t len, void *o);
+typedef attr_handler (*handler_for_type)(int type);
 
 static bool extract_ifindex(const void *data, uint16_t len, void *o)
 {
@@ -150,7 +151,7 @@
        return true;
 }
 
-static attr_handler handler_for_type(enum nl80211_attrs type)
+static attr_handler handler_for_nl80211(int type)
 {
        switch (type) {
        case NL80211_ATTR_IFINDEX:
@@ -158,6 +159,7 @@
        case NL80211_ATTR_WIPHY:
        case NL80211_ATTR_IFTYPE:
        case NL80211_ATTR_KEY_TYPE:
+       case NL80211_ATTR_SCAN_FLAGS:
                return extract_uint32;
        case NL80211_ATTR_WDEV:
        case NL80211_ATTR_COOKIE:
@@ -181,6 +183,8 @@
        case NL80211_ATTR_FRAME:
                return extract_iovec;
        case NL80211_ATTR_WIPHY_BANDS:
+       case NL80211_ATTR_SURVEY_INFO:
+       case NL80211_ATTR_KEY:
                return extract_nested;
        case NL80211_ATTR_KEY_IDX:
                return extract_u8;
@@ -191,6 +195,32 @@
        return NULL;
 }
 
+static attr_handler handler_for_survey_info(int type)
+{
+       switch (type) {
+       case NL80211_SURVEY_INFO_NOISE:
+               return extract_u8;
+       case NL80211_SURVEY_INFO_FREQUENCY:
+               return extract_uint32;
+       default:
+               break;
+       }
+
+       return NULL;
+}
+
+static attr_handler handler_for_key(int type)
+{
+       switch (type) {
+       case NL80211_KEY_SEQ:
+               return extract_iovec;
+       default:
+               break;
+       }
+
+       return NULL;
+}
+
 struct attr_entry {
        uint16_t type;
        void *data;
@@ -198,10 +228,9 @@
        bool present : 1;
 };
 
-int nl80211_parse_attrs(struct l_genl_msg *msg, int tag, ...)
+static int parse_attrs(struct l_genl_attr *attr, handler_for_type handler,
+                       int tag, va_list args)
 {
-       struct l_genl_attr attr;
-       va_list args;
        struct l_queue *entries;
        const struct l_queue_entry *e;
        struct attr_entry *entry;
@@ -210,10 +239,6 @@
        const void *data;
        int ret;
 
-       if (!l_genl_attr_init(&attr, msg))
-               return -EINVAL;
-
-       va_start(args, tag);
        entries = l_queue_new();
        ret = -ENOSYS;
 
@@ -222,7 +247,7 @@
 
                entry->type = tag;
                entry->data = va_arg(args, void *);
-               entry->handler = handler_for_type(tag);
+               entry->handler = handler(tag);
                l_queue_push_tail(entries, entry);
 
                if (!entry->handler)
@@ -231,9 +256,7 @@
                tag = va_arg(args, enum nl80211_attrs);
        }
 
-       va_end(args);
-
-       while (l_genl_attr_next(&attr, &type, &len, &data)) {
+       while (l_genl_attr_next(attr, &type, &len, &data)) {
                for (e = l_queue_get_entries(entries); e; e = e->next) {
                        entry = e->data;
 
@@ -251,7 +274,7 @@
 
                /* For nested attributes use the outer attribute as data */
                if (entry->handler == extract_nested)
-                       data = &attr;
+                       data = attr;
 
                if (!entry->handler(data, len, entry->data)) {
                        ret = -EINVAL;
@@ -284,6 +307,50 @@
        return ret;
 }
 
+int nl80211_parse_attrs(struct l_genl_msg *msg, int tag, ...)
+{
+       struct l_genl_attr attr;
+       va_list args;
+       int ret;
+
+       if (!l_genl_attr_init(&attr, msg))
+               return -EINVAL;
+
+       va_start(args, tag);
+
+       ret = parse_attrs(&attr, handler_for_nl80211, tag, args);
+
+       va_end(args);
+
+       return ret;
+}
+
+int nl80211_parse_nested(struct l_genl_attr *attr, int type, int tag, ...)
+{
+       handler_for_type handler;
+       va_list args;
+       int ret;
+
+       switch (type) {
+       case NL80211_ATTR_SURVEY_INFO:
+               handler = handler_for_survey_info;
+               break;
+       case NL80211_ATTR_KEY:
+               handler = handler_for_key;
+               break;
+       default:
+               return -ENOTSUP;
+       }
+
+       va_start(args, tag);
+
+       ret = parse_attrs(attr, handler, tag, args);
+
+       va_end(args);
+
+       return ret;
+}
+
 struct l_genl_msg *nl80211_build_deauthenticate(uint32_t ifindex,
                                                const uint8_t addr[static 6],
                                                uint16_t reason_code)
@@ -517,46 +584,29 @@
 
 const void *nl80211_parse_get_key_seq(struct l_genl_msg *msg)
 {
-       struct l_genl_attr attr, nested;
-       uint16_t type, len;
-       const void *data;
+       struct l_genl_attr nested;
+       struct iovec iov;
 
-       if (l_genl_msg_get_error(msg) < 0 || !l_genl_attr_init(&attr, msg)) {
+       if (l_genl_msg_get_error(msg) < 0 ||
+                       nl80211_parse_attrs(msg, NL80211_ATTR_KEY, &nested,
+                                               NL80211_ATTR_UNSPEC) < 0) {
                l_error("GET_KEY failed for the GTK: %i",
                        l_genl_msg_get_error(msg));
                return NULL;
        }
 
-       while (l_genl_attr_next(&attr, &type, &len, &data)) {
-               if (type != NL80211_ATTR_KEY)
-                       continue;
-
-               break;
-       }
-
-       if (type != NL80211_ATTR_KEY || !l_genl_attr_recurse(&attr, &nested)) {
+       if (nl80211_parse_nested(&nested, NL80211_ATTR_KEY, NL80211_KEY_SEQ,
+                                       &iov, NL80211_ATTR_UNSPEC)) {
                l_error("Can't recurse into ATTR_KEY in GET_KEY reply");
                return NULL;
        }
 
-       while (l_genl_attr_next(&nested, &type, &len, &data)) {
-               if (type != NL80211_KEY_SEQ)
-                       continue;
-
-               break;
-       }
-
-       if (type != NL80211_KEY_SEQ) {
-               l_error("KEY_SEQ not returned in GET_KEY reply");
-               return NULL;
-       }
-
-       if (len != 6) {
+       if (iov.iov_len != 6) {
                l_error("KEY_SEQ length != 6 in GET_KEY reply");
                return NULL;
        }
 
-       return data;
+       return iov.iov_base;
 }
 
 struct l_genl_msg *nl80211_build_cmd_frame(uint32_t ifindex,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/src/nl80211util.h 
new/iwd-2.19/src/nl80211util.h
--- old/iwd-2.18/src/nl80211util.h      2023-11-27 17:00:15.000000000 +0100
+++ new/iwd-2.19/src/nl80211util.h      2024-07-08 22:13:39.000000000 +0200
@@ -28,6 +28,7 @@
 struct handshake_state;
 
 int nl80211_parse_attrs(struct l_genl_msg *msg, int tag, ...);
+int nl80211_parse_nested(struct l_genl_attr *attr, int type, int tag, ...);
 
 struct l_genl_msg *nl80211_build_deauthenticate(uint32_t ifindex,
                                                const uint8_t addr[static 6],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/src/scan.c new/iwd-2.19/src/scan.c
--- old/iwd-2.18/src/scan.c     2024-06-04 15:38:25.000000000 +0200
+++ new/iwd-2.19/src/scan.c     2024-07-08 22:13:39.000000000 +0200
@@ -132,6 +132,18 @@
         */
        unsigned int get_fw_scan_cmd_id;
        struct wiphy *wiphy;
+
+       unsigned int get_survey_cmd_id;
+};
+
+struct scan_survey {
+       int8_t noise;
+};
+
+struct scan_survey_results {
+       struct scan_survey survey_2_4[14];
+       struct scan_survey survey_5[196];
+       struct scan_survey survey_6[233];
 };
 
 struct scan_results {
@@ -140,6 +152,9 @@
        uint64_t time_stamp;
        struct scan_request *sr;
        struct scan_freq_set *freqs;
+       struct scan_survey_results survey;
+
+       bool survey_parsed : 1;
 };
 
 static bool start_next_scan_request(struct wiphy_radio_work_item *item);
@@ -217,6 +232,9 @@
        if (sc->get_fw_scan_cmd_id && nl80211)
                l_genl_family_cancel(nl80211, sc->get_fw_scan_cmd_id);
 
+       if (sc->get_survey_cmd_id && nl80211)
+               l_genl_family_cancel(nl80211, sc->get_survey_cmd_id);
+
        wiphy_state_watch_remove(sc->wiphy, sc->wiphy_watch_id);
 
        l_free(sc);
@@ -1326,6 +1344,8 @@
                                                NULL) < 0)
                                l_warn("Unable to parse BSS Load IE for "
                                        MAC, MAC_STR(bss->addr));
+                       else
+                               bss->have_utilization = true;
 
                        break;
                case IE_TYPE_VENDOR_SPECIFIC:
@@ -1515,7 +1535,6 @@
        size_t beacon_ies_len;
 
        bss = l_new(struct scan_bss, 1);
-       bss->utilization = 127;
        bss->source_frame = SCAN_BSS_BEACON;
 
        while (l_genl_attr_next(attr, &type, &len, &data)) {
@@ -1663,6 +1682,8 @@
 {
        static const double RANK_HIGH_UTILIZATION_FACTOR = 0.8;
        static const double RANK_LOW_UTILIZATION_FACTOR = 1.2;
+       static const double RANK_HIGH_SNR_FACTOR = 1.2;
+       static const double RANK_LOW_SNR_FACTOR = 0.8;
        double rank;
        uint32_t irank;
        /*
@@ -1684,10 +1705,19 @@
                rank *= RANK_6G_FACTOR;
 
        /* Rank loaded APs lower and lightly loaded APs higher */
-       if (bss->utilization >= 192)
-               rank *= RANK_HIGH_UTILIZATION_FACTOR;
-       else if (bss->utilization <= 63)
-               rank *= RANK_LOW_UTILIZATION_FACTOR;
+       if (bss->have_utilization) {
+               if (bss->utilization >= 192)
+                       rank *= RANK_HIGH_UTILIZATION_FACTOR;
+               else if (bss->utilization <= 63)
+                       rank *= RANK_LOW_UTILIZATION_FACTOR;
+       }
+
+       if (bss->have_snr) {
+               if (bss->snr <= 15)
+                       rank *= RANK_LOW_SNR_FACTOR;
+               else if (bss->snr >= 30)
+                       rank *= RANK_HIGH_SNR_FACTOR;
+       }
 
        irank = rank;
 
@@ -1707,7 +1737,6 @@
 
        bss = l_new(struct scan_bss, 1);
        memcpy(bss->addr, mpdu->address_2, 6);
-       bss->utilization = 127;
        bss->source_frame = SCAN_BSS_PROBE_REQ;
        bss->frequency = frequency;
        bss->signal_strength = rssi;
@@ -1824,6 +1853,41 @@
        return (bss->rank > new_bss->rank) ? 1 : -1;
 }
 
+static bool scan_survey_get_snr(struct scan_results *results,
+                                       uint32_t freq, int32_t signal,
+                                       int8_t *snr)
+{
+       uint8_t channel;
+       enum band_freq band;
+       int8_t noise = 0;
+
+       if (!results->survey_parsed)
+               return false;
+
+       channel = band_freq_to_channel(freq, &band);
+       if (L_WARN_ON(!channel))
+               return false;
+
+       switch (band) {
+       case BAND_FREQ_2_4_GHZ:
+               noise = results->survey.survey_2_4[channel].noise;
+               break;
+       case BAND_FREQ_5_GHZ:
+               noise = results->survey.survey_5[channel].noise;
+               break;
+       case BAND_FREQ_6_GHZ:
+               noise = results->survey.survey_6[channel].noise;
+               break;
+       }
+
+       if (noise) {
+               *snr = signal - noise;
+               return true;
+       }
+
+       return false;
+}
+
 static void get_scan_callback(struct l_genl_msg *msg, void *user_data)
 {
        struct scan_results *results = user_data;
@@ -1849,6 +1913,10 @@
                bss->time_stamp = results->time_stamp -
                                        seen_ms_ago * L_USEC_PER_MSEC;
 
+       bss->have_snr = scan_survey_get_snr(results, bss->frequency,
+                                               bss->signal_strength / 100,
+                                               &bss->snr);
+
        scan_bss_compute_rank(bss);
        l_queue_insert(results->bss_list, bss, scan_bss_rank_compare, NULL);
 }
@@ -1925,11 +1993,88 @@
        l_free(results);
 }
 
+static void get_survey_callback(struct l_genl_msg *msg, void *user_data)
+{
+       struct scan_results *results = user_data;
+       struct scan_survey_results *survey = &results->survey;
+       struct l_genl_attr attr;
+       uint32_t freq;
+       int8_t noise;
+       uint8_t channel;
+       enum band_freq band;
+
+       if (nl80211_parse_attrs(msg, NL80211_ATTR_SURVEY_INFO, &attr,
+                               NL80211_ATTR_UNSPEC) < 0)
+               return;
+
+       if (nl80211_parse_nested(&attr, NL80211_ATTR_SURVEY_INFO,
+                                       NL80211_SURVEY_INFO_FREQUENCY, &freq,
+                                       NL80211_SURVEY_INFO_NOISE, &noise,
+                                       NL80211_ATTR_UNSPEC) < 0)
+               return;
+
+       channel = band_freq_to_channel(freq, &band);
+       if (!channel)
+               return;
+
+       /* At least one frequency was surveyed */
+       results->survey_parsed = true;
+
+       switch (band) {
+       case BAND_FREQ_2_4_GHZ:
+               survey->survey_2_4[channel].noise = noise;
+               break;
+       case BAND_FREQ_5_GHZ:
+               survey->survey_5[channel].noise = noise;
+               break;
+       case BAND_FREQ_6_GHZ:
+               survey->survey_6[channel].noise = noise;
+               break;
+       }
+}
+
+static void get_results(struct scan_results *results)
+{
+       struct l_genl_msg *scan_msg;
+
+       scan_msg = l_genl_msg_new_sized(NL80211_CMD_GET_SCAN, 8);
+
+       l_genl_msg_append_attr(scan_msg, NL80211_ATTR_WDEV, 8,
+                                       &results->sc->wdev_id);
+       results->sc->get_scan_cmd_id = l_genl_family_dump(nl80211, scan_msg,
+                                               get_scan_callback,
+                                               results, get_scan_done);
+}
+
+static void get_survey_done(void *user_data)
+{
+       struct scan_results *results = user_data;
+       struct scan_context *sc = results->sc;
+
+       sc->get_survey_cmd_id = 0;
+
+       get_results(results);
+}
+
+static bool scan_survey(struct scan_results *results)
+{
+       struct scan_context *sc = results->sc;
+       struct l_genl_msg *survey_msg;
+
+       survey_msg = l_genl_msg_new(NL80211_CMD_GET_SURVEY);
+       l_genl_msg_append_attr(survey_msg, NL80211_ATTR_WDEV, 8,
+                               &sc->wdev_id);
+       sc->get_survey_cmd_id = l_genl_family_dump(nl80211, survey_msg,
+                                               get_survey_callback, results,
+                                               get_survey_done);
+
+       return sc->get_survey_cmd_id != 0;
+}
+
 static void scan_get_results(struct scan_context *sc, struct scan_request *sr,
                                struct scan_freq_set *freqs)
 {
        struct scan_results *results;
-       struct l_genl_msg *scan_msg;
 
        results = l_new(struct scan_results, 1);
        results->sc = sc;
@@ -1938,13 +2083,12 @@
        results->bss_list = l_queue_new();
        results->freqs = freqs;
 
-       scan_msg = l_genl_msg_new_sized(NL80211_CMD_GET_SCAN, 8);
+       if (scan_survey(results))
+               return;
+       else
+               l_warn("failed to start a scan survey");
 
-       l_genl_msg_append_attr(scan_msg, NL80211_ATTR_WDEV, 8,
-                                       &sc->wdev_id);
-       sc->get_scan_cmd_id = l_genl_family_dump(nl80211, scan_msg,
-                                               get_scan_callback,
-                                               results, get_scan_done);
+       get_results(results);
 }
 
 static void scan_wiphy_watch(struct wiphy *wiphy,
@@ -2021,16 +2165,14 @@
 
 static bool scan_parse_flush_flag_from_msg(struct l_genl_msg *msg)
 {
-       struct l_genl_attr attr;
-       uint16_t type, len;
-       const void *data;
+       uint32_t flags;
 
-       if (!l_genl_attr_init(&attr, msg))
+       if (nl80211_parse_attrs(msg, NL80211_ATTR_SCAN_FLAGS, &flags,
+                                       NL80211_ATTR_UNSPEC) < 0)
                return false;
 
-       while (l_genl_attr_next(&attr, &type, &len, &data))
-               if (type == NL80211_SCAN_FLAG_FLUSH)
-                       return true;
+       if (flags & NL80211_SCAN_FLAG_FLUSH)
+               return true;
 
        return false;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/src/scan.h new/iwd-2.19/src/scan.h
--- old/iwd-2.18/src/scan.h     2024-06-04 15:38:25.000000000 +0200
+++ new/iwd-2.19/src/scan.h     2024-07-08 22:13:39.000000000 +0200
@@ -75,6 +75,7 @@
        uint64_t parent_tsf;
        uint8_t *wfd;           /* Concatenated WFD IEs */
        ssize_t wfd_size;       /* Size of Concatenated WFD IEs */
+       int8_t snr;
        bool mde_present : 1;
        bool cc_present : 1;
        bool cap_rm_neighbor_report : 1;
@@ -89,6 +90,8 @@
        bool dpp_configurator : 1;
        bool sae_pw_id_used : 1;
        bool sae_pw_id_exclusive : 1;
+       bool have_snr : 1;
+       bool have_utilization : 1;
 };
 
 struct scan_parameters {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/src/station.c new/iwd-2.19/src/station.c
--- old/iwd-2.18/src/station.c  2024-03-04 08:53:21.000000000 +0100
+++ new/iwd-2.19/src/station.c  2024-07-08 22:13:39.000000000 +0200
@@ -402,6 +402,27 @@
        return (bss->signal_strength > new_bss->signal_strength) ? 1 : -1;
 }
 
+static void station_print_scan_bss(const struct scan_bss *bss)
+{
+       uint32_t kbps100 = DIV_ROUND_CLOSEST(bss->data_rate, 100000);
+       char optional[64] = {0};
+       char *ptr = optional;
+
+       if (bss->have_snr)
+               ptr += sprintf(ptr, ", snr: %d", bss->snr);
+
+       if (bss->have_utilization)
+               ptr += sprintf(ptr, ", load: %u/255", bss->utilization);
+
+       l_debug("Processing BSS '%s' with SSID: %s, freq: %u, rank: %u, "
+                       "strength: %i, data_rate: %u.%u%s",
+                       util_address_to_string(bss->addr),
+                       util_ssid_to_utf8(bss->ssid_len, bss->ssid),
+                       bss->frequency, bss->rank, bss->signal_strength,
+                       kbps100 / 10, kbps100 % 10,
+                       optional);
+}
+
 /*
  * Returns the network object the BSS was added to or NULL if ignored.
  */
@@ -412,14 +433,8 @@
        enum security security;
        const char *path;
        char ssid[33];
-       uint32_t kbps100 = DIV_ROUND_CLOSEST(bss->data_rate, 100000);
 
-       l_debug("Processing BSS '%s' with SSID: %s, freq: %u, rank: %u, "
-                       "strength: %i, data_rate: %u.%u",
-                       util_address_to_string(bss->addr),
-                       util_ssid_to_utf8(bss->ssid_len, bss->ssid),
-                       bss->frequency, bss->rank, bss->signal_strength,
-                       kbps100 / 10, kbps100 % 10);
+       station_print_scan_bss(bss);
 
        if (util_ssid_is_hidden(bss->ssid_len, bss->ssid)) {
                l_debug("BSS has hidden SSID");
@@ -2434,6 +2449,8 @@
                goto done;
        }
 
+       station_debug_event(station, "ft-authenticating");
+
        if (station->connected_bss->frequency == bss->frequency) {
                ft_authenticate_onchannel(netdev_get_ifindex(station->netdev),
                                                bss);
@@ -2655,15 +2672,9 @@
 
        while ((bss = l_queue_pop_head(bss_list))) {
                double rank;
-               uint32_t kbps100 = DIV_ROUND_CLOSEST(bss->data_rate, 100000);
                struct roam_bss *rbss;
 
-               l_debug("Processing BSS '%s' with SSID: %s, freq: %u, rank: %u,"
-                               " strength: %i, data_rate: %u.%u",
-                               util_address_to_string(bss->addr),
-                               util_ssid_to_utf8(bss->ssid_len, bss->ssid),
-                               bss->frequency, bss->rank, bss->signal_strength,
-                               kbps100 / 10, kbps100 % 10);
+               station_print_scan_bss(bss);
 
                /* Skip the BSS we are connected to */
                if (!memcmp(bss->addr, station->connected_bss->addr, 6))
@@ -3477,10 +3488,10 @@
 
        switch (event) {
        case NETDEV_EVENT_AUTHENTICATING:
-               l_debug("Authenticating");
+               station_debug_event(station, "authenticating");
                break;
        case NETDEV_EVENT_ASSOCIATING:
-               l_debug("Associating");
+               station_debug_event(station, "associating");
                break;
        case NETDEV_EVENT_DISCONNECT_BY_AP:
        case NETDEV_EVENT_DISCONNECT_BY_SME:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.18/unit/test-nl80211util.c 
new/iwd-2.19/unit/test-nl80211util.c
--- old/iwd-2.18/unit/test-nl80211util.c        1970-01-01 01:00:00.000000000 
+0100
+++ new/iwd-2.19/unit/test-nl80211util.c        2024-07-08 22:13:39.000000000 
+0200
@@ -0,0 +1,63 @@
+
+#include <assert.h>
+#include <ell/ell.h>
+#include "src/nl80211util.h"
+#include "linux/nl80211.h"
+
+static void test_parse_attrs(const void *data)
+{
+       struct l_genl_msg *msg = l_genl_msg_new(NL80211_CMD_NEW_INTERFACE);
+       uint32_t ifindex = 1;
+       uint32_t freq = 2;
+       int ret;
+
+       l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
+       l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY_FREQ, 4, &freq);
+
+       ret = nl80211_parse_attrs(msg, NL80211_ATTR_IFINDEX, &ifindex,
+                                       NL80211_ATTR_WIPHY_FREQ, &freq,
+                                       NL80211_ATTR_UNSPEC);
+       l_genl_msg_unref(msg);
+       assert(ret == 0);
+}
+
+static void test_parse_nested(const void *data)
+{
+       struct l_genl_msg *msg = l_genl_msg_new(NL80211_CMD_NEW_INTERFACE);
+       uint32_t ifindex = 1;
+       uint32_t freq = 2;
+       uint8_t noise = 3;
+       uint8_t noise_out;
+       struct l_genl_attr nested;
+       int ret;
+       int ret_nested;
+
+       l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
+       l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY_FREQ, 4, &freq);
+
+       l_genl_msg_enter_nested(msg, NL80211_ATTR_SURVEY_INFO);
+       l_genl_msg_append_attr(msg, NL80211_SURVEY_INFO_NOISE, 1, &noise);
+       l_genl_msg_leave_nested(msg);
+
+       ret = nl80211_parse_attrs(msg, NL80211_ATTR_IFINDEX, &ifindex,
+                                       NL80211_ATTR_WIPHY_FREQ, &freq,
+                                       NL80211_ATTR_SURVEY_INFO, &nested,
+                                       NL80211_ATTR_UNSPEC);
+       ret_nested = nl80211_parse_nested(&nested, NL80211_ATTR_SURVEY_INFO,
+                                       NL80211_SURVEY_INFO_NOISE, &noise_out,
+                                       NL80211_ATTR_UNSPEC);
+       l_genl_msg_unref(msg);
+       assert(ret == 0);
+       assert(ret_nested == 0);
+       assert(noise_out == noise);
+}
+
+int main(int argc, char *argv[])
+{
+       l_test_init(&argc, &argv);
+
+       l_test_add("/nl80211util parse attrs", test_parse_attrs, NULL);
+       l_test_add("/nl80211util parse nested", test_parse_nested, NULL);
+
+       return l_test_run();
+}

Reply via email to