diff options
125 files changed, 2462 insertions, 541 deletions
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS index 1dc7547..053e8ec 100644 --- a/CONTRIBUTIONS +++ b/CONTRIBUTIONS @@ -140,7 +140,7 @@ The license terms used for hostap.git files Modified BSD license (no advertisement clause): -Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. Redistribution and use in source and binary forms, with or without @@ -1,7 +1,7 @@ wpa_supplicant and hostapd -------------------------- -Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. @@ -1,7 +1,7 @@ wpa_supplicant and hostapd -------------------------- -Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. These programs are licensed under the BSD license (the one with diff --git a/debian/changelog b/debian/changelog index 008e84d..26e1743 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +wpa (2:2.7-1) experimental; urgency=medium + + * New upstream version 2.7. + * Enable FILS. + * Add debian/upstream/signing-key.asc, update debian/watch to + verify PGP signatures on tarballs. + + -- Andrej Shadura <andrewsh@debian.org> Mon, 03 Dec 2018 19:36:56 +0100 + wpa (2:2.7~git20181004+1dd66fc-1) experimental; urgency=medium * New upstream snapshot 2.7~git20181004+1dd66fc. diff --git a/debian/config/hostapd/kfreebsd b/debian/config/hostapd/kfreebsd index a08cc5a..5c0e8f5 100644 --- a/debian/config/hostapd/kfreebsd +++ b/debian/config/hostapd/kfreebsd @@ -365,7 +365,7 @@ LIBS += -ldl # Fast Initial Link Setup (FILS) (IEEE 802.11ai) # Note: This is an experimental and not yet complete implementation. This # should not be enabled for production use. -#CONFIG_FILS=y +CONFIG_FILS=y # FILS shared key authentication with PFS #CONFIG_FILS_SK_PFS=y diff --git a/debian/config/hostapd/linux b/debian/config/hostapd/linux index 2bd683a..3070f34 100644 --- a/debian/config/hostapd/linux +++ b/debian/config/hostapd/linux @@ -358,7 +358,7 @@ CONFIG_ACS=y # Fast Initial Link Setup (FILS) (IEEE 802.11ai) # Note: This is an experimental and not yet complete implementation. This # should not be enabled for production use. -#CONFIG_FILS=y +CONFIG_FILS=y # FILS shared key authentication with PFS #CONFIG_FILS_SK_PFS=y diff --git a/debian/config/wpasupplicant/kfreebsd b/debian/config/wpasupplicant/kfreebsd index 33f4fc2..504cdb0 100644 --- a/debian/config/wpasupplicant/kfreebsd +++ b/debian/config/wpasupplicant/kfreebsd @@ -569,7 +569,7 @@ LIBS += -ldl # Fast Initial Link Setup (FILS) (IEEE 802.11ai) # Note: This is an experimental and not yet complete implementation. This # should not be enabled for production use. -#CONFIG_FILS=y +CONFIG_FILS=y # FILS shared key authentication with PFS #CONFIG_FILS_SK_PFS=y diff --git a/debian/config/wpasupplicant/linux b/debian/config/wpasupplicant/linux index a7a709c..691f0ba 100644 --- a/debian/config/wpasupplicant/linux +++ b/debian/config/wpasupplicant/linux @@ -563,7 +563,7 @@ CONFIG_ACS=y # Fast Initial Link Setup (FILS) (IEEE 802.11ai) # Note: This is an experimental and not yet complete implementation. This # should not be enabled for production use. -#CONFIG_FILS=y +CONFIG_FILS=y # FILS shared key authentication with PFS #CONFIG_FILS_SK_PFS=y diff --git a/debian/gbp.conf b/debian/gbp.conf index 6c268aa..d1d69b1 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -1,3 +1,3 @@ [DEFAULT] debian-branch=debian/experimental -upstream-branch=upstream/snapshots +upstream-branch=upstream/latest diff --git a/debian/patches/dbus-available-sta.patch b/debian/patches/dbus-available-sta.patch index de4af53..e699090 100644 --- a/debian/patches/dbus-available-sta.patch +++ b/debian/patches/dbus-available-sta.patch @@ -1,26 +1,19 @@ -From: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com> -Date: Mon, 7 May 2018 15:36:30 +0200 -Subject: [PATCH] dbus: Expose connected stations on D-Bus +From 0709a1b6878d60d0512f65905106166f06c4c405 Mon Sep 17 00:00:00 2001 +From: Andrej Shadura <andrew.shadura@collabora.co.uk> +Date: Sun, 7 Oct 2018 11:49:19 +0200 +Subject: [PATCH v2 1/2] dbus: Use dbus_bool_t, not int for boolean function + arguments +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit -Make it possible to list connected stations in AP mode over D-Bus, along -with some of their properties: rx/tx packets, bytes, capabilities, etc. - -Signed-off-by: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com> - -Rebased by Julian Andres Klode <juliank@ubuntu.com> and updated to use -the new getter API. - -Further modified by Andrej Shadura to not error out when not in AP mode. - -Signed-off-by: Andrej Shadura <andrewsh@debian.org> +Properties argument specifies whether to add object’s properties +or not, hence it doesn’t need to be int. +Signed-off-by: Andrej Shadura <andrew.shadura@collabora.co.uk> --- - wpa_supplicant/dbus/dbus_new.c | 245 +++++++++++++++++-- - wpa_supplicant/dbus/dbus_new.h | 25 ++ - wpa_supplicant/dbus/dbus_new_handlers.c | 313 ++++++++++++++++++++++++ - wpa_supplicant/dbus/dbus_new_handlers.h | 14 ++ - wpa_supplicant/notify.c | 6 + - 5 files changed, 589 insertions(+), 14 deletions(-) + wpa_supplicant/dbus/dbus_new.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -32,17 +25,129 @@ Signed-off-by: Andrej Shadura <andrewsh@debian.org> #ifdef CONFIG_AP /* until needed by something else */ -@@ -2151,6 +2152,9 @@ +@@ -128,7 +129,7 @@ + * Notify listeners about event related with interface + */ + static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s, +- const char *sig_name, int properties) ++ const char *sig_name, dbus_bool_t properties) + { + struct wpas_dbus_priv *iface; + DBusMessage *msg; +@@ -230,7 +231,7 @@ + */ + static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s, + const char *bss_obj_path, +- const char *sig_name, int properties) ++ const char *sig_name, dbus_bool_t properties) + { + struct wpas_dbus_priv *iface; + DBusMessage *msg; +@@ -364,7 +365,7 @@ + */ + static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s, + int id, const char *sig_name, +- int properties) ++ dbus_bool_t properties) + { + struct wpas_dbus_priv *iface; + DBusMessage *msg; +@@ -1077,6 +1078,75 @@ + } + + ++/** ++ * wpas_dbus_signal_station - Send an event signal related to a station object ++ * @wpa_s: %wpa_supplicant network interface data ++ * @station_obj_path: Station object path ++ * @sig_name: signal name - StationAdded or StationRemoved ++ * @properties: Whether to add second argument with object properties ++ * ++ * Notify listeners about event related with station ++ */ ++static void wpas_dbus_signal_station(struct wpa_supplicant *wpa_s, ++ const char *station_obj_path, ++ const char *sig_name, dbus_bool_t properties) ++{ ++ struct wpas_dbus_priv *iface; ++ DBusMessage *msg; ++ DBusMessageIter iter; ++ ++ iface = wpa_s->global->dbus; ++ ++ /* Do nothing if the control interface is not turned on */ ++ if (iface == NULL || !wpa_s->dbus_new_path) ++ return; ++ ++ msg = dbus_message_new_signal(wpa_s->dbus_new_path, ++ WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name); ++ if (msg == NULL) ++ return; ++ ++ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, ++ &station_obj_path) || ++ (properties && ++ !wpa_dbus_get_object_properties(iface, station_obj_path, ++ WPAS_DBUS_NEW_IFACE_STA, ++ &iter))) ++ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); ++ else ++ dbus_connection_send(iface->con, msg, NULL); ++ dbus_message_unref(msg); ++} ++ ++ ++/** ++ * wpas_dbus_signal_station_added - Send a Station added signal ++ * @wpa_s: %wpa_supplicant network interface data ++ * @station_obj_path: new Station object path ++ * ++ * Notify listeners about adding new Station ++ */ ++static void wpas_dbus_signal_station_added(struct wpa_supplicant *wpa_s, ++ const char *station_obj_path) ++{ ++ wpas_dbus_signal_station(wpa_s, station_obj_path, "StationAdded", TRUE); ++} ++ ++ ++/** ++ * wpas_dbus_signal_station_removed - Send a Station removed signal ++ * @wpa_s: %wpa_supplicant network interface data ++ * @station_obj_path: Station object path ++ * ++ * Notify listeners about removing Station ++ */ ++static void wpas_dbus_signal_station_removed(struct wpa_supplicant *wpa_s, ++ const char *station_obj_path) ++{ ++ wpas_dbus_signal_station(wpa_s, station_obj_path, "StationRemoved", FALSE); ++} ++ ++ + #ifdef CONFIG_P2P + + /** +@@ -1882,7 +1952,7 @@ + */ + static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s, + int id, const char *sig_name, +- int properties) ++ dbus_bool_t properties) + { + struct wpas_dbus_priv *iface; + DBusMessage *msg; +@@ -2151,6 +2221,9 @@ case WPAS_DBUS_PROP_BSSS: prop = "BSSs"; break; -+ case WPAS_DBUS_PROP_STAS: ++ case WPAS_DBUS_PROP_STATIONS: + prop = "Stations"; + break; case WPAS_DBUS_PROP_CURRENT_AUTH_MODE: prop = "CurrentAuthMode"; break; -@@ -2244,6 +2248,39 @@ +@@ -2244,6 +2317,39 @@ /** @@ -82,7 +187,7 @@ Signed-off-by: Andrej Shadura <andrewsh@debian.org> * wpas_dbus_signal_debug_level_changed - Signals change of debug param * @global: wpa_global structure * -@@ -2857,6 +2894,164 @@ +@@ -2857,6 +2963,166 @@ } @@ -148,7 +253,7 @@ Signed-off-by: Andrej Shadura <andrewsh@debian.org> + const u8 *sta) +{ + struct wpas_dbus_priv *ctrl_iface; -+ char sta_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; ++ char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s == NULL || wpa_s->global == NULL) @@ -157,19 +262,20 @@ Signed-off-by: Andrej Shadura <andrewsh@debian.org> + if (ctrl_iface == NULL) + return 0; + -+ os_snprintf(sta_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, ++ os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(sta)); + + wpa_printf(MSG_DEBUG, "dbus: Unregister STA object '%s'", -+ sta_obj_path); -+ if (wpa_dbus_unregister_object_per_iface(ctrl_iface, sta_obj_path)) { ++ station_obj_path); ++ if (wpa_dbus_unregister_object_per_iface(ctrl_iface, station_obj_path)) { + wpa_printf(MSG_ERROR, "dbus: Cannot unregister STA object %s", -+ sta_obj_path); ++ station_obj_path); + return -1; + } + -+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STAS); ++ wpas_dbus_signal_station_added(wpa_s, station_obj_path); ++ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS); + + return 0; +} @@ -189,7 +295,7 @@ Signed-off-by: Andrej Shadura <andrewsh@debian.org> +{ + struct wpas_dbus_priv *ctrl_iface; + struct wpa_dbus_object_desc *obj_desc; -+ char sta_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; ++ char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + struct sta_handler_args *arg; + + /* Do nothing if the control interface is not turned on */ @@ -199,7 +305,7 @@ Signed-off-by: Andrej Shadura <andrewsh@debian.org> + if (ctrl_iface == NULL) + return 0; + -+ os_snprintf(sta_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, ++ os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(sta)); + @@ -225,16 +331,17 @@ Signed-off-by: Andrej Shadura <andrewsh@debian.org> + wpas_dbus_sta_signals); + + wpa_printf(MSG_DEBUG, "dbus: Register STA object '%s'", -+ sta_obj_path); -+ if (wpa_dbus_register_object_per_iface(ctrl_iface, sta_obj_path, ++ station_obj_path); ++ if (wpa_dbus_register_object_per_iface(ctrl_iface, station_obj_path, + wpa_s->ifname, obj_desc)) { + wpa_printf(MSG_ERROR, + "Cannot register STA dbus object %s.", -+ sta_obj_path); ++ station_obj_path); + goto err; + } + -+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STAS); ++ wpas_dbus_signal_station_removed(wpa_s, station_obj_path); ++ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS); + + return 0; + @@ -247,7 +354,7 @@ Signed-off-by: Andrej Shadura <andrewsh@debian.org> static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { { "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_scan, -@@ -3501,6 +3696,11 @@ +@@ -3501,6 +3767,11 @@ NULL }, #endif /* CONFIG_MESH */ @@ -259,6 +366,104 @@ Signed-off-by: Andrej Shadura <andrewsh@debian.org> { NULL, NULL, NULL, NULL, NULL, NULL } }; +@@ -3770,6 +4041,19 @@ + END_ARGS + } + }, ++ { "StationAdded", WPAS_DBUS_NEW_IFACE_INTERFACE, ++ { ++ { "path", "o", ARG_OUT }, ++ { "properties", "a{sv}", ARG_OUT }, ++ END_ARGS ++ } ++ }, ++ { "StationRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE, ++ { ++ { "path", "o", ARG_OUT }, ++ END_ARGS ++ } ++ }, + { "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "path", "o", ARG_OUT }, +@@ -4078,7 +4362,7 @@ + */ + static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s, + const u8 *dev_addr, const char *interface, +- const char *sig_name, int properties) ++ const char *sig_name, dbus_bool_t properties) + { + struct wpas_dbus_priv *iface; + DBusMessage *msg; +--- a/wpa_supplicant/dbus/dbus_new.h ++++ b/wpa_supplicant/dbus/dbus_new.h +@@ -12,6 +12,7 @@ + + #include "common/defs.h" + #include "p2p/p2p.h" ++#include "ap/sta_info.h" + + struct wpa_global; + struct wpa_supplicant; +@@ -29,6 +30,7 @@ + WPAS_DBUS_PROP_CURRENT_NETWORK, + WPAS_DBUS_PROP_CURRENT_AUTH_MODE, + WPAS_DBUS_PROP_BSSS, ++ WPAS_DBUS_PROP_STATIONS, + WPAS_DBUS_PROP_DISCONNECT_REASON, + WPAS_DBUS_PROP_ASSOC_STATUS_CODE, + }; +@@ -46,6 +48,10 @@ + WPAS_DBUS_BSS_PROP_AGE, + }; + ++enum wpas_dbus_sta_prop { ++ WPAS_DBUS_STA_PROP_ADDRESS, ++}; ++ + #define WPAS_DBUS_OBJECT_PATH_MAX 150 + + #define WPAS_DBUS_NEW_SERVICE "fi.w1.wpa_supplicant1" +@@ -62,6 +68,9 @@ + #define WPAS_DBUS_NEW_BSSIDS_PART "BSSs" + #define WPAS_DBUS_NEW_IFACE_BSS WPAS_DBUS_NEW_INTERFACE ".BSS" + ++#define WPAS_DBUS_NEW_STAS_PART "Stations" ++#define WPAS_DBUS_NEW_IFACE_STA WPAS_DBUS_NEW_INTERFACE ".Station" ++ + #define WPAS_DBUS_NEW_IFACE_P2PDEVICE \ + WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice" + +@@ -164,6 +173,10 @@ + u8 bssid[ETH_ALEN], unsigned int id); + int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, + u8 bssid[ETH_ALEN], unsigned int id); ++int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, ++ const u8 *sta); ++int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, ++ const u8 *sta); + void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, + const char *name); + void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s, +@@ -345,6 +358,18 @@ + { + return 0; + } ++ ++static inline int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, ++ const u8 *sta) ++{ ++ return 0; ++} ++ ++static inline int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, ++ const u8 *sta) ++{ ++ return 0; ++} + + static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, + const char *name) --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -22,6 +22,10 @@ @@ -618,82 +823,13 @@ Signed-off-by: Andrej Shadura <andrewsh@debian.org> DECLARE_ACCESSOR(wpas_dbus_getter_bss_bssid); DECLARE_ACCESSOR(wpas_dbus_getter_bss_ssid); DECLARE_ACCESSOR(wpas_dbus_getter_bss_privacy); ---- a/wpa_supplicant/dbus/dbus_new.h -+++ b/wpa_supplicant/dbus/dbus_new.h -@@ -12,6 +12,7 @@ - - #include "common/defs.h" - #include "p2p/p2p.h" -+#include "ap/sta_info.h" - - struct wpa_global; - struct wpa_supplicant; -@@ -29,6 +30,7 @@ - WPAS_DBUS_PROP_CURRENT_NETWORK, - WPAS_DBUS_PROP_CURRENT_AUTH_MODE, - WPAS_DBUS_PROP_BSSS, -+ WPAS_DBUS_PROP_STAS, - WPAS_DBUS_PROP_DISCONNECT_REASON, - WPAS_DBUS_PROP_ASSOC_STATUS_CODE, - }; -@@ -46,6 +48,10 @@ - WPAS_DBUS_BSS_PROP_AGE, - }; - -+enum wpas_dbus_sta_prop { -+ WPAS_DBUS_STA_PROP_ADDRESS, -+}; -+ - #define WPAS_DBUS_OBJECT_PATH_MAX 150 - - #define WPAS_DBUS_NEW_SERVICE "fi.w1.wpa_supplicant1" -@@ -62,6 +68,9 @@ - #define WPAS_DBUS_NEW_BSSIDS_PART "BSSs" - #define WPAS_DBUS_NEW_IFACE_BSS WPAS_DBUS_NEW_INTERFACE ".BSS" - -+#define WPAS_DBUS_NEW_STAS_PART "Stations" -+#define WPAS_DBUS_NEW_IFACE_STA WPAS_DBUS_NEW_INTERFACE ".Station" -+ - #define WPAS_DBUS_NEW_IFACE_P2PDEVICE \ - WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice" - -@@ -164,6 +173,10 @@ - u8 bssid[ETH_ALEN], unsigned int id); - int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, - u8 bssid[ETH_ALEN], unsigned int id); -+int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, -+ const u8 *sta); -+int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, -+ const u8 *sta); - void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, - const char *name); - void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s, -@@ -345,6 +358,18 @@ - { - return 0; - } -+ -+static inline int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, -+ const u8 *sta) -+{ -+ return 0; -+} -+ -+static inline int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, -+ const u8 *sta) -+{ -+ return 0; -+} - - static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, - const char *name) --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -720,6 +720,9 @@ wpas_dbus_signal_p2p_peer_joined(wpa_s, p2p_dev_addr); #endif /* CONFIG_P2P */ -+ /* Unregister the station */ ++ /* Register the station */ + wpas_dbus_register_sta(wpa_s, sta); + /* Notify listeners a new station has been authorized */ diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc new file mode 100644 index 0000000..2896588 --- /dev/null +++ b/debian/upstream/signing-key.asc @@ -0,0 +1,36 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGiBDoydw4RBAC9vfqCsU+dgrxUSdGf70zrEAIBxcjeqHusovztR65XOWE0ccjm +QS2TVgJM+OzYg9FJG7DuLQZDwhR10BZKJfG97fNyZVBCoO90bEcTufn96oceJlz/ +MHmy99+i6wYdIKYzvmaxcC1QPhENr1scgin9nMiW1MTPJ7sSgjDqd0QPVwCgmaZU +pzhKRusR5E/MmgI2kz73Ui0D/03lVNypkQTbuBp1q71YqT9qjO8+5kXU5QXJhel0 +qUgJHcu3rdnIVaiANw1qauMM0DtnRKOtcaZntn03sFNnaJRx0JlmLa/cMP0nm1kP +nR6Q3Cruz7InJnJZDXGsGH/ku4OcYLUJ8UgqzaO0J5o66j7pxQQDo1UAs4PQaoYq +/ECbA/9B6b3TzuHdqUgS/g2AYTc5MU+i92ydrBv2g9SPuH78m/X4YicGR1HF7yNi +J/hiVa/axBUHpXE4vW0Bndj1bN4sctFeGGezGRaLiiggZkBBNnL8nF5eZebLvPrv +4kr8Cchz+lGF5UFNVyLWwi/I5CSUqUtSXOD1Q9WcXoqJcrE2brQXSm91bmkgTWFs +aW5lbiA8akB3MS5maT6IYgQTEQIAIgIbIwYLCQgHAwIEFQIIAwMWAgECHgECF4AF +AkZbB/QCGQEACgkQK270Mu/IlfpuGACfd0WargWDeja0VW+R9TSKjRIfO1cAn1A8 +nkiso1bg/CvU56wSvpU4MpF6tBlKb3VuaSBNYWxpbmVuIDxqbUBraXIubnU+iF8E +ExECAB8FAkZbB5sCGyMGCwkIBwMCBBUCCAMDFgIBAh4BAheAAAoJECtu9DLvyJX6 +BmAAnRSeK5z2ClLwuV5i1CtP9w2v85TkAJ9XLkaqrNqX4yDxoHqbEpHkHZ6d17Qg +Sm91bmkgTWFsaW5lbiA8am1Aam0uZXBpdGVzdC5maT6IVwQTEQIAFwUCOjJ3DgUL +BwoDBAMVAwIDFgIBAheAAAoJECtu9DLvyJX6jS8AnixjTt+aerNHx8woqO7WGGqQ +h15YAJ4iIDUXZ/vQZny1FG/ewzE/rdUVmrQiSm91bmkgTWFsaW5lbiA8amttYWxp +bmVAY2MuaHV0LmZpPohXBBMRAgAXBQI6Mn1JBQsHCgMEAxUDAgMWAgECF4AACgkQ +K270Mu/IlfqZmQCeN9xC1eqSD3xiUa/z+SMA2Gd5NvkAnRuwbogLyTyBb8HqC1Lx +ISWkTSBvuQINBDoyd1sQCAC8qbv50m22q9hhs54GMD+Xemg0dHiHuuTtVPYugJqT +SlhSS8QJBdulR8hYYDGHbTzjB/ksiQFOcISZZ+zQRIGqLbNldf6taGUTIhZkIh09 +0RYLXCYoMFB8XLBOaLVRy7SMwsPXdbIRkT9v9CzMjZcTUVjwObQKRpTie0JZhc// +CUmY76scpRY5ifDXT9NOr5uMA3W5FI1AFc3d856BYhdnhcuJn+QQS+Xsj3r2vpVz +YHoS+nT0nQ9iwmqPtRHep+t1cudqEouaWT8tpXkSB0Y0MjOPyGnNDkg9om3gj5QK +zMDcQCxCVTHjqVUrmW6Bs2Rm2YVMBu/TIG4E9hEK8Ma/AAMFB/4pOot8lGbAJcov +gtSEvna6WyOnFtmC8UCXJyf1MnzzLAO6Fvf8cz16ig2o+7bgKiQeWxwd7LJEicv2 +kD33fZl3OqSZbNdfsOxB9g+jtWC+vOXGKzr6Pi7fIBXgkhxF/eWbhFg7Kj4rd+jB +I9F7uK/wPyY8JivH8vy2w6Boipc3S7qcUn5Gk58w0EuZrAHSGKt9QWd/p7ppIfgg +mbc77YFWzM/z9fiMWp4+YIJkEH6unz3+91qQXUC4JGL6QMnsIoieqoAk/6rHMCTf +hFSvQxuhxpLUI+PT9sAvIBZLZta6hvIiYVpSTzZxiVmuioVHUhPVQdcpO5Mrr1VH +DwC+ZH8miEYEGBECAAYFAjoyd1sACgkQK270Mu/IlfrRCACfWEtm3et85knJeUK2 +ApdQ54Evxn4AoIYi35jctzD/SfJzPiE15zTRS8NN +=UdTW +-----END PGP PUBLIC KEY BLOCK----- diff --git a/debian/uscan-hook b/debian/uscan-hook index fbe2d7a..8321437 100755 --- a/debian/uscan-hook +++ b/debian/uscan-hook @@ -3,7 +3,7 @@ set -e # This script is invoked by uscan after downloading a new tarball -if [ "x$1" != "x--upstream-version" ] || [ $# != 3 ]; then +if [ "$1" != "--upstream-version" ] || [ $# != 3 ]; then echo "invalid arguments: $*" >&2 exit 2 fi diff --git a/debian/watch b/debian/watch index 8eae097..b78d8d5 100644 --- a/debian/watch +++ b/debian/watch @@ -2,4 +2,4 @@ # We need to generate a merged wpa tarball from wpa_supplicant and hostapd, # so use our own script instead of uupdate. version=3 -http://w1.fi/releases/hostapd-([\.0-9]+)\.tar\.gz debian debian/uscan-hook +opts=pgpmode=auto http://w1.fi/releases/hostapd-([\.0-9]+)\.tar\.gz debian debian/uscan-hook diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog index d2b669b..f1366b4 100644 --- a/hostapd/ChangeLog +++ b/hostapd/ChangeLog @@ -1,5 +1,60 @@ ChangeLog for hostapd +2018-12-02 - v2.7 + * fixed WPA packet number reuse with replayed messages and key + reinstallation + [http://w1.fi/security/2017-1/] (CVE-2017-13082) + * added support for FILS (IEEE 802.11ai) shared key authentication + * added support for OWE (Opportunistic Wireless Encryption, RFC 8110; + and transition mode defined by WFA) + * added support for DPP (Wi-Fi Device Provisioning Protocol) + * FT: + - added local generation of PMK-R0/PMK-R1 for FT-PSK + (ft_psk_generate_local=1) + - replaced inter-AP protocol with a cleaner design that is more + easily extensible; this breaks backward compatibility and requires + all APs in the ESS to be updated at the same time to maintain FT + functionality + - added support for wildcard R0KH/R1KH + - replaced r0_key_lifetime (minutes) parameter with + ft_r0_key_lifetime (seconds) + - fixed wpa_psk_file use for FT-PSK + - fixed FT-SAE PMKID matching + - added expiration to PMK-R0 and PMK-R1 cache + - added IEEE VLAN support (including tagged VLANs) + - added support for SHA384 based AKM + * SAE + - fixed some PMKSA caching cases with SAE + - added support for configuring SAE password separately of the + WPA2 PSK/passphrase + - added option to require MFP for SAE associations + (sae_require_pmf=1) + - fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection + for SAE; + note: this is not backwards compatible, i.e., both the AP and + station side implementations will need to be update at the same + time to maintain interoperability + - added support for Password Identifier + * hostapd_cli: added support for command history and completion + * added support for requesting beacon report + * large number of other fixes, cleanup, and extensions + * added option to configure EAPOL-Key retry limits + (wpa_group_update_count and wpa_pairwise_update_count) + * removed all PeerKey functionality + * fixed nl80211 AP mode configuration regression with Linux 4.15 and + newer + * added support for using wolfSSL cryptographic library + * fixed some 20/40 MHz coexistence cases where the BSS could drop to + 20 MHz even when 40 MHz would be allowed + * Hotspot 2.0 + - added support for setting Venue URL ANQP-element (venue_url) + - added support for advertising Hotspot 2.0 operator icons + - added support for Roaming Consortium Selection element + - added support for Terms and Conditions + - added support for OSEN connection in a shared RSN BSS + * added support for using OpenSSL 1.1.1 + * added EAP-pwd server support for salted passwords + 2016-10-02 - v2.6 * fixed EAP-pwd last fragment validation [http://w1.fi/security/2015-7/] (CVE-2015-5314) diff --git a/hostapd/README b/hostapd/README index 298391b..ae53176 100644 --- a/hostapd/README +++ b/hostapd/README @@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator and RADIUS authentication server ================================================================ -Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with diff --git a/hostapd/config_file.c b/hostapd/config_file.c index b1ab13e..b26da71 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2049,6 +2049,24 @@ static int hs20_parse_osu_nai(struct hostapd_bss_config *bss, } +static int hs20_parse_osu_nai2(struct hostapd_bss_config *bss, + char *pos, int line) +{ + if (bss->last_osu == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line); + return -1; + } + + os_free(bss->last_osu->osu_nai2); + bss->last_osu->osu_nai2 = os_strdup(pos); + if (bss->last_osu->osu_nai2 == NULL) + return -1; + bss->hs20_osu_providers_nai_count++; + + return 0; +} + + static int hs20_parse_osu_method_list(struct hostapd_bss_config *bss, char *pos, int line) { @@ -3761,6 +3779,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "osu_nai") == 0) { if (hs20_parse_osu_nai(bss, pos, line) < 0) return 1; + } else if (os_strcmp(buf, "osu_nai2") == 0) { + if (hs20_parse_osu_nai2(bss, pos, line) < 0) + return 1; } else if (os_strcmp(buf, "osu_method_list") == 0) { if (hs20_parse_osu_method_list(bss, pos, line) < 0) return 1; @@ -4087,6 +4108,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + } else if (os_strcmp(buf, "coloc_intf_reporting") == 0) { + bss->coloc_intf_reporting = atoi(pos); #endif /* CONFIG_OWE */ } else { wpa_printf(MSG_ERROR, diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 2d68e88..75f12e5 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -992,6 +992,42 @@ fail: return ret; } + +static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + struct sta_info *sta; + const char *pos; + unsigned int auto_report, timeout; + + if (hwaddr_aton(cmd, addr)) { + wpa_printf(MSG_DEBUG, "Invalid STA MAC address"); + return -1; + } + + sta = ap_get_sta(hapd, addr); + if (!sta) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for Collocated Interference Request", + MAC2STR(addr)); + return -1; + } + + pos = cmd + 17; + if (*pos != ' ') + return -1; + pos++; + auto_report = atoi(pos); + pos = os_strchr(pos, ' '); + if (!pos) + return -1; + pos++; + timeout = atoi(pos); + + return wnm_send_coloc_intf_req(hapd, sta, auto_report, timeout); +} + #endif /* CONFIG_WNM_AP */ @@ -1386,6 +1422,12 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) hostapd_disassoc_deny_mac(hapd); } else if (os_strcasecmp(cmd, "accept_mac_file") == 0) { hostapd_disassoc_accept_mac(hapd); + } else if (os_strncmp(cmd, "wme_ac_", 7) == 0 || + os_strncmp(cmd, "wmm_ac_", 7) == 0) { + hapd->parameter_set_count++; + if (ieee802_11_update_beacons(hapd->iface)) + wpa_printf(MSG_DEBUG, + "Failed to update beacons with WMM parameters"); } } @@ -2092,7 +2134,7 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd) if (!pos) return -1; pos++; - if (hexstr2bin(pos, seq, sizeof(6)) < 0) + if (hexstr2bin(pos, seq, sizeof(seq)) < 0) return -1; pos += 2 * 6; if (*pos != ' ') @@ -2955,6 +2997,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) { if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11)) reply_len = -1; + } else if (os_strncmp(buf, "COLOC_INTF_REQ ", 15) == 0) { + if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15)) + reply_len = -1; #endif /* CONFIG_WNM_AP */ } else if (os_strcmp(buf, "GET_CONFIG") == 0) { reply_len = hostapd_ctrl_iface_get_config(hapd, reply, diff --git a/hostapd/defconfig b/hostapd/defconfig index c67c662..77a894d 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -31,7 +31,7 @@ CONFIG_DRIVER_NL80211=y #CONFIG_LIBNL20=y # Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored) -#CONFIG_LIBNL32=y +CONFIG_LIBNL32=y # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 70f9713..a005217 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -2227,12 +2227,15 @@ own_ip_addr=127.0.0.1 # OSU Providers # One or more sets of following parameter. Each OSU provider is started by the # mandatory osu_server_uri item. The other parameters add information for the -# last added OSU provider. +# last added OSU provider. osu_nai specifies the OSU_NAI value for OSEN +# authentication when using a standalone OSU BSS. osu_nai2 specifies the OSU_NAI +# value for OSEN authentication when using a shared BSS (Single SSID) for OSU. # #osu_server_uri=https://example.com/osu/ #osu_friendly_name=eng:Example operator #osu_friendly_name=fin:Esimerkkipalveluntarjoaja #osu_nai=anonymous@example.com +#osu_nai2=anonymous@example.com #osu_method_list=1 0 #osu_icon=icon32 #osu_icon=icon64 diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index fbec5d2..489da39 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1,6 +1,6 @@ /* * hostapd - command line interface for hostapd daemon - * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -21,7 +21,7 @@ static const char *const hostapd_cli_version = "hostapd_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> and contributors"; static struct wpa_ctrl *ctrl_conn; static int hostapd_cli_quit = 0; @@ -1637,7 +1637,7 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { { "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove, NULL, "*|<id> = remove DPP configurator" }, - { "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_get_key, + { "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key, NULL, "<id> = Get DPP configurator's private key" }, { "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL, diff --git a/hostapd/main.c b/hostapd/main.c index cbeb607..414dfe4 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -1,6 +1,6 @@ /* * hostapd / main() - * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -253,7 +253,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface) * * This function is used to parse configuration file for a full interface (one * or more BSSes sharing the same radio) and allocate memory for the BSS - * interfaces. No actiual driver operations are started. + * interfaces. No actual driver operations are started. */ static struct hostapd_iface * hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name, @@ -456,7 +456,7 @@ static void show_version(void) "hostapd v" VERSION_STR "\n" "User space daemon for IEEE 802.11 AP management,\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" - "Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> " + "Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> " "and contributors\n"); } @@ -873,27 +873,8 @@ int main(int argc, char *argv[]) */ interfaces.terminate_on_error = interfaces.count; for (i = 0; i < interfaces.count; i++) { - if (hostapd_driver_init(interfaces.iface[i])) - goto out; -#ifdef CONFIG_MBO - for (j = 0; j < interfaces.iface[i]->num_bss; j++) { - struct hostapd_data *hapd = interfaces.iface[i]->bss[j]; - - if (hapd && (hapd->conf->oce & OCE_STA_CFON) && - (interfaces.iface[i]->drv_flags & - WPA_DRIVER_FLAGS_OCE_STA_CFON)) - hapd->enable_oce = OCE_STA_CFON; - - if (hapd && (hapd->conf->oce & OCE_AP) && - (interfaces.iface[i]->drv_flags & - WPA_DRIVER_FLAGS_OCE_STA_CFON)) { - /* TODO: Need to add OCE-AP support */ - wpa_printf(MSG_ERROR, - "OCE-AP feature is not yet supported"); - } - } -#endif /* CONFIG_MBO */ - if (hostapd_setup_interface(interfaces.iface[i])) + if (hostapd_driver_init(interfaces.iface[i]) || + hostapd_setup_interface(interfaces.iface[i])) goto out; } diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c index 5854b72..d75c845 100644 --- a/hs20/client/oma_dm_client.c +++ b/hs20/client/oma_dm_client.c @@ -111,6 +111,12 @@ static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx, xml_node_t *syncml, *synchdr; xml_namespace_t *ns; + if (!ctx->devid) { + wpa_printf(MSG_ERROR, + "DevId from devinfo.xml is not available - cannot use OMA DM"); + return NULL; + } + syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns, "SyncML"); diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c index b8791b6..636e106 100644 --- a/hs20/client/osu_client.c +++ b/hs20/client/osu_client.c @@ -436,7 +436,7 @@ static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname, if (node == NULL) { wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS"); xml_node_free(ctx->xml, pps); - return -1; + return -2; } ret = download_cert(ctx, node, ca_fname); @@ -463,7 +463,7 @@ static int cmd_dl_aaa_ca(struct hs20_osu_client *ctx, const char *pps_fname, if (node == NULL) { wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS"); xml_node_free(ctx->xml, pps); - return -1; + return -2; } aaa = xml_node_first_child(ctx->xml, node); @@ -485,7 +485,7 @@ static int download_trust_roots(struct hs20_osu_client *ctx, { char *dir, *pos; char fname[300]; - int ret; + int ret, ret1; dir = os_strdup(pps_fname); if (dir == NULL) @@ -500,9 +500,13 @@ static int download_trust_roots(struct hs20_osu_client *ctx, snprintf(fname, sizeof(fname), "%s/ca.pem", dir); ret = cmd_dl_osu_ca(ctx, pps_fname, fname); snprintf(fname, sizeof(fname), "%s/polupd-ca.pem", dir); - cmd_dl_polupd_ca(ctx, pps_fname, fname); + ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname); + if (ret == 0 && ret1 == -1) + ret = -1; snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir); - cmd_dl_aaa_ca(ctx, pps_fname, fname); + ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname); + if (ret == 0 && ret1 == -1) + ret = -1; os_free(dir); @@ -1987,6 +1991,7 @@ struct osu_data { char osu_ssid[33]; char osu_ssid2[33]; char osu_nai[256]; + char osu_nai2[256]; struct osu_lang_text friendly_name[MAX_OSU_VALS]; size_t friendly_name_count; struct osu_lang_text serv_desc[MAX_OSU_VALS]; @@ -2057,6 +2062,12 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count) continue; } + if (os_strncmp(buf, "osu_nai2=", 9) == 0) { + os_snprintf(last->osu_nai2, sizeof(last->osu_nai2), + "%s", buf + 9); + continue; + } + if (strncmp(buf, "friendly_name=", 14) == 0) { struct osu_lang_text *txt; if (last->friendly_name_count == MAX_OSU_VALS) @@ -2134,7 +2145,7 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count) static int osu_connect(struct hs20_osu_client *ctx, const char *bssid, const char *ssid, const char *ssid2, const char *url, unsigned int methods, int no_prod_assoc, - const char *osu_nai) + const char *osu_nai, const char *osu_nai2) { int id; const char *ifname = ctx->ifname; @@ -2166,6 +2177,8 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid, return -1; if (set_network_quoted(ifname, id, "ssid", ssid) < 0) return -1; + if (ssid2) + osu_nai = osu_nai2; if (osu_nai && os_strlen(osu_nai) > 0) { char dir[255], fname[300]; if (getcwd(dir, sizeof(dir)) == NULL) @@ -2184,6 +2197,10 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid, set_network_quoted(ifname, id, "identity", osu_nai) < 0 || set_network_quoted(ifname, id, "ca_cert", fname) < 0) return -1; + } else if (ssid2) { + wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]"); + write_summary(ctx, "No OSU_NAI set for RSN[OSEN]"); + return -1; } else { if (set_network(ifname, id, "key_mgmt", "NONE") < 0) return -1; @@ -2363,6 +2380,8 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir, fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2); if (last->osu_nai[0]) fprintf(f, "NAI: %s<br>\n", last->osu_nai); + if (last->osu_nai2[0]) + fprintf(f, "NAI2: %s<br>\n", last->osu_nai2); fprintf(f, "URL: %s<br>\n" "methods:%s%s<br>\n" "</small></p>\n", @@ -2449,7 +2468,8 @@ selected: ret = osu_connect(ctx, last->bssid, last->osu_ssid, last->osu_ssid2, last->url, last->methods, - no_prod_assoc, last->osu_nai); + no_prod_assoc, last->osu_nai, + last->osu_nai2); } } else ret = -1; @@ -3048,24 +3068,17 @@ static int init_ctx(struct hs20_osu_client *ctx) return -1; devinfo = node_from_file(ctx->xml, "devinfo.xml"); - if (!devinfo) { - wpa_printf(MSG_ERROR, "devinfo.xml not found"); - return -1; - } - - devid = get_node(ctx->xml, devinfo, "DevId"); - if (devid) { - char *tmp = xml_node_get_text(ctx->xml, devid); - if (tmp) { - ctx->devid = os_strdup(tmp); - xml_node_get_text_free(ctx->xml, tmp); + if (devinfo) { + devid = get_node(ctx->xml, devinfo, "DevId"); + if (devid) { + char *tmp = xml_node_get_text(ctx->xml, devid); + + if (tmp) { + ctx->devid = os_strdup(tmp); + xml_node_get_text_free(ctx->xml, tmp); + } } - } - xml_node_free(ctx->xml, devinfo); - - if (ctx->devid == NULL) { - wpa_printf(MSG_ERROR, "Could not fetch DevId from devinfo.xml"); - return -1; + xml_node_free(ctx->xml, devinfo); } ctx->http = http_init_ctx(ctx, ctx->xml); diff --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c index 591f66b..abd6867 100644 --- a/hs20/server/hs20_spp_server.c +++ b/hs20/server/hs20_spp_server.c @@ -70,6 +70,10 @@ static int process(struct hs20_svc *ctx) ctx->addr = getenv("HS20ADDR"); if (ctx->addr) debug_print(ctx, 1, "Connection from %s", ctx->addr); + ctx->test = getenv("HS20TEST"); + if (ctx->test) + debug_print(ctx, 1, "Requested test functionality: %s", + ctx->test); user = getenv("HS20USER"); if (user && strlen(user) == 0) diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c index c3681ee..e5af4c2 100644 --- a/hs20/server/spp_server.c +++ b/hs20/server/spp_server.c @@ -69,14 +69,14 @@ static int db_add_session(struct hs20_svc *ctx, else addr[0] = '\0'; sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm," - "operation,password,redirect_uri,mac_addr) " + "operation,password,redirect_uri,mac_addr,test) " "VALUES " "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')," - "%Q,%Q,%Q,%d,%Q,%Q,%Q)", + "%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)", sessionid, user ? user : "", realm ? realm : "", operation, pw ? pw : "", redirect_uri ? redirect_uri : "", - addr); + addr, ctx->test); if (sql == NULL) return -1; debug_print(ctx, 1, "DB: %s", sql); @@ -336,6 +336,29 @@ static void add_text_node_conf(struct hs20_svc *ctx, const char *realm, } +static void add_text_node_conf_corrupt(struct hs20_svc *ctx, const char *realm, + xml_node_t *parent, const char *name, + const char *field) +{ + char *val; + + val = db_get_osu_config_val(ctx, realm, field); + if (val) { + size_t len; + + len = os_strlen(val); + if (len > 0) { + if (val[len - 1] == '0') + val[len - 1] = '1'; + else + val[len - 1] = '0'; + } + } + xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : ""); + os_free(val); +} + + static int new_password(char *buf, int buflen) { int i; @@ -540,7 +563,8 @@ static xml_node_t * build_username_password(struct hs20_svc *ctx, static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred, - const char *user, const char *pw) + const char *user, const char *pw, + int machine_managed) { xml_node_t *node; @@ -548,7 +572,8 @@ static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred, if (node == NULL) return -1; - add_text_node(ctx, node, "MachineManaged", "TRUE"); + add_text_node(ctx, node, "MachineManaged", + machine_managed ? "TRUE" : "FALSE"); add_text_node(ctx, node, "SoftTokenApp", ""); add_eap_ttls(ctx, node); @@ -573,7 +598,7 @@ static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred) static xml_node_t * build_credential_pw(struct hs20_svc *ctx, const char *user, const char *realm, - const char *pw) + const char *pw, int machine_managed) { xml_node_t *cred; @@ -583,7 +608,7 @@ static xml_node_t * build_credential_pw(struct hs20_svc *ctx, return NULL; } add_creation_date(ctx, cred); - if (add_username_password(ctx, cred, user, pw) < 0) { + if (add_username_password(ctx, cred, user, pw, machine_managed) < 0) { xml_node_free(ctx->xml, cred); return NULL; } @@ -600,7 +625,7 @@ static xml_node_t * build_credential(struct hs20_svc *ctx, if (new_password(new_pw, new_pw_len) < 0) return NULL; debug_print(ctx, 1, "Update password to '%s'", new_pw); - return build_credential_pw(ctx, user, realm, new_pw); + return build_credential_pw(ctx, user, realm, new_pw, 1); } @@ -710,8 +735,23 @@ static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx, cred = build_credential_cert(ctx, real_user ? real_user : user, realm, cert); } else { - cred = build_credential(ctx, real_user ? real_user : user, - realm, new_pw, sizeof(new_pw)); + char *pw; + + pw = db_get_session_val(ctx, user, realm, session_id, + "password"); + if (pw && pw[0]) { + debug_print(ctx, 1, "New password from the user: '%s'", + pw); + snprintf(new_pw, sizeof(new_pw), "%s", pw); + free(pw); + cred = build_credential_pw(ctx, + real_user ? real_user : user, + realm, new_pw, 0); + } else { + cred = build_credential(ctx, + real_user ? real_user : user, + realm, new_pw, sizeof(new_pw)); + } } free(real_user); if (!cred) { @@ -728,7 +768,7 @@ static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx, } snprintf(buf, sizeof(buf), - "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential", + "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential", realm); if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) { @@ -794,7 +834,7 @@ static xml_node_t * policy_remediation(struct hs20_svc *ctx, return NULL; snprintf(buf, sizeof(buf), - "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy", + "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy", realm); if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) { @@ -947,8 +987,10 @@ static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx, redirect_uri); else if (type && strcmp(type, "policy") == 0) ret = policy_remediation(ctx, user, realm, session_id, dmacc); - else + else if (type && strcmp(type, "machine") == 0) ret = machine_remediation(ctx, user, realm, session_id, dmacc); + else + ret = no_sub_rem(ctx, user, realm, session_id); free(type); return ret; @@ -1050,7 +1092,7 @@ static xml_node_t * hs20_policy_update(struct hs20_svc *ctx, return NULL; snprintf(buf, sizeof(buf), - "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy", + "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy", realm); if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) { @@ -1222,9 +1264,9 @@ static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm, static xml_node_t * build_pps(struct hs20_svc *ctx, const char *user, const char *realm, const char *pw, const char *cert, - int machine_managed) + int machine_managed, const char *test) { - xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp; + xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p; xml_node_t *cred, *eap, *userpw; pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL, @@ -1234,7 +1276,7 @@ static xml_node_t * build_pps(struct hs20_svc *ctx, add_text_node(ctx, pps, "UpdateIdentifier", "1"); - c = xml_node_create(ctx->xml, pps, NULL, "Credential1"); + c = xml_node_create(ctx->xml, pps, NULL, "Cred01"); add_text_node(ctx, c, "CredentialPriority", "1"); @@ -1242,18 +1284,51 @@ static xml_node_t * build_pps(struct hs20_svc *ctx, aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1"); add_text_node_conf(ctx, realm, aaa1, "CertURL", "aaa_trust_root_cert_url"); - add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint", - "aaa_trust_root_cert_fingerprint"); + if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) { + debug_print(ctx, 1, + "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint"); + add_text_node_conf_corrupt(ctx, realm, aaa1, + "CertSHA256Fingerprint", + "aaa_trust_root_cert_fingerprint"); + } else { + add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint", + "aaa_trust_root_cert_fingerprint"); + } + + if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) { + debug_print(ctx, 1, + "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint"); + p = xml_node_create(ctx->xml, c, NULL, "Policy"); + upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate"); + add_text_node(ctx, upd, "UpdateInterval", "30"); + add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated"); + add_text_node(ctx, upd, "Restriction", "Unrestricted"); + add_text_node_conf(ctx, realm, upd, "URI", "policy_url"); + trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot"); + add_text_node_conf(ctx, realm, trust, "CertURL", + "policy_trust_root_cert_url"); + add_text_node_conf_corrupt(ctx, realm, trust, + "CertSHA256Fingerprint", + "policy_trust_root_cert_fingerprint"); + } upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate"); add_text_node(ctx, upd, "UpdateInterval", "4294967295"); - add_text_node(ctx, upd, "UpdateMethod", "ClientInitiated"); + add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated"); add_text_node(ctx, upd, "Restriction", "HomeSP"); add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url"); trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot"); add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url"); - add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint", - "trust_root_cert_fingerprint"); + if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) { + debug_print(ctx, 1, + "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint"); + add_text_node_conf_corrupt(ctx, realm, trust, + "CertSHA256Fingerprint", + "trust_root_cert_fingerprint"); + } else { + add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint", + "trust_root_cert_fingerprint"); + } homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP"); add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name"); @@ -1337,7 +1412,7 @@ static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx, xml_node_t *pps, *tnds; char buf[400]; char *str; - char *user, *realm, *pw, *type, *mm; + char *user, *realm, *pw, *type, *mm, *test; const char *status; int cert = 0; int machine_managed = 0; @@ -1396,9 +1471,15 @@ static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx, return NULL; fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert"); + test = db_get_session_val(ctx, NULL, NULL, session_id, "test"); + if (test) + debug_print(ctx, 1, "TEST: Requested special behavior: %s", + test); pps = build_pps(ctx, user, realm, pw, - fingerprint ? fingerprint : NULL, machine_managed); + fingerprint ? fingerprint : NULL, machine_managed, + test); free(fingerprint); + free(test); if (!pps) { xml_node_free(ctx->xml, spp_node); free(user); @@ -1469,7 +1550,7 @@ static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx, return NULL; } - cred = build_credential_pw(ctx, free_account, realm, pw); + cred = build_credential_pw(ctx, free_account, realm, pw, 1); free(free_account); free(pw); if (!cred) { @@ -1484,7 +1565,7 @@ static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx, return NULL; snprintf(buf, sizeof(buf), - "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential", + "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential", realm); if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) { @@ -2181,6 +2262,9 @@ static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx, "", dmacc); free(val); } + if (oper == POLICY_UPDATE) + db_update_val(ctx, user, realm, "polupd_done", "1", + dmacc); ret = build_spp_exchange_complete( ctx, session_id, "Exchange complete, release TLS connection", NULL); diff --git a/hs20/server/spp_server.h b/hs20/server/spp_server.h index 7b27be3..3556f5c 100644 --- a/hs20/server/spp_server.h +++ b/hs20/server/spp_server.h @@ -16,6 +16,7 @@ struct hs20_svc { FILE *debug_log; sqlite3 *db; const char *addr; + const char *test; }; diff --git a/hs20/server/sql.txt b/hs20/server/sql.txt index 2ecd9c2..666ef13 100644 --- a/hs20/server/sql.txt +++ b/hs20/server/sql.txt @@ -23,7 +23,8 @@ CREATE TABLE sessions( devdetail TEXT, cert TEXT, cert_pem TEXT, - mac_addr TEXT + mac_addr TEXT, + test TEXT ); CREATE index sessions_id_index ON sessions(id); @@ -53,7 +54,9 @@ CREATE TABLE users( cert TEXT, cert_pem TEXT, t_c_timestamp INTEGER, - mac_addr TEXT + mac_addr TEXT, + last_msk TEXT, + polupd_done TEXT, ); CREATE TABLE wildcards( diff --git a/hs20/server/www/remediation-pw.php b/hs20/server/www/remediation-pw.php new file mode 100644 index 0000000..76fdccb --- /dev/null +++ b/hs20/server/www/remediation-pw.php @@ -0,0 +1,41 @@ +<?php + +require('config.php'); + +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} + +if (isset($_POST["id"])) + $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]); +else + die("Missing session id"); + +$pw = $_POST["password"]; +if (strlen($id) < 32 || !isset($pw)) { + die("Invalid POST data"); +} + +$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch(); +if ($row == false) { + die("Session not found"); +} +$user = $row['user']; +$realm = $row['realm']; + +$uri = $row['redirect_uri']; +$rowid = $row['rowid']; + +if (!$db->exec("UPDATE sessions SET password='$pw' WHERE rowid=$rowid")) { + die("Failed to update session database"); +} + +$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " . + "VALUES ('$user', '$realm', '$id', " . + "strftime('%Y-%m-%d %H:%M:%f','now'), " . + "'completed user input response for subscription remediation')"); + +header("Location: $uri", true, 302); + +?> diff --git a/hs20/server/www/remediation.php b/hs20/server/www/remediation.php index 392a7bd..3628065 100644 --- a/hs20/server/www/remediation.php +++ b/hs20/server/www/remediation.php @@ -6,13 +6,50 @@ <?php -echo "SessionID: " . $_GET["session_id"] . "<br>\n"; +require('config.php'); -echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n"; +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} -?> +if (isset($_GET["session_id"])) + $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["session_id"]); +else + $id = 0; +echo "SessionID: " . $id . "<br>\n"; + +$row = $db->query("SELECT * FROM sessions WHERE id='$id'")->fetch(); +if ($row == false) { + die("Session not found"); +} + +$username = $row['user']; +echo "User: " . $username . "@" . $row['realm'] . "<br>\n"; + +$user = $db->query("SELECT machine_managed,methods FROM users WHERE identity='$username'")->fetch(); +if ($user == false) { + die("User not found"); +} -This will provide a new machine-generated password. +echo "<hr><br>\n"; + +$cert = $user['methods'] == "TLS" || strncmp($username, "cert-", 5) == 0; + +if ($cert) { + echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n"; +} else if ($user['machine_managed'] == "1") { + echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n"; + echo "This will provide a new machine-generated password.<br>\n"; +} else { + echo "<form action=\"remediation-pw.php\" method=\"POST\">\n"; + echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n"; + echo "New password: <input type=\"password\" name=\"password\"><br>\n"; + echo "<input type=\"submit\" value=\"Change password\">\n"; + echo "</form>\n"; +} + +?> </body> </html> diff --git a/hs20/server/www/signup.php b/hs20/server/www/signup.php index aeb2f68..80a9d40 100644 --- a/hs20/server/www/signup.php +++ b/hs20/server/www/signup.php @@ -15,19 +15,30 @@ if (!$db) { die($sqliteerror); } -$row = $db->query("SELECT realm FROM sessions WHERE id='$id'")->fetch(); +$row = $db->query("SELECT realm,test FROM sessions WHERE id='$id'")->fetch(); if ($row == false) { die("Session not found for id: $id"); } $realm = $row['realm']; +$test = $row['test']; + +if (strlen($test) > 0) { + echo "<p style=\"color:#FF0000\">Special test functionality: $test</red></big></p>\n"; +} echo "<h3>Sign up for a subscription - $realm</h3>\n"; +echo "<p>This page can be used to select between three different types of subscriptions for testing purposes.</p>\n"; + +echo "<h4>Option 1 - shared free access credential</h4>\n"; + $row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch(); if ($row && strlen($row['value']) > 0) { echo "<p><a href=\"free.php?session_id=$id\">Sign up for free access</a></p>\n"; } +echo "<h4>Option 2 - username/password credential</h4>\n"; + echo "<form action=\"add-mo.php\" method=\"POST\">\n"; echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n"; ?> @@ -39,6 +50,8 @@ Password: <input type="password" name="password"><br> </form> <?php +echo "<h4>Option 3 - client certificate credential</h4>\n"; + echo "<p><a href=\"cert-enroll.php?id=$id\">Enroll a client certificate</a></p>\n" ?> diff --git a/hs20/server/www/spp.php b/hs20/server/www/spp.php index 002d028..f10e5ab 100644 --- a/hs20/server/www/spp.php +++ b/hs20/server/www/spp.php @@ -20,6 +20,11 @@ if (isset($_GET["realm"])) { die("Realm not specified"); } +if (isset($_GET["test"])) + $test = PREG_REPLACE("/[^0-9a-zA-Z\_\-]/i", '', $_GET["test"]); +else + $test = ""; + unset($user); putenv("HS20CERT"); @@ -100,6 +105,7 @@ $postdata = file_get_contents("php://input"); putenv("HS20POST=$postdata"); $addr = $_SERVER["REMOTE_ADDR"]; putenv("HS20ADDR=$addr"); +putenv("HS20TEST=$test"); $last = exec("$osu_root/spp/hs20_spp_server -r$osu_root -f/tmp/hs20_spp_server.log", $output, $ret); diff --git a/hs20/server/www/users.php b/hs20/server/www/users.php index b6c6298..f546de3 100644 --- a/hs20/server/www/users.php +++ b/hs20/server/www/users.php @@ -191,6 +191,9 @@ if ($rem == "") { } echo "<br>\n"; +if (strncmp($row['identity'], "cert-", 5) != 0) + echo "Machine managed: " . ($row['machine_managed'] == "1" ? "TRUE" : "FALSE") . "<br>\n"; + echo "<form>Policy: <select name=\"policy\" " . "onChange=\"window.location='users.php?cmd=policy&id=" . $row['rowid'] . "&policy=' + this.value;\">\n"; @@ -313,10 +316,10 @@ if ($id == 0 && $cmd != 'eventlog') { echo "[<a href=\"users.php?cmd=eventlog&limit=50\">Eventlog</a>] "; echo "<br>\n"; -echo "<table border=1>\n"; -echo "<tr><th>User<th>Realm<th>Remediation<th>Policy<th>Account type<th>Phase 2 method(s)<th>DevId<th>MAC Address<th>T&C\n"; +echo "<table border=1 cellspacing=0 cellpadding=0>\n"; +echo "<tr><th>User<th>Realm<th><small>Remediation</small><th>Policy<th><small>Account type</small><th><small>Phase 2 method(s)</small><th>DevId<th>MAC Address<th>T&C\n"; -$res = $db->query('SELECT rowid,* FROM users WHERE phase2=1'); +$res = $db->query('SELECT rowid,* FROM users WHERE phase2=1 ORDER BY identity'); foreach ($res as $row) { echo "<tr><td><a href=\"users.php?id=" . $row['rowid'] . "\"> " . $row['identity'] . " </a>"; @@ -324,7 +327,7 @@ foreach ($res as $row) { $rem = $row['remediation']; echo "<td>"; if ($rem == "") { - echo "Not required"; + echo "-"; } else if ($rem == "user") { echo "User"; } else if ($rem == "policy") { @@ -339,18 +342,18 @@ foreach ($res as $row) { echo "<td>shared"; else echo "<td>default"; - echo "<td>" . $row['methods']; + echo "<td><small>" . $row['methods'] . "</small>"; echo "<td>"; $xml = xml_parser_create(); xml_parse_into_struct($xml, $row['devinfo'], $devinfo); foreach($devinfo as $k) { if ($k['tag'] == 'DEVID') { - echo $k['value']; + echo "<small>" . $k['value'] . "</small>"; break; } } - echo "<td>" . $row['mac_addr']; - echo "<td>" . $row['t_c_timestamp']; + echo "<td><small>" . $row['mac_addr'] . "</small>"; + echo "<td><small>" . $row['t_c_timestamp'] . "</small>"; echo "\n"; } echo "</table>\n"; diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 820cba9..f9b6f29 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -631,6 +631,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(p->icons[j]); os_free(p->icons); os_free(p->osu_nai); + os_free(p->osu_nai2); os_free(p->service_desc); } os_free(conf->hs20_osu_providers); diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 5b71126..778366d 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -585,10 +585,12 @@ struct hostapd_bss_config { char **icons; size_t icons_count; char *osu_nai; + char *osu_nai2; unsigned int service_desc_count; struct hostapd_lang_string *service_desc; } *hs20_osu_providers, *last_osu; size_t hs20_osu_providers_count; + size_t hs20_osu_providers_nai_count; char **hs20_operator_icon; size_t hs20_operator_icon_count; unsigned int hs20_deauth_req_timeout; @@ -682,6 +684,8 @@ struct hostapd_bss_config { char owe_transition_ifname[IFNAMSIZ + 1]; int *owe_groups; #endif /* CONFIG_OWE */ + + int coloc_intf_reporting; }; /** diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 728d7f0..067cf86 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -176,7 +176,8 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, #endif /* CONFIG_HS20 */ #ifdef CONFIG_MBO - if (hapd->conf->mbo_enabled || hapd->enable_oce) { + if (hapd->conf->mbo_enabled || + OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) { pos = hostapd_eid_mbo(hapd, buf, sizeof(buf)); if (add_buf_data(&beacon, buf, pos - buf) < 0 || add_buf_data(&proberesp, buf, pos - buf) < 0 || diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c index 66d255c..95d004e 100644 --- a/src/ap/authsrv.c +++ b/src/ap/authsrv.c @@ -155,6 +155,40 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd) #endif /* RADIUS_SERVER */ +#ifdef EAP_TLS_FUNCS +static void authsrv_tls_event(void *ctx, enum tls_event ev, + union tls_event_data *data) +{ + switch (ev) { + case TLS_CERT_CHAIN_SUCCESS: + wpa_printf(MSG_DEBUG, "authsrv: remote certificate verification success"); + break; + case TLS_CERT_CHAIN_FAILURE: + wpa_printf(MSG_INFO, "authsrv: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'", + data->cert_fail.reason, + data->cert_fail.depth, + data->cert_fail.subject, + data->cert_fail.reason_txt); + break; + case TLS_PEER_CERTIFICATE: + wpa_printf(MSG_DEBUG, "authsrv: peer certificate: depth=%d serial_num=%s subject=%s", + data->peer_cert.depth, + data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A", + data->peer_cert.subject); + break; + case TLS_ALERT: + if (data->alert.is_local) + wpa_printf(MSG_DEBUG, "authsrv: local TLS alert: %s", + data->alert.description); + else + wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s", + data->alert.description); + break; + } +} +#endif /* EAP_TLS_FUNCS */ + + int authsrv_init(struct hostapd_data *hapd) { #ifdef EAP_TLS_FUNCS @@ -167,6 +201,8 @@ int authsrv_init(struct hostapd_data *hapd) os_memset(&conf, 0, sizeof(conf)); conf.tls_session_lifetime = hapd->conf->tls_session_lifetime; conf.tls_flags = hapd->conf->tls_flags; + conf.event_cb = authsrv_tls_event; + conf.cb_ctx = hapd; hapd->ssl_ctx = tls_init(&conf); if (hapd->ssl_ctx == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize TLS"); diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 7d079d2..59bd4af 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -453,8 +453,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, /* Extended supported rates */ pos = hostapd_eid_ext_supp_rates(hapd, pos); - /* RSN, MDIE, WPA */ - pos = hostapd_eid_wpa(hapd, pos, epos - pos); + /* RSN, MDIE */ + if (hapd->conf->wpa != WPA_PROTO_WPA) + pos = hostapd_eid_wpa(hapd, pos, epos - pos); pos = hostapd_eid_bss_load(hapd, pos, epos - pos); @@ -517,6 +518,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_eid_vendor_vht(hapd, pos); #endif /* CONFIG_IEEE80211AC */ + /* WPA */ + if (hapd->conf->wpa == WPA_PROTO_WPA) + pos = hostapd_eid_wpa(hapd, pos, epos - pos); + /* Wi-Fi Alliance WMM */ pos = hostapd_eid_wmm(hapd, pos); @@ -1152,9 +1157,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, /* Extended supported rates */ tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos); - /* RSN, MDIE, WPA */ - tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - - tailpos); + /* RSN, MDIE */ + if (hapd->conf->wpa != WPA_PROTO_WPA) + tailpos = hostapd_eid_wpa(hapd, tailpos, + tail + BEACON_TAIL_BUF_SIZE - + tailpos); tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - @@ -1223,6 +1230,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_vendor_vht(hapd, tailpos); #endif /* CONFIG_IEEE80211AC */ + /* WPA */ + if (hapd->conf->wpa == WPA_PROTO_WPA) + tailpos = hostapd_eid_wpa(hapd, tailpos, + tail + BEACON_TAIL_BUF_SIZE - + tailpos); + /* Wi-Fi Alliance WMM */ tailpos = hostapd_eid_wmm(hapd, tailpos); diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 4ec044e..149f389 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -505,9 +505,9 @@ static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd, } -static void hostapd_dpp_set_configurator(struct hostapd_data *hapd, - struct dpp_authentication *auth, - const char *cmd) +static int hostapd_dpp_set_configurator(struct hostapd_data *hapd, + struct dpp_authentication *auth, + const char *cmd) { const char *pos, *end; struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL; @@ -521,7 +521,7 @@ static void hostapd_dpp_set_configurator(struct hostapd_data *hapd, char *group_id = NULL; if (!cmd) - return; + return 0; wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd); pos = os_strstr(cmd, " ssid="); @@ -618,10 +618,12 @@ static void hostapd_dpp_set_configurator(struct hostapd_data *hapd, conf_ap->akm = DPP_AKM_PSK; if (psk_set) { os_memcpy(conf_ap->psk, psk, PMK_LEN); - } else { + } else if (pass_len > 0) { conf_ap->passphrase = os_strdup(pass); if (!conf_ap->passphrase) goto fail; + } else { + goto fail; } } else if (os_strstr(cmd, " conf=ap-dpp")) { conf_ap->akm = DPP_AKM_DPP; @@ -663,13 +665,15 @@ static void hostapd_dpp_set_configurator(struct hostapd_data *hapd, auth->conf_ap = conf_ap; auth->conf = conf; os_free(group_id); - return; + return 0; fail: - wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters"); + wpa_msg(hapd->msg_ctx, MSG_INFO, + "DPP: Failed to set configurator parameters"); dpp_configuration_free(conf_sta); dpp_configuration_free(conf_ap); os_free(group_id); + return -1; } @@ -842,7 +846,11 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd) if (!hapd->dpp_auth) goto fail; hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); - hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, cmd); + if (hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, cmd) < 0) { + dpp_auth_deinit(hapd->dpp_auth); + hapd->dpp_auth = NULL; + goto fail; + } hapd->dpp_auth->neg_freq = neg_freq; @@ -967,8 +975,12 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src, return; } hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); - hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, - hapd->dpp_configurator_params); + if (hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, + hapd->dpp_configurator_params) < 0) { + dpp_auth_deinit(hapd->dpp_auth); + hapd->dpp_auth = NULL; + return; + } os_memcpy(hapd->dpp_auth->peer_mac_addr, src, ETH_ALEN); wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR @@ -1892,9 +1904,9 @@ int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd) return -1; curve = get_param(cmd, " curve="); - hostapd_dpp_set_configurator(hapd, auth, cmd); - - if (dpp_configurator_own_config(auth, curve, 1) == 0) { + hostapd_dpp_set_testing_options(hapd, auth); + if (hostapd_dpp_set_configurator(hapd, auth, cmd) == 0 && + dpp_configurator_own_config(auth, curve, 1) == 0) { hostapd_dpp_handle_config_obj(hapd, auth); ret = 0; } diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 98a2eec..a726a6f 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -338,10 +338,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, goto fail; } #ifdef CONFIG_IEEE80211W - if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && + if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == + (WLAN_STA_ASSOC | WLAN_STA_MFP) && + !sta->sa_query_timed_out && sta->sa_query_count > 0) ap_check_sa_query_timeout(hapd, sta); - if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && + if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == + (WLAN_STA_ASSOC | WLAN_STA_MFP) && + !sta->sa_query_timed_out && (sta->auth_alg != WLAN_AUTH_FT)) { /* * STA has already been associated with MFP and SA @@ -1068,19 +1072,23 @@ static void hostapd_action_rx(struct hostapd_data *hapd, struct sta_info *sta; size_t plen __maybe_unused; u16 fc; + u8 *action __maybe_unused; - if (drv_mgmt->frame_len < 24 + 1) + if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1) return; - plen = drv_mgmt->frame_len - 24 - 1; + plen = drv_mgmt->frame_len - IEEE80211_HDRLEN - 1; mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame; fc = le_to_host16(mgmt->frame_control); if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) return; /* handled by the driver */ - wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d", - mgmt->u.action.category, (int) plen); + action = (u8 *) &mgmt->u.action.u; + wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR + " da " MACSTR " plen %d", + mgmt->u.action.category, *action, + MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen); sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c index fab307f..296d5c2 100644 --- a/src/ap/eap_user_db.c +++ b/src/ap/eap_user_db.c @@ -92,7 +92,7 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[]) } else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) { user->remediation = strlen(argv[i]) > 0; } else if (os_strcmp(col[i], "t_c_timestamp") == 0 && argv[i]) { - user->t_c_timestamp = strtol(argv[i], 0, 10); + user->t_c_timestamp = strtol(argv[i], NULL, 10); } } diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c index 04fb3e1..a7df810 100644 --- a/src/ap/gas_serv.c +++ b/src/ap/gas_serv.c @@ -181,6 +181,8 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd, wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); if (hapd->conf->hs20_osu_providers_count) wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST); + if (hapd->conf->hs20_osu_providers_nai_count) + wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST); if (hapd->conf->hs20_icons_count) wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST); if (hapd->conf->hs20_operator_icon_count) @@ -817,6 +819,40 @@ static void anqp_add_osu_providers_list(struct hostapd_data *hapd, } +static void anqp_add_osu_provider_nai(struct wpabuf *buf, + struct hs20_osu_provider *p) +{ + /* OSU_NAI for shared BSS (Single SSID) */ + if (p->osu_nai2) { + wpabuf_put_u8(buf, os_strlen(p->osu_nai2)); + wpabuf_put_str(buf, p->osu_nai2); + } else { + wpabuf_put_u8(buf, 0); + } +} + + +static void anqp_add_osu_providers_nai_list(struct hostapd_data *hapd, + struct wpabuf *buf) +{ + if (hapd->conf->hs20_osu_providers_nai_count) { + size_t i; + u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); + wpabuf_put_be24(buf, OUI_WFA); + wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); + wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST); + wpabuf_put_u8(buf, 0); /* Reserved */ + + for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) { + anqp_add_osu_provider_nai( + buf, &hapd->conf->hs20_osu_providers[i]); + } + + gas_anqp_set_element_len(buf, len); + } +} + + static void anqp_add_icon_binary_file(struct hostapd_data *hapd, struct wpabuf *buf, const u8 *name, size_t name_len) @@ -1024,6 +1060,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len); if (request & ANQP_REQ_OPERATOR_ICON_METADATA) anqp_add_operator_icon_metadata(hapd, buf); + if (request & ANQP_REQ_OSU_PROVIDERS_NAI_LIST) + anqp_add_osu_providers_nai_list(hapd, buf); #endif /* CONFIG_HS20 */ #ifdef CONFIG_MBO @@ -1216,6 +1254,11 @@ static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype, "Operator Icon Metadata", hapd->conf->hs20_operator_icon_count, qi); break; + case HS20_STYPE_OSU_PROVIDERS_NAI_LIST: + set_anqp_req(ANQP_REQ_OSU_PROVIDERS_NAI_LIST, + "OSU Providers NAI List", + hapd->conf->hs20_osu_providers_nai_count, qi); + break; default: wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u", subtype); diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h index 0afdcb1..2cf1817 100644 --- a/src/ap/gas_serv.h +++ b/src/ap/gas_serv.h @@ -62,6 +62,8 @@ (0x10000 << HS20_STYPE_ICON_REQUEST) #define ANQP_REQ_OPERATOR_ICON_METADATA \ (0x10000 << HS20_STYPE_OPERATOR_ICON_METADATA) +#define ANQP_REQ_OSU_PROVIDERS_NAI_LIST \ + (0x10000 << HS20_STYPE_OSU_PROVIDERS_NAI_LIST) /* The first MBO ANQP-element can be included in the optimized bitmap. */ #define ANQP_REQ_MBO_CELL_DATA_CONN_PREF \ (BIT(29) << MBO_ANQP_SUBTYPE_CELL_CONN_PREF) diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 23d2720..7501bac 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -176,8 +176,27 @@ static void hostapd_clear_old(struct hostapd_iface *iface) } +static int hostapd_iface_conf_changed(struct hostapd_config *newconf, + struct hostapd_config *oldconf) +{ + size_t i; + + if (newconf->num_bss != oldconf->num_bss) + return 1; + + for (i = 0; i < newconf->num_bss; i++) { + if (os_strcmp(newconf->bss[i]->iface, + oldconf->bss[i]->iface) != 0) + return 1; + } + + return 0; +} + + int hostapd_reload_config(struct hostapd_iface *iface) { + struct hapd_interfaces *interfaces = iface->interfaces; struct hostapd_data *hapd = iface->bss[0]; struct hostapd_config *newconf, *oldconf; size_t j; @@ -200,6 +219,35 @@ int hostapd_reload_config(struct hostapd_iface *iface) hostapd_clear_old(iface); oldconf = hapd->iconf; + if (hostapd_iface_conf_changed(newconf, oldconf)) { + char *fname; + int res; + + wpa_printf(MSG_DEBUG, + "Configuration changes include interface/BSS modification - force full disable+enable sequence"); + fname = os_strdup(iface->config_fname); + if (!fname) { + hostapd_config_free(newconf); + return -1; + } + hostapd_remove_iface(interfaces, hapd->conf->iface); + iface = hostapd_init(interfaces, fname); + os_free(fname); + hostapd_config_free(newconf); + if (!iface) { + wpa_printf(MSG_ERROR, + "Failed to initialize interface on config reload"); + return -1; + } + iface->interfaces = interfaces; + interfaces->iface[interfaces->count] = iface; + interfaces->count++; + res = hostapd_enable_iface(iface); + if (res < 0) + wpa_printf(MSG_ERROR, + "Failed to enable interface on config reload"); + return res; + } iface->conf = newconf; for (j = 0; j < iface->num_bss; j++) { @@ -2620,6 +2668,11 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface) !!(hapd_iface->drv_flags & WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); +#ifdef NEED_AP_MLME + for (j = 0; j < hapd_iface->num_bss; j++) + hostapd_cleanup_cs_params(hapd_iface->bss[j]); +#endif /* NEED_AP_MLME */ + /* same as hostapd_interface_deinit without deinitializing ctrl-iface */ for (j = 0; j < hapd_iface->num_bss; j++) { struct hostapd_data *hapd = hapd_iface->bss[j]; @@ -2677,7 +2730,7 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname, if (conf == NULL) { wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for " "configuration", __func__); - return NULL; + return NULL; } if (driver) { @@ -3428,7 +3481,6 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface, const struct hostapd_freq_params *freq_params) { int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT; - unsigned int i; wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes"); @@ -3470,10 +3522,8 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface, /* * cs_params must not be cleared earlier because the freq_params * argument may actually point to one of these. + * These params will be cleared during interface disable below. */ - for (i = 0; i < iface->num_bss; i++) - hostapd_cleanup_cs_params(iface->bss[i]); - hostapd_disable_iface(iface); hostapd_enable_iface(iface); } diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 9a520f3..d304c11 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -14,6 +14,13 @@ #include "ap_config.h" #include "drivers/driver.h" +#define OCE_STA_CFON_ENABLED(hapd) \ + ((hapd->conf->oce & OCE_STA_CFON) && \ + (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON)) +#define OCE_AP_ENABLED(hapd) \ + ((hapd->conf->oce & OCE_AP) && \ + (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_AP)) + struct wpa_ctrl_dst; struct radius_server_data; struct upnp_wps_device_sm; @@ -324,11 +331,6 @@ struct hostapd_data { #ifdef CONFIG_MBO unsigned int mbo_assoc_disallow; - /** - * enable_oce - Enable OCE if it is enabled by user and device also - * supports OCE. - */ - u8 enable_oce; #endif /* CONFIG_MBO */ struct dl_list nr_db; diff --git a/src/ap/hs20.c b/src/ap/hs20.c index 98d016d..e265569 100644 --- a/src/ap/hs20.c +++ b/src/ap/hs20.c @@ -184,13 +184,14 @@ int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd, { struct wpabuf *buf; int ret; - size_t url_len = os_strlen(url); + size_t url_len; if (!url) { wpa_printf(MSG_INFO, "HS 2.0: No T&C Server URL available"); return -1; } + url_len = os_strlen(url); if (5 + url_len > 255) { wpa_printf(MSG_INFO, "HS 2.0: Too long T&C Server URL for WNM-Notification: '%s'", diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index 84e74ee..5279abc 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -679,7 +679,8 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface) if (!ieee80211n_supported_ht_capab(iface)) return -1; #ifdef CONFIG_IEEE80211AC - if (!ieee80211ac_supported_vht_capab(iface)) + if (iface->conf->ieee80211ac && + !ieee80211ac_supported_vht_capab(iface)) return -1; #endif /* CONFIG_IEEE80211AC */ ret = ieee80211n_check_40mhz(iface); diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index d8b34fa..f9bb99d 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1665,9 +1665,11 @@ ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr, is_probe_req); if (res == HOSTAPD_ACL_REJECT) { - wpa_printf(MSG_INFO, - "Station " MACSTR " not allowed to authenticate", - MAC2STR(addr)); + if (!is_probe_req) + wpa_printf(MSG_DEBUG, + "Station " MACSTR + " not allowed to authenticate", + MAC2STR(addr)); return HOSTAPD_ACL_REJECT; } @@ -2583,10 +2585,14 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, if (resp != WLAN_STATUS_SUCCESS) return resp; #ifdef CONFIG_IEEE80211W - if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && + if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == + (WLAN_STA_ASSOC | WLAN_STA_MFP) && + !sta->sa_query_timed_out && sta->sa_query_count > 0) ap_check_sa_query_timeout(hapd, sta); - if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && + if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == + (WLAN_STA_ASSOC | WLAN_STA_MFP) && + !sta->sa_query_timed_out && (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) { /* * STA has already been associated with MFP and SA @@ -2916,7 +2922,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, #endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_OWE - if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) + if (sta && status_code == WLAN_STATUS_SUCCESS && + (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p, buf + buflen - p, ies, ies_len); @@ -3063,7 +3070,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_OWE if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && - sta && sta->owe_ecdh && + sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS && wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) { struct wpabuf *pub; @@ -3746,9 +3753,9 @@ static int handle_action(struct hostapd_data *hapd, unsigned int freq) { struct sta_info *sta; - sta = ap_get_sta(hapd, mgmt->sa); + u8 *action __maybe_unused; - if (len < IEEE80211_HDRLEN + 1) { + if (len < IEEE80211_HDRLEN + 2 + 1) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "handle_action - too short payload (len=%lu)", @@ -3756,6 +3763,14 @@ static int handle_action(struct hostapd_data *hapd, return 0; } + action = (u8 *) &mgmt->u.action.u; + wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR + " da " MACSTR " len %d freq %u", + mgmt->u.action.category, *action, + MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq); + + sta = ap_get_sta(hapd, mgmt->sa); + if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action " @@ -4052,7 +4067,8 @@ static void handle_auth_cb(struct hostapd_data *hapd, sta = ap_get_sta(hapd, mgmt->da); if (!sta) { - wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found", + wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR + " not found", MAC2STR(mgmt->da)); return; } diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c index a3f8609..49e9bf8 100644 --- a/src/ap/ieee802_11_shared.c +++ b/src/ap/ieee802_11_shared.c @@ -178,6 +178,10 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) case 1: /* Bits 8-15 */ if (hapd->conf->proxy_arp) *pos |= 0x10; /* Bit 12 - Proxy ARP */ + if (hapd->conf->coloc_intf_reporting) { + /* Bit 13 - Collocated Interference Reporting */ + *pos |= 0x20; + } break; case 2: /* Bits 16-23 */ if (hapd->conf->wnm_sleep_mode) @@ -548,7 +552,8 @@ u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len) u8 mbo[9], *mbo_pos = mbo; u8 *pos = eid; - if (!hapd->conf->mbo_enabled && !hapd->enable_oce) + if (!hapd->conf->mbo_enabled && + !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd)) return eid; if (hapd->conf->mbo_enabled) { @@ -564,12 +569,11 @@ u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len) *mbo_pos++ = hapd->mbo_assoc_disallow; } - if (hapd->enable_oce & (OCE_AP | OCE_STA_CFON)) { + if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) { u8 ctrl; ctrl = OCE_RELEASE; - if ((hapd->enable_oce & (OCE_AP | OCE_STA_CFON)) == - OCE_STA_CFON) + if (OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd)) ctrl |= OCE_IS_STA_CFON; *mbo_pos++ = OCE_ATTR_ID_CAPA_IND; @@ -587,7 +591,8 @@ u8 hostapd_mbo_ie_len(struct hostapd_data *hapd) { u8 len; - if (!hapd->conf->mbo_enabled && !hapd->enable_oce) + if (!hapd->conf->mbo_enabled && + !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd)) return 0; /* @@ -599,7 +604,7 @@ u8 hostapd_mbo_ie_len(struct hostapd_data *hapd) len += 3 + (hapd->mbo_assoc_disallow ? 3 : 0); /* OCE capability indication attribute (3) */ - if (hapd->enable_oce & (OCE_AP | OCE_STA_CFON)) + if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) len += 3; return len; diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 985f8b7..185279f 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -683,6 +683,8 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, #ifdef CONFIG_HS20 if (hapd->conf->hs20) { u8 ver = 1; /* Release 2 */ + if (HS20_VERSION > 0x10) + ver = 2; /* Release 3 */ if (!radius_msg_add_wfa( msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION, &ver, 1)) { diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c index 31e4fc6..01fecee 100644 --- a/src/ap/vlan_init.c +++ b/src/ap/vlan_init.c @@ -138,6 +138,8 @@ int vlan_init(struct hostapd_data *hapd) !hapd->conf->vlan) { /* dynamic vlans enabled but no (or empty) vlan_file given */ struct hostapd_vlan *vlan; + int ret; + vlan = os_zalloc(sizeof(*vlan)); if (vlan == NULL) { wpa_printf(MSG_ERROR, "Out of memory while assigning " @@ -146,8 +148,16 @@ int vlan_init(struct hostapd_data *hapd) } vlan->vlan_id = VLAN_ID_WILDCARD; - os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#", - hapd->conf->iface); + ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#", + hapd->conf->iface); + if (ret >= (int) sizeof(vlan->ifname)) { + wpa_printf(MSG_WARNING, + "VLAN: Interface name was truncated to %s", + vlan->ifname); + } else if (ret < 0) { + os_free(vlan); + return ret; + } vlan->next = hapd->conf->vlan; hapd->conf->vlan = vlan; } diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c index 710fe50..1e8f58b 100644 --- a/src/ap/wnm_ap.c +++ b/src/ap/wnm_ap.c @@ -453,6 +453,48 @@ static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd, } +static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd, + const u8 *addr, const u8 *buf, + size_t len) +{ + u8 dialog_token; + char *hex; + size_t hex_len; + + if (!hapd->conf->coloc_intf_reporting) { + wpa_printf(MSG_DEBUG, + "WNM: Ignore unexpected Collocated Interference Report from " + MACSTR, MAC2STR(addr)); + return; + } + + if (len < 1) { + wpa_printf(MSG_DEBUG, + "WNM: Ignore too short Collocated Interference Report from " + MACSTR, MAC2STR(addr)); + return; + } + dialog_token = *buf++; + len--; + + wpa_printf(MSG_DEBUG, + "WNM: Received Collocated Interference Report frame from " + MACSTR " (dialog_token=%u)", + MAC2STR(addr), dialog_token); + wpa_hexdump(MSG_MSGDUMP, "WNM: Collocated Interference Report Elements", + buf, len); + + hex_len = 2 * len + 1; + hex = os_malloc(hex_len); + if (!hex) + return; + wpa_snprintf_hex(hex, hex_len, buf, len); + wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, COLOC_INTF_REPORT MACSTR " %d %s", + MAC2STR(addr), dialog_token, hex); + os_free(hex); +} + + int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { @@ -483,6 +525,10 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload, plen); return 0; + case WNM_COLLOCATED_INTERFERENCE_REPORT: + ieee802_11_rx_wnm_coloc_intf_report(hapd, mgmt->sa, payload, + plen); + return 0; } wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR, @@ -681,3 +727,40 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta, return 0; } + + +int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta, + unsigned int auto_report, unsigned int timeout) +{ + u8 buf[100], *pos; + struct ieee80211_mgmt *mgmt; + u8 dialog_token = 1; + + if (auto_report > 3 || timeout > 63) + return -1; + os_memset(buf, 0, sizeof(buf)); + mgmt = (struct ieee80211_mgmt *) buf; + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memcpy(mgmt->da, sta->addr, ETH_ALEN); + os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + mgmt->u.action.category = WLAN_ACTION_WNM; + mgmt->u.action.u.coloc_intf_req.action = + WNM_COLLOCATED_INTERFERENCE_REQ; + mgmt->u.action.u.coloc_intf_req.dialog_token = dialog_token; + mgmt->u.action.u.coloc_intf_req.req_info = auto_report | (timeout << 2); + pos = &mgmt->u.action.u.coloc_intf_req.req_info; + pos++; + + wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to " + MACSTR " (dialog_token=%u auto_report=%u timeout=%u)", + MAC2STR(sta->addr), dialog_token, auto_report, timeout); + if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { + wpa_printf(MSG_DEBUG, + "WNM: Failed to send Collocated Interference Request frame"); + return -1; + } + + return 0; +} diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h index 56d0f88..1806ba0 100644 --- a/src/ap/wnm_ap.h +++ b/src/ap/wnm_ap.h @@ -24,5 +24,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta, const u8 *nei_rep, size_t nei_rep_len, const u8 *mbo_attrs, size_t mbo_len); void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx); +int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta, + unsigned int auto_report, unsigned int timeout); #endif /* WNM_AP_H */ diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index e8d46ab..f6792e0 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -1451,7 +1451,7 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth, now.sec; else if (session_timeout && r1->session_timeout) *session_timeout = 1; - else + else if (session_timeout) *session_timeout = 0; return 0; } diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 421dd5a..cdcc5de 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -751,6 +751,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, #ifdef CONFIG_SAE if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_OPTIONAL && + wpa_auth->conf.sae_require_mfp && wpa_key_mgmt_sae(sm->wpa_key_mgmt) && !(data.capabilities & WPA_CAPABILITY_MFPC)) { wpa_printf(MSG_DEBUG, @@ -1067,7 +1068,11 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm, const u8 *req_ies, size_t req_ies_len) { int res; - struct wpa_auth_config *conf = &sm->wpa_auth->conf; + struct wpa_auth_config *conf; + + if (!sm) + return pos; + conf = &sm->wpa_auth->conf; #ifdef CONFIG_TESTING_OPTIONS if (conf->own_ie_override_len) { @@ -1081,7 +1086,7 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm, } #endif /* CONFIG_TESTING_OPTIONS */ - res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len, + res = wpa_write_rsn_ie(conf, pos, max_len, sm->pmksa ? sm->pmksa->pmkid : NULL); if (res < 0) return pos; diff --git a/src/common/dpp.c b/src/common/dpp.c index 677f586..e715e04 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -2854,7 +2854,7 @@ static int dpp_auth_build_resp_status(struct dpp_authentication *auth, i_pubkey_hash = test_hash; } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) { wpa_printf(MSG_INFO, "DPP: TESTING - no Status"); - status = -1; + status = 255; } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) { wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce"); i_nonce = NULL; @@ -3457,7 +3457,7 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr, } #endif /* CONFIG_TESTING_OPTIONS */ - if (!auth->initiator) { + if (!auth->initiator || !auth->peer_bi) { dpp_auth_fail(auth, "Unexpected Authentication Response"); return NULL; } @@ -3638,7 +3638,7 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr, goto fail; } - if (auth->own_bi && auth->peer_bi) { + if (auth->own_bi) { /* Mutual authentication */ if (dpp_auth_derive_l_initiator(auth) < 0) goto fail; @@ -3846,7 +3846,7 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, } #endif /* CONFIG_TESTING_OPTIONS */ - if (auth->initiator) { + if (auth->initiator || !auth->own_bi) { dpp_auth_fail(auth, "Unexpected Authentication Confirm"); return -1; } @@ -3904,7 +3904,7 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, "Initiator Bootstrapping Key Hash mismatch"); return -1; } - } else if (auth->own_bi && auth->peer_bi) { + } else if (auth->peer_bi) { /* Mutual authentication and peer did not include its * Bootstrapping Key Hash attribute. */ dpp_auth_fail(auth, @@ -4757,7 +4757,7 @@ static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk, goto fail; } if (os_strcmp(token->string, "EC") != 0) { - wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s", + wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'", token->string); goto fail; } @@ -6586,6 +6586,32 @@ static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, } +static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len, + const char *identifier) +{ + if (!attr_id && identifier) { + wpa_printf(MSG_DEBUG, + "DPP: No PKEX code identifier received, but expected one"); + return 0; + } + + if (attr_id && !identifier) { + wpa_printf(MSG_DEBUG, + "DPP: PKEX code identifier received, but not expecting one"); + return 0; + } + + if (attr_id && identifier && + (os_strlen(identifier) != attr_id_len || + os_memcmp(identifier, attr_id, attr_id_len) != 0)) { + wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch"); + return 0; + } + + return 1; +} + + struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, struct dpp_bootstrap_info *bi, const u8 *own_mac, @@ -6630,19 +6656,11 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, } #endif /* CONFIG_TESTING_OPTIONS */ + attr_id_len = 0; attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER, &attr_id_len); - if (!attr_id && identifier) { - wpa_printf(MSG_DEBUG, - "DPP: No PKEX code identifier received, but expected one"); + if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier)) return NULL; - } - if (attr_id && identifier && - (os_strlen(identifier) != attr_id_len || - os_memcmp(identifier, attr_id, attr_id_len) != 0)) { - wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch"); - return NULL; - } attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP, &attr_group_len); @@ -7014,16 +7032,11 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, return NULL; } + attr_id_len = 0; attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER, &attr_id_len); - if (!attr_id && pkex->identifier) { - wpa_printf(MSG_DEBUG, - "DPP: No PKEX code identifier received, but expected one"); - return NULL; - } - if (attr_id && pkex->identifier && - (os_strlen(pkex->identifier) != attr_id_len || - os_memcmp(pkex->identifier, attr_id, attr_id_len) != 0)) { + if (!dpp_pkex_identifier_match(attr_id, attr_id_len, + pkex->identifier)) { dpp_pkex_fail(pkex, "PKEX code identifier mismatch"); return NULL; } diff --git a/src/common/gas_server.c b/src/common/gas_server.c index b258675..ca46758 100644 --- a/src/common/gas_server.c +++ b/src/common/gas_server.c @@ -97,8 +97,10 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler, return; response = os_zalloc(sizeof(*response)); - if (!response) + if (!response) { + wpabuf_free(query_resp); return; + } wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response); response->freq = freq; response->handler = handler; @@ -119,6 +121,7 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler, handler->adv_proto_id_len + resp_frag_len); if (!resp) { + wpabuf_free(query_resp); gas_server_free_response(response); return; } @@ -257,6 +260,7 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response) handler->adv_proto_id_len + resp_frag_len); if (!resp) { + dl_list_del(&response->list); gas_server_free_response(response); return; } diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index e03a095..762e731 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -922,6 +922,16 @@ struct ieee80211_mgmt { u8 variable[]; } STRUCT_PACKED bss_tm_query; struct { + u8 action; /* 11 */ + u8 dialog_token; + u8 req_info; + } STRUCT_PACKED coloc_intf_req; + struct { + u8 action; /* 12 */ + u8 dialog_token; + u8 variable[]; + } STRUCT_PACKED coloc_intf_report; + struct { u8 action; /* 15 */ u8 variable[]; } STRUCT_PACKED slf_prot_action; @@ -1331,6 +1341,7 @@ enum wmm_ac { #define HS20_STYPE_ICON_REQUEST 10 #define HS20_STYPE_ICON_BINARY_FILE 11 #define HS20_STYPE_OPERATOR_ICON_METADATA 12 +#define HS20_STYPE_OSU_PROVIDERS_NAI_LIST 13 #define HS20_DGAF_DISABLED 0x01 #define HS20_PPS_MO_ID_PRESENT 0x02 diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index 72140f3..7c75d08 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -158,6 +158,11 @@ enum qca_radiotap_vendor_ids { * timer value. Uses the attributes defines in * enum qca_wlan_vendor_attr_ocb_get_tsf_resp. * + * @QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES: Command/event to update the + * link properties of the respective interface. As an event, is used + * to notify the connected station's status. The attributes for this + * command are defined in enum qca_wlan_vendor_attr_link_properties. + * * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START: Command used to * start the P2P Listen offload function in device and pass the listen * channel, period, interval, count, device types, and vendor specific @@ -469,6 +474,31 @@ enum qca_radiotap_vendor_ids { * qca_wlan_vendor_attr_roam_scan. Some drivers may not send these events * in few cases, e.g., if the host processor is sleeping when this event * is generated in firmware. + * + * @QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG: This command is used to + * configure parameters per peer to capture Channel Frequency Response + * (CFR) and enable Periodic CFR capture. The attributes for this command + * are defined in enum qca_wlan_vendor_peer_cfr_capture_attr. + * + * @QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT: Event to indicate changes + * in throughput dynamically. The driver estimates the throughput based on + * number of packets being transmitted/received per second and indicates + * the changes in throughput to user space. Userspace tools can use this + * information to configure kernel's TCP parameters in order to achieve + * peak throughput. Optionally, the driver will also send guidance on + * modifications to kernel's TCP parameters which can be referred by + * userspace tools. The attributes used with this event are defined in enum + * qca_wlan_vendor_attr_throughput_change. + * + * @QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG: This command is used to set + * priorities among different types of traffic during coex scenarios. + * Current supported prioritization is among WLAN/BT/ZIGBEE with different + * profiles mentioned in enum qca_coex_config_profiles. The associated + * attributes used with this command are defined in enum + * qca_vendor_attr_coex_config. + * + * Based on the config provided, FW will boost the weight and prioritize + * the traffic for that subsystem (WLAN/BT/Zigbee). */ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, @@ -630,6 +660,9 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER = 170, QCA_NL80211_VENDOR_SUBCMD_NAN_EXT = 171, QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT = 172, + QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG = 173, + QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT = 174, + QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG = 175, }; enum qca_wlan_vendor_attr { @@ -4945,6 +4978,10 @@ enum qca_wlan_vendor_attr_ndp_params { * and ndp confirm. */ QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL = 29, + /* Unsigned 8-bit value indicating if NDP remote peer supports NAN NDPE. + * 1:support 0:not support + */ + QCA_WLAN_VENDOR_ATTR_PEER_NDPE_SUPPORT = 30, /* keep last */ QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST, @@ -5403,6 +5440,23 @@ enum qca_wlan_he_mac_padding_dur { QCA_WLAN_HE_16US_OF_PROCESS_TIME = 2, }; +/** + * enum qca_wlan_he_om_ctrl_ch_bw - HE OM control field BW configuration + * + * Indicates the HE Operating mode control channel width setting value. + * + * @QCA_WLAN_HE_OM_CTRL_BW_20M: Primary 20 MHz + * @QCA_WLAN_HE_OM_CTRL_BW_40M: Primary 40 MHz + * @QCA_WLAN_HE_OM_CTRL_BW_80M: Primary 80 MHz + * @QCA_WLAN_HE_OM_CTRL_BW_160M: 160 MHz and 80+80 MHz + */ +enum qca_wlan_he_om_ctrl_ch_bw { + QCA_WLAN_HE_OM_CTRL_BW_20M = 0, + QCA_WLAN_HE_OM_CTRL_BW_40M = 1, + QCA_WLAN_HE_OM_CTRL_BW_80M = 2, + QCA_WLAN_HE_OM_CTRL_BW_160M = 3, +}; + /* Attributes for data used by * QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION */ @@ -5594,6 +5648,61 @@ enum qca_wlan_vendor_attr_wifi_test_config { */ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_RESUME = 26, + /* 8-bit unsigned value to set the HE operating mode control + * (OM CTRL) Channel Width subfield. + * The Channel Width subfield indicates the operating channel width + * supported by the STA for both reception and transmission. + * Uses the enum qca_wlan_he_om_ctrl_ch_bw values. + * This setting is cleared with the + * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG + * flag attribute to reset defaults. + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_BW = 27, + + /* 8-bit unsigned value to configure the number of spatial + * streams in HE operating mode control field. + * This setting is cleared with the + * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG + * flag attribute to reset defaults. + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_NSS = 28, + + /* Flag attribute to configure the UL MU disable bit in + * HE operating mode control field. + * This setting is cleared with the + * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG + * flag attribute to reset defaults. + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_UL_MU_DISABLE = 29, + + /* Flag attribute to clear the previously set HE operating mode + * control field configuration. + * This attribute is used to configure the testbed device to reset + * defaults to clear any previously set HE operating mode control + * field configuration. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG = 30, + + /* 8-bit unsigned value to configure HE single user PPDU + * transmission. By default this setting is disabled and it + * is disabled in the reset defaults of the device configuration. + * This attribute is used to configure the testbed device. + * 1-enable, 0-disable + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_SUPPDU = 31, + + /* 8-bit unsigned value to configure action frame transmission + * in HE trigger based PPDU transmission. + * By default this setting is disabled and it is disabled in + * the reset defaults of the device configuration. + * This attribute is used to configure the testbed device. + * 1-enable, 0-disable + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_ACTION_TX_TB_PPDU = 32, + /* keep last */ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX = @@ -5920,4 +6029,219 @@ enum qca_wlan_vendor_attr_roam_scan { QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_AFTER_LAST - 1, }; +/** + * enum qca_wlan_vendor_cfr_method - QCA vendor CFR methods used by + * attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD as part of vendor + * command QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG. + */ +enum qca_wlan_vendor_cfr_method { + /* CFR method using QOS Null frame */ + QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL = 0, +}; + +/** + * enum qca_wlan_vendor_peer_cfr_capture_attr - Used by the vendor command + * QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG to configure peer + * Channel Frequency Response capture parameters and enable periodic CFR + * capture. + */ +enum qca_wlan_vendor_peer_cfr_capture_attr { + QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_INVALID = 0, + /* 6-byte MAC address of the peer. + * This attribute is mandatory. + */ + QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR = 1, + /* Enable peer CFR Capture, flag attribute. + * This attribute is mandatory to enable peer CFR capture. + * If this attribute is not present, peer CFR capture is disabled. + */ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE = 2, + /* BW of measurement, attribute uses the values in enum nl80211_chan_width + * Supported values: 20, 40, 80, 80+80, 160. + * Note that all targets may not support all bandwidths. + * u8 attribute. This attribute is mandatory if attribute + * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used. + */ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH = 3, + /* Periodicity of CFR measurement in msec. + * Periodicity should be a multiple of Base timer. + * Current Base timer value supported is 10 msecs (default). + * 0 for one shot capture. u32 attribute. + * This attribute is mandatory if attribute + * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used. + */ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY = 4, + /* Method used to capture Channel Frequency Response. + * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method. + * u8 attribute. This attribute is mandatory if attribute + * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used. + */ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD = 5, + /* Enable periodic CFR capture, flag attribute. + * This attribute is mandatory to enable Periodic CFR capture. + * If this attribute is not present, periodic CFR capture is disabled. + */ + QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE = 6, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX = + QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_throughput_level - Current throughput level + * + * Indicates the current level of throughput calculated by the driver. The + * driver may choose different thresholds to decide whether the throughput level + * is low or medium or high based on variety of parameters like physical link + * capacity of the current connection, the number of packets being dispatched + * per second, etc. The throughput level events might not be consistent with the + * actual current throughput value being observed. + * + * @QCA_WLAN_THROUGHPUT_LEVEL_LOW: Low level of throughput + * @QCA_WLAN_THROUGHPUT_LEVEL_MEDIUM: Medium level of throughput + * @QCA_WLAN_THROUGHPUT_LEVEL_HIGH: High level of throughput + */ +enum qca_wlan_throughput_level { + QCA_WLAN_THROUGHPUT_LEVEL_LOW = 0, + QCA_WLAN_THROUGHPUT_LEVEL_MEDIUM = 1, + QCA_WLAN_THROUGHPUT_LEVEL_HIGH = 2, +}; + +/** + * enum qca_wlan_vendor_attr_throughput_change - Vendor subcmd attributes to + * report throughput changes from the driver to user space. enum values are used + * for netlink attributes sent with + * %QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT sub command. + */ +enum qca_wlan_vendor_attr_throughput_change { + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_INVALID = 0, + /* Indicates the direction of throughput in which the change is being + * reported. u8 attribute. Value is 0 for TX and 1 for RX. + */ + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_DIRECTION = 1, + /* Indicates the newly observed throughput level. enum + * qca_wlan_throughput_level describes the possible range of values. + * u8 attribute. + */ + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_THROUGHPUT_LEVEL = 2, + /* Indicates the driver's guidance on the new value to be set to + * kernel's TCP parameter tcp_limit_output_bytes. u32 attribute. The + * driver may optionally include this attribute. + */ + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_LIMIT_OUTPUT_BYTES = 3, + /* Indicates the driver's guidance on the new value to be set to + * kernel's TCP parameter tcp_adv_win_scale. s8 attribute. Possible + * values are from -31 to 31. The driver may optionally include this + * attribute. + */ + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_ADV_WIN_SCALE = 4, + /* Indicates the driver's guidance on the new value to be set to + * kernel's TCP parameter tcp_delack_seg. u32 attribute. The driver may + * optionally include this attribute. + */ + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_DELACK_SEG = 5, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_MAX = + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_AFTER_LAST - 1, +}; + +/** + * enum qca_coex_config_profiles - This enum defines different types of + * traffic streams that can be prioritized one over the other during coex + * scenarios. + * The types defined in this enum are categorized in the below manner. + * 0 - 31 values corresponds to WLAN + * 32 - 63 values corresponds to BT + * 64 - 95 values corresponds to Zigbee + * @QCA_WIFI_STA_DISCOVERY: Prioritize discovery frames for WLAN STA + * @QCA_WIFI_STA_CONNECTION: Prioritize connection frames for WLAN STA + * @QCA_WIFI_STA_CLASS_3_MGMT: Prioritize class 3 mgmt frames for WLAN STA + * @QCA_WIFI_STA_DATA : Prioritize data frames for WLAN STA + * @QCA_WIFI_STA_ALL: Priritize all frames for WLAN STA + * @QCA_WIFI_SAP_DISCOVERY: Prioritize discovery frames for WLAN SAP + * @QCA_WIFI_SAP_CONNECTION: Prioritize connection frames for WLAN SAP + * @QCA_WIFI_SAP_CLASS_3_MGMT: Prioritize class 3 mgmt frames for WLAN SAP + * @QCA_WIFI_SAP_DATA: Prioritize data frames for WLAN SAP + * @QCA_WIFI_SAP_ALL: Prioritize all frames for WLAN SAP + * @QCA_BT_A2DP: Prioritize BT A2DP + * @QCA_BT_BLE: Prioritize BT BLE + * @QCA_BT_SCO: Prioritize BT SCO + * @QCA_ZB_LOW: Prioritize Zigbee Low + * @QCA_ZB_HIGH: Prioritize Zigbee High + */ +enum qca_coex_config_profiles { + /* 0 - 31 corresponds to WLAN */ + QCA_WIFI_STA_DISCOVERY = 0, + QCA_WIFI_STA_CONNECTION = 1, + QCA_WIFI_STA_CLASS_3_MGMT = 2, + QCA_WIFI_STA_DATA = 3, + QCA_WIFI_STA_ALL = 4, + QCA_WIFI_SAP_DISCOVERY = 5, + QCA_WIFI_SAP_CONNECTION = 6, + QCA_WIFI_SAP_CLASS_3_MGMT = 7, + QCA_WIFI_SAP_DATA = 8, + QCA_WIFI_SAP_ALL = 9, + /* 32 - 63 corresponds to BT */ + QCA_BT_A2DP = 32, + QCA_BT_BLE = 33, + QCA_BT_SCO = 34, + /* 64 - 95 corresponds to Zigbee */ + QCA_ZB_LOW = 64, + QCA_ZB_HIGH = 65 +}; + +/** + * enum qca_vendor_attr_coex_config - Specifies vendor coex config attributes + * + * @QCA_VENDOR_ATTR_COEX_CONFIG_PROFILES: This attribute contains variable + * length array of 8-bit values from enum qca_coex_config_profiles. + * FW will prioritize the profiles in the order given in the array encapsulated + * in this attribute. + * For example: + * ----------------------------------------------------------------------- + * | 1 | 34 | 32 | 65 | + * ----------------------------------------------------------------------- + * If the attribute contains the values defined in above array then it means + * 1) Wifi STA connection has priority over BT_SCO, BT_A2DP and ZIGBEE HIGH. + * 2) BT_SCO has priority over BT_A2DP. + * 3) BT_A2DP has priority over ZIGBEE HIGH. + * Profiles which are not listed in this array shall not be preferred over the + * profiles which are listed in the array as a part of this attribute. + */ +enum qca_vendor_attr_coex_config { + QCA_VENDOR_ATTR_COEX_CONFIG_INVALID = 0, + QCA_VENDOR_ATTR_COEX_CONFIG_PROFILES = 1, + + /* Keep last */ + QCA_VENDOR_ATTR_COEX_CONFIG_AFTER_LAST, + QCA_VENDOR_ATTR_COEX_CONFIG_MAX = + QCA_VENDOR_ATTR_COEX_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_link_properties - Represent the link properties. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR: MAC address of the peer + * (STA/AP) for the connected link. + * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_STA_FLAGS: Attribute containing a + * &struct nl80211_sta_flag_update for the respective connected link. MAC + * address of the peer represented by + * QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR. + */ +enum qca_wlan_vendor_attr_link_properties { + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_INVALID = 0, + /* 1 - 3 are reserved */ + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR = 4, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_STA_FLAGS = 5, + + /* Keep last */ + QCA_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST, + QCA_VENDOR_ATTR_LINK_PROPERTIES_MAX = + QCA_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST - 1, +}; + #endif /* QCA_VENDOR_H */ diff --git a/src/common/version.h b/src/common/version.h index 16c1004..2f47903 100644 --- a/src/common/version.h +++ b/src/common/version.h @@ -9,6 +9,6 @@ #define GIT_VERSION_STR_POSTFIX "" #endif /* GIT_VERSION_STR_POSTFIX */ -#define VERSION_STR "2.7-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX +#define VERSION_STR "2.7" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX #endif /* VERSION_H */ diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 14c5769..2d98904 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -1202,6 +1202,8 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, pos = rsn_ie + 6; left = rsn_ie_len - 6; + data->group_cipher = WPA_CIPHER_GTK_NOT_USED; + data->key_mgmt = WPA_KEY_MGMT_OSEN; data->proto = WPA_PROTO_OSEN; } else { const struct rsn_ie_hdr *hdr; diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 4ee6400..f65077e 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -332,6 +332,13 @@ extern "C" { /* BSS Transition Management Response frame received */ #define BSS_TM_RESP "BSS-TM-RESP " +/* Collocated Interference Request frame received; + * parameters: <dialog token> <automatic report enabled> <report timeout> */ +#define COLOC_INTF_REQ "COLOC-INTF-REQ " +/* Collocated Interference Report frame received; + * parameters: <STA address> <dialog token> <hexdump of report elements> */ +#define COLOC_INTF_REPORT "COLOC-INTF-REPORT " + /* MBO IE with cellular data connection preference received */ #define MBO_CELL_PREFERENCE "MBO-CELL-PREFERENCE " diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index f4cff43..f89053a 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -29,6 +29,7 @@ #include "sha1.h" #include "sha256.h" #include "sha384.h" +#include "sha512.h" #include "md5.h" #include "aes_wrap.h" #include "crypto.h" diff --git a/src/crypto/tls.h b/src/crypto/tls.h index 585db8b..481b346 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -64,6 +64,7 @@ union tls_event_data { size_t hash_len; const char *altsubject[TLS_MAX_ALT_SUBJECT]; int num_altsubject; + const char *serial_num; } peer_cert; struct { @@ -253,6 +254,18 @@ void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn); int tls_connection_established(void *tls_ctx, struct tls_connection *conn); /** + * tls_connection_peer_serial_num - Fetch peer certificate serial number + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * Returns: Allocated string buffer containing the peer certificate serial + * number or %NULL on error. + * + * The caller is responsible for freeing the returned buffer with os_free(). + */ +char * tls_connection_peer_serial_num(void *tls_ctx, + struct tls_connection *conn); + +/** * tls_connection_shutdown - Shutdown TLS connection * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index 7ee3fa3..36dafd2 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -295,6 +295,14 @@ int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) } +char * tls_connection_peer_serial_num(void *tls_ctx, + struct tls_connection *conn) +{ + /* TODO */ + return NULL; +} + + int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) { struct tls_global *global = ssl_ctx; diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index c7cb5de..d289c94 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -177,6 +177,14 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn) } +char * tls_connection_peer_serial_num(void *tls_ctx, + struct tls_connection *conn) +{ + /* TODO */ + return NULL; +} + + int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) { #ifdef CONFIG_TLS_INTERNAL_CLIENT diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c index dd5681e..5d0c6bd 100644 --- a/src/crypto/tls_none.c +++ b/src/crypto/tls_none.c @@ -45,6 +45,13 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn) } +char * tls_connection_peer_serial_num(void *tls_ctx, + struct tls_connection *conn) +{ + return NULL; +} + + int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) { return -1; diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 79ac909..0d5ebda 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -111,6 +111,12 @@ static int RSA_bits(const RSA *r) return BN_num_bits(r->n); } #endif /* CONFIG_SUITEB */ + + +static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x) +{ + return ASN1_STRING_data((ASN1_STRING *) x); +} #endif #ifdef ANDROID @@ -1540,6 +1546,31 @@ int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) } +char * tls_connection_peer_serial_num(void *tls_ctx, + struct tls_connection *conn) +{ + ASN1_INTEGER *ser; + char *serial_num; + size_t len; + + if (!conn->peer_cert) + return NULL; + + ser = X509_get_serialNumber(conn->peer_cert); + if (!ser) + return NULL; + + len = ASN1_STRING_length(ser) * 2 + 1; + serial_num = os_malloc(len); + if (!serial_num) + return NULL; + wpa_snprintf_hex_uppercase(serial_num, len, + ASN1_STRING_get0_data(ser), + ASN1_STRING_length(ser)); + return serial_num; +} + + int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) @@ -1824,6 +1855,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn, GENERAL_NAME *gen; void *ext; stack_index_t i; + ASN1_INTEGER *ser; + char serial_num[128]; #ifdef CONFIG_SHA256 u8 hash[32]; #endif /* CONFIG_SHA256 */ @@ -1852,6 +1885,14 @@ static void openssl_tls_cert_event(struct tls_connection *conn, ev.peer_cert.depth = depth; ev.peer_cert.subject = subject; + ser = X509_get_serialNumber(err_cert); + if (ser) { + wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num), + ASN1_STRING_get0_data(ser), + ASN1_STRING_length(ser)); + ev.peer_cert.serial_num = serial_num; + } + ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL); for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { char *pos; diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c index 9544e2f..cc8c704 100644 --- a/src/crypto/tls_wolfssl.c +++ b/src/crypto/tls_wolfssl.c @@ -347,6 +347,14 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn) } +char * tls_connection_peer_serial_num(void *tls_ctx, + struct tls_connection *conn) +{ + /* TODO */ + return NULL; +} + + int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) { WOLFSSL_SESSION *session; diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 22a37cc..4ac9f16 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1577,6 +1577,8 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_OCE_STA_CFON 0x0020000000000000ULL /** Driver supports MFP-optional in the connect command */ #define WPA_DRIVER_FLAGS_MFP_OPTIONAL 0x0040000000000000ULL +/** Driver is a self-managed regulatory device */ +#define WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY 0x0080000000000000ULL u64 flags; #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \ @@ -1911,8 +1913,21 @@ enum chan_width { CHAN_WIDTH_UNKNOWN }; +#define WPA_INVALID_NOISE 9999 + /** * struct wpa_signal_info - Information about channel signal quality + * @frequency: control frequency + * @above_threshold: true if the above threshold was crossed + * (relevant for a CQM event) + * @current_signal: in dBm + * @avg_signal: in dBm + * @avg_beacon_signal: in dBm + * @current_noise: %WPA_INVALID_NOISE if not supported + * @current_txrate: current TX rate + * @chanwidth: channel width + * @center_frq1: center frequency for the first segment + * @center_frq2: center frequency for the second segment (if relevant) */ struct wpa_signal_info { u32 frequency; diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index 16c2ae9..62f5baa 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -1329,11 +1329,11 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, } atheros_raw_receive(drv, NULL, (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); - } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) { + } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) { /* Format: "Manage.auth <frame len>" | zero padding | frame */ int len = atoi(custom + 12); - if (len < 0 || - MGMT_FRAM_TAG_SIZE + len > end - custom) { + if (len < 0 || + MGMT_FRAM_TAG_SIZE + len > end - custom) { wpa_printf(MSG_DEBUG, "Invalid Manage.auth event length %d", len); return; @@ -1342,7 +1342,7 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); #endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R || CONFIG_FILS */ #ifdef ATHEROS_USE_RAW_RECEIVE - } else if (os_strncmp(custom, "Manage.action ", 14) == 0) { + } else if (os_strncmp(custom, "Manage.action ", 14) == 0) { /* Format: "Manage.assoc_req <frame len>" | zero padding | frame */ int len = atoi(custom + 14); diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c index e89b3ba..4f6629f 100644 --- a/src/drivers/driver_macsec_linux.c +++ b/src/drivers/driver_macsec_linux.c @@ -639,7 +639,7 @@ static int do_dump(struct macsec_drv_data *drv, u8 txsa, u64 rxsci, u8 rxsa, DRV_PREFIX "failed to communicate: %d (%s)", ret, nl_geterror(-ret)); - ctx->cb_arg.pn = 0; + ctx->cb_arg.pn = NULL; out_free_msg: nlmsg_free(msg); @@ -1009,7 +1009,7 @@ static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci) */ static int macsec_drv_create_transmit_sc( void *priv, struct transmit_sc *sc, - enum confidentiality_offset conf_offset) + unsigned int conf_offset) { struct macsec_drv_data *drv = priv; struct rtnl_link *link; diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c index e397950..8372393 100644 --- a/src/drivers/driver_macsec_qca.c +++ b/src/drivers/driver_macsec_qca.c @@ -383,7 +383,7 @@ static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa) } -int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa) +static int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa) { struct macsec_qca_data *drv = priv; int ret = 0; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 39a02d3..871a5d0 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -40,6 +40,29 @@ #include "driver_nl80211.h" +/* support for extack if compilation headers are too old */ +#ifndef NETLINK_EXT_ACK +#define NETLINK_EXT_ACK 11 +enum nlmsgerr_attrs { + NLMSGERR_ATTR_UNUSED, + NLMSGERR_ATTR_MSG, + NLMSGERR_ATTR_OFFS, + NLMSGERR_ATTR_COOKIE, + + __NLMSGERR_ATTR_MAX, + NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1 +}; +#endif +#ifndef NLM_F_CAPPED +#define NLM_F_CAPPED 0x100 +#endif +#ifndef NLM_F_ACK_TLVS +#define NLM_F_ACK_TLVS 0x200 +#endif +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + #ifndef CONFIG_LIBNL20 /* * libnl 1.1 has a bug, it tries to allocate socket numbers densely @@ -302,8 +325,35 @@ static int finish_handler(struct nl_msg *msg, void *arg) static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { + struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1; + int len = nlh->nlmsg_len; + struct nlattr *attrs; + struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; int *ret = arg; + int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh); + *ret = err->error; + + if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) + return NL_SKIP; + + if (!(nlh->nlmsg_flags & NLM_F_CAPPED)) + ack_len += err->msg.nlmsg_len - sizeof(*nlh); + + if (len <= ack_len) + return NL_STOP; + + attrs = (void *) ((unsigned char *) nlh + ack_len); + len -= ack_len; + + nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL); + if (tb[NLMSGERR_ATTR_MSG]) { + len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]), + nla_len(tb[NLMSGERR_ATTR_MSG])); + wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s", + len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG])); + } + return NL_SKIP; } @@ -342,7 +392,7 @@ static int send_and_recv(struct nl80211_global *global, void *valid_data) { struct nl_cb *cb; - int err = -ENOMEM; + int err = -ENOMEM, opt; if (!msg) return -ENOMEM; @@ -351,6 +401,11 @@ static int send_and_recv(struct nl80211_global *global, if (!cb) goto out; + /* try to set NETLINK_EXT_ACK to 1, ignoring errors */ + opt = 1; + setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK, + NETLINK_EXT_ACK, &opt, sizeof(opt)); + err = nl_send_auto_complete(nl_handle, msg); if (err < 0) goto out; @@ -1414,7 +1469,7 @@ int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv, { struct nl_msg *msg; - sig->current_signal = -9999; + sig->current_signal = -WPA_INVALID_NOISE; sig->current_txrate = 0; if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) || @@ -1476,7 +1531,7 @@ int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv, { struct nl_msg *msg; - sig_change->current_noise = 9999; + sig_change->current_noise = WPA_INVALID_NOISE; sig_change->frequency = drv->assoc_freq; msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); @@ -2145,6 +2200,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) /* WNM-Sleep Mode Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0) ret = -1; +#ifdef CONFIG_WNM + /* WNM - Collocated Interference Request */ + if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0) + ret = -1; +#endif /* CONFIG_WNM */ #ifdef CONFIG_HS20 /* WNM-Notification */ @@ -3105,7 +3165,8 @@ static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params, int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, const u8 *addr, int cmd, u16 reason_code, - int local_state_change) + int local_state_change, + struct nl_handle *nl_connect) { int ret; struct nl_msg *msg; @@ -3119,7 +3180,10 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, return -1; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (nl_connect) + ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL); + else + ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret) { wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: MLME command failed: reason=%u ret=%d (%s)", @@ -3130,7 +3194,8 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, - int reason_code) + int reason_code, + struct nl_handle *nl_connect) { int ret; int drv_associated = drv->associated; @@ -3139,7 +3204,7 @@ static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, nl80211_mark_disconnected(drv); /* Disconnect command doesn't need BSSID - it uses cached value */ ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT, - reason_code, 0); + reason_code, 0, nl_connect); /* * For locally generated disconnect, supplicant already generates a * DEAUTH event, so ignore the event from NL80211. @@ -3161,13 +3226,19 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss, nl80211_mark_disconnected(drv); return nl80211_leave_ibss(drv, 1); } - if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) - return wpa_driver_nl80211_disconnect(drv, reason_code); + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { + struct nl_handle *nl_connect = NULL; + + if (bss->use_nl_connect) + nl_connect = bss->nl_connect; + return wpa_driver_nl80211_disconnect(drv, reason_code, + nl_connect); + } wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)", __func__, MAC2STR(addr), reason_code); nl80211_mark_disconnected(drv); ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, - reason_code, 0); + reason_code, 0, NULL); /* * For locally generated deauthenticate, supplicant already generates a * DEAUTH event, so ignore the event from NL80211. @@ -5582,7 +5653,7 @@ static int wpa_driver_nl80211_connect( "disconnecting before reassociation " "attempt"); if (wpa_driver_nl80211_disconnect( - drv, WLAN_REASON_PREV_AUTH_NOT_VALID)) + drv, WLAN_REASON_PREV_AUTH_NOT_VALID, nl_connect)) return -1; ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect); } @@ -5613,8 +5684,13 @@ static int wpa_driver_nl80211_associate( if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0) return -1; - if (params->auth_alg & WPA_AUTH_ALG_SAE) + if (params->auth_alg & WPA_AUTH_ALG_SAE) { nl_connect = bss->nl_connect; + bss->use_nl_connect = 1; + } else { + bss->use_nl_connect = 0; + } + return wpa_driver_nl80211_connect(drv, params, nl_connect); } @@ -6221,6 +6297,7 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs, struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; struct nlattr *txq, *params; + int res; msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY); if (!msg) @@ -6266,7 +6343,11 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs, nla_nest_end(msg, txq); - if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) + res = send_and_recv_msgs(drv, msg, NULL, NULL); + wpa_printf(MSG_DEBUG, + "nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d", + queue, aifs, cw_min, cw_max, burst_time, res); + if (res == 0) return 0; msg = NULL; fail: @@ -6525,8 +6606,15 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, struct wpa_driver_nl80211_data *drv = bss->drv; char name[IFNAMSIZ + 1]; union wpa_event_data event; + int ret; + + ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid); + if (ret >= (int) sizeof(name)) + wpa_printf(MSG_WARNING, + "nl80211: WDS interface name was truncated"); + else if (ret < 0) + return ret; - os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid); if (ifname_wds) os_strlcpy(ifname_wds, name, IFNAMSIZ + 1); diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 5ac0c7d..bc562ba 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -66,6 +66,7 @@ struct i802_bss { unsigned int wdev_id_set:1; unsigned int added_if:1; unsigned int static_ap:1; + unsigned int use_nl_connect:1; u8 addr[ETH_ALEN]; @@ -252,7 +253,8 @@ int wpa_driver_nl80211_set_mode(struct i802_bss *bss, enum nl80211_iftype nlmode); int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, const u8 *addr, int cmd, u16 reason_code, - int local_state_change); + int local_state_change, + struct nl_handle *nl_connect); int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv); void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv); diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index a51b50d..7b360d2 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -818,6 +818,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) capa->max_csa_counters = nla_get_u8(tb[NL80211_ATTR_MAX_CSA_COUNTERS]); + if (tb[NL80211_ATTR_WIPHY_SELF_MANAGED_REG]) + capa->flags |= WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY; + return NL_SKIP; } @@ -1918,6 +1921,13 @@ static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv, return -ENOMEM; nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG); + if (drv->capa.flags & WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY) { + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx)) { + nlmsg_free(msg); + return -1; + } + } + return send_and_recv_msgs(drv, msg, nl80211_get_reg, results); } diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 5b8efbc..205b4cd 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -754,12 +754,12 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, * disconnection event for the old AP may show up after * we have started connection with the new AP. */ - wpa_printf(MSG_DEBUG, - "nl80211: Ignore deauth/disassoc event from old AP " - MACSTR - " when already connecting with " MACSTR, - MAC2STR(bssid), - MAC2STR(drv->auth_attempt_bssid)); + wpa_printf(MSG_DEBUG, + "nl80211: Ignore deauth/disassoc event from old AP " + MACSTR + " when already connecting with " MACSTR, + MAC2STR(bssid), + MAC2STR(drv->auth_attempt_bssid)); return; } @@ -2271,7 +2271,7 @@ static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv, ed.sta_opmode.addr = nla_data(tb[NL80211_ATTR_MAC]); if (tb[NL80211_ATTR_SMPS_MODE]) { - smps_mode = nla_get_u32(tb[NL80211_ATTR_SMPS_MODE]); + smps_mode = nla_get_u8(tb[NL80211_ATTR_SMPS_MODE]); switch (smps_mode) { case NL80211_SMPS_OFF: ed.sta_opmode.smps_mode = SMPS_OFF; diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c index 9376d11..f25cd79 100644 --- a/src/drivers/driver_nl80211_monitor.c +++ b/src/drivers/driver_nl80211_monitor.c @@ -361,8 +361,17 @@ int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) */ snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4); } else { + int ret; + /* Non-P2P interface with AP functionality. */ - snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname); + ret = os_snprintf(buf, IFNAMSIZ, "mon.%s", + drv->first_bss->ifname); + if (ret >= (int) sizeof(buf)) + wpa_printf(MSG_DEBUG, + "nl80211: Monitor interface name has been truncated to %s", + buf); + else if (ret < 0) + return ret; } buf[IFNAMSIZ - 1] = '\0'; diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index 86501f4..33a8d35 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -866,7 +866,8 @@ static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv, "mismatch (" MACSTR ")", MAC2STR(addr)); wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, - WLAN_REASON_PREV_AUTH_NOT_VALID, 1); + WLAN_REASON_PREV_AUTH_NOT_VALID, 1, + NULL); } } diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index 933b8d9..20abaab 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -2428,8 +2428,8 @@ static int wpa_driver_wext_signal_poll(void *priv, struct wpa_signal_info *si) struct iwreq iwr; os_memset(si, 0, sizeof(*si)); - si->current_signal = -9999; - si->current_noise = 9999; + si->current_signal = -WPA_INVALID_NOISE; + si->current_noise = WPA_INVALID_NOISE; si->chanwidth = CHAN_WIDTH_UNKNOWN; os_memset(&iwr, 0, sizeof(iwr)); diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c index 7e09dcf..c7537b7 100644 --- a/src/drivers/driver_wired.c +++ b/src/drivers/driver_wired.c @@ -96,16 +96,16 @@ static void handle_data(void *ctx, unsigned char *buf, size_t len) hdr = (struct ieee8023_hdr *) buf; switch (ntohs(hdr->ethertype)) { - case ETH_P_PAE: - wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); - sa = hdr->src; - os_memset(&event, 0, sizeof(event)); - event.new_sta.addr = sa; - wpa_supplicant_event(ctx, EVENT_NEW_STA, &event); - - pos = (u8 *) (hdr + 1); - left = len - sizeof(*hdr); - drv_event_eapol_rx(ctx, sa, pos, left); + case ETH_P_PAE: + wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); + sa = hdr->src; + os_memset(&event, 0, sizeof(event)); + event.new_sta.addr = sa; + wpa_supplicant_event(ctx, EVENT_NEW_STA, &event); + + pos = (u8 *) (hdr + 1); + left = len - sizeof(*hdr); + drv_event_eapol_rx(ctx, sa, pos, left); break; default: diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c index 90ac3cf..761c16a 100644 --- a/src/eap_peer/eap_pwd.c +++ b/src/eap_peer/eap_pwd.c @@ -696,7 +696,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, const struct wpabuf *reqData, const u8 *payload, size_t payload_len) { - struct crypto_hash *hash; + struct crypto_hash *hash = NULL; u32 cs; u16 grp; u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; @@ -783,6 +783,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, /* random function fin */ eap_pwd_h_final(hash, conf); + hash = NULL; ptr = (u8 *) payload; if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) { @@ -836,6 +837,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, /* all done */ eap_pwd_h_final(hash, conf); + hash = NULL; if (compute_keys(data->grp, data->k, data->my_scalar, data->server_scalar, conf, ptr, @@ -860,6 +862,10 @@ fin: } else { eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION); } + + /* clean allocated memory */ + if (hash) + eap_pwd_h_final(hash, conf); } diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h index bb3641f..4fbc661 100644 --- a/src/eap_server/eap.h +++ b/src/eap_server/eap.h @@ -152,6 +152,7 @@ void eap_sm_notify_cached(struct eap_sm *sm); void eap_sm_pending_cb(struct eap_sm *sm); int eap_sm_method_pending(struct eap_sm *sm); const u8 * eap_get_identity(struct eap_sm *sm, size_t *len); +const char * eap_get_serial_num(struct eap_sm *sm); struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm); void eap_server_clear_identity(struct eap_sm *sm); void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source, diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h index 3d6f8d5..cf8a9f0 100644 --- a/src/eap_server/eap_i.h +++ b/src/eap_server/eap_i.h @@ -159,6 +159,7 @@ struct eap_sm { void *eap_method_priv; u8 *identity; size_t identity_len; + char *serial_num; /* Whether Phase 2 method should validate identity match */ int require_identity_match; int lastId; /* Identifier used in the last EAP-Packet */ diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c index c9da72e..38a1b5c 100644 --- a/src/eap_server/eap_server.c +++ b/src/eap_server/eap_server.c @@ -1920,6 +1920,7 @@ void eap_server_sm_deinit(struct eap_sm *sm) wpabuf_free(sm->lastReqData); wpabuf_free(sm->eap_if.eapRespData); os_free(sm->identity); + os_free(sm->serial_num); os_free(sm->pac_opaque_encr_key); os_free(sm->eap_fast_a_id); os_free(sm->eap_fast_a_id_info); @@ -1991,6 +1992,17 @@ const u8 * eap_get_identity(struct eap_sm *sm, size_t *len) } +/** + * eap_get_serial_num - Get the serial number of user certificate + * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() + * Returns: Pointer to the serial number or %NULL if not available + */ +const char * eap_get_serial_num(struct eap_sm *sm) +{ + return sm->serial_num; +} + + void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len) { #ifdef CONFIG_ERP diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c index 4f9cb08..0ae7867 100644 --- a/src/eap_server/eap_server_tls_common.c +++ b/src/eap_server/eap_server_tls_common.c @@ -341,6 +341,11 @@ int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0; } + if (!sm->serial_num && + tls_connection_established(sm->ssl_ctx, data->conn)) + sm->serial_num = tls_connection_peer_serial_num(sm->ssl_ctx, + data->conn); + return 0; } diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index b2fd9b7..e3afc0d 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -826,18 +826,28 @@ static void db_update_last_msk(struct radius_session *sess, const char *msk) char *id_str = NULL; const u8 *id; size_t id_len; + const char *serial_num; if (!sess->server->db) return; - id = eap_get_identity(sess->eap, &id_len); - if (!id) - return; - id_str = os_malloc(id_len + 1); - if (!id_str) - return; - os_memcpy(id_str, id, id_len); - id_str[id_len] = '\0'; + serial_num = eap_get_serial_num(sess->eap); + if (serial_num) { + id_len = 5 + os_strlen(serial_num) + 1; + id_str = os_malloc(id_len); + if (!id_str) + return; + os_snprintf(id_str, id_len, "cert-%s", serial_num); + } else { + id = eap_get_identity(sess->eap, &id_len); + if (!id) + return; + id_str = os_malloc(id_len + 1); + if (!id_str) + return; + os_memcpy(id_str, id, id_len); + id_str[id_len] = '\0'; + } sql = sqlite3_mprintf("UPDATE users SET last_msk=%Q WHERE identity=%Q", msk, id_str); diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index 14b346a..345b0c8 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -2159,11 +2159,11 @@ static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout, sm, peer); #ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK " - "expiration"); - eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); - } + if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) { + wpa_printf(MSG_DEBUG, + "TDLS: Testing - disable TPK expiration"); + eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); + } #endif /* CONFIG_TDLS_TESTING */ } diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 8e95cbd..e0c9130 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -1007,7 +1007,7 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm, } wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x", + "WPA: IGTK keyid %d pn " COMPACT_MACSTR, keyidx, MAC2STR(igtk->pn)); wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len); if (keyidx > 4095) { diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c index 062e6fe..dfb4b67 100644 --- a/src/utils/browser-wpadebug.c +++ b/src/utils/browser-wpadebug.c @@ -97,6 +97,7 @@ int hs20_web_browser(const char *url) if (pid == 0) { /* run the external command in the child process */ char *argv[14]; + char *envp[] = { "PATH=/system/bin:/vendor/bin", NULL }; argv[0] = "browser-wpadebug"; argv[1] = "start"; @@ -113,8 +114,8 @@ int hs20_web_browser(const char *url) argv[12] = "-3"; /* USER_CURRENT_OR_SELF */ argv[13] = NULL; - execv("/system/bin/am", argv); - wpa_printf(MSG_ERROR, "execv: %s", strerror(errno)); + execve("/system/bin/am", argv, envp); + wpa_printf(MSG_ERROR, "execve: %s", strerror(errno)); exit(0); return -1; } diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c index 62758d8..a56462b 100644 --- a/src/utils/wpa_debug.c +++ b/src/utils/wpa_debug.c @@ -58,6 +58,10 @@ static int wpa_to_android_level(int level) #ifndef CONFIG_NO_STDOUT_DEBUG #ifdef CONFIG_DEBUG_FILE +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + static FILE *out_file = NULL; #endif /* CONFIG_DEBUG_FILE */ @@ -539,6 +543,8 @@ int wpa_debug_reopen_file(void) int wpa_debug_open_file(const char *path) { #ifdef CONFIG_DEBUG_FILE + int out_fd; + if (!path) return 0; @@ -548,10 +554,28 @@ int wpa_debug_open_file(const char *path) last_path = os_strdup(path); } - out_file = fopen(path, "a"); + out_fd = open(path, O_CREAT | O_APPEND | O_WRONLY, + S_IRUSR | S_IWUSR | S_IRGRP); + if (out_fd < 0) { + wpa_printf(MSG_ERROR, + "%s: Failed to open output file descriptor, using standard output", + __func__); + return -1; + } + +#ifdef __linux__ + if (fcntl(out_fd, F_SETFD, FD_CLOEXEC) < 0) { + wpa_printf(MSG_DEBUG, + "%s: Failed to set FD_CLOEXEC - continue without: %s", + __func__, strerror(errno)); + } +#endif /* __linux__ */ + + out_file = fdopen(out_fd, "a"); if (out_file == NULL) { wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open " "output file, using standard output"); + close(out_fd); return -1; } #ifndef _WIN32 diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog index f28055f..bf4daaa 100644 --- a/wpa_supplicant/ChangeLog +++ b/wpa_supplicant/ChangeLog @@ -1,5 +1,75 @@ ChangeLog for wpa_supplicant +2018-12-02 - v2.7 + * fixed WPA packet number reuse with replayed messages and key + reinstallation + [https://w1.fi/security/2017-1/] (CVE-2017-13077, CVE-2017-13078, + CVE-2017-13079, CVE-2017-13080, CVE-2017-13081, CVE-2017-13082, + CVE-2017-13086, CVE-2017-13087, CVE-2017-13088) + * fixed unauthenticated EAPOL-Key decryption in wpa_supplicant + [https://w1.fi/security/2018-1/] (CVE-2018-14526) + * added support for FILS (IEEE 802.11ai) shared key authentication + * added support for OWE (Opportunistic Wireless Encryption, RFC 8110; + and transition mode defined by WFA) + * added support for DPP (Wi-Fi Device Provisioning Protocol) + * added support for RSA 3k key case with Suite B 192-bit level + * fixed Suite B PMKSA caching not to update PMKID during each 4-way + handshake + * fixed EAP-pwd pre-processing with PasswordHashHash + * added EAP-pwd client support for salted passwords + * fixed a regression in TDLS prohibited bit validation + * started to use estimated throughput to avoid undesired signal + strength based roaming decision + * MACsec/MKA: + - new macsec_linux driver interface support for the Linux + kernel macsec module + - number of fixes and extensions + * added support for external persistent storage of PMKSA cache + (PMKSA_GET/PMKSA_ADD control interface commands; and + MESH_PMKSA_GET/MESH_PMKSA_SET for the mesh case) + * fixed mesh channel configuration pri/sec switch case + * added support for beacon report + * large number of other fixes, cleanup, and extensions + * added support for randomizing local address for GAS queries + (gas_rand_mac_addr parameter) + * fixed EAP-SIM/AKA/AKA' ext auth cases within TLS tunnel + * added option for using random WPS UUID (auto_uuid=1) + * added SHA256-hash support for OCSP certificate matching + * fixed EAP-AKA' to add AT_KDF into Synchronization-Failure + * fixed a regression in RSN pre-authentication candidate selection + * added option to configure allowed group management cipher suites + (group_mgmt network profile parameter) + * removed all PeerKey functionality + * fixed nl80211 AP and mesh mode configuration regression with + Linux 4.15 and newer + * added ap_isolate configuration option for AP mode + * added support for nl80211 to offload 4-way handshake into the driver + * added support for using wolfSSL cryptographic library + * SAE + - added support for configuring SAE password separately of the + WPA2 PSK/passphrase + - fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection + for SAE; + note: this is not backwards compatible, i.e., both the AP and + station side implementations will need to be update at the same + time to maintain interoperability + - added support for Password Identifier + - fixed FT-SAE PMKID matching + * Hotspot 2.0 + - added support for fetching of Operator Icon Metadata ANQP-element + - added support for Roaming Consortium Selection element + - added support for Terms and Conditions + - added support for OSEN connection in a shared RSN BSS + - added support for fetching Venue URL information + * added support for using OpenSSL 1.1.1 + * FT + - disabled PMKSA caching with FT since it is not fully functional + - added support for SHA384 based AKM + - added support for BIP ciphers BIP-CMAC-256, BIP-GMAC-128, + BIP-GMAC-256 in addition to previously supported BIP-CMAC-128 + - fixed additional IE inclusion in Reassociation Request frame when + using FT protocol + 2016-10-02 - v2.6 * fixed WNM Sleep Mode processing when PMF is not enabled [http://w1.fi/security/2015-6/] (CVE-2015-5310) diff --git a/wpa_supplicant/README b/wpa_supplicant/README index 730714b..2a3265f 100644 --- a/wpa_supplicant/README +++ b/wpa_supplicant/README @@ -1,7 +1,7 @@ WPA Supplicant ============== -Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 5aa07ea..3a41db9 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -103,6 +103,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp) ANQP_DUP(hs20_operating_class); ANQP_DUP(hs20_osu_providers_list); ANQP_DUP(hs20_operator_icon_metadata); + ANQP_DUP(hs20_osu_providers_nai_list); #endif /* CONFIG_HS20 */ #undef ANQP_DUP @@ -187,6 +188,7 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) wpabuf_free(anqp->hs20_operating_class); wpabuf_free(anqp->hs20_osu_providers_list); wpabuf_free(anqp->hs20_operator_icon_metadata); + wpabuf_free(anqp->hs20_osu_providers_nai_list); #endif /* CONFIG_HS20 */ os_free(anqp); diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 9179385..5251b2c 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -51,6 +51,7 @@ struct wpa_bss_anqp { struct wpabuf *hs20_operating_class; struct wpabuf *hs20_osu_providers_list; struct wpabuf *hs20_operator_icon_metadata; + struct wpabuf *hs20_osu_providers_nai_list; #endif /* CONFIG_HS20 */ }; diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index dd7f603..c439606 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -3155,14 +3155,16 @@ static int wpa_config_set_cred_roaming_consortiums(struct wpa_cred *cred, } roaming_consortiums_len[num_roaming_consortiums] = len / 2; num_roaming_consortiums++; - if (num_roaming_consortiums > MAX_ROAMING_CONS) { + + if (!end) + break; + + if (num_roaming_consortiums >= MAX_ROAMING_CONS) { wpa_printf(MSG_INFO, "Too many roaming_consortiums OIs"); return -1; } - if (!end) - break; pos = end + 1; } @@ -4753,6 +4755,7 @@ static const struct global_parse_data global_fields[] = { { INT(gas_rand_addr_lifetime), 0 }, { INT_RANGE(gas_rand_mac_addr, 0, 2), 0 }, { INT_RANGE(dpp_config_processing, 0, 2), 0 }, + { INT_RANGE(coloc_intf_reporting, 0, 1), 0 }, }; #undef FUNC diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index ad4dd88..cd7571f 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1469,6 +1469,15 @@ struct wpa_config { * profile automatically */ int dpp_config_processing; + + /** + * coloc_intf_reporting - Colocated interference reporting + * + * dot11CoLocIntfReportingActivated + * 0 = disabled (false) + * 1 = enabled (true) + */ + int coloc_intf_reporting; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index aa73f9d..09115e1 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1511,7 +1511,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->dpp_config_processing) fprintf(f, "dpp_config_processing=%d\n", config->dpp_config_processing); - + if (config->coloc_intf_reporting) + fprintf(f, "coloc_intf_reporting=%d\n", + config->coloc_intf_reporting); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 3000c43..d2a52d7 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -927,6 +927,16 @@ struct wpa_ssid { * 1 = disable transition mode (allow connection only with OWE) */ int owe_only; + + /** + * owe_transition_bss_select_count - OWE transition BSS select count + * + * This is an internally used variable (i.e., not used in external + * configuration) to track the number of selection attempts done for + * OWE BSS in transition mode. This allows fallback to an open BSS if + * the selection attempts for OWE BSS exceed the configured threshold. + */ + int owe_transition_bss_select_count; }; #endif /* CONFIG_SSID_H */ diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index fe39c25..77a3133 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -750,6 +750,15 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value); } else if (os_strcasecmp(cmd, "roaming") == 0) { ret = wpa_drv_roaming(wpa_s, atoi(value), NULL); +#ifdef CONFIG_WNM + } else if (os_strcasecmp(cmd, "coloc_intf_elems") == 0) { + struct wpabuf *elems; + + elems = wpabuf_parse_bin(value); + if (!elems) + return -1; + wnm_set_coloc_intf_elems(wpa_s, elems); +#endif /* CONFIG_WNM */ } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); @@ -4809,6 +4818,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, anqp->hs20_osu_providers_list); pos = anqp_add_hex(pos, end, "hs20_operator_icon_metadata", anqp->hs20_operator_icon_metadata); + pos = anqp_add_hex(pos, end, "hs20_osu_providers_nai_list", + anqp->hs20_osu_providers_nai_list); #endif /* CONFIG_HS20 */ dl_list_for_each(elem, &anqp->anqp_elems, @@ -7435,6 +7446,22 @@ static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd list); } + +static int wpas_ctrl_iface_coloc_intf_report(struct wpa_supplicant *wpa_s, + char *cmd) +{ + struct wpabuf *elems; + int ret; + + elems = wpabuf_parse_bin(cmd); + if (!elems) + return -1; + + ret = wnm_send_coloc_intf_report(wpa_s, 0, elems); + wpabuf_free(elems); + return ret; +} + #endif /* CONFIG_WNM */ @@ -10421,6 +10448,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) { if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14)) reply_len = -1; + } else if (os_strncmp(buf, "COLOC_INTF_REPORT ", 18) == 0) { + if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18)) + reply_len = -1; #endif /* CONFIG_WNM */ } else if (os_strcmp(buf, "FLUSH") == 0) { wpa_supplicant_ctrl_iface_flush(wpa_s); diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index e0f16bb..d4deb0f 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -2131,11 +2131,6 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, case WPAS_DBUS_PROP_AP_SCAN: prop = "ApScan"; break; -#ifdef CONFIG_IEEE80211W - case WPAS_DBUS_PROP_PMF: - prop = "Pmf"; - break; -#endif /* CONFIG_IEEE80211W */ case WPAS_DBUS_PROP_SCANNING: prop = "Scanning"; break; @@ -3307,13 +3302,6 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = { wpas_dbus_setter_ap_scan, NULL }, -#ifdef CONFIG_IEEE80211W - { "Pmf", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", - wpas_dbus_getter_pmf, - wpas_dbus_setter_pmf, - NULL - }, -#endif /* CONFIG_IEEE80211W */ { "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", wpas_dbus_getter_bss_expire_age, wpas_dbus_setter_bss_expire_age, diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h index e68acb7..40ae133 100644 --- a/wpa_supplicant/dbus/dbus_new.h +++ b/wpa_supplicant/dbus/dbus_new.h @@ -22,7 +22,6 @@ struct wps_credential; enum wpas_dbus_prop { WPAS_DBUS_PROP_AP_SCAN, - WPAS_DBUS_PROP_PMF, WPAS_DBUS_PROP_SCANNING, WPAS_DBUS_PROP_STATE, WPAS_DBUS_PROP_CURRENT_BSS, diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index a3c98fa..94773b3 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -980,8 +980,8 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( const struct wpa_dbus_property_desc *property_desc, DBusMessageIter *iter, DBusError *error, void *user_data) { - const char *capabilities[8] = { NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL }; + const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; size_t num_items = 0; #ifdef CONFIG_FILS struct wpa_global *global = user_data; @@ -1020,6 +1020,12 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( if (fils_sk_pfs_supported) capabilities[num_items++] = "fils_sk_pfs"; #endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211R + capabilities[num_items++] = "ft"; +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_SHA384 + capabilities[num_items++] = "sha384"; +#endif /* CONFIG_SHA384 */ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_STRING, @@ -3012,61 +3018,6 @@ dbus_bool_t wpas_dbus_setter_ap_scan( } -#ifdef CONFIG_IEEE80211W - -/** - * wpas_dbus_getter_pmf - Control PMF default - * @iter: Pointer to incoming dbus message iter - * @error: Location to store error on failure - * @user_data: Function specific data - * Returns: TRUE on success, FALSE on failure - * - * Getter function for "Pmf" property. - */ -dbus_bool_t wpas_dbus_getter_pmf( - const struct wpa_dbus_property_desc *property_desc, - DBusMessageIter *iter, DBusError *error, void *user_data) -{ - struct wpa_supplicant *wpa_s = user_data; - dbus_uint32_t pmf = wpa_s->conf->pmf; - - return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, - &pmf, error); -} - - -/** - * wpas_dbus_setter_pmf - Control PMF default - * @iter: Pointer to incoming dbus message iter - * @error: Location to store error on failure - * @user_data: Function specific data - * Returns: TRUE on success, FALSE on failure - * - * Setter function for "Pmf" property. - */ -dbus_bool_t wpas_dbus_setter_pmf( - const struct wpa_dbus_property_desc *property_desc, - DBusMessageIter *iter, DBusError *error, void *user_data) -{ - struct wpa_supplicant *wpa_s = user_data; - dbus_uint32_t pmf; - - if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, - &pmf)) - return FALSE; - - if (pmf > 2) { - dbus_set_error_const(error, DBUS_ERROR_FAILED, - "Pmf must be 0, 1, or 2"); - return FALSE; - } - wpa_s->conf->pmf = pmf; - return TRUE; -} - -#endif /* CONFIG_IEEE80211W */ - - /** * wpas_dbus_getter_fast_reauth - Control fast * reauthentication (TLS session resumption) diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h index 26652ad..6f952cc 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/wpa_supplicant/dbus/dbus_new_handlers.h @@ -141,8 +141,6 @@ DECLARE_ACCESSOR(wpas_dbus_getter_state); DECLARE_ACCESSOR(wpas_dbus_getter_scanning); DECLARE_ACCESSOR(wpas_dbus_getter_ap_scan); DECLARE_ACCESSOR(wpas_dbus_setter_ap_scan); -DECLARE_ACCESSOR(wpas_dbus_getter_pmf); -DECLARE_ACCESSOR(wpas_dbus_setter_pmf); DECLARE_ACCESSOR(wpas_dbus_getter_fast_reauth); DECLARE_ACCESSOR(wpas_dbus_setter_fast_reauth); DECLARE_ACCESSOR(wpas_dbus_getter_disconnect_reason); diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 08f5857..af281e5 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -44,7 +44,7 @@ CONFIG_DRIVER_NL80211=y #CONFIG_LIBNL20=y # Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored) -#CONFIG_LIBNL32=y +CONFIG_LIBNL32=y # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml index 25cfd06..ae6bafe 100644 --- a/wpa_supplicant/doc/docbook/eapol_test.sgml +++ b/wpa_supplicant/doc/docbook/eapol_test.sgml @@ -194,7 +194,7 @@ eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1 </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2017, + <para>wpa_supplicant is copyright (c) 2003-2018, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml index fa94ae4..d3e4dbe 100644 --- a/wpa_supplicant/doc/docbook/wpa_background.sgml +++ b/wpa_supplicant/doc/docbook/wpa_background.sgml @@ -90,7 +90,7 @@ <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2017, + <para>wpa_supplicant is copyright (c) 2003-2018, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml index be3045a..766dd2c 100644 --- a/wpa_supplicant/doc/docbook/wpa_cli.sgml +++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml @@ -345,7 +345,7 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2017, + <para>wpa_supplicant is copyright (c) 2003-2018, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml index cee9ed6..91662d5 100644 --- a/wpa_supplicant/doc/docbook/wpa_gui.sgml +++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml @@ -91,7 +91,7 @@ </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2017, + <para>wpa_supplicant is copyright (c) 2003-2018, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml index 6667a07..2f86b0b 100644 --- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml +++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml @@ -62,7 +62,7 @@ </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2017, + <para>wpa_supplicant is copyright (c) 2003-2018, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml index 3796b93..4a5f319 100644 --- a/wpa_supplicant/doc/docbook/wpa_priv.sgml +++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml @@ -137,7 +137,7 @@ wpa_supplicant -i ath0 -c wpa_supplicant.conf </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2017, + <para>wpa_supplicant is copyright (c) 2003-2018, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml index 80b3878..eeb9c07 100644 --- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml +++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml @@ -729,7 +729,7 @@ fi </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2017, + <para>wpa_supplicant is copyright (c) 2003-2018, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 899c4c2..7bc4661 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -527,9 +527,9 @@ static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s, } -static void wpas_dpp_set_configurator(struct wpa_supplicant *wpa_s, - struct dpp_authentication *auth, - const char *cmd) +static int wpas_dpp_set_configurator(struct wpa_supplicant *wpa_s, + struct dpp_authentication *auth, + const char *cmd) { const char *pos, *end; struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL; @@ -543,7 +543,7 @@ static void wpas_dpp_set_configurator(struct wpa_supplicant *wpa_s, char *group_id = NULL; if (!cmd) - return; + return 0; wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd); pos = os_strstr(cmd, " ssid="); @@ -607,10 +607,12 @@ static void wpas_dpp_set_configurator(struct wpa_supplicant *wpa_s, conf_sta->akm = DPP_AKM_PSK; if (psk_set) { os_memcpy(conf_sta->psk, psk, PMK_LEN); - } else { + } else if (pass_len > 0) { conf_sta->passphrase = os_strdup(pass); if (!conf_sta->passphrase) goto fail; + } else { + goto fail; } } else if (os_strstr(cmd, " conf=sta-dpp")) { conf_sta->akm = DPP_AKM_DPP; @@ -684,13 +686,14 @@ static void wpas_dpp_set_configurator(struct wpa_supplicant *wpa_s, auth->conf_ap = conf_ap; auth->conf = conf; os_free(group_id); - return; + return 0; fail: - wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters"); + wpa_msg(wpa_s, MSG_INFO, "DPP: Failed to set configurator parameters"); dpp_configuration_free(conf_sta); dpp_configuration_free(conf_ap); os_free(group_id); + return -1; } @@ -869,7 +872,11 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) if (!wpa_s->dpp_auth) goto fail; wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth); - wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth, cmd); + if (wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth, cmd) < 0) { + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + goto fail; + } wpa_s->dpp_auth->neg_freq = neg_freq; @@ -1015,29 +1022,6 @@ void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s) } -void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s, - unsigned int freq) -{ - if (!wpa_s->dpp_listen_freq && !wpa_s->dpp_pending_listen_freq) - return; - - wpa_printf(MSG_DEBUG, - "DPP: remain-on-channel callback (off_channel_freq=%u dpp_pending_listen_freq=%d roc_waiting_drv_freq=%d freq=%u)", - wpa_s->off_channel_freq, wpa_s->dpp_pending_listen_freq, - wpa_s->roc_waiting_drv_freq, freq); - if (wpa_s->off_channel_freq && - wpa_s->off_channel_freq == wpa_s->dpp_pending_listen_freq) { - wpa_printf(MSG_DEBUG, "DPP: Listen on %u MHz started", freq); - wpa_s->dpp_pending_listen_freq = 0; - } else { - wpa_printf(MSG_DEBUG, - "DPP: Ignore remain-on-channel callback (off_channel_freq=%u dpp_pending_listen_freq=%d freq=%u)", - wpa_s->off_channel_freq, - wpa_s->dpp_pending_listen_freq, freq); - } -} - - void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq) { @@ -1142,8 +1126,12 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src, return; } wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth); - wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth, - wpa_s->dpp_configurator_params); + if (wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth, + wpa_s->dpp_configurator_params) < 0) { + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + return; + } os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN); if (wpa_s->dpp_listen_freq && @@ -1346,7 +1334,8 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); return; } - if (!resp || status_code != WLAN_STATUS_SUCCESS) { + if (result != GAS_QUERY_SUCCESS || + !resp || status_code != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed"); goto fail; } @@ -2286,9 +2275,9 @@ int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd) return -1; curve = get_param(cmd, " curve="); - wpas_dpp_set_configurator(wpa_s, auth, cmd); - - if (dpp_configurator_own_config(auth, curve, 0) == 0) { + wpas_dpp_set_testing_options(wpa_s, auth); + if (wpas_dpp_set_configurator(wpa_s, auth, cmd) == 0 && + dpp_configurator_own_config(auth, curve, 0) == 0) { wpas_dpp_handle_config_obj(wpa_s, auth); ret = 0; } diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h index 9b539df..5a4f06e 100644 --- a/wpa_supplicant/dpp_supplicant.h +++ b/wpa_supplicant/dpp_supplicant.h @@ -19,8 +19,6 @@ int wpas_dpp_bootstrap_info(struct wpa_supplicant *wpa_s, int id, int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd); int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd); void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s); -void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s, - unsigned int freq); void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq); void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 349f819..37d429d 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -50,6 +50,9 @@ #include "dpp_supplicant.h" +#define MAX_OWE_TRANSITION_BSS_SELECT_COUNT 5 + + #ifndef CONFIG_NO_SCAN_PROCESSING static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, int new_scan, int own_request); @@ -314,6 +317,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) wpas_rrm_reset(wpa_s); wpa_s->wnmsleep_used = 0; + wnm_clear_coloc_intf_reporting(wpa_s); #ifdef CONFIG_TESTING_OPTIONS wpa_s->last_tk_alg = WPA_ALG_NONE; @@ -703,6 +707,19 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, #ifdef CONFIG_OWE if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only && !wpa_ie && !rsn_ie) { + if (wpa_s->owe_transition_select && + wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE) && + ssid->owe_transition_bss_select_count + 1 <= + MAX_OWE_TRANSITION_BSS_SELECT_COUNT) { + ssid->owe_transition_bss_select_count++; + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip OWE transition BSS (selection count %d does not exceed %d)", + ssid->owe_transition_bss_select_count, + MAX_OWE_TRANSITION_BSS_SELECT_COUNT); + wpa_s->owe_transition_search = 1; + return 0; + } if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, " allow in OWE transition mode"); @@ -1387,8 +1404,11 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, for (i = 0; i < wpa_s->last_scan_res_used; i++) { struct wpa_bss *bss = wpa_s->last_scan_res[i]; + + wpa_s->owe_transition_select = 1; *selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group, only_first_ssid, 1); + wpa_s->owe_transition_select = 0; if (!*selected_ssid) continue; wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR @@ -1935,6 +1955,7 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, if (wpa_s->p2p_mgmt) return 0; /* no normal connection on p2p_mgmt interface */ + wpa_s->owe_transition_search = 0; selected = wpa_supplicant_pick_network(wpa_s, &ssid); #ifdef CONFIG_MESH @@ -2036,6 +2057,17 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, return 0; } #endif /* CONFIG_WPS */ +#ifdef CONFIG_OWE + if (wpa_s->owe_transition_search) { + wpa_dbg(wpa_s, MSG_DEBUG, + "OWE: Use shorter wait during transition mode search"); + timeout_sec = 0; + timeout_usec = 500000; + wpa_supplicant_req_new_scan(wpa_s, timeout_sec, + timeout_usec); + return 0; + } +#endif /* CONFIG_OWE */ if (wpa_supplicant_req_sched_scan(wpa_s)) wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); @@ -3999,6 +4031,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, { struct wpa_supplicant *wpa_s = ctx; int resched; +#ifndef CONFIG_NO_STDOUT_DEBUG + int level = MSG_DEBUG; +#endif /* CONFIG_NO_STDOUT_DEBUG */ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED && event != EVENT_INTERFACE_ENABLED && @@ -4012,9 +4047,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } #ifndef CONFIG_NO_STDOUT_DEBUG -{ - int level = MSG_DEBUG; - if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) { const struct ieee80211_hdr *hdr; u16 fc; @@ -4027,7 +4059,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_dbg(wpa_s, level, "Event %s (%d) received", event_to_string(event), event); -} #endif /* CONFIG_NO_STDOUT_DEBUG */ switch (event) { @@ -4054,6 +4085,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } #endif /* CONFIG_TESTING_OPTIONS */ wpa_supplicant_event_assoc(wpa_s, data); + wpa_s->assoc_status_code = WLAN_STATUS_SUCCESS; if (data && (data->assoc_info.authorized || (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && @@ -4308,6 +4340,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_AP */ wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS); + wnm_clear_coloc_intf_reporting(wpa_s); break; #ifdef CONFIG_AP #ifdef NEED_AP_MLME diff --git a/wpa_supplicant/examples/wps-ap-cli b/wpa_supplicant/examples/wps-ap-cli index cc2cff2..15d913e 100755 --- a/wpa_supplicant/examples/wps-ap-cli +++ b/wpa_supplicant/examples/wps-ap-cli @@ -14,12 +14,12 @@ pbc() enter_pin() { echo "Enter a PIN from a station to be enrolled to the network." - echo -n "Enrollee PIN: " + printf "Enrollee PIN: " read pin cpin=`$CLI wps_check_pin "$pin" | tail -1` if [ "$cpin" = "FAIL-CHECKSUM" ]; then echo "Checksum digit is not valid" - echo -n "Do you want to use this PIN (y/n)? " + printf "Do you want to use this PIN (y/n)? " read resp case "$resp" in y*) @@ -52,7 +52,7 @@ main_menu() echo "3: Show current configuration" echo "0: Exit wps-ap-cli" - echo -n "Command: " + printf "Command: " read cmd case "$cmd" in diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c index e00c5af..f418790 100644 --- a/wpa_supplicant/hs20_supplicant.c +++ b/wpa_supplicant/hs20_supplicant.c @@ -54,6 +54,7 @@ struct osu_provider { char server_uri[256]; u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */ char osu_nai[256]; + char osu_nai2[256]; struct osu_lang_string friendly_name[OSU_MAX_ITEMS]; size_t friendly_name_count; struct osu_lang_string serv_desc[OSU_MAX_ITEMS]; @@ -673,6 +674,15 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, wpabuf_alloc_copy(pos, slen); } break; + case HS20_STYPE_OSU_PROVIDERS_NAI_LIST: + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR + " OSU Providers NAI List", MAC2STR(sa)); + if (anqp) { + wpabuf_free(anqp->hs20_osu_providers_nai_list); + anqp->hs20_osu_providers_nai_list = + wpabuf_alloc_copy(pos, slen); + } + break; default: wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype); break; @@ -759,6 +769,8 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s) } if (osu->osu_nai[0]) fprintf(f, "osu_nai=%s\n", osu->osu_nai); + if (osu->osu_nai2[0]) + fprintf(f, "osu_nai2=%s\n", osu->osu_nai2); for (j = 0; j < osu->friendly_name_count; j++) { fprintf(f, "friendly_name=%s:%s\n", osu->friendly_name[j].lang, @@ -1103,6 +1115,35 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) "extra data after OSU Providers", (int) (end - pos)); } + + prov_anqp = bss->anqp->hs20_osu_providers_nai_list; + if (!prov_anqp) + continue; + wpa_printf(MSG_DEBUG, + "HS 2.0: Parsing OSU Providers NAI List from " + MACSTR, MAC2STR(bss->bssid)); + wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers NAI List", + prov_anqp); + pos = wpabuf_head(prov_anqp); + end = pos + wpabuf_len(prov_anqp); + num_providers = 0; + while (end - pos > 0) { + len = *pos++; + if (end - pos < len) { + wpa_printf(MSG_DEBUG, + "HS 2.0: Not enough room for OSU_NAI"); + break; + } + if (num_providers >= wpa_s->osu_prov_count) { + wpa_printf(MSG_DEBUG, + "HS 2.0: Ignore unexpected OSU Provider NAI List entries"); + break; + } + os_memcpy(wpa_s->osu_prov[num_providers].osu_nai2, + pos, len); + pos += len; + num_providers++; + } } wpa_s->fetch_osu_icon_in_progress = 1; diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index f3f88d3..60c8be9 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -303,8 +303,10 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY); if (all) wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS); - if (all) + if (all) { wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST); + wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_NAI_LIST); + } gas_anqp_set_element_len(extra, len_pos); } #endif /* CONFIG_HS20 */ diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c index d166cfe..eafb0af 100644 --- a/wpa_supplicant/mesh_mpm.c +++ b/wpa_supplicant/mesh_mpm.c @@ -222,13 +222,14 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, if (!sta) return; - buf_len = 2 + /* capability info */ + buf_len = 2 + /* Category and Action */ + 2 + /* capability info */ 2 + /* AID */ 2 + 8 + /* supported rates */ 2 + (32 - 8) + 2 + 32 + /* mesh ID */ 2 + 7 + /* mesh config */ - 2 + 23 + /* peering management */ + 2 + 24 + /* peering management */ 2 + 96 + /* AMPE */ 2 + 16; /* MIC */ #ifdef CONFIG_IEEE80211N diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 56d53fb..ee39e0c 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -677,6 +677,87 @@ static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s, } +static void wpa_add_scan_ssid(struct wpa_supplicant *wpa_s, + struct wpa_driver_scan_params *params, + size_t max_ssids, const u8 *ssid, size_t ssid_len) +{ + unsigned int j; + + for (j = 0; j < params->num_ssids; j++) { + if (params->ssids[j].ssid_len == ssid_len && + params->ssids[j].ssid && + os_memcmp(params->ssids[j].ssid, ssid, ssid_len) == 0) + return; /* already in the list */ + } + + if (params->num_ssids + 1 > max_ssids) { + wpa_printf(MSG_DEBUG, "Over max scan SSIDs for manual request"); + return; + } + + wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s", + wpa_ssid_txt(ssid, ssid_len)); + + params->ssids[params->num_ssids].ssid = ssid; + params->ssids[params->num_ssids].ssid_len = ssid_len; + params->num_ssids++; +} + + +static void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s, + struct wpa_driver_scan_params *params, + struct wpa_ssid *ssid, size_t max_ssids) +{ +#ifdef CONFIG_OWE + struct wpa_bss *bss; + + if (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE)) + return; + + wpa_printf(MSG_DEBUG, "OWE: Look for transition mode AP. ssid=%s", + wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + + dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { + const u8 *owe, *pos, *end; + const u8 *owe_ssid; + size_t owe_ssid_len; + + if (bss->ssid_len != ssid->ssid_len || + os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) != 0) + continue; + + owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE); + if (!owe || owe[1] < 4) + continue; + + pos = owe + 6; + end = owe + 2 + owe[1]; + + /* Must include BSSID and ssid_len */ + if (end - pos < ETH_ALEN + 1) + return; + + /* Skip BSSID */ + pos += ETH_ALEN; + owe_ssid_len = *pos++; + owe_ssid = pos; + + if ((size_t) (end - pos) < owe_ssid_len || + owe_ssid_len > SSID_MAX_LEN) + return; + + wpa_printf(MSG_DEBUG, + "OWE: scan_ssids: transition mode OWE ssid=%s", + wpa_ssid_txt(owe_ssid, owe_ssid_len)); + + wpa_add_scan_ssid(wpa_s, params, max_ssids, + owe_ssid, owe_ssid_len); + return; + } +#endif /* CONFIG_OWE */ +} + + static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params, size_t max_ssids) @@ -691,33 +772,17 @@ static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s, max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids; for (i = 0; i < wpa_s->scan_id_count; i++) { - unsigned int j; - ssid = wpa_config_get_network(wpa_s->conf, wpa_s->scan_id[i]); - if (!ssid || !ssid->scan_ssid) + if (!ssid) continue; - - for (j = 0; j < params->num_ssids; j++) { - if (params->ssids[j].ssid_len == ssid->ssid_len && - params->ssids[j].ssid && - os_memcmp(params->ssids[j].ssid, ssid->ssid, - ssid->ssid_len) == 0) - break; - } - if (j < params->num_ssids) - continue; /* already in the list */ - - if (params->num_ssids + 1 > max_ssids) { - wpa_printf(MSG_DEBUG, - "Over max scan SSIDs for manual request"); - break; - } - - wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s", - wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); - params->ssids[params->num_ssids].ssid = ssid->ssid; - params->ssids[params->num_ssids].ssid_len = ssid->ssid_len; - params->num_ssids++; + if (ssid->scan_ssid) + wpa_add_scan_ssid(wpa_s, params, max_ssids, + ssid->ssid, ssid->ssid_len); + /* + * Also add the SSID of the OWE BSS, to allow discovery of + * transition mode APs more quickly. + */ + wpa_add_owe_scan_ssid(wpa_s, params, ssid, max_ssids); } wpa_s->scan_id_count = 0; @@ -984,6 +1049,17 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) if (params.num_ssids + 1 >= max_ssids) break; } + + if (!wpas_network_disabled(wpa_s, ssid)) { + /* + * Also add the SSID of the OWE BSS, to allow + * discovery of transition mode APs more + * quickly. + */ + wpa_add_owe_scan_ssid(wpa_s, ¶ms, ssid, + max_ssids); + } + ssid = ssid->next; if (ssid == start) break; diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 708a347..39c8069 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -72,7 +72,7 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s) if (sae_set_group(&wpa_s->sme.sae, group) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d", wpa_s->sme.sae.group); - return 0; + return 0; } wpa_s->sme.sae_group_index++; } @@ -240,6 +240,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, u8 ext_capab[18]; int ext_capab_len; int skip_auth; + u8 *wpa_ie; + size_t wpa_ie_len; #ifdef CONFIG_MBO const u8 *mbo_ie; #endif /* CONFIG_MBO */ @@ -352,6 +354,20 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpas_connect_work_done(wpa_s); return; } +#ifdef CONFIG_HS20 + } else if (wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) && + (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) { + /* No PMKSA caching, but otherwise similar to RSN/WPA */ + wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); + if (wpa_supplicant_set_suites(wpa_s, bss, ssid, + wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len)) { + wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA " + "key management and encryption suites"); + wpas_connect_work_done(wpa_s); + return; + } +#endif /* CONFIG_HS20 */ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) { /* @@ -391,6 +407,28 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_s->sme.assoc_req_ie_len = 0; } + /* In case the WPA vendor IE is used, it should be placed after all the + * non-vendor IEs, as the lower layer expects the IEs to be ordered as + * defined in the standard. Store the WPA IE so it can later be + * inserted at the correct location. + */ + wpa_ie = NULL; + wpa_ie_len = 0; + if (wpa_s->wpa_proto == WPA_PROTO_WPA) { + wpa_ie = os_memdup(wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + if (wpa_ie) { + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Storing WPA IE"); + + wpa_ie_len = wpa_s->sme.assoc_req_ie_len; + wpa_s->sme.assoc_req_ie_len = 0; + } else { + wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed copy WPA IE"); + wpas_connect_work_done(wpa_s); + return; + } + } + #ifdef CONFIG_IEEE80211R ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) @@ -527,6 +565,26 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_HS20 */ + if (wpa_ie) { + size_t len; + + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Reinsert WPA IE"); + + len = sizeof(wpa_s->sme.assoc_req_ie) - + wpa_s->sme.assoc_req_ie_len; + + if (len > wpa_ie_len) { + os_memcpy(wpa_s->sme.assoc_req_ie + + wpa_s->sme.assoc_req_ie_len, + wpa_ie, wpa_ie_len); + wpa_s->sme.assoc_req_ie_len += wpa_ie_len; + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Failed to add WPA IE"); + } + + os_free(wpa_ie); + } + if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) { struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]; size_t len; @@ -837,10 +895,10 @@ static int sme_external_auth_build_buf(struct wpabuf *buf, os_memcpy(resp->da, da, ETH_ALEN); os_memcpy(resp->sa, sa, ETH_ALEN); os_memcpy(resp->bssid, da, ETH_ALEN); - resp->u.auth.auth_alg = WLAN_AUTH_SAE; - resp->seq_ctrl = seq_num << 4; - resp->u.auth.auth_transaction = auth_transaction; - resp->u.auth.status_code = WLAN_STATUS_SUCCESS; + resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE); + resp->seq_ctrl = host_to_le16(seq_num << 4); + resp->u.auth.auth_transaction = host_to_le16(auth_transaction); + resp->u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS); if (params) wpabuf_put_buf(buf, params); @@ -900,7 +958,8 @@ static void sme_handle_external_auth_start(struct wpa_supplicant *wpa_s, for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (!wpas_network_disabled(wpa_s, ssid) && ssid_str_len == ssid->ssid_len && - os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0) + os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0 && + (ssid->key_mgmt & WPA_KEY_MGMT_SAE)) break; } if (ssid) @@ -1119,13 +1178,14 @@ void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, return; } - if (header->u.auth.auth_alg == WLAN_AUTH_SAE) { + if (le_to_host16(header->u.auth.auth_alg) == WLAN_AUTH_SAE) { int res; - res = sme_sae_auth(wpa_s, header->u.auth.auth_transaction, - header->u.auth.status_code, - header->u.auth.variable, - len - auth_length, 1, header->sa); + res = sme_sae_auth( + wpa_s, le_to_host16(header->u.auth.auth_transaction), + le_to_host16(header->u.auth.status_code), + header->u.auth.variable, + len - auth_length, 1, header->sa); if (res < 0) { /* Notify failure to the driver */ sme_send_external_auth_status( @@ -1460,14 +1520,18 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group) { group = wpa_s->current_ssid->owe_group; - } else { + } else if (wpa_s->assoc_status_code == + WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { if (wpa_s->last_owe_group == 19) group = 20; else if (wpa_s->last_owe_group == 20) group = 21; else group = OWE_DH_GROUP; + } else { + group = OWE_DH_GROUP; } + wpa_s->last_owe_group = group; wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group); owe_ie = owe_build_assoc_req(wpa_s->wpa, group); @@ -1499,6 +1563,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, params.wpa_ie = wpa_s->sme.assoc_req_ie_len ? wpa_s->sme.assoc_req_ie : NULL; params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; + wpa_hexdump(MSG_DEBUG, "SME: Association Request IEs", + params.wpa_ie, params.wpa_ie_len); params.pairwise_suite = wpa_s->pairwise_cipher; params.group_suite = wpa_s->group_cipher; params.mgmt_group_suite = wpa_s->mgmt_group_cipher; @@ -1519,9 +1585,85 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms); #endif /* CONFIG_VHT_OVERRIDES */ #ifdef CONFIG_IEEE80211R - if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { + if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies && + get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len, + WLAN_EID_RIC_DATA)) { + /* There seems to be a pretty inconvenient bug in the Linux + * kernel IE splitting functionality when RIC is used. For now, + * skip correct behavior in IE construction here (i.e., drop the + * additional non-FT-specific IEs) to avoid kernel issues. This + * is fine since RIC is used only for testing purposes in the + * current implementation. */ + wpa_printf(MSG_INFO, + "SME: Linux kernel workaround - do not try to include additional IEs with RIC"); params.wpa_ie = wpa_s->sme.ft_ies; params.wpa_ie_len = wpa_s->sme.ft_ies_len; + } else if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { + const u8 *rm_en, *pos, *end; + size_t rm_en_len = 0; + u8 *rm_en_dup = NULL, *wpos; + + /* Remove RSNE, MDE, FTE to allow them to be overridden with + * FT specific values */ + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_RSN); + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_MOBILITY_DOMAIN); + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_FAST_BSS_TRANSITION); + rm_en = get_ie(wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len, + WLAN_EID_RRM_ENABLED_CAPABILITIES); + if (rm_en) { + /* Need to remove RM Enabled Capabilities element as + * well temporarily, so that it can be placed between + * RSNE and MDE. */ + rm_en_len = 2 + rm_en[1]; + rm_en_dup = os_memdup(rm_en, rm_en_len); + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_RRM_ENABLED_CAPABILITIES); + } + wpa_hexdump(MSG_DEBUG, + "SME: Association Request IEs after FT IE removal", + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + if (wpa_s->sme.assoc_req_ie_len + wpa_s->sme.ft_ies_len + + rm_en_len > sizeof(wpa_s->sme.assoc_req_ie)) { + wpa_printf(MSG_ERROR, + "SME: Not enough buffer room for FT IEs in Association Request frame"); + os_free(rm_en_dup); + return; + } + + os_memmove(wpa_s->sme.assoc_req_ie + wpa_s->sme.ft_ies_len + + rm_en_len, + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + pos = wpa_s->sme.ft_ies; + end = pos + wpa_s->sme.ft_ies_len; + wpos = wpa_s->sme.assoc_req_ie; + if (*pos == WLAN_EID_RSN) { + os_memcpy(wpos, pos, 2 + pos[1]); + wpos += 2 + pos[1]; + pos += 2 + pos[1]; + } + if (rm_en_dup) { + os_memcpy(wpos, rm_en_dup, rm_en_len); + wpos += rm_en_len; + os_free(rm_en_dup); + } + os_memcpy(wpos, pos, end - pos); + wpa_s->sme.assoc_req_ie_len += wpa_s->sme.ft_ies_len + + rm_en_len; + params.wpa_ie = wpa_s->sme.assoc_req_ie; + params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; + wpa_hexdump(MSG_DEBUG, + "SME: Association Request IEs after FT override", + params.wpa_ie, params.wpa_ie_len); } #endif /* CONFIG_IEEE80211R */ params.mode = mode; diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 7c410e7..6b68fc9 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -338,6 +338,9 @@ void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) wpa_s->wnm_num_neighbor_report = 0; os_free(wpa_s->wnm_neighbor_report_elements); wpa_s->wnm_neighbor_report_elements = NULL; + + wpabuf_free(wpa_s->coloc_intf_elems); + wpa_s->coloc_intf_elems = NULL; } @@ -1717,6 +1720,46 @@ static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, } +static void ieee802_11_rx_wnm_coloc_intf_req(struct wpa_supplicant *wpa_s, + const u8 *sa, const u8 *frm, + int len) +{ + u8 dialog_token, req_info, auto_report, timeout; + + if (!wpa_s->conf->coloc_intf_reporting) + return; + + /* Dialog Token [1] | Request Info [1] */ + + if (len < 2) + return; + dialog_token = frm[0]; + req_info = frm[1]; + auto_report = req_info & 0x03; + timeout = req_info >> 2; + + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Received Collocated Interference Request (dialog_token %u auto_report %u timeout %u sa " MACSTR ")", + dialog_token, auto_report, timeout, MAC2STR(sa)); + + if (dialog_token == 0) + return; /* only nonzero values are used for request */ + + if (wpa_s->wpa_state != WPA_COMPLETED || + os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { + wpa_dbg(wpa_s, MSG_DEBUG, + "WNM: Collocated Interference Request frame not from current AP - ignore it"); + return; + } + + wpa_msg(wpa_s, MSG_INFO, COLOC_INTF_REQ "%u %u %u", + dialog_token, auto_report, timeout); + wpa_s->coloc_intf_dialog_token = dialog_token; + wpa_s->coloc_intf_auto_report = auto_report; + wpa_s->coloc_intf_timeout = timeout; +} + + void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, const struct ieee80211_mgmt *mgmt, size_t len) { @@ -1750,8 +1793,75 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, case WNM_NOTIFICATION_REQ: ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); break; + case WNM_COLLOCATED_INTERFERENCE_REQ: + ieee802_11_rx_wnm_coloc_intf_req(wpa_s, mgmt->sa, pos, + end - pos); + break; default: wpa_printf(MSG_ERROR, "WNM: Unknown request"); break; } } + + +int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token, + const struct wpabuf *elems) +{ + struct wpabuf *buf; + int ret; + + if (wpa_s->wpa_state < WPA_ASSOCIATED || !elems) + return -1; + + wpa_printf(MSG_DEBUG, "WNM: Send Collocated Interference Report to " + MACSTR " (dialog token %u)", + MAC2STR(wpa_s->bssid), dialog_token); + + buf = wpabuf_alloc(3 + wpabuf_len(elems)); + if (!buf) + return -1; + + wpabuf_put_u8(buf, WLAN_ACTION_WNM); + wpabuf_put_u8(buf, WNM_COLLOCATED_INTERFERENCE_REPORT); + wpabuf_put_u8(buf, dialog_token); + wpabuf_put_buf(buf, elems); + + ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, + wpa_s->own_addr, wpa_s->bssid, + wpabuf_head_u8(buf), wpabuf_len(buf), 0); + wpabuf_free(buf); + return ret; +} + + +void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s, + struct wpabuf *elems) +{ + wpabuf_free(wpa_s->coloc_intf_elems); + if (elems && wpabuf_len(elems) == 0) { + wpabuf_free(elems); + elems = NULL; + } + wpa_s->coloc_intf_elems = elems; + + if (wpa_s->conf->coloc_intf_reporting && wpa_s->coloc_intf_elems && + wpa_s->coloc_intf_dialog_token && + (wpa_s->coloc_intf_auto_report == 1 || + wpa_s->coloc_intf_auto_report == 3)) { + /* TODO: Check that there has not been less than + * wpa_s->coloc_intf_timeout * 200 TU from the last report. + */ + wnm_send_coloc_intf_report(wpa_s, + wpa_s->coloc_intf_dialog_token, + wpa_s->coloc_intf_elems); + } +} + + +void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_WNM + wpa_s->coloc_intf_dialog_token = 0; + wpa_s->coloc_intf_auto_report = 0; +#endif /* CONFIG_WNM */ +} diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h index 02cd1cd..29625f8 100644 --- a/wpa_supplicant/wnm_sta.h +++ b/wpa_supplicant/wnm_sta.h @@ -65,11 +65,16 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, int cand_list); void wnm_deallocate_memory(struct wpa_supplicant *wpa_s); +int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token, + const struct wpabuf *elems); +void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s, + struct wpabuf *elems); #ifdef CONFIG_WNM int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail); +void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s); #else /* CONFIG_WNM */ @@ -79,6 +84,10 @@ static inline int wnm_scan_process(struct wpa_supplicant *wpa_s, return 0; } +static inline void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s) +{ +} + #endif /* CONFIG_WNM */ #endif /* WNM_STA_H */ diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 05e3ebf..7793554 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - command line interface for wpa_supplicant daemon - * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -29,7 +29,7 @@ static const char *const wpa_cli_version = "wpa_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> and contributors"; #define VENDOR_ELEM_FRAME_ID \ " 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \ diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 4531c62..e587d7e 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -68,7 +68,7 @@ const char *const wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" -"Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi> and contributors"; const char *const wpa_supplicant_license = "This software may be distributed under the terms of the BSD license.\n" @@ -1216,13 +1216,12 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0"); proto = WPA_PROTO_WPA; #ifdef CONFIG_HS20 - } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN)) { + } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN) && + wpa_parse_wpa_ie(bss_osen, 2 + bss_osen[1], &ie) == 0 && + (ie.group_cipher & ssid->group_cipher) && + (ie.pairwise_cipher & ssid->pairwise_cipher) && + (ie.key_mgmt & ssid->key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN"); - /* TODO: parse OSEN element */ - os_memset(&ie, 0, sizeof(ie)); - ie.group_cipher = WPA_CIPHER_CCMP; - ie.pairwise_cipher = WPA_CIPHER_CCMP; - ie.key_mgmt = WPA_KEY_MGMT_OSEN; proto = WPA_PROTO_OSEN; } else if (bss_rsn && (ssid->proto & WPA_PROTO_OSEN) && wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 && @@ -1645,6 +1644,10 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) case 0: /* Bits 0-7 */ break; case 1: /* Bits 8-15 */ + if (wpa_s->conf->coloc_intf_reporting) { + /* Bit 13 - Collocated Interference Reporting */ + *pos |= 0x20; + } break; case 2: /* Bits 16-23 */ #ifdef CONFIG_WNM @@ -2494,6 +2497,19 @@ static u8 * wpas_populate_assoc_ies( os_free(wpa_ie); return NULL; } +#ifdef CONFIG_HS20 + } else if (bss && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) && + (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) { + /* No PMKSA caching, but otherwise similar to RSN/WPA */ + wpa_ie_len = max_wpa_ie_len; + if (wpa_supplicant_set_suites(wpa_s, bss, ssid, + wpa_ie, &wpa_ie_len)) { + wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA " + "key management and encryption suites"); + os_free(wpa_ie); + return NULL; + } +#endif /* CONFIG_HS20 */ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss && wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) { /* @@ -2738,14 +2754,18 @@ static u8 * wpas_populate_assoc_ies( if (ssid->owe_group) { group = ssid->owe_group; - } else { + } else if (wpa_s->assoc_status_code == + WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { if (wpa_s->last_owe_group == 19) group = 20; else if (wpa_s->last_owe_group == 20) group = 21; else group = OWE_DH_GROUP; + } else { + group = OWE_DH_GROUP; } + wpa_s->last_owe_group = group; wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group); owe_ie = owe_build_assoc_req(wpa_s->wpa, group); @@ -3307,6 +3327,7 @@ static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s, return; ssid->disabled = 0; + ssid->owe_transition_bss_select_count = 0; wpas_clear_temp_disabled(wpa_s, ssid, 1); wpas_notify_network_enabled_changed(wpa_s, ssid); @@ -3571,6 +3592,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, wpa_s->disconnected = 0; wpa_s->reassociate = 1; wpa_s->last_owe_group = 0; + if (ssid) + ssid->owe_transition_bss_select_count = 0; if (wpa_s->connect_without_scan || wpa_supplicant_fast_associate(wpa_s) != 1) { diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 9b8d1fa..8b749f4 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -743,6 +743,8 @@ struct wpa_supplicant { unsigned int mac_addr_changed:1; unsigned int added_vif:1; unsigned int wnmsleep_used:1; + unsigned int owe_transition_select:1; + unsigned int owe_transition_search:1; struct os_reltime last_mac_addr_change; int last_mac_addr_style; @@ -1057,6 +1059,10 @@ struct wpa_supplicant { struct neighbor_report *wnm_neighbor_report_elements; struct os_reltime wnm_cand_valid_until; u8 wnm_cand_from_bss[ETH_ALEN]; + struct wpabuf *coloc_intf_elems; + u8 coloc_intf_dialog_token; + u8 coloc_intf_auto_report; + u8 coloc_intf_timeout; #ifdef CONFIG_MBO unsigned int wnm_mbo_trans_reason_present:1; u8 wnm_mbo_transition_reason; |