Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package iwd for openSUSE:Factory checked in 
at 2022-12-25 15:14:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/iwd (Old)
 and      /work/SRC/openSUSE:Factory/.iwd.new.1563 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "iwd"

Sun Dec 25 15:14:48 2022 rev:34 rq:1045126 version:2.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/iwd/iwd.changes  2022-12-04 14:58:29.664318675 
+0100
+++ /work/SRC/openSUSE:Factory/.iwd.new.1563/iwd.changes        2022-12-25 
15:15:03.985445580 +0100
@@ -1,0 +2,9 @@
+Fri Dec 23 20:03:14 UTC 2022 - Dirk Müller <dmuel...@suse.com>
+
+- update to 2.1:
+  * Fix issue with handling FT-over-DS action.
+  * Fix issue with handling scan and 6 GHz support check.
+  * Fix issue with handling when periodic scans get aborted.
+  * Add support for using 5 GHz frequencies in AP mode.
+
+-------------------------------------------------------------------

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

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

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

Other differences:
------------------
++++++ iwd.spec ++++++
--- /var/tmp/diff_new_pack.Qy6530/_old  2022-12-25 15:15:04.593449021 +0100
+++ /var/tmp/diff_new_pack.Qy6530/_new  2022-12-25 15:15:04.597449043 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           iwd
-Version:        2.0
+Version:        2.1
 Release:        0
 Summary:        Wireless daemon for Linux
 License:        LGPL-2.1-or-later

++++++ iwd-2.0.tar.xz -> iwd-2.1.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/ChangeLog new/iwd-2.1/ChangeLog
--- old/iwd-2.0/ChangeLog       2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/ChangeLog       2022-12-18 20:59:36.000000000 +0100
@@ -1,3 +1,9 @@
+ver 2.1:
+       Fix issue with handling FT-over-DS action.
+       Fix issue with handling scan and 6 GHz support check.
+       Fix issue with handling when periodic scans get aborted.
+       Add support for using 5 GHz frequencies in AP mode.
+
 ver 2.0:
        Fix issue with handling P2P and limiting ciphers to CCMP.
        Fix issue with scanning before forced roaming action.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/client/command.c new/iwd-2.1/client/command.c
--- old/iwd-2.0/client/command.c        2022-09-07 20:42:27.000000000 +0200
+++ new/iwd-2.1/client/command.c        2022-12-18 20:59:36.000000000 +0100
@@ -753,7 +753,7 @@
        argv += optind;
        argc -= optind;
 
-       if (argc < 2) {
+       if (argc < 1) {
                interactive_mode = true;
                return false;
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/configure new/iwd-2.1/configure
--- old/iwd-2.0/configure       2022-11-18 13:33:34.000000000 +0100
+++ new/iwd-2.1/configure       2022-12-18 21:01:21.000000000 +0100
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for iwd 2.0.
+# Generated by GNU Autoconf 2.71 for iwd 2.1.
 #
 #
 # 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.0'
-PACKAGE_STRING='iwd 2.0'
+PACKAGE_VERSION='2.1'
+PACKAGE_STRING='iwd 2.1'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1421,7 +1421,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.0 to adapt to many kinds of systems.
+\`configure' configures iwd 2.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1492,7 +1492,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of iwd 2.0:";;
+     short | recursive ) echo "Configuration of iwd 2.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1643,7 +1643,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-iwd configure 2.0
+iwd configure 2.1
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1861,7 +1861,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.0, which was
+It was created by iwd $as_me 2.1, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3136,7 +3136,7 @@
 
 # Define the identity of the package.
  PACKAGE='iwd'
- VERSION='2.0'
+ VERSION='2.1'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -13986,7 +13986,7 @@
                        test "${enable_monitor}" != "no" ||
                        test "${enable_wired}" = "yes" ||
                        test "${enable_hwsim}" = "yes"); then
-               ell_min_version="0.54"
+               ell_min_version="0.55"
        else
                ell_min_version="0.5"
        fi
@@ -14712,7 +14712,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.0, which was
+This file was extended by iwd $as_me 2.1, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -14780,7 +14780,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-iwd config.status 2.0
+iwd config.status 2.1
 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.0/configure.ac new/iwd-2.1/configure.ac
--- old/iwd-2.0/configure.ac    2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/configure.ac    2022-12-18 20:59:36.000000000 +0100
@@ -1,5 +1,5 @@
 AC_PREREQ([2.69])
-AC_INIT([iwd],[2.0])
+AC_INIT([iwd],[2.1])
 
 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.54"
+               ell_min_version="0.55"
        else
                ell_min_version="0.5"
        fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/ell/checksum.c new/iwd-2.1/ell/checksum.c
--- old/iwd-2.0/ell/checksum.c  2021-03-29 14:19:13.000000000 +0200
+++ new/iwd-2.1/ell/checksum.c  2022-12-18 20:40:29.000000000 +0100
@@ -146,55 +146,22 @@
        return sk;
 }
 
-/**
- * l_checksum_new:
- * @type: checksum type
- *
- * Creates new #l_checksum, using the checksum algorithm @type.
- *
- * Returns: a newly allocated #l_checksum object.
- **/
-LIB_EXPORT struct l_checksum *l_checksum_new(enum l_checksum_type type)
-{
-       struct l_checksum *checksum;
-       int fd;
-
-       if (!is_valid_index(checksum_algs, type) || !checksum_algs[type].name)
-               return NULL;
-
-       checksum = l_new(struct l_checksum, 1);
-       checksum->alg_info = &checksum_algs[type];
-
-       fd = create_alg(checksum->alg_info->name);
-       if (fd < 0)
-               goto error;
-
-       checksum->sk = accept4(fd, NULL, 0, SOCK_CLOEXEC);
-       close(fd);
-
-       if (checksum->sk < 0)
-               goto error;
-
-       return checksum;
-
-error:
-       l_free(checksum);
-       return NULL;
-}
-
-LIB_EXPORT struct l_checksum *l_checksum_new_cmac_aes(const void *key,
-                                                       size_t key_len)
+static struct l_checksum *checksum_new_common(const char *alg, int sockopt,
+                                               const void *data, size_t len,
+                                               struct checksum_info *info)
 {
        struct l_checksum *checksum;
        int fd;
 
-       fd = create_alg("cmac(aes)");
+       fd = create_alg(alg);
        if (fd < 0)
                return NULL;
 
-       if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
-               close(fd);
-               return NULL;
+       if (data) {
+               if (setsockopt(fd, SOL_ALG, sockopt, data, len) < 0) {
+                       close(fd);
+                       return NULL;
+               }
        }
 
        checksum = l_new(struct l_checksum, 1);
@@ -206,40 +173,44 @@
                return NULL;
        }
 
-       checksum->alg_info = &checksum_cmac_aes_alg;
+       checksum->alg_info = info;
        return checksum;
 }
 
-LIB_EXPORT struct l_checksum *l_checksum_new_hmac(enum l_checksum_type type,
-                                         const void *key, size_t key_len)
+/**
+ * l_checksum_new:
+ * @type: checksum type
+ *
+ * Creates new #l_checksum, using the checksum algorithm @type.
+ *
+ * Returns: a newly allocated #l_checksum object.
+ **/
+LIB_EXPORT struct l_checksum *l_checksum_new(enum l_checksum_type type)
 {
-       struct l_checksum *checksum;
-       int fd;
-
-       if (!is_valid_index(checksum_hmac_algs, type) ||
-                       !checksum_hmac_algs[type].name)
-               return NULL;
-
-       fd = create_alg(checksum_hmac_algs[type].name);
-       if (fd < 0)
+       if (!is_valid_index(checksum_algs, type) || !checksum_algs[type].name)
                return NULL;
 
-       if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
-               close(fd);
-               return NULL;
-       }
+       return checksum_new_common(checksum_algs[type].name, 0, NULL, 0,
+                                       &checksum_algs[type]);
+}
 
-       checksum = l_new(struct l_checksum, 1);
-       checksum->sk = accept4(fd, NULL, 0, SOCK_CLOEXEC);
-       close(fd);
+LIB_EXPORT struct l_checksum *l_checksum_new_cmac_aes(const void *key,
+                                                       size_t key_len)
+{
+       return checksum_new_common("cmac(aes)", ALG_SET_KEY, key, key_len,
+                                       &checksum_cmac_aes_alg);
+}
 
-       if (checksum->sk < 0) {
-               l_free(checksum);
+LIB_EXPORT struct l_checksum *l_checksum_new_hmac(enum l_checksum_type type,
+                                       const void *key, size_t key_len)
+{
+       if (!is_valid_index(checksum_hmac_algs, type) ||
+                       !checksum_hmac_algs[type].name)
                return NULL;
-       }
 
-       checksum->alg_info = &checksum_hmac_algs[type];
-       return checksum;
+       return checksum_new_common(checksum_hmac_algs[type].name,
+                                       ALG_SET_KEY, key, key_len,
+                                       &checksum_hmac_algs[type]);
 }
 
 /**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/ell/dhcp.c new/iwd-2.1/ell/dhcp.c
--- old/iwd-2.0/ell/dhcp.c      2022-11-18 10:08:38.000000000 +0100
+++ new/iwd-2.1/ell/dhcp.c      2022-12-18 20:40:29.000000000 +0100
@@ -365,12 +365,27 @@
                                        unsigned int len)
 {
        struct sockaddr_in si;
+       int r;
 
        memset(&si, 0, sizeof(si));
        si.sin_family = AF_INET;
        si.sin_port = L_CPU_TO_BE16(DHCP_PORT_SERVER);
        si.sin_addr.s_addr = client->lease->server_address;
-       return client->transport->send(client->transport, &si, request, len);
+
+       /*
+        * sendto() might fail with an EPERM error, which most likely means
+        * that the unicast was prevented by netfilter.  Ignore this case
+        * and assume that once the REBINDING timeout is hit, a broadcast
+        * will go through which will have a chance of renewing the lease
+        */
+       r = client->transport->send(client->transport, &si, request, len);
+       if (r == -EPERM) {
+               CLIENT_DEBUG("transport->send() failed with EPERM -> ignore");
+               CLIENT_DEBUG("Is a firewall denying unicast DHCP packets?");
+               return 0;
+       }
+
+       return r;
 }
 
 static int dhcp_client_send_request(struct l_dhcp_client *client)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/ap.c new/iwd-2.1/src/ap.c
--- old/iwd-2.0/src/ap.c        2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/src/ap.c        2022-12-18 20:59:36.000000000 +0100
@@ -70,6 +70,7 @@
        char ssid[33];
        char passphrase[64];
        uint8_t psk[32];
+       enum band_freq band;
        uint8_t channel;
        uint8_t *authorized_macs;
        unsigned int authorized_macs_num;
@@ -985,7 +986,7 @@
                                        frame_xchg_cb_t callback,
                                        void *user_data)
 {
-       uint32_t ch_freq = band_channel_to_freq(ap->channel, BAND_FREQ_2_4_GHZ);
+       uint32_t ch_freq = band_channel_to_freq(ap->channel, ap->band);
        uint64_t wdev_id = netdev_get_wdev_id(ap->netdev);
        struct iovec iov[2];
 
@@ -2408,7 +2409,7 @@
        uint32_t nl_akm = CRYPTO_AKM_PSK;
        uint32_t wpa_version = NL80211_WPA_VERSION_2;
        uint32_t auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
-       uint32_t ch_freq = band_channel_to_freq(ap->channel, BAND_FREQ_2_4_GHZ);
+       uint32_t ch_freq = band_channel_to_freq(ap->channel, ap->band);
        uint32_t ch_width = NL80211_CHAN_WIDTH_20;
        unsigned int i;
 
@@ -3170,6 +3171,33 @@
        return list;
 }
 
+static bool ap_validate_band_channel(struct ap_state *ap)
+{
+       struct wiphy *wiphy = netdev_get_wiphy(ap->netdev);
+       uint32_t freq;
+       const struct band_freq_attrs *attr;
+
+       if (!(wiphy_get_supported_bands(wiphy) & ap->band)) {
+               l_error("AP hardware does not support band");
+               return -EINVAL;
+       }
+
+       freq = band_channel_to_freq(ap->channel, ap->band);
+       if (!freq) {
+               l_error("AP invalid band (%s) and channel (%u) combination",
+                       (ap->band & BAND_FREQ_5_GHZ) ? "5Ghz" : "2.4GHz",
+                       ap->channel);
+               return false;
+       }
+
+       attr = wiphy_get_frequency_info(wiphy, freq);
+       if (!attr || attr->disabled) {
+               l_error("AP frequency %u disabled or unsupported", freq);
+               return false;
+       }
+       return true;
+}
+
 static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
                                bool *out_cck_rates)
 {
@@ -3214,17 +3242,31 @@
                unsigned int uintval;
 
                if (!l_settings_get_uint(config, "General", "Channel",
-                                               &uintval) ||
-                               !band_channel_to_freq(uintval,
-                                                       BAND_FREQ_2_4_GHZ)) {
+                                               &uintval)) {
                        l_error("AP Channel value unsupported");
                        return -EINVAL;
                }
 
                ap->channel = uintval;
-       } else
+
+               /*
+                * 6GHz is not supported so we can use only a channel number to
+                * distinguish between 2.4 and 5GHz.
+                */
+               if (ap->channel >= 36)
+                       ap->band = BAND_FREQ_5_GHZ;
+               else
+                       ap->band = BAND_FREQ_2_4_GHZ;
+       } else {
                /* TODO: Start a Get Survey to decide the channel */
                ap->channel = 6;
+               ap->band = BAND_FREQ_2_4_GHZ;
+       }
+
+       if (!ap_validate_band_channel(ap)) {
+               l_error("AP Band and Channel combination invalid");
+               return -EINVAL;
+       }
 
        strval = l_settings_get_string(config, "WSC", "DeviceName");
        if (strval) {
@@ -3290,7 +3332,13 @@
                l_strfreev(strvval);
        }
 
-       if (l_settings_get_value(config, "General", "NoCCKRates")) {
+       /*
+        * Since 5GHz won't ever support only CCK rates we can ignore this
+        * setting on that band.
+        */
+       if (ap->band & BAND_FREQ_5_GHZ)
+               *out_cck_rates = false;
+       else if (l_settings_get_value(config, "General", "NoCCKRates")) {
                bool boolval;
 
                if (!l_settings_get_bool(config, "General", "NoCCKRates",
@@ -3381,6 +3429,9 @@
        uint64_t wdev_id = netdev_get_wdev_id(netdev);
        int err;
        bool cck_rates = true;
+       const uint8_t *rates;
+       unsigned int num_rates;
+       unsigned int i;
 
        if (L_WARN_ON(!config)) {
                if (err_out)
@@ -3406,22 +3457,17 @@
 
        wsc_uuid_from_addr(netdev_get_address(netdev), ap->wsc_uuid_r);
 
+       rates = wiphy_get_supported_rates(wiphy, ap->band, &num_rates);
+       if (!rates)
+               goto error;
+
        ap->rates = l_uintset_new(200);
 
-       /* TODO: Pick from actual supported rates */
-       if (!cck_rates) {
-               l_uintset_put(ap->rates, 12); /* 6 Mbps*/
-               l_uintset_put(ap->rates, 18); /* 9 Mbps*/
-               l_uintset_put(ap->rates, 24); /* 12 Mbps*/
-               l_uintset_put(ap->rates, 36); /* 18 Mbps*/
-               l_uintset_put(ap->rates, 48); /* 24 Mbps*/
-               l_uintset_put(ap->rates, 72); /* 36 Mbps*/
-               l_uintset_put(ap->rates, 96); /* 48 Mbps*/
-               l_uintset_put(ap->rates, 108); /* 54 Mbps*/
-       } else {
-               l_uintset_put(ap->rates, 2); /* 1 Mbps*/
-               l_uintset_put(ap->rates, 11); /* 5.5 Mbps*/
-               l_uintset_put(ap->rates, 22); /* 11 Mbps*/
+       for (i = 0; i < num_rates; i++) {
+               if (cck_rates && !L_IN_SET(rates[i], 2, 4, 11, 22))
+                       continue;
+
+               l_uintset_put(ap->rates, rates[i]);
        }
 
        if (!frame_watch_add(wdev_id, 0, 0x0000 |
@@ -4080,7 +4126,7 @@
        if (!ap_if->ap || !ap_if->ap->started)
                return false;
 
-       freq = band_channel_to_freq(ap_if->ap->channel, BAND_FREQ_2_4_GHZ);
+       freq = band_channel_to_freq(ap_if->ap->channel, ap_if->ap->band);
 
        l_dbus_message_builder_append_basic(builder, 'u', &freq);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/band.c new/iwd-2.1/src/band.c
--- old/iwd-2.0/src/band.c      2022-09-07 20:42:27.000000000 +0200
+++ new/iwd-2.1/src/band.c      2022-12-18 20:59:36.000000000 +0100
@@ -36,6 +36,8 @@
        if (band->he_capabilities)
                l_queue_destroy(band->he_capabilities, l_free);
 
+       l_free(band->freq_attrs);
+
        l_free(band);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/band.h new/iwd-2.1/src/band.h
--- old/iwd-2.0/src/band.h      2022-09-07 20:42:27.000000000 +0200
+++ new/iwd-2.1/src/band.h      2022-12-18 20:59:36.000000000 +0100
@@ -55,8 +55,16 @@
        uint8_t he_mcs_set[12];
 };
 
+struct band_freq_attrs {
+       bool supported : 1;
+       bool disabled : 1;
+       bool no_ir : 1;
+} __attribute__ ((packed));
+
 struct band {
        enum band_freq freq;
+       struct band_freq_attrs *freq_attrs;
+       size_t freqs_len;
        /* Each entry is type struct band_he_capabilities */
        struct l_queue *he_capabilities;
        uint8_t vht_mcs_set[8];
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/ft.c new/iwd-2.1/src/ft.c
--- old/iwd-2.0/src/ft.c        2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/src/ft.c        2022-12-18 20:59:36.000000000 +0100
@@ -54,8 +54,12 @@
        uint8_t *authenticator_ie;
        uint8_t prev_bssid[6];
        uint32_t frequency;
+       uint32_t ds_frequency;
        uint32_t offchannel_id;
 
+       struct l_timeout *timeout;
+       struct wiphy_radio_work_item work;
+
        struct ie_ft_info ft_info;
 
        bool parsed : 1;
@@ -830,6 +834,11 @@
 
        info->parsed = true;
 
+       l_timeout_remove(info->timeout);
+       info->timeout = NULL;
+
+       wiphy_radio_work_done(netdev_get_wiphy(netdev), info->work.id);
+
        return;
 
 ft_error:
@@ -868,6 +877,9 @@
        if (info->authenticator_ie)
                l_free(info->authenticator_ie);
 
+       if (info->timeout)
+               l_timeout_remove(info->timeout);
+
        l_free(info);
 }
 
@@ -900,19 +912,17 @@
        handshake_state_derive_ptk(hs);
 }
 
-int ft_action(uint32_t ifindex, uint32_t freq, const struct scan_bss *target)
+static bool ft_send_action(struct wiphy_radio_work_item *work)
 {
-       struct netdev *netdev = netdev_find(ifindex);
+       struct ft_info *info = l_container_of(work, struct ft_info, work);
+       struct netdev *netdev = netdev_find(info->ifindex);
        struct handshake_state *hs = netdev_get_handshake(netdev);
-       struct ft_info *info;
        uint8_t ft_req[14];
        struct iovec iov[5];
        uint8_t ies[512];
        size_t len;
        int ret = -EINVAL;
 
-       info = ft_info_new(hs, target);
-
        ft_req[0] = 6; /* FT category */
        ft_req[1] = 1; /* FT Request action */
        memcpy(ft_req + 2, info->spa, 6);
@@ -928,17 +938,47 @@
        iov[1].iov_base = ies;
        iov[1].iov_len = len;
 
-       ret = tx_frame(hs->ifindex, 0x00d0, freq, hs->aa, iov, 2);
+       ret = tx_frame(hs->ifindex, 0x00d0, info->ds_frequency, hs->aa, iov, 2);
        if (ret < 0)
                goto failed;
 
        l_queue_push_tail(info_list, info);
 
-       return 0;
+       return false;
 
 failed:
-       l_free(info);
-       return ret;
+       l_debug("FT-over-DS action failed to "MAC, MAC_STR(hs->aa));
+
+       ft_info_destroy(info);
+       return true;
+}
+
+struct wiphy_radio_work_item_ops ft_ops = {
+       .do_work = ft_send_action,
+};
+
+static void ft_ds_timeout(struct l_timeout *timeout, void *user_data)
+{
+       struct ft_info *info = user_data;
+       struct netdev *netdev = netdev_find(info->ifindex);
+
+       wiphy_radio_work_done(netdev_get_wiphy(netdev), info->work.id);
+}
+
+int ft_action(uint32_t ifindex, uint32_t freq, const struct scan_bss *target)
+{
+       struct netdev *netdev = netdev_find(ifindex);
+       struct handshake_state *hs = netdev_get_handshake(netdev);
+       struct ft_info *info;
+
+       info = ft_info_new(hs, target);
+       info->ds_frequency = freq;
+       info->timeout = l_timeout_create_ms(200, ft_ds_timeout, info, NULL);
+
+       wiphy_radio_work_insert(netdev_get_wiphy(netdev), &info->work,
+                               WIPHY_WORK_PRIORITY_FT, &ft_ops);
+
+       return 0;
 }
 
 void __ft_rx_authenticate(uint32_t ifindex, const uint8_t *frame,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/iwd.ap.5 new/iwd-2.1/src/iwd.ap.5
--- old/iwd-2.0/src/iwd.ap.5    2022-11-18 13:35:29.000000000 +0100
+++ new/iwd-2.1/src/iwd.ap.5    2022-12-18 21:03:12.000000000 +0100
@@ -61,8 +61,17 @@
 T}     T{
 Channel number
 .sp
-Optional channel number for the access point to operate on.  Only the
-2.4GHz\-band channels are currently allowed.
+Optional channel number for the access point to operate on. If omitted
+the channel will be chosen automatically. Channels greater than or equal
+to 36 will select the 5GHz band for the AP to operate on.
+.sp
+Note: Due to regulatory requirements the linux kernel does not allow or
+strictly limits 5GHz use in AP mode while in world roaming. These
+frequencies become available once the country is set, either via IWD\(aqs
+main.conf option \fB[General].Country\fP (see \fBman iwd.config\fP) or
+externally (e.g. iw reg set <CC>). If you are having trouble using 5GHz
+ensure the country is set, and that the desired frequency/channel is
+unrestricted.
 T}
 _
 .TE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/iwd.ap.rst new/iwd-2.1/src/iwd.ap.rst
--- old/iwd-2.0/src/iwd.ap.rst  2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/src/iwd.ap.rst  2022-12-18 20:59:36.000000000 +0100
@@ -55,8 +55,17 @@
    * - Channel
      - Channel number
 
-       Optional channel number for the access point to operate on.  Only the
-       2.4GHz-band channels are currently allowed.
+       Optional channel number for the access point to operate on. If omitted
+       the channel will be chosen automatically. Channels greater than or equal
+       to 36 will select the 5GHz band for the AP to operate on.
+
+       Note: Due to regulatory requirements the linux kernel does not allow or
+       strictly limits 5GHz use in AP mode while in world roaming. These
+       frequencies become available once the country is set, either via IWD's
+       main.conf option ``[General].Country`` (see ``man iwd.config``) or
+       externally (e.g. iw reg set <CC>). If you are having trouble using 5GHz
+       ensure the country is set, and that the desired frequency/channel is
+       unrestricted.
 
 Network Authentication Settings
 -------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/iwd.config.5 new/iwd-2.1/src/iwd.config.5
--- old/iwd-2.0/src/iwd.config.5        2022-11-18 13:35:27.000000000 +0100
+++ new/iwd-2.1/src/iwd.config.5        2022-12-18 21:03:10.000000000 +0100
@@ -274,7 +274,7 @@
 .sp
 Sets the global default that tells \fBiwd\fP whether it should configure
 IPv6 addresses and routes (either provided via static settings,
-Router Advertisements or DHCPv6 protocol).  This setting is disabled
+Router Advertisements or DHCPv6 protocol).  This setting is enabled
 by default.  This setting can also be overridden on a per\-network basis.
 T}
 _
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/iwd.config.rst 
new/iwd-2.1/src/iwd.config.rst
--- old/iwd-2.0/src/iwd.config.rst      2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/src/iwd.config.rst      2022-12-18 20:59:36.000000000 +0100
@@ -232,7 +232,7 @@
 
        Sets the global default that tells **iwd** whether it should configure
        IPv6 addresses and routes (either provided via static settings,
-       Router Advertisements or DHCPv6 protocol).  This setting is disabled
+       Router Advertisements or DHCPv6 protocol).  This setting is enabled
        by default.  This setting can also be overridden on a per-network basis.
 
    * - NameResolvingService
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/nl80211util.c 
new/iwd-2.1/src/nl80211util.c
--- old/iwd-2.0/src/nl80211util.c       2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/src/nl80211util.c       2022-12-18 20:59:36.000000000 +0100
@@ -502,19 +502,21 @@
 
 int nl80211_parse_supported_frequencies(struct l_genl_attr *band_freqs,
                                        struct scan_freq_set *supported_list,
-                                       struct scan_freq_set *disabled_list)
+                                       struct band_freq_attrs *list,
+                                       size_t num_channels)
 {
        uint16_t type, len;
        const void *data;
        struct l_genl_attr attr;
        struct l_genl_attr nested;
+       uint8_t channel;
 
        if (!l_genl_attr_recurse(band_freqs, &nested))
                return -EBADMSG;
 
        while (l_genl_attr_next(&nested, NULL, NULL, NULL)) {
                uint32_t freq = 0;
-               bool disabled = false;
+               struct band_freq_attrs freq_attr = { 0 };
 
                if (!l_genl_attr_recurse(&nested, &attr))
                        continue;
@@ -523,9 +525,13 @@
                        switch (type) {
                        case NL80211_FREQUENCY_ATTR_FREQ:
                                freq = *((uint32_t *) data);
+                               freq_attr.supported = true;
                                break;
                        case NL80211_FREQUENCY_ATTR_DISABLED:
-                               disabled = true;
+                               freq_attr.disabled = true;
+                               break;
+                       case NL80211_FREQUENCY_ATTR_NO_IR:
+                               freq_attr.no_ir = true;
                                break;
                        }
                }
@@ -533,11 +539,17 @@
                if (!freq)
                        continue;
 
+               channel = band_freq_to_channel(freq, NULL);
+               if (!channel)
+                       continue;
+
+               if (L_WARN_ON(channel > num_channels))
+                       continue;
+
                if (supported_list)
                        scan_freq_set_add(supported_list, freq);
 
-               if (disabled && disabled_list)
-                       scan_freq_set_add(disabled_list, freq);
+               list[channel] = freq_attr;
        }
 
        return 0;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/nl80211util.h 
new/iwd-2.1/src/nl80211util.h
--- old/iwd-2.0/src/nl80211util.h       2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/src/nl80211util.h       2022-12-18 20:59:36.000000000 +0100
@@ -24,6 +24,7 @@
 
 struct band_chandef;
 struct scan_freq_set;
+struct band_freq_attrs;
 
 int nl80211_parse_attrs(struct l_genl_msg *msg, int tag, ...);
 
@@ -58,5 +59,6 @@
 
 int nl80211_parse_chandef(struct l_genl_msg *msg, struct band_chandef *out);
 int nl80211_parse_supported_frequencies(struct l_genl_attr *band_freqs,
-                                       struct scan_freq_set *supported,
-                                       struct scan_freq_set *disabled);
+                                       struct scan_freq_set *supported_list,
+                                       struct band_freq_attrs *list,
+                                       size_t num_channels);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/scan.c new/iwd-2.1/src/scan.c
--- old/iwd-2.0/src/scan.c      2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/src/scan.c      2022-12-18 20:59:36.000000000 +0100
@@ -83,7 +83,6 @@
        bool canceled : 1; /* Is scan_cancel being called on this request? */
        bool passive:1; /* Active or Passive scan? */
        bool started : 1; /* Has TRIGGER_SCAN succeeded at least once? */
-       bool periodic : 1; /* Started as a periodic scan? */
        /*
         * Set to true if the TRIGGER_SCAN command at the head of the 'cmds'
         * queue was acked by the kernel indicating that the scan request was
@@ -426,7 +425,7 @@
                 * rates we don't want to advertise support for 802.11b rates.
                 */
                if (L_WARN_ON(!(supported = wiphy_get_supported_rates(sc->wiphy,
-                                                       NL80211_BAND_2GHZ,
+                                                       BAND_FREQ_2_4_GHZ,
                                                        &num_supported))))
                        goto done;
 
@@ -997,7 +996,6 @@
 static bool scan_periodic_queue(struct scan_context *sc)
 {
        struct scan_parameters params = {};
-       struct scan_request *sr;
 
        if (sc->sp.needs_active_scan && known_networks_has_hidden()) {
                params.randomize_mac_addr_hint = true;
@@ -1015,13 +1013,7 @@
                                        scan_periodic_notify, sc,
                                        scan_periodic_destroy);
 
-       if (!sc->sp.id)
-               return false;
-
-       sr = l_queue_peek_tail(sc->requests);
-       sr->periodic = true;
-
-       return true;
+       return sc->sp.id != 0;
 }
 
 static bool scan_periodic_is_disabled(void)
@@ -1933,12 +1925,9 @@
        struct scan_freq_set *freqs_6ghz;
        struct scan_freq_set *allowed;
        bool allow_6g;
-       const struct scan_freq_set *supported =
-                                       wiphy_get_supported_freqs(wiphy);
 
-       /* Only care about regulatory events, and if 6GHz capable */
-       if (event != WIPHY_STATE_WATCH_EVENT_REGDOM_DONE ||
-                       !(scan_freq_set_get_bands(supported) & BAND_FREQ_6_GHZ))
+       /* Only care about completed regulatory dumps */
+       if (event != WIPHY_STATE_WATCH_EVENT_REGDOM_DONE)
                return;
 
        if (!sc->sp.id)
@@ -2242,13 +2231,7 @@
 
                if (sr->triggered) {
                        sr->triggered = false;
-
-                       /* If periodic scan, don't report the abort */
-                       if (sr->periodic) {
-                               l_queue_remove(sc->requests, sr);
-                               wiphy_radio_work_done(sc->wiphy, sr->work.id);
-                       } else
-                               scan_finished(sc, -ECANCELED, NULL, NULL, sr);
+                       scan_finished(sc, -ECANCELED, NULL, NULL, sr);
                } else if (wiphy_radio_work_is_running(sc->wiphy,
                                                        sr->work.id)) {
                        /*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/station.c new/iwd-2.1/src/station.c
--- old/iwd-2.0/src/station.c   2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/src/station.c   2022-12-18 20:59:36.000000000 +0100
@@ -1407,8 +1407,6 @@
 {
        _auto_(scan_freq_set_free) struct scan_freq_set *known_freq_set = NULL;
        bool known_6ghz;
-       const struct scan_freq_set *disabled = wiphy_get_disabled_freqs(
-                                                               station->wiphy);
 
        if (wiphy_regdom_is_updating(station->wiphy)) {
                l_debug("regdom is updating, delaying quick scan");
@@ -1430,9 +1428,11 @@
         * this since its so limited, so return an error which will fall back to
         * full autoconnect.
         */
-       if ((scan_freq_set_get_bands(disabled) & BAND_FREQ_6_GHZ) &&
-                               wiphy_country_is_unknown(station->wiphy) &&
-                               known_6ghz)
+       if (wiphy_get_supported_bands(station->wiphy) & BAND_FREQ_6_GHZ &&
+                       wiphy_band_is_disabled(station->wiphy,
+                                               BAND_FREQ_6_GHZ) &&
+                       wiphy_country_is_unknown(station->wiphy) &&
+                       known_6ghz)
                return -ENOTSUP;
 
        if (!wiphy_constrain_freq_set(station->wiphy, known_freq_set)) {
@@ -1812,10 +1812,6 @@
        struct scan_freq_set *freq_set_md, *freq_set_no_md;
        uint32_t current_freq = 0;
        struct handshake_state *hs = netdev_get_handshake(station->netdev);
-       const struct scan_freq_set *supported =
-                               wiphy_get_supported_freqs(station->wiphy);
-       const struct scan_freq_set *disabled =
-                               wiphy_get_disabled_freqs(station->wiphy);
 
        freq_set_md = scan_freq_set_new();
        freq_set_no_md = scan_freq_set_new();
@@ -1828,6 +1824,7 @@
                uint32_t freq;
                enum band_freq band;
                const uint8_t *cc = NULL;
+               const struct band_freq_attrs *attr;
 
                if (ie_tlv_iter_get_tag(&iter) != IE_TYPE_NEIGHBOR_REPORT)
                        continue;
@@ -1853,8 +1850,8 @@
                        continue;
 
                /* Skip if frequency is not supported or disabled */
-               if (!scan_freq_set_contains(supported, freq) ||
-                               scan_freq_set_contains(disabled, freq))
+               attr = wiphy_get_frequency_info(station->wiphy, freq);
+               if (!attr || attr->disabled)
                        continue;
 
                if (!memcmp(info.addr,
@@ -1973,47 +1970,6 @@
        return true;
 }
 
-static void station_ft_ds_action_start(struct station *station)
-{
-       struct handshake_state *hs = netdev_get_handshake(station->netdev);
-       uint16_t mdid;
-       const struct l_queue_entry *entry;
-       struct scan_bss *bss;
-       struct ie_rsn_info rsn_info;
-
-       if (!station_can_fast_transition(hs, station->connected_bss) ||
-                                               !(hs->mde[4] & 1))
-               return;
-
-       if (ie_parse_mobility_domain_from_data(hs->mde, hs->mde[1] + 2,
-                                               &mdid, NULL, NULL) < 0)
-               return;
-
-       for (entry = network_bss_list_get_entries(station->connected_network);
-                                               entry; entry = entry->next) {
-               bss = entry->data;
-
-               if (bss == station->connected_bss)
-                       continue;
-
-               if (mdid != l_get_le16(bss->mde))
-                       continue;
-
-               if (scan_bss_get_rsn_info(bss, &rsn_info) < 0)
-                       continue;
-
-               if (!IE_AKM_IS_FT(rsn_info.akm_suites))
-                       continue;
-
-               /*
-                * Fire and forget. Netdev will maintain a cache of responses
-                * and when the time comes these can be referenced for a roam
-                */
-               ft_action(netdev_get_ifindex(station->netdev),
-                               station->connected_bss->frequency, bss);
-       }
-}
-
 static void station_roamed(struct station *station)
 {
        station->roam_scan_full = false;
@@ -2042,8 +1998,6 @@
 
        l_queue_clear(station->roam_bss_list, l_free);
 
-       station_ft_ds_action_start(station);
-
        station_enter_state(station, STATION_STATE_CONNECTED);
 }
 
@@ -2297,7 +2251,7 @@
 
        ret = ft_associate(netdev_get_ifindex(station->netdev), bss->addr);
        if (ret == -ENOENT) {
-               station_debug_event(station, "ft-over-air-roam-failed");
+               station_debug_event(station, "ft-roam-failed");
 try_next:
                station_transition_start(station);
                return true;
@@ -2327,7 +2281,6 @@
        const struct network_info *info = network_get_info(connected);
        const struct iovec *vendor_ies;
        size_t iov_elems = 0;
-       int ret;
 
        /* Rebuild handshake RSN for target AP */
        if (station_build_handshake_rsn(hs, station->wiphy,
@@ -2338,34 +2291,17 @@
        vendor_ies = network_info_get_extra_ies(info, bss, &iov_elems);
        handshake_state_set_vendor_ies(hs, vendor_ies, iov_elems);
 
-       if ((hs->mde[4] & 1)) {
-               ret = ft_associate(netdev_get_ifindex(station->netdev),
-                                       bss->addr);
-               /* No action responses from this BSS, try over air */
-               if (ret == -ENOENT) {
-                       station_debug_event(station, "try-ft-over-air");
-                       goto try_over_air;
-               } else if (ret < 0)
-                       return false;
-
-               station->connected_bss = bss;
-               station->preparing_roam = false;
-               station_enter_state(station, STATION_STATE_FT_ROAMING);
-
-               return true;
-       } else {
-try_over_air:
-               /*
-                * Send FT-Authenticate and insert a work item which will be
-                * gated until authentication completes
-                */
+       /* Both ft_action/ft_authenticate will gate the associate work item */
+       if ((hs->mde[4] & 1))
+               ft_action(netdev_get_ifindex(station->netdev),
+                               station->connected_bss->frequency, bss);
+       else
                ft_authenticate(netdev_get_ifindex(station->netdev), bss);
 
-               wiphy_radio_work_insert(station->wiphy, &station->ft_work,
+       wiphy_radio_work_insert(station->wiphy, &station->ft_work,
                                WIPHY_WORK_PRIORITY_CONNECT, &ft_work_ops);
 
-               return true;
-       }
+       return true;
 }
 
 static bool station_try_next_transition(struct station *station,
@@ -3117,8 +3053,6 @@
                        l_warn("Could not request neighbor report");
        }
 
-       station_ft_ds_action_start(station);
-
        network_connected(station->connected_network);
 
        if (station->netconfig) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/util.c new/iwd-2.1/src/util.c
--- old/iwd-2.0/src/util.c      2022-09-07 20:42:27.000000000 +0200
+++ new/iwd-2.1/src/util.c      2022-12-18 20:59:36.000000000 +0100
@@ -360,6 +360,28 @@
        return false;
 }
 
+bool scan_freq_set_remove(struct scan_freq_set *freqs, uint32_t freq)
+{
+       enum band_freq band;
+       uint8_t channel;
+
+       channel = band_freq_to_channel(freq, &band);
+       if (!channel)
+               return false;
+
+       switch (band) {
+       case BAND_FREQ_2_4_GHZ:
+               freqs->channels_2ghz &= ~(1 << (channel - 1));
+               return true;
+       case BAND_FREQ_5_GHZ:
+               return l_uintset_take(freqs->channels_5ghz, channel);
+       case BAND_FREQ_6_GHZ:
+               return l_uintset_take(freqs->channels_6ghz, channel);
+       }
+
+       return false;
+}
+
 bool scan_freq_set_contains(const struct scan_freq_set *freqs, uint32_t freq)
 {
        enum band_freq band;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/util.h new/iwd-2.1/src/util.h
--- old/iwd-2.0/src/util.h      2022-09-07 20:42:27.000000000 +0200
+++ new/iwd-2.1/src/util.h      2022-12-18 20:59:36.000000000 +0100
@@ -111,6 +111,7 @@
 struct scan_freq_set *scan_freq_set_new(void);
 void scan_freq_set_free(struct scan_freq_set *freqs);
 bool scan_freq_set_add(struct scan_freq_set *freqs, uint32_t freq);
+bool scan_freq_set_remove(struct scan_freq_set *freqs, uint32_t freq);
 bool scan_freq_set_contains(const struct scan_freq_set *freqs, uint32_t freq);
 uint32_t scan_freq_set_get_bands(const struct scan_freq_set *freqs);
 void scan_freq_set_foreach(const struct scan_freq_set *freqs,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/wiphy.c new/iwd-2.1/src/wiphy.c
--- old/iwd-2.0/src/wiphy.c     2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/src/wiphy.c     2022-12-18 20:59:36.000000000 +0100
@@ -496,6 +496,67 @@
        return wiphy->disabled_freqs;
 }
 
+static struct band *wiphy_get_band(const struct wiphy *wiphy, enum band_freq 
band)
+{
+       switch (band) {
+       case BAND_FREQ_2_4_GHZ:
+               return wiphy->band_2g;
+       case BAND_FREQ_5_GHZ:
+               return wiphy->band_5g;
+       case BAND_FREQ_6_GHZ:
+               return wiphy->band_6g;
+       default:
+               return NULL;
+       }
+}
+
+const struct band_freq_attrs *wiphy_get_frequency_info(
+                                               const struct wiphy *wiphy,
+                                               uint32_t freq)
+{
+       struct band_freq_attrs *attr;
+       enum band_freq band;
+       uint8_t channel;
+       struct band *bandp;
+
+       channel = band_freq_to_channel(freq, &band);
+       if (!channel)
+               return NULL;
+
+       bandp = wiphy_get_band(wiphy, band);
+       if (!bandp)
+               return NULL;
+
+       attr = &bandp->freq_attrs[channel];
+       if (!attr->supported)
+               return NULL;
+
+       return attr;
+}
+
+bool wiphy_band_is_disabled(const struct wiphy *wiphy, enum band_freq band)
+{
+       struct band_freq_attrs attr;
+       unsigned int i;
+       struct band *bandp;
+
+       bandp = wiphy_get_band(wiphy, band);
+       if (!bandp)
+               return true;
+
+       for (i = 0; i < bandp->freqs_len; i++) {
+               attr = bandp->freq_attrs[i];
+
+               if (!attr.supported)
+                       continue;
+
+               if (!attr.disabled)
+                       return false;
+       }
+
+       return true;
+}
+
 bool wiphy_supports_probe_resp_offload(struct wiphy *wiphy)
 {
        return wiphy->ap_probe_resp_offload;
@@ -745,8 +806,35 @@
 bool wiphy_constrain_freq_set(const struct wiphy *wiphy,
                                                struct scan_freq_set *set)
 {
+       struct band *bands[3] = { wiphy->band_2g,
+                                       wiphy->band_5g, wiphy->band_6g };
+       unsigned int b;
+       unsigned int i;
+
        scan_freq_set_constrain(set, wiphy->supported_freqs);
-       scan_freq_set_subtract(set, wiphy->disabled_freqs);
+
+       for (b = 0; b < L_ARRAY_SIZE(bands); b++) {
+               struct band *band = bands[b];
+
+               if (!band)
+                       continue;
+
+               for (i = 0; i < band->freqs_len; i++) {
+                       uint32_t freq;
+
+                       if (!band->freq_attrs[i].supported)
+                               continue;
+
+                       if (!band->freq_attrs[i].disabled)
+                               continue;
+
+                       freq = band_channel_to_freq(i, band->freq);
+                       if (!freq)
+                               continue;
+
+                       scan_freq_set_remove(set, freq);
+               }
+       }
 
        if (!scan_freq_set_get_bands(set))
                /* The set is empty. */
@@ -788,24 +876,11 @@
        return wiphy->supported_iftypes & (1 << (iftype - 1));
 }
 
-const uint8_t *wiphy_get_supported_rates(struct wiphy *wiphy, unsigned int 
band,
+const uint8_t *wiphy_get_supported_rates(struct wiphy *wiphy,
+                                               enum band_freq band,
                                                unsigned int *out_num)
 {
-       struct band *bandp;
-
-       switch (band) {
-       case NL80211_BAND_2GHZ:
-               bandp = wiphy->band_2g;
-               break;
-       case NL80211_BAND_5GHZ:
-               bandp = wiphy->band_5g;
-               break;
-       case NL80211_BAND_6GHZ:
-               bandp = wiphy->band_6g;
-               break;
-       default:
-               return NULL;
-       }
+       struct band *bandp = wiphy_get_band(wiphy, band);
 
        if (!bandp)
                return NULL;
@@ -863,19 +938,9 @@
        if (band_freq_to_channel(bss->frequency, &band) == 0)
                return -ENOTSUP;
 
-       switch (band) {
-       case BAND_FREQ_2_4_GHZ:
-               bandp = wiphy->band_2g;
-               break;
-       case BAND_FREQ_5_GHZ:
-               bandp = wiphy->band_5g;
-               break;
-       case BAND_FREQ_6_GHZ:
-               bandp = wiphy->band_6g;
-               break;
-       default:
+       bandp = wiphy_get_band(wiphy, band);
+       if (!bandp)
                return -ENOTSUP;
-       }
 
        ie_tlv_iter_init(&iter, ies, ies_len);
 
@@ -951,7 +1016,7 @@
 
 bool wiphy_regdom_is_updating(struct wiphy *wiphy)
 {
-       return wiphy->pending_freqs != NULL;
+       return wiphy->dump_id || (!wiphy->self_managed && wiphy_dump_id);
 }
 
 uint32_t wiphy_state_watch_add(struct wiphy *wiphy,
@@ -1470,19 +1535,23 @@
                struct band **bandp;
                struct band *band;
                enum band_freq freq;
+               size_t num_channels;
 
                switch (type) {
                case NL80211_BAND_2GHZ:
                        bandp = &wiphy->band_2g;
                        freq = BAND_FREQ_2_4_GHZ;
+                       num_channels = 14;
                        break;
                case NL80211_BAND_5GHZ:
                        bandp = &wiphy->band_5g;
                        freq = BAND_FREQ_5_GHZ;
+                       num_channels = 196;
                        break;
                case NL80211_BAND_6GHZ:
                        bandp = &wiphy->band_6g;
                        freq = BAND_FREQ_6_GHZ;
+                       num_channels = 233;
                        break;
                default:
                        continue;
@@ -1497,6 +1566,9 @@
                                continue;
 
                        band->freq = freq;
+                       band->freq_attrs = l_new(struct band_freq_attrs,
+                                                       num_channels);
+                       band->freqs_len = num_channels;
 
                        /* Reset iter to beginning */
                        if (!l_genl_attr_recurse(bands, &attr)) {
@@ -1506,7 +1578,6 @@
                } else
                        band = *bandp;
 
-
                while (l_genl_attr_next(&attr, &type, &len, &data)) {
                        struct l_genl_attr nested;
 
@@ -1514,7 +1585,8 @@
                        case NL80211_BAND_ATTR_FREQS:
                                nl80211_parse_supported_frequencies(&attr,
                                                        wiphy->supported_freqs,
-                                                       wiphy->disabled_freqs);
+                                                       band->freq_attrs,
+                                                       band->freqs_len);
                                break;
 
                        case NL80211_BAND_ATTR_RATES:
@@ -1969,6 +2041,7 @@
        struct l_genl_attr bands;
        struct l_genl_attr attr;
        uint16_t type;
+       struct band *band;
 
        if (nl80211_parse_attrs(msg, NL80211_ATTR_WIPHY, &id,
                                        NL80211_ATTR_WIPHY_BANDS, &bands,
@@ -1979,7 +2052,28 @@
        if (L_WARN_ON(!wiphy))
                return;
 
-       while (l_genl_attr_next(&bands, NULL, NULL, NULL)) {
+       /* Unregistered means the wiphy is blacklisted, don't bother parsing */
+       if (!wiphy->registered)
+               return;
+
+       while (l_genl_attr_next(&bands, &type, NULL, NULL)) {
+               switch (type) {
+               case NL80211_BAND_2GHZ:
+                       band = wiphy->band_2g;
+                       break;
+               case NL80211_BAND_5GHZ:
+                       band = wiphy->band_5g;
+                       break;
+               case NL80211_BAND_6GHZ:
+                       band = wiphy->band_6g;
+                       break;
+               default:
+                       continue;
+               }
+
+               if (L_WARN_ON(!band))
+                       continue;
+
                if (!l_genl_attr_recurse(&bands, &attr))
                        return;
 
@@ -1987,8 +2081,14 @@
                        if (type != NL80211_BAND_ATTR_FREQS)
                                continue;
 
+                       /*
+                        * Just write over the old list for each frequency. In
+                        * theory no new frequencies should be added so there
+                        * should never be any stale values.
+                        */
                        nl80211_parse_supported_frequencies(&attr, NULL,
-                                                       wiphy->pending_freqs);
+                                                       band->freq_attrs,
+                                                       band->freqs_len);
                }
        }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iwd-2.0/src/wiphy.h new/iwd-2.1/src/wiphy.h
--- old/iwd-2.0/src/wiphy.h     2022-11-18 13:31:49.000000000 +0100
+++ new/iwd-2.1/src/wiphy.h     2022-12-18 20:59:36.000000000 +0100
@@ -28,7 +28,9 @@
 struct scan_freq_set;
 struct wiphy_radio_work_item;
 struct ie_rsn_info;
+struct band_freq_attrs;
 enum security;
+enum band_freq;
 
 typedef bool (*wiphy_radio_work_func_t)(struct wiphy_radio_work_item *item);
 typedef void (*wiphy_radio_work_destroy_func_t)(
@@ -99,6 +101,12 @@
 const struct scan_freq_set *wiphy_get_supported_freqs(
                                                const struct wiphy *wiphy);
 const struct scan_freq_set *wiphy_get_disabled_freqs(const struct wiphy 
*wiphy);
+
+const struct band_freq_attrs *wiphy_get_frequency_info(
+                                               const struct wiphy *wiphy,
+                                               uint32_t freq);
+bool wiphy_band_is_disabled(const struct wiphy *wiphy, enum band_freq band);
+
 bool wiphy_supports_probe_resp_offload(struct wiphy *wiphy);
 bool wiphy_can_transition_disable(struct wiphy *wiphy);
 bool wiphy_can_offload(struct wiphy *wiphy);
@@ -112,7 +120,8 @@
 uint16_t wiphy_get_max_scan_ie_len(struct wiphy *wiphy);
 uint32_t wiphy_get_max_roc_duration(struct wiphy *wiphy);
 bool wiphy_supports_iftype(struct wiphy *wiphy, uint32_t iftype);
-const uint8_t *wiphy_get_supported_rates(struct wiphy *wiphy, unsigned int 
band,
+const uint8_t *wiphy_get_supported_rates(struct wiphy *wiphy,
+                                               enum band_freq band,
                                                unsigned int *out_num);
 bool wiphy_supports_adhoc_rsn(struct wiphy *wiphy);
 bool wiphy_can_offchannel_tx(struct wiphy *wiphy);

Reply via email to