Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package iwd for openSUSE:Factory checked in 
at 2021-11-27 00:51:29
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/iwd (Old)
 and      /work/SRC/openSUSE:Factory/.iwd.new.1895 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "iwd"

Sat Nov 27 00:51:29 2021 rev:24 rq:933999 version:1.20

Changes:
--------
--- /work/SRC/openSUSE:Factory/iwd/iwd.changes  2021-11-08 17:25:14.492734968 
+0100
+++ /work/SRC/openSUSE:Factory/.iwd.new.1895/iwd.changes        2021-11-27 
00:52:19.766593853 +0100
@@ -1,0 +2,8 @@
+Fri Nov 26 07:34:37 UTC 2021 - Malte Ohmstede <malte.ohmst...@gmail.com>
+
+- update to v1.20
+  * Fix issue with handling Hotspot 2.0 requirements.
+  * Add support for evict_nocarrier setting during roaming.
+  * Add support for experimental NetworkConfigurationAgent API.
+
+-------------------------------------------------------------------

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

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

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

Other differences:
------------------
++++++ iwd.spec ++++++
--- /var/tmp/diff_new_pack.kcugFk/_old  2021-11-27 00:52:20.246592195 +0100
+++ /var/tmp/diff_new_pack.kcugFk/_new  2021-11-27 00:52:20.250592181 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           iwd
-Version:        1.19
+Version:        1.20
 Release:        0
 Summary:        Wireless daemon for Linux
 License:        LGPL-2.1-or-later
@@ -33,7 +33,7 @@
 BuildRequires:  readline-devel
 BuildRequires:  systemd-rpm-macros
 BuildRequires:  pkgconfig(dbus-1)
-BuildRequires:  pkgconfig(ell) >= 0.45
+BuildRequires:  pkgconfig(ell) >= 0.46
 BuildRequires:  pkgconfig(systemd)
 %{?systemd_ordering}
 

++++++ iwd-1.19.tar.xz -> iwd-1.20.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/AUTHORS new/iwd-1.20/AUTHORS
--- old/iwd-1.19/AUTHORS        2021-08-22 06:20:36.000000000 +0200
+++ new/iwd-1.20/AUTHORS        2021-11-18 21:21:21.000000000 +0100
@@ -31,3 +31,5 @@
 Joseph Benden <j...@benden.us>
 Michael Johnson <mjohnson...@gmail.com>
 Matt Oberle <matt.r.obe...@gmail.com>
+Marc-Antoine Perennou <marc-anto...@perennou.com>
+Torsten Schmitz <noreply.tors...@gmail.com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/ChangeLog new/iwd-1.20/ChangeLog
--- old/iwd-1.19/ChangeLog      2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/ChangeLog      2021-11-18 21:21:21.000000000 +0100
@@ -1,3 +1,8 @@
+ver 1.20:
+       Fix issue with handling Hotspot 2.0 requirements.
+       Add support for evict_nocarrier setting during roaming.
+       Add support for experimental NetworkConfigurationAgent API.
+
 ver 1.19:
        Fix issue with handling OCV if offloading is supported.
        Fix issue with handling SA Query on channel switch event.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/Makefile.am new/iwd-1.20/Makefile.am
--- old/iwd-1.19/Makefile.am    2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/Makefile.am    2021-11-18 21:21:21.000000000 +0100
@@ -246,6 +246,7 @@
                                        src/diagnostic.h src/diagnostic.c \
                                        src/ip-pool.h src/ip-pool.c \
                                        src/band.h src/band.c \
+                                       src/sysfs.h src/sysfs.c \
                                        $(eap_sources) \
                                        $(builtin_sources)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/Makefile.in new/iwd-1.20/Makefile.in
--- old/iwd-1.19/Makefile.in    2021-11-02 19:52:37.000000000 +0100
+++ new/iwd-1.20/Makefile.in    2021-11-18 21:23:10.000000000 +0100
@@ -300,14 +300,15 @@
        src/module.c src/rrm.c src/frame-xchg.h src/frame-xchg.c \
        src/eap-wsc.c src/eap-wsc.h src/wscutil.h src/wscutil.c \
        src/diagnostic.h src/diagnostic.c src/ip-pool.h src/ip-pool.c \
-       src/band.h src/band.c src/eap.c src/eap.h src/eap-private.h \
-       src/eap-md5.c src/eap-tls.c src/eap-ttls.c src/eap-mschapv2.c \
-       src/eap-mschapv2.h src/eap-sim.c src/eap-aka.c src/eap-peap.c \
-       src/eap-gtc.c src/eap-pwd.c src/util.h src/util.c src/crypto.h \
-       src/crypto.c src/simutil.h src/simutil.c src/simauth.h \
-       src/simauth.c src/watchlist.h src/watchlist.c \
-       src/eap-tls-common.h src/eap-tls-common.c src/mschaputil.h \
-       src/mschaputil.c src/ofono.c
+       src/band.h src/band.c src/sysfs.h src/sysfs.c src/eap.c \
+       src/eap.h src/eap-private.h src/eap-md5.c src/eap-tls.c \
+       src/eap-ttls.c src/eap-mschapv2.c src/eap-mschapv2.h \
+       src/eap-sim.c src/eap-aka.c src/eap-peap.c src/eap-gtc.c \
+       src/eap-pwd.c src/util.h src/util.c src/crypto.h src/crypto.c \
+       src/simutil.h src/simutil.c src/simauth.h src/simauth.c \
+       src/watchlist.h src/watchlist.c src/eap-tls-common.h \
+       src/eap-tls-common.c src/mschaputil.h src/mschaputil.c \
+       src/ofono.c
 am__objects_3 = src/eap.$(OBJEXT) src/eap-md5.$(OBJEXT) \
        src/eap-tls.$(OBJEXT) src/eap-ttls.$(OBJEXT) \
        src/eap-mschapv2.$(OBJEXT) src/eap-sim.$(OBJEXT) \
@@ -342,8 +343,8 @@
 @DAEMON_TRUE@  src/rrm.$(OBJEXT) src/frame-xchg.$(OBJEXT) \
 @DAEMON_TRUE@  src/eap-wsc.$(OBJEXT) src/wscutil.$(OBJEXT) \
 @DAEMON_TRUE@  src/diagnostic.$(OBJEXT) src/ip-pool.$(OBJEXT) \
-@DAEMON_TRUE@  src/band.$(OBJEXT) $(am__objects_3) \
-@DAEMON_TRUE@  $(am__objects_5)
+@DAEMON_TRUE@  src/band.$(OBJEXT) src/sysfs.$(OBJEXT) \
+@DAEMON_TRUE@  $(am__objects_3) $(am__objects_5)
 src_iwd_OBJECTS = $(am_src_iwd_OBJECTS)
 am__tools_hwsim_SOURCES_DIST = tools/hwsim.c src/mpdu.h src/util.h \
        src/util.c src/storage.h src/storage.c src/common.h \
@@ -573,12 +574,13 @@
        src/$(DEPDIR)/sae.Po src/$(DEPDIR)/scan.Po \
        src/$(DEPDIR)/simauth.Po src/$(DEPDIR)/simutil.Po \
        src/$(DEPDIR)/station.Po src/$(DEPDIR)/storage.Po \
-       src/$(DEPDIR)/util.Po src/$(DEPDIR)/watchlist.Po \
-       src/$(DEPDIR)/wiphy.Po src/$(DEPDIR)/wsc.Po \
-       src/$(DEPDIR)/wscutil.Po tools/$(DEPDIR)/hwsim.Po \
-       tools/$(DEPDIR)/probe-req.Po unit/$(DEPDIR)/test-arc4.Po \
-       unit/$(DEPDIR)/test-band.Po unit/$(DEPDIR)/test-client.Po \
-       unit/$(DEPDIR)/test-cmac-aes.Po unit/$(DEPDIR)/test-crypto.Po \
+       src/$(DEPDIR)/sysfs.Po src/$(DEPDIR)/util.Po \
+       src/$(DEPDIR)/watchlist.Po src/$(DEPDIR)/wiphy.Po \
+       src/$(DEPDIR)/wsc.Po src/$(DEPDIR)/wscutil.Po \
+       tools/$(DEPDIR)/hwsim.Po tools/$(DEPDIR)/probe-req.Po \
+       unit/$(DEPDIR)/test-arc4.Po unit/$(DEPDIR)/test-band.Po \
+       unit/$(DEPDIR)/test-client.Po unit/$(DEPDIR)/test-cmac-aes.Po \
+       unit/$(DEPDIR)/test-crypto.Po \
        unit/$(DEPDIR)/test-eap-mschapv2.Po \
        unit/$(DEPDIR)/test-eap-sim.Po unit/$(DEPDIR)/test-eapol.Po \
        unit/$(DEPDIR)/test-hmac-md5.Po \
@@ -1266,6 +1268,7 @@
 @DAEMON_TRUE@                                  src/diagnostic.h 
src/diagnostic.c \
 @DAEMON_TRUE@                                  src/ip-pool.h src/ip-pool.c \
 @DAEMON_TRUE@                                  src/band.h src/band.c \
+@DAEMON_TRUE@                                  src/sysfs.h src/sysfs.c \
 @DAEMON_TRUE@                                  $(eap_sources) \
 @DAEMON_TRUE@                                  $(builtin_sources)
 
@@ -1894,6 +1897,7 @@
 src/ip-pool.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
 src/band.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/sysfs.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/eap.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/eap-md5.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
@@ -2243,6 +2247,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/simutil.Po@am__quote@ # 
am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/station.Po@am__quote@ # 
am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/storage.Po@am__quote@ # 
am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sysfs.Po@am__quote@ # 
am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/util.Po@am__quote@ # 
am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/watchlist.Po@am__quote@ # 
am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/wiphy.Po@am__quote@ # 
am--include-marker
@@ -3334,6 +3339,7 @@
        -rm -f src/$(DEPDIR)/simutil.Po
        -rm -f src/$(DEPDIR)/station.Po
        -rm -f src/$(DEPDIR)/storage.Po
+       -rm -f src/$(DEPDIR)/sysfs.Po
        -rm -f src/$(DEPDIR)/util.Po
        -rm -f src/$(DEPDIR)/watchlist.Po
        -rm -f src/$(DEPDIR)/wiphy.Po
@@ -3555,6 +3561,7 @@
        -rm -f src/$(DEPDIR)/simutil.Po
        -rm -f src/$(DEPDIR)/station.Po
        -rm -f src/$(DEPDIR)/storage.Po
+       -rm -f src/$(DEPDIR)/sysfs.Po
        -rm -f src/$(DEPDIR)/util.Po
        -rm -f src/$(DEPDIR)/watchlist.Po
        -rm -f src/$(DEPDIR)/wiphy.Po
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/client/command.h 
new/iwd-1.20/client/command.h
--- old/iwd-1.19/client/command.h       2019-10-30 11:50:34.000000000 +0100
+++ new/iwd-1.20/client/command.h       2021-11-18 21:21:21.000000000 +0100
@@ -83,10 +83,14 @@
 } __attribute__((aligned(8)));
 
 #define COMMAND_FAMILY(name, init, exit)                               \
+       _Pragma("GCC diagnostic push")                                  \
+       _Pragma("GCC diagnostic ignored \"-Wattributes\"")              \
        static struct command_family_desc __command_family_ ## name     \
-               __attribute__((used, section("__command"), aligned(8))) = {\
+               __attribute__((used, retain,                            \
+                               section("__command"), aligned(8))) = {  \
                        #name, init, exit                               \
                };                                                      \
+       _Pragma("GCC diagnostic pop")
 
 bool command_init(char **argv, int argc);
 void command_exit(void);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/client/dbus-proxy.c 
new/iwd-1.20/client/dbus-proxy.c
--- old/iwd-1.19/client/dbus-proxy.c    2020-03-25 10:37:15.000000000 +0100
+++ new/iwd-1.20/client/dbus-proxy.c    2021-11-18 21:21:21.000000000 +0100
@@ -315,7 +315,8 @@
        }
 
        proxy = callback_data->user_data;
-       if (!strcmp(proxy->type->interface, IWD_AGENT_MANAGER_INTERFACE))
+       if (!strcmp(proxy->type->interface, IWD_AGENT_MANAGER_INTERFACE) ||
+                       !strcmp(proxy->type->interface, IWD_DAEMON_INTERFACE))
                return;
 
 quit:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/client/dbus-proxy.h 
new/iwd-1.20/client/dbus-proxy.h
--- old/iwd-1.19/client/dbus-proxy.h    2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/client/dbus-proxy.h    2021-11-18 21:21:21.000000000 +0100
@@ -118,10 +118,14 @@
 } __attribute__((aligned(8)));
 
 #define INTERFACE_TYPE(interface, init, exit)                          \
+       _Pragma("GCC diagnostic push")                                  \
+       _Pragma("GCC diagnostic ignored \"-Wattributes\"")              \
        static struct interface_type_desc __interface_type_ ## interface\
-               __attribute__((used, section("__interface"), aligned(8))) = {\
+               __attribute__((used, retain, section("__interface"),    \
+                                       aligned(8))) = {                \
                        #interface, init, exit                          \
                };                                                      \
+       _Pragma("GCC diagnostic pop")
 
 bool dbus_proxy_init(void);
 bool dbus_proxy_exit(void);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/configure new/iwd-1.20/configure
--- old/iwd-1.19/configure      2021-11-02 19:52:30.000000000 +0100
+++ new/iwd-1.20/configure      2021-11-18 21:23:04.000000000 +0100
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for iwd 1.19.
+# Generated by GNU Autoconf 2.69 for iwd 1.20.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@
 # Identity of this package.
 PACKAGE_NAME='iwd'
 PACKAGE_TARNAME='iwd'
-PACKAGE_VERSION='1.19'
-PACKAGE_STRING='iwd 1.19'
+PACKAGE_VERSION='1.20'
+PACKAGE_STRING='iwd 1.20'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1394,7 +1394,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 1.19 to adapt to many kinds of systems.
+\`configure' configures iwd 1.20 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1465,7 +1465,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of iwd 1.19:";;
+     short | recursive ) echo "Configuration of iwd 1.20:";;
    esac
   cat <<\_ACEOF
 
@@ -1616,7 +1616,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-iwd configure 1.19
+iwd configure 1.20
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1981,7 +1981,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 1.19, which was
+It was created by iwd $as_me 1.20, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2844,7 +2844,7 @@
 
 # Define the identity of the package.
  PACKAGE='iwd'
- VERSION='1.19'
+ VERSION='1.20'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -13349,7 +13349,7 @@
                        test "${enable_monitor}" != "no" ||
                        test "${enable_wired}" = "yes" ||
                        test "${enable_hwsim}" = "yes"); then
-               ell_min_version="0.45"
+               ell_min_version="0.46"
        else
                ell_min_version="0.5"
        fi
@@ -14078,7 +14078,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 1.19, which was
+This file was extended by iwd $as_me 1.20, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -14144,7 +14144,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-iwd config.status 1.19
+iwd config.status 1.20
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/configure.ac new/iwd-1.20/configure.ac
--- old/iwd-1.19/configure.ac   2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/configure.ac   2021-11-18 21:21:21.000000000 +0100
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(iwd, 1.19)
+AC_INIT(iwd, 1.20)
 
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_AUX_DIR(build-aux)
@@ -263,7 +263,7 @@
                        test "${enable_monitor}" != "no" ||
                        test "${enable_wired}" = "yes" ||
                        test "${enable_hwsim}" = "yes"); then
-               ell_min_version="0.45"
+               ell_min_version="0.46"
        else
                ell_min_version="0.5"
        fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/ell/dhcp-server.c 
new/iwd-1.20/ell/dhcp-server.c
--- old/iwd-1.19/ell/dhcp-server.c      2021-09-14 21:48:51.000000000 +0200
+++ new/iwd-1.20/ell/dhcp-server.c      2021-11-18 20:53:14.000000000 +0100
@@ -1032,10 +1032,6 @@
                server->address = ia.s_addr;
        }
 
-       /* Assign a default gateway if not already set */
-       if (!server->gateway)
-               server->gateway = server->address;
-
        /* Assign a default netmask if not already */
        if (!server->netmask) {
                if (inet_pton(AF_INET,"255.255.255.0", &ia) != 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/ell/dhcp6.c new/iwd-1.20/ell/dhcp6.c
--- old/iwd-1.19/ell/dhcp6.c    2021-03-29 14:19:13.000000000 +0200
+++ new/iwd-1.20/ell/dhcp6.c    2021-11-18 20:53:14.000000000 +0100
@@ -850,6 +850,14 @@
                client->event_handler(client, event, client->event_data);
 }
 
+static void dhcp6_client_enter_state(struct l_dhcp6_client *client,
+                                       enum dhcp6_state new_state)
+{
+       client->state = new_state;
+       l_util_debug(client->debug_handler, client->debug_data,
+                       "Entering state: %s", dhcp6_state_to_str(new_state));
+}
+
 static inline void dhcp6_client_new_transaction(struct l_dhcp6_client *client,
                                                enum dhcp6_state new_state)
 {
@@ -858,9 +866,7 @@
        client->transaction_id = l_getrandom_uint32() & 0x00FFFFFFU;
        client->transaction_start_t = 0;
 
-       client->state = new_state;
-       l_util_debug(client->debug_handler, client->debug_data,
-                       "Entering state: %s", dhcp6_state_to_str(new_state));
+       dhcp6_client_enter_state(client, new_state);
 }
 
 static void dhcp6_client_timeout_send(struct l_timeout *timeout,
@@ -960,21 +966,27 @@
 {
        uint32_t t1 = _dhcp6_lease_get_t1(client->lease);
        uint32_t t2 = _dhcp6_lease_get_t2(client->lease);
+       enum l_dhcp6_client_event event;
 
        client->lease_start_t = l_time_now();
 
        /* TODO: Emit IP_CHANGED if any addresses were removed / added */
        if (client->state == DHCP6_STATE_REQUESTING ||
                        client->state == DHCP6_STATE_SOLICITING)
-               dhcp6_client_event_notify(client,
-                                       L_DHCP6_CLIENT_EVENT_LEASE_OBTAINED);
+               event = L_DHCP6_CLIENT_EVENT_LEASE_OBTAINED;
        else
-               dhcp6_client_event_notify(client,
-                                       L_DHCP6_CLIENT_EVENT_LEASE_RENEWED);
+               event = L_DHCP6_CLIENT_EVENT_LEASE_RENEWED;
 
        l_timeout_remove(client->timeout_lease);
        client->timeout_lease = NULL;
 
+       /*
+        * Switch over to BOUND state so that l_dhcp6_client_get_lease() will
+        * return the lease properly
+        */
+       dhcp6_client_enter_state(client, DHCP6_STATE_BOUND);
+       dhcp6_client_event_notify(client, event);
+
        if (t1 == 0xffffffff || t2 == 0xffffffff) {
                CLIENT_DEBUG("T1 (%u) or T2 (%u) was infinite", t1, t2);
                return;
@@ -1402,7 +1414,6 @@
                l_timeout_remove(client->timeout_send);
                client->timeout_send = NULL;
                dhcp6_client_setup_lease(client);
-               dhcp6_client_new_transaction(client, r);
                return;
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/ell/log.h new/iwd-1.20/ell/log.h
--- old/iwd-1.19/ell/log.h      2020-09-05 09:26:19.000000000 +0200
+++ new/iwd-1.20/ell/log.h      2021-11-18 20:53:14.000000000 +0100
@@ -61,12 +61,20 @@
        unsigned int flags;
 } __attribute__((aligned(8)));
 
+/*
+ * Set the retain attribute so that the section cannot be discarded by ld
+ * --gc-sections -z start-stop-gc. Older compilers would warn for the unknown
+ *  attribute, so just disable -Wattributes.
+ */
 #define L_DEBUG_SYMBOL(symbol, format, ...) do { \
+_Pragma("GCC diagnostic push") \
+_Pragma("GCC diagnostic ignored \"-Wattributes\"") \
        static struct l_debug_desc symbol \
-       __attribute__((used, section("__ell_debug"), aligned(8))) = { \
+       __attribute__((used, retain, section("__ell_debug"), aligned(8))) = { \
                .file = __FILE__, .func = __func__, \
                .flags = L_DEBUG_FLAG_DEFAULT, \
        }; \
+_Pragma("GCC diagnostic pop") \
        if (symbol.flags & L_DEBUG_FLAG_PRINT) \
                l_log(L_LOG_DEBUG, "%s:%s() " format, __FILE__, \
                                        __func__ , ##__VA_ARGS__); \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/anqp.c new/iwd-1.20/src/anqp.c
--- old/iwd-1.19/src/anqp.c     2021-08-22 06:20:37.000000000 +0200
+++ new/iwd-1.20/src/anqp.c     2021-11-18 21:21:21.000000000 +0100
@@ -256,7 +256,7 @@
                                &anqp_frame_prefix, anqp_response_frame_event,
                                NULL);
 
-       return true;
+       return request->id;
 }
 
 void anqp_cancel(uint32_t id)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/ap.c new/iwd-1.20/src/ap.c
--- old/iwd-1.19/src/ap.c       2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/src/ap.c       2021-11-18 21:21:21.000000000 +0100
@@ -101,6 +101,8 @@
        bool started : 1;
        bool gtk_set : 1;
        bool netconfig_set_addr4 : 1;
+       bool in_event : 1;
+       bool free_pending : 1;
 };
 
 struct sta_state {
@@ -250,6 +252,35 @@
        }
 }
 
+static bool ap_event_done(struct ap_state *ap, bool prev_in_event)
+{
+       ap->in_event = prev_in_event;
+
+       if (!prev_in_event && ap->free_pending) {
+               ap_free(ap);
+               return true;
+       }
+
+       return ap->free_pending;
+}
+
+/*
+ * Returns true if the AP is considered freed and the caller must avoid
+ * accessing @ap.
+ */
+static bool ap_event(struct ap_state *ap, enum ap_event_type event,
+                       const void *event_data)
+{
+       bool prev = ap->in_event;
+
+       if (ap->free_pending)
+               return true;
+
+       ap->in_event = true;
+       ap->ops->handle_event(event, event_data, ap->user_data);
+       return ap_event_done(ap, prev);
+}
+
 static void ap_del_station(struct sta_state *sta, uint16_t reason,
                                bool disassociate)
 {
@@ -284,23 +315,34 @@
        ap_stop_handshake(sta);
 
        /*
+        * If the event handler tears the AP down, we've made sure above that
+        * a subsequent ap_sta_free(sta) has no need to access sta->ap.
+        */
+       if (send_event)
+               if (ap_event(ap, AP_EVENT_STATION_REMOVED, &event_data))
+                       return;
+
+       /*
         * Expire any DHCP leases owned by this client when it disconnects to
         * make it harder for somebody to DoS the IP pool.  If the client
         * comes back and the lease is still in the expired leases list they
         * will get their IP back.
         */
        if (ap->netconfig_dhcp) {
+               bool prev = ap->in_event;
+
+               /*
+                * If the LEASE_EXPIRED event in ap_dhcp_event_cb triggers an
+                * ap_free(), delay cleanup to avoid destroying the DHCP
+                * server midway through l_dhcp_server_expire_by_mac().
+                */
+               ap->in_event = true;
+
                sta->ip_alloc_lease = NULL;
                l_dhcp_server_expire_by_mac(ap->netconfig_dhcp, sta->addr);
-       }
 
-       /*
-        * If the event handler tears the AP down, we've made sure above that
-        * a subsequent ap_sta_free(sta) has no need to access sta->ap.
-        */
-       if (send_event)
-               ap->ops->handle_event(AP_EVENT_STATION_REMOVED, &event_data,
-                                       ap->user_data);
+               ap_event_done(ap, prev);
+       }
 }
 
 static bool ap_sta_match_addr(const void *a, const void *b)
@@ -335,19 +377,16 @@
 static void ap_new_rsna(struct sta_state *sta)
 {
        struct ap_state *ap = sta->ap;
+       struct ap_event_station_added_data event_data = {};
 
        l_debug("STA "MAC" authenticated", MAC_STR(sta->addr));
 
        sta->rsna = true;
 
-       if (ap->ops->handle_event) {
-               struct ap_event_station_added_data event_data = {};
-               event_data.mac = sta->addr;
-               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);
-       }
+       event_data.mac = sta->addr;
+       event_data.assoc_ies = sta->assoc_ies;
+       event_data.assoc_ies_len = sta->assoc_ies_len;
+       ap_event(ap, AP_EVENT_STATION_ADDED, &event_data);
 }
 
 static void ap_drop_rsna(struct sta_state *sta)
@@ -356,6 +395,7 @@
        struct l_genl_msg *msg;
        uint32_t ifindex = netdev_get_ifindex(sta->ap->netdev);
        uint8_t key_id = 0;
+       struct ap_event_station_removed_data event_data = {};
 
        sta->rsna = false;
 
@@ -380,12 +420,8 @@
 
        ap_stop_handshake(sta);
 
-       if (ap->ops->handle_event) {
-               struct ap_event_station_removed_data event_data = {};
-               event_data.mac = sta->addr;
-               ap->ops->handle_event(AP_EVENT_STATION_REMOVED, &event_data,
-                                       ap->user_data);
-       }
+       event_data.mac = sta->addr;
+       ap_event(ap, AP_EVENT_STATION_REMOVED, &event_data);
 }
 
 static void ap_set_rsn_info(struct ap_state *ap, struct ie_rsn_info *rsn)
@@ -405,7 +441,7 @@
        ap->wsc_dpid = 0;
        ap_update_beacon(ap);
 
-       ap->ops->handle_event(AP_EVENT_PBC_MODE_EXIT, NULL, ap->user_data);
+       ap_event(ap, AP_EVENT_PBC_MODE_EXIT, NULL);
 }
 
 struct ap_pbc_record_expiry_data {
@@ -1090,9 +1126,7 @@
                                        &expiry_data);
 
                event_data.mac = sta->addr;
-               sta->ap->ops->handle_event(AP_EVENT_REGISTRATION_SUCCESS,
-                                               &event_data,
-                                               sta->ap->user_data);
+               ap_event(sta->ap, AP_EVENT_REGISTRATION_SUCCESS, &event_data);
                break;
        default:
                break;
@@ -1594,11 +1628,11 @@
        const char *ssid = NULL;
        const uint8_t *rsn = NULL;
        size_t ssid_len = 0;
-       struct l_uintset *rates = NULL;
+       _auto_(l_uintset_free) struct l_uintset *rates = NULL;
        struct ie_rsn_info rsn_info;
        int err;
        struct ie_tlv_iter iter;
-       uint8_t *wsc_data = NULL;
+       _auto_(l_free) uint8_t *wsc_data = NULL;
        ssize_t wsc_data_len;
        bool fils_ip_req = false;
        struct ie_fils_ip_addr_request_info fils_ip_req_info;
@@ -1685,9 +1719,6 @@
                        goto bad_frame;
                }
 
-               l_free(wsc_data);
-               wsc_data = NULL;
-
                if (wsc_req.request_type !=
                                WSC_REQUEST_TYPE_ENROLLEE_OPEN_8021X) {
                        err = MMPDU_REASON_CODE_INVALID_IE;
@@ -1728,8 +1759,9 @@
                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);
+
+               if (ap_event(ap, AP_EVENT_REGISTRATION_START, &event_data))
+                       return;
 
                /*
                 * Since we're starting the PBC Registration Protocol
@@ -1781,7 +1813,7 @@
        if (sta->rates)
                l_uintset_free(sta->rates);
 
-       sta->rates = rates;
+       sta->rates = l_steal_ptr(rates);
 
        l_free(sta->assoc_ies);
 
@@ -1823,11 +1855,6 @@
        else if (sta->associated)
                ap_stop_handshake(sta);
 
-       if (rates)
-               l_uintset_free(rates);
-
-       l_free(wsc_data);
-
        if (!ap_assoc_resp(ap, sta, sta->addr, err, reassoc,
                                req, (void *) ies + ies_len - (void *) req,
                                NULL, ap_fail_assoc_resp_cb))
@@ -2209,6 +2236,7 @@
 {
        struct ap_event_start_failed_data data = { err };
 
+       ap->in_event = true;
        ap->ops->handle_event(AP_EVENT_START_FAILED, &data, ap->user_data);
        ap_reset(ap);
        l_genl_family_free(ap->nl80211);
@@ -2224,13 +2252,11 @@
 
        switch (event) {
        case L_DHCP_SERVER_EVENT_NEW_LEASE:
-               ap->ops->handle_event(AP_EVENT_DHCP_NEW_LEASE, lease,
-                                       ap->user_data);
+               ap_event(ap, AP_EVENT_DHCP_NEW_LEASE, lease);
                break;
 
        case L_DHCP_SERVER_EVENT_LEASE_EXPIRED:
-               ap->ops->handle_event(AP_EVENT_DHCP_LEASE_EXPIRED, lease,
-                                       ap->user_data);
+               ap_event(ap, AP_EVENT_DHCP_LEASE_EXPIRED, lease);
                break;
 
        default:
@@ -2267,7 +2293,7 @@
        }
 
        ap->started = true;
-       ap->ops->handle_event(AP_EVENT_STARTED, NULL, ap->user_data);
+       ap_event(ap, AP_EVENT_STARTED, NULL);
 }
 
 static struct l_genl_msg *ap_build_cmd_start_ap(struct ap_state *ap)
@@ -2552,6 +2578,8 @@
 
        switch (l_genl_msg_get_command(msg)) {
        case NL80211_CMD_STOP_AP:
+               ap->in_event = true;
+
                if (ap->start_stop_cmd_id) {
                        struct ap_event_start_failed_data data = { -ECANCELED };
 
@@ -3304,7 +3332,9 @@
 
        if (ap->started) {
                ap->started = false;
-               ap->ops->handle_event(AP_EVENT_STOPPING, NULL, ap->user_data);
+
+               if (ap_event(ap, AP_EVENT_STOPPING, NULL))
+                       return;
        }
 
        ap_reset(ap);
@@ -3355,6 +3385,11 @@
 /* Free @ap without a graceful shutdown */
 void ap_free(struct ap_state *ap)
 {
+       if (ap->in_event) {
+               ap->free_pending = true;
+               return;
+       }
+
        ap_reset(ap);
        l_genl_family_free(ap->nl80211);
        l_free(ap);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/eap-private.h 
new/iwd-1.20/src/eap-private.h
--- old/iwd-1.19/src/eap-private.h      2020-09-05 09:43:41.000000000 +0200
+++ new/iwd-1.20/src/eap-private.h      2021-11-18 21:21:21.000000000 +0100
@@ -94,10 +94,14 @@
 } __attribute__((aligned(8)));
 
 #define EAP_METHOD_BUILTIN(name, init, exit)                           \
+       _Pragma("GCC diagnostic push")                                  \
+       _Pragma("GCC diagnostic ignored \"-Wattributes\"")              \
        static struct eap_method_desc __eap_builtin_ ## name            \
-               __attribute__((used, section("__eap"), aligned(8))) = { \
+               __attribute__((used, retain, section("__eap"),          \
+                              aligned(8))) = {                         \
                        #name, init, exit                               \
                };                                                      \
+       _Pragma("GCC diagnostic pop")
 
 int eap_register_method(struct eap_method *method);
 int eap_unregister_method(struct eap_method *method);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/eap.c new/iwd-1.20/src/eap.c
--- old/iwd-1.19/src/eap.c      2021-05-04 15:01:25.000000000 +0200
+++ new/iwd-1.20/src/eap.c      2021-11-18 21:21:21.000000000 +0100
@@ -413,8 +413,14 @@
        return buf;
 }
 
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
 #define IS_EXPANDED_RESPONSE(id, t) \
        (type == EAP_TYPE_EXPANDED && vendor_id == (id) && vendor_type == (t))
+_Pragma("GCC diagnostic pop")
+
+#define RESPONSE_IS(t) \
+       (type == (t) || IS_EXPANDED_RESPONSE(0, (t)))
 
 static void eap_handle_response(struct eap_state *eap, const uint8_t *pkt,
                                size_t len)
@@ -428,14 +434,6 @@
                                eap->method->vendor_id[2];
        uint32_t our_vendor_type = eap->method->vendor_type;
 
-       bool response_is(enum eap_type wanted)
-       {
-               if (type == wanted)
-                       return true;
-
-               return IS_EXPANDED_RESPONSE(0, wanted);
-       }
-
        if (len < 1)
                /* Invalid packets to be ignored */
                return;
@@ -461,7 +459,7 @@
                        return;
        }
 
-       if (response_is(EAP_TYPE_NAK)) {
+       if (RESPONSE_IS(EAP_TYPE_NAK)) {
                l_debug("EAP peer not configured for method: %s",
                        eap_type_to_str(our_type, our_vendor_id,
                                                        our_vendor_type));
@@ -500,7 +498,7 @@
         */
 
        if (!eap->identity) {
-               if (!response_is(EAP_TYPE_IDENTITY))
+               if (!RESPONSE_IS(EAP_TYPE_IDENTITY))
                        goto unsupported_method;
 
                /*
@@ -528,7 +526,7 @@
         * (with the exception of the Nak)
         */
        if (our_type != EAP_TYPE_EXPANDED) {
-               if (response_is(our_type))
+               if (RESPONSE_IS(our_type))
                        goto handle_response;
        } else if (IS_EXPANDED_RESPONSE(our_vendor_id, our_vendor_type))
                goto handle_response;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/ie.c new/iwd-1.20/src/ie.c
--- old/iwd-1.19/src/ie.c       2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/src/ie.c       2021-11-18 21:21:21.000000000 +0100
@@ -2035,7 +2035,8 @@
 }
 
 int ie_parse_hs20_indication(struct ie_tlv_iter *iter, uint8_t *version_out,
-                               uint16_t *pps_mo_id_out, uint8_t *domain_id_out)
+                               uint16_t *pps_mo_id_out, uint8_t *domain_id_out,
+                               bool *dgaf_disable_out)
 {
        unsigned int len = ie_tlv_iter_get_length(iter);
        const uint8_t *data = ie_tlv_iter_get_data(iter);
@@ -2060,6 +2061,9 @@
        if (pps_mo_present && domain_id_present)
                return -EPROTOTYPE;
 
+       if (dgaf_disable_out)
+               *dgaf_disable_out = test_bit(&hs20_config, 0);
+
        if (version_out)
                *version_out = bit_field(hs20_config, 4, 4);
 
@@ -2087,7 +2091,7 @@
 
 int ie_parse_hs20_indication_from_data(const uint8_t *data, size_t len,
                                        uint8_t *version, uint16_t *pps_mo_id,
-                                       uint8_t *domain_id)
+                                       uint8_t *domain_id, bool *dgaf_disable)
 {
        struct ie_tlv_iter iter;
 
@@ -2099,7 +2103,8 @@
        if (ie_tlv_iter_get_tag(&iter) != IE_TYPE_VENDOR_SPECIFIC)
                return -EPROTOTYPE;
 
-       return ie_parse_hs20_indication(&iter, version, pps_mo_id, domain_id);
+       return ie_parse_hs20_indication(&iter, version, pps_mo_id, domain_id,
+                                               dgaf_disable);
 }
 
 /*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/ie.h new/iwd-1.20/src/ie.h
--- old/iwd-1.19/src/ie.h       2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/src/ie.h       2021-11-18 21:21:21.000000000 +0100
@@ -616,10 +616,11 @@
 int ie_build_roaming_consortium(const uint8_t *rc, size_t rc_len, uint8_t *to);
 
 int ie_parse_hs20_indication(struct ie_tlv_iter *iter, uint8_t *version,
-                               uint16_t *pps_mo_id, uint8_t *domain_id);
+                               uint16_t *pps_mo_id, uint8_t *domain_id,
+                               bool *dgaf_disable);
 int ie_parse_hs20_indication_from_data(const uint8_t *data, size_t len,
                                        uint8_t *version, uint16_t *pps_mo_id,
-                                       uint8_t *domain_id);
+                                       uint8_t *domain_id, bool *dgaf_disable);
 int ie_build_hs20_indication(uint8_t version, uint8_t *to);
 
 enum ie_rsnx_capability {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/module.h new/iwd-1.20/src/module.h
--- old/iwd-1.19/src/module.h   2020-04-14 20:38:37.000000000 +0200
+++ new/iwd-1.20/src/module.h   2021-11-18 21:21:21.000000000 +0100
@@ -33,19 +33,25 @@
 };
 
 #define IWD_MODULE(name, init, exit)                                   \
+       _Pragma("GCC diagnostic push")                                  \
+       _Pragma("GCC diagnostic ignored \"-Wattributes\"")              \
        static struct iwd_module_desc __iwd_module_ ## name             \
-               __attribute__((used, section("__iwd_module"), aligned(8))) = {\
+               __attribute__((used, retain, section("__iwd_module"),   \
+                              aligned(8))) = {                         \
                        #name, init, exit                               \
-               };
+               };                                                      \
+       _Pragma("GCC diagnostic pop")
 
 #define IWD_MODULE_DEPENDS(name, dep)                                  \
-       static struct iwd_module_depends                                \
-                               __iwd_module__##name##_##dep            \
-               __attribute__((used, section("__iwd_module_dep"),       \
-                                       aligned(8))) = {                \
-                       .self = #name,                                  \
-                       .target = #dep,                                 \
-               };
+       _Pragma("GCC diagnostic push")                                  \
+       _Pragma("GCC diagnostic ignored \"-Wattributes\"")              \
+       static struct iwd_module_depends __iwd_module__##name##_##dep   \
+               __attribute__((used, retain,                            \
+                       section("__iwd_module_dep"), aligned(8))) = {   \
+                               .self = #name,                          \
+                               .target = #dep,                         \
+               };                                                      \
+       _Pragma("GCC diagnostic pop")
 
 int iwd_modules_init(void);
 void iwd_modules_exit(void);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/netconfig.c new/iwd-1.20/src/netconfig.c
--- old/iwd-1.19/src/netconfig.c        2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/src/netconfig.c        2021-11-18 21:21:21.000000000 +0100
@@ -50,6 +50,7 @@
 #include "src/util.h"
 #include "src/ie.h"
 #include "src/netconfig.h"
+#include "src/sysfs.h"
 
 struct netconfig {
        uint32_t ifindex;
@@ -102,38 +103,6 @@
        l_info("%s%s", prefix, str);
 }
 
-static int write_string(const char *file, const char *value)
-{
-       size_t l = strlen(value);
-       int fd;
-       int r;
-
-       fd = L_TFR(open(file, O_WRONLY));
-       if (fd < 0)
-               return -errno;
-
-       r = L_TFR(write(fd, value, l));
-       L_TFR(close(fd));
-
-       return r;
-}
-
-static int sysfs_write_ipv6_setting(const char *ifname, const char *setting,
-                                       const char *value)
-{
-       int r;
-
-       L_AUTO_FREE_VAR(char *, file) =
-               l_strdup_printf("/proc/sys/net/ipv6/conf/%s/%s",
-                                                       ifname, setting);
-
-       r = write_string(file, value);
-       if (r < 0)
-               l_error("Unable to write %s to %s", setting, file);
-
-       return r;
-}
-
 static void netconfig_free_settings(struct netconfig *netconfig)
 {
        l_rtnl_address_free(netconfig->v4_address);
@@ -207,6 +176,36 @@
        return addr_str;
 }
 
+static bool netconfig_use_fils_addr(struct netconfig *netconfig, int af)
+{
+       if ((af == AF_INET ? netconfig->rtm_protocol :
+                               netconfig->rtm_v6_protocol) != RTPROT_DHCP)
+               return false;
+
+       if (!netconfig->fils_override)
+               return false;
+
+       if (af == AF_INET)
+               return !!netconfig->fils_override->ipv4_addr;
+
+       return !l_memeqzero(netconfig->fils_override->ipv6_addr, 16);
+}
+
+static bool netconfig_use_fils_gateway(struct netconfig *netconfig, int af)
+{
+       if ((af == AF_INET ? netconfig->rtm_protocol :
+                               netconfig->rtm_v6_protocol) != RTPROT_DHCP)
+               return false;
+
+       if (!netconfig->fils_override)
+               return false;
+
+       if (af == AF_INET)
+               return !!netconfig->fils_override->ipv4_gateway;
+
+       return !l_memeqzero(netconfig->fils_override->ipv6_gateway, 16);
+}
+
 static char **netconfig_get_dns_list(struct netconfig *netconfig, int af,
                                        const uint8_t **out_dns_mac)
 {
@@ -490,7 +489,7 @@
                return gateway;
 
        case RTPROT_DHCP:
-               if (fils && fils->ipv4_gateway) {
+               if (netconfig_use_fils_gateway(netconfig, AF_INET)) {
                        gateway = netconfig_ipv4_to_string(fils->ipv4_gateway);
 
                        if (gateway && out_mac &&
@@ -558,10 +557,7 @@
 
        gateway = l_settings_get_string(netconfig->active_settings,
                                                "IPv6", "Gateway");
-       if (!gateway && netconfig->rtm_v6_protocol == RTPROT_DHCP &&
-                       netconfig->fils_override &&
-                       !l_memeqzero(netconfig->fils_override->ipv6_gateway,
-                                       16)) {
+       if (!gateway && netconfig_use_fils_gateway(netconfig, AF_INET6)) {
                gateway = netconfig_ipv6_to_string(
                                        netconfig->fils_override->ipv6_gateway);
 
@@ -729,8 +725,7 @@
                        ip, ifa->ifa_prefixlen);
 
        if (netconfig->rtm_v6_protocol != RTPROT_DHCP ||
-                       (netconfig->fils_override &&
-                        !l_memeqzero(netconfig->fils_override->ipv6_addr, 16)))
+                       netconfig_use_fils_addr(netconfig, AF_INET6))
                return;
 
        inet_pton(AF_INET6, ip, &in6);
@@ -844,10 +839,8 @@
        }
 }
 
-static bool netconfig_ipv4_routes_install(struct netconfig *netconfig)
+static bool netconfig_ipv4_subnet_route_install(struct netconfig *netconfig)
 {
-       L_AUTO_FREE_VAR(char *, gateway) = NULL;
-       const uint8_t *gateway_mac = NULL;
        struct in_addr in_addr;
        char ip[INET_ADDRSTRLEN];
        char network[INET_ADDRSTRLEN];
@@ -870,10 +863,19 @@
                                                netconfig_route_generic_cb,
                                                netconfig, NULL)) {
                l_error("netconfig: Failed to add subnet route.");
-
                return false;
        }
 
+       return true;
+}
+
+static bool netconfig_ipv4_gateway_route_install(struct netconfig *netconfig)
+{
+       L_AUTO_FREE_VAR(char *, gateway) = NULL;
+       const uint8_t *gateway_mac = NULL;
+       struct in_addr in_addr;
+       char ip[INET_ADDRSTRLEN];
+
        gateway = netconfig_ipv4_get_gateway(netconfig, &gateway_mac);
        if (!gateway) {
                l_debug("No gateway obtained from %s.",
@@ -889,6 +891,10 @@
                return true;
        }
 
+       if (!l_rtnl_address_get_address(netconfig->v4_address, ip) ||
+                       inet_pton(AF_INET, ip, &in_addr) < 1)
+               return false;
+
        netconfig->route4_add_gateway_cmd_id =
                l_rtnl_route4_add_gateway(rtnl, netconfig->ifindex, gateway, ip,
                                                ROUTE_PRIORITY_OFFSET,
@@ -902,23 +908,20 @@
                return false;
        }
 
-       if (gateway_mac) {
-               /*
-                * Attempt to use the gateway MAC address received from the AP
-                * by writing the mapping directly into the netdev's ARP table
-                * so as to save one data frame roundtrip before first IP
-                * connections are established.  This is very low-priority but
-                * print error messages just because they may indicate bigger
-                * problems.
-                */
-               if (!l_rtnl_neighbor_set_hwaddr(rtnl, netconfig->ifindex,
+       /*
+        * Attempt to use the gateway MAC address received from the AP by
+        * writing the mapping directly into the netdev's ARP table so as
+        * to save one data frame roundtrip before first IP connections
+        * are established.  This is very low-priority but print error
+        * messages just because they may indicate bigger problems.
+        */
+       if (gateway_mac && !l_rtnl_neighbor_set_hwaddr(rtnl, netconfig->ifindex,
                                        AF_INET,
                                        &netconfig->fils_override->ipv4_gateway,
                                        gateway_mac, 6,
                                        netconfig_set_neighbor_entry_cb, NULL,
                                        NULL))
-                       l_debug("l_rtnl_neighbor_set_hwaddr failed");
-       }
+               l_debug("l_rtnl_neighbor_set_hwaddr failed");
 
        return true;
 }
@@ -939,10 +942,9 @@
 
        netconfig_gateway_to_arp(netconfig);
 
-       if (!netconfig_ipv4_routes_install(netconfig)) {
-               l_error("netconfig: Failed to install IPv4 routes.");
+       if (!netconfig_ipv4_subnet_route_install(netconfig) ||
+                       !netconfig_ipv4_gateway_route_install(netconfig))
                return;
-       }
 
        netconfig_set_dns(netconfig);
        netconfig_set_domains(netconfig);
@@ -1215,9 +1217,7 @@
        struct netdev *netdev = netdev_find(netconfig->ifindex);
        bool set_address = (netconfig->rtm_protocol == RTPROT_STATIC);
 
-       if (netconfig->rtm_protocol == RTPROT_DHCP &&
-                       netconfig->fils_override &&
-                       netconfig->fils_override->ipv4_addr) {
+       if (netconfig_use_fils_addr(netconfig, AF_INET)) {
                L_AUTO_FREE_VAR(char *, addr_str) = netconfig_ipv4_to_string(
                                        netconfig->fils_override->ipv4_addr);
                uint8_t prefix_len = netconfig->fils_override->ipv4_prefix_len;
@@ -1298,9 +1298,7 @@
 
        sysfs_write_ipv6_setting(netdev_get_name(netdev), "disable_ipv6", "0");
 
-       if (netconfig->rtm_v6_protocol == RTPROT_DHCP &&
-                       netconfig->fils_override &&
-                       !l_memeqzero(netconfig->fils_override->ipv6_addr, 16)) {
+       if (netconfig_use_fils_addr(netconfig, AF_INET6)) {
                uint8_t prefix_len = netconfig->fils_override->ipv6_prefix_len;
                L_AUTO_FREE_VAR(char *, addr_str) = netconfig_ipv6_to_string(
                                        netconfig->fils_override->ipv6_addr);
@@ -1499,7 +1497,7 @@
        return true;
 }
 
-bool netconfig_reconfigure(struct netconfig *netconfig)
+bool netconfig_reconfigure(struct netconfig *netconfig, bool set_arp_gw)
 {
        /*
         * Starting with kernel 4.20, ARP cache is flushed when the netdev
@@ -1508,7 +1506,8 @@
         * lost or delayed.  Try to force the gateway into the ARP cache
         * to alleviate this
         */
-       netconfig_gateway_to_arp(netconfig);
+       if (set_arp_gw)
+               netconfig_gateway_to_arp(netconfig);
 
        if (netconfig->rtm_protocol == RTPROT_DHCP) {
                /* TODO l_dhcp_client sending a DHCP inform request */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/netconfig.h new/iwd-1.20/src/netconfig.h
--- old/iwd-1.19/src/netconfig.h        2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/src/netconfig.h        2021-11-18 21:21:21.000000000 +0100
@@ -36,7 +36,7 @@
 bool netconfig_configure(struct netconfig *netconfig,
                                netconfig_notify_func_t notify,
                                void *user_data);
-bool netconfig_reconfigure(struct netconfig *netconfig);
+bool netconfig_reconfigure(struct netconfig *netconfig, bool set_arp_gw);
 bool netconfig_reset(struct netconfig *netconfig);
 char *netconfig_get_dhcp_server_ipv4(struct netconfig *netconfig);
 bool netconfig_get_fils_ip_req(struct netconfig *netconfig,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/scan.c new/iwd-1.20/src/scan.c
--- old/iwd-1.19/src/scan.c     2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/src/scan.c     2021-11-18 21:21:21.000000000 +0100
@@ -1058,6 +1058,7 @@
 {
        uint16_t cost_level;
        uint16_t cost_flags;
+       bool dgaf_disable;
 
        if (!bss->wpa && is_ie_wpa_ie(data, len)) {
                bss->wpa = l_memdup(data - 2, len + 2);
@@ -1071,9 +1072,11 @@
 
        if (is_ie_wfa_ie(data, len, IE_WFA_OI_HS20_INDICATION)) {
                if (ie_parse_hs20_indication_from_data(data - 2, len + 2,
-                                       &bss->hs20_version, NULL, NULL) < 0)
+                                       &bss->hs20_version, NULL, NULL,
+                                       &dgaf_disable) < 0)
                        return;
 
+               bss->hs20_dgaf_disable = dgaf_disable;
                bss->hs20_capable = true;
                return;
        }
@@ -1252,6 +1255,23 @@
                        bss->rc_ie = l_memdup(iter.data - 2, iter.len + 2);
 
                        break;
+
+               case IE_TYPE_EXTENDED_CAPABILITIES:
+                       /* 802.11-2020 9.4.2.26
+                        *
+                        * "The length of the Extended Capabilities field is
+                        * variable. If fewer bits are received in an Extended
+                        * Capabilities field than shown in Table 9-153, the
+                        * rest of the Extended Capabilities field bits are
+                        * assumed to be zero"
+                        *
+                        * Currently only Proxy ARP bit (12) is checked, and if
+                        * not found, this is not a fatal error.
+                        */
+                       if (iter.len < 2)
+                               break;
+
+                       bss->proxy_arp = test_bit(iter.data, 12);
                }
        }
 
@@ -1608,6 +1628,10 @@
 {
        const struct scan_bss *new_bss = a, *bss = b;
 
+       if (bss->rank == new_bss->rank)
+               return (bss->signal_strength >
+                                       new_bss->signal_strength) ? 1 : -1;
+
        return (bss->rank > new_bss->rank) ? 1 : -1;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/scan.h new/iwd-1.20/src/scan.h
--- old/iwd-1.19/src/scan.h     2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/src/scan.h     2021-11-18 21:21:21.000000000 +0100
@@ -86,6 +86,8 @@
        bool anqp_capable : 1;
        bool hs20_capable : 1;
        bool force_default_sae_group : 1;
+       bool proxy_arp : 1;
+       bool hs20_dgaf_disable : 1;
        uint8_t cost_level : 3;
        uint8_t cost_flags : 4;
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/station.c new/iwd-1.20/src/station.c
--- old/iwd-1.19/src/station.c  2021-11-02 19:50:50.000000000 +0100
+++ new/iwd-1.20/src/station.c  2021-11-18 21:21:21.000000000 +0100
@@ -57,12 +57,15 @@
 #include "src/anqputil.h"
 #include "src/diagnostic.h"
 #include "src/frame-xchg.h"
+#include "src/sysfs.h"
 
 static struct l_queue *station_list;
 static uint32_t netdev_watch;
 static uint32_t mfp_setting;
 static uint32_t roam_retry_interval;
 static bool anqp_disabled;
+static bool supports_arp_evict_nocarrier;
+static bool supports_ndisc_evict_nocarrier;
 static struct watchlist event_watches;
 
 struct station {
@@ -695,6 +698,10 @@
                struct scan_bss *open = entry->data;
                struct ie_owe_transition_info *open_info = open->owe_trans;
 
+               /* AP does not advertise owe transition */
+               if (!open_info)
+                       continue;
+
                /*
                 * Check if this is an Open/Hidden pair:
                 *
@@ -1384,6 +1391,44 @@
        return "invalid";
 }
 
+static void station_set_evict_nocarrier(struct station *station, bool value)
+{
+       char *v = value ? "1" : "0";
+
+       if (supports_arp_evict_nocarrier)
+               sysfs_write_ipv4_setting(netdev_get_name(station->netdev),
+                                       "arp_evict_nocarrier", v);
+
+       if (supports_ndisc_evict_nocarrier)
+               sysfs_write_ipv6_setting(netdev_get_name(station->netdev),
+                                       "ndisc_evict_nocarrier", v);
+}
+
+/*
+ * Handles dropping ARP (IPv4) and neighbor advertisements (IPv6) settings.
+ */
+static void station_set_drop_neighbor_discovery(struct station *station,
+                                               bool value)
+{
+       char *v = value ? "1" : "0";
+
+       sysfs_write_ipv4_setting(netdev_get_name(station->netdev),
+                               "drop_gratuitous_arp", v);
+       sysfs_write_ipv6_setting(netdev_get_name(station->netdev),
+                               "drop_unsolicited_na", v);
+}
+
+static void station_set_drop_unicast_l2_multicast(struct station *station,
+                                                       bool value)
+{
+       char *v = value ? "1" : "0";
+
+       sysfs_write_ipv4_setting(netdev_get_name(station->netdev),
+                               "drop_unicast_in_l2_multicast", v);
+       sysfs_write_ipv6_setting(netdev_get_name(station->netdev),
+                               "drop_unicast_in_l2_multicast", v);
+}
+
 static void station_enter_state(struct station *station,
                                                enum station_state state)
 {
@@ -1431,19 +1476,46 @@
 
                periodic_scan_stop(station);
                break;
-       case STATION_STATE_DISCONNECTED:
-               periodic_scan_stop(station);
-               break;
        case STATION_STATE_CONNECTED:
                l_dbus_object_add_interface(dbus,
                                        netdev_get_path(station->netdev),
                                        IWD_STATION_DIAGNOSTIC_INTERFACE,
                                        station);
                periodic_scan_stop(station);
+
+               station_set_evict_nocarrier(station, true);
+
+               /*
+                * Hotspot Specification 2.0 - Section 6.5
+                *
+                * " - Shall drop all received {gratuitous ARP, unsolicited
+                *     Neighbor Advertisement} messages when the Proxy ARP field
+                *     is set to 1 in the Extended Capabilities element of the
+                *     serving AP.
+                *
+                *   - When the serving AP transmits frames containing an HS2.0
+                *     Indication element in which the value of the DGAF Disable
+                *     bit subfield is set to 0, the mobile device should
+                *     discard all received unicast IP packets that were
+                *     decrypted using the GTK"
+                */
+               if (station->connected_bss->proxy_arp)
+                       station_set_drop_neighbor_discovery(station, true);
+               if (station->connected_bss->hs20_dgaf_disable)
+                       station_set_drop_unicast_l2_multicast(station, true);
+
+               break;
+       case STATION_STATE_DISCONNECTED:
+               periodic_scan_stop(station);
+
+               station_set_evict_nocarrier(station, true);
+               station_set_drop_neighbor_discovery(station, false);
+               station_set_drop_unicast_l2_multicast(station, false);
                break;
        case STATION_STATE_DISCONNECTING:
                break;
        case STATION_STATE_ROAMING:
+               station_set_evict_nocarrier(station, false);
                break;
        }
 
@@ -1833,7 +1905,8 @@
                station_roam_timeout_rearm(station, roam_retry_interval);
 
        if (station->netconfig)
-               netconfig_reconfigure(station->netconfig);
+               netconfig_reconfigure(station->netconfig,
+                                       !supports_arp_evict_nocarrier);
 
        if (station->roam_freqs) {
                scan_freq_set_free(station->roam_freqs);
@@ -4457,6 +4530,11 @@
        if (!netconfig_enabled())
                l_info("station: Network configuration is disabled.");
 
+       supports_arp_evict_nocarrier = sysfs_supports_ipv4_setting("all",
+                                               "arp_evict_nocarrier");
+       supports_ndisc_evict_nocarrier = sysfs_supports_ipv6_setting("all",
+                                               "ndisc_evict_nocarrier");
+
        watchlist_init(&event_watches, NULL);
 
        return 0;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/sysfs.c new/iwd-1.20/src/sysfs.c
--- old/iwd-1.19/src/sysfs.c    1970-01-01 01:00:00.000000000 +0100
+++ new/iwd-1.20/src/sysfs.c    2021-11-18 21:21:21.000000000 +0100
@@ -0,0 +1,109 @@
+/*
+ *
+ *  Wireless daemon for Linux
+ *
+ *  Copyright (C) 2021  Intel 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 <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <ell/ell.h>
+
+#include "src/sysfs.h"
+
+static int write_string(const char *file, const char *value)
+{
+       size_t l = strlen(value);
+       int fd;
+       int r;
+
+       fd = L_TFR(open(file, O_WRONLY));
+       if (fd < 0)
+               return -errno;
+
+       r = L_TFR(write(fd, value, l));
+       L_TFR(close(fd));
+
+       return r;
+}
+
+static bool sysfs_supports_ip_setting(const char *ipv, const char *ifname,
+                                       const char *setting)
+{
+       struct stat st;
+       int err;
+       L_AUTO_FREE_VAR(char *, file) =
+               l_strdup_printf("/proc/sys/net/%s/conf/%s/%s", ipv,
+                                                       ifname, setting);
+
+       err = stat(file, &st);
+
+       if (!err && S_ISREG(st.st_mode) != 0)
+               return true;
+
+       return false;
+}
+
+bool sysfs_supports_ipv6_setting(const char *ifname, const char *setting)
+{
+       return sysfs_supports_ip_setting("ipv6", ifname, setting);
+}
+
+int sysfs_write_ipv6_setting(const char *ifname, const char *setting,
+                                       const char *value)
+{
+       int r;
+
+       L_AUTO_FREE_VAR(char *, file) =
+               l_strdup_printf("/proc/sys/net/ipv6/conf/%s/%s",
+                                                       ifname, setting);
+
+       r = write_string(file, value);
+       if (r < 0)
+               l_error("Unable to write %s to %s", setting, file);
+
+       return r;
+}
+
+bool sysfs_supports_ipv4_setting(const char *ifname, const char *setting)
+{
+       return sysfs_supports_ip_setting("ipv4", ifname, setting);
+}
+
+int sysfs_write_ipv4_setting(const char *ifname, const char *setting,
+                                       const char *value)
+{
+       int r;
+
+       L_AUTO_FREE_VAR(char *, file) =
+               l_strdup_printf("/proc/sys/net/ipv4/conf/%s/%s",
+                                                       ifname, setting);
+
+       r = write_string(file, value);
+       if (r < 0)
+               l_error("Unable to write %s to %s", setting, file);
+
+       return r;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-1.19/src/sysfs.h new/iwd-1.20/src/sysfs.h
--- old/iwd-1.19/src/sysfs.h    1970-01-01 01:00:00.000000000 +0100
+++ new/iwd-1.20/src/sysfs.h    2021-11-18 21:21:21.000000000 +0100
@@ -0,0 +1,28 @@
+/*
+ *
+ *  Wireless daemon for Linux
+ *
+ *  Copyright (C) 2021  Intel 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
+ *
+ */
+
+bool sysfs_supports_ipv6_setting(const char *ifname, const char *setting);
+int sysfs_write_ipv6_setting(const char *ifname, const char *setting,
+                                       const char *value);
+bool sysfs_supports_ipv4_setting(const char *ifname, const char *setting);
+int sysfs_write_ipv4_setting(const char *ifname, const char *setting,
+                                       const char *value);

Reply via email to