]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
D-Bus: Interworking network selection
authorDamien Dejean <damiendejean@chromium.org>
Wed, 8 Dec 2021 07:45:32 +0000 (07:45 +0000)
committerJouni Malinen <j@w1.fi>
Sun, 12 Dec 2021 15:51:46 +0000 (17:51 +0200)
Add the "InterworkingSelect" method to the DBus API to trigger an
Interworking scan with ANQP fetches. When a BSS that matches a
configured credential is found, the result is emitted using the signal
"InterworkingAPAdded". Completion of the full InterworkingSelect
operation is indicated with the "InterworkingSelectDone" signal.

Signed-off-by: Damien Dejean <damiendejean@chromium.org>
doc/dbus.doxygen
tests/hwsim/test_dbus.py
wpa_supplicant/dbus/dbus_new.c
wpa_supplicant/dbus/dbus_new.h
wpa_supplicant/dbus/dbus_new_handlers.c
wpa_supplicant/dbus/dbus_new_handlers.h
wpa_supplicant/interworking.c
wpa_supplicant/notify.c
wpa_supplicant/notify.h

index 68fc84572ee4ef43b2723c354d91ea3200543b2f..f6ab820001086b169d237488dce36304530ba6b9 100644 (file)
@@ -574,6 +574,10 @@ fi.w1.wpa_supplicant1.CreateInterface.
        <h3>RemoveAllCreds ( ) --> nothing</h3>
        <p>Remove all configured Interworking/Hotspot 2.0 credentials.</p>
       </li>
+      <li>
+       <h3>InterworkingSelect ( ) --> nothing</h3>
+       <p>Perform Interworking (Hotspot 2.0) network selection.</p>
+      </li>
       <li>
        <h3>EAPLogoff ( ) --> nothing</h3>
        <p>IEEE 802.1X EAPOL state machine logoff.</p>
@@ -1283,6 +1287,14 @@ fi.w1.wpa_supplicant1.CreateInterface.
          <dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "addr", "dst", "bssid", "ies", "signal".</dd>
        </dl>
       </li>
+
+      <li>
+       <h3>InterworkingAPAdded ( o : bss, o : cred, a{sv} : args )</h3>
+      </li>
+
+      <li>
+       <h3>InterworkingSelectDone ( )</h3>
+      </li>
     </ul>
 
 
index 4edd0fd7359c73ee54ddccf787df3892c50ad1ea..28fb050147367b863aa7a46e4e67b69d1f999417 100644 (file)
@@ -6136,3 +6136,69 @@ def test_dbus_creds(dev, apdev):
         raise Exception("Credential remove failed")
     if not "FAIL" in dev[0].get_cred(1, 'domain'):
         raise Exception("Credential remove failed")
+
+def test_dbus_interworking(dev, apdev):
+    "D-Bus interworking selection"
+    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    params = {"ssid": "test-interworking", "wpa": "2",
+              "wpa_key_mgmt": "WPA-EAP", "rsn_pairwise": "CCMP",
+              "ieee8021x": "1", "eapol_version": "2",
+              "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
+              "ca_cert": "auth_serv/ca.pem",
+              "server_cert": "auth_serv/server.pem",
+              "private_key": "auth_serv/server.key",
+              "interworking": "1",
+              "domain_name": "server.w1.fi",
+              "nai_realm": "0,server.w1.fi,21[2:4][5:7]",
+              "roaming_consortium": "2233445566",
+              "hs20": "1", "anqp_domain_id": "1234"}
+
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    class TestDbusInterworking(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.interworking_ap_seen = False
+            self.interworking_select_done = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_select)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.interworkingAPAdded, WPAS_DBUS_IFACE,
+                            "InterworkingAPAdded")
+            self.add_signal(self.interworkingSelectDone, WPAS_DBUS_IFACE,
+                            "InterworkingSelectDone")
+            self.loop.run()
+            return self
+
+        def interworkingAPAdded(self, bss, cred, properties):
+            logger.debug("interworkingAPAdded: bss=%s cred=%s %s" % (bss, cred, str(properties)))
+            if self.cred == cred:
+                self.interworking_ap_seen = True
+
+        def interworkingSelectDone(self):
+            logger.debug("interworkingSelectDone")
+            self.interworking_select_done = True
+            self.loop.quit()
+
+        def run_select(self, *args):
+            args = {"domain": "server.w1.fi",
+                    "realm": "server.w1.fi",
+                    "eap": "TTLS",
+                    "phase2": "auth=MSCHAPV2",
+                    "username": "user",
+                    "password": "password",
+                    "domain_suffix_match": "server.w1.fi",
+                    "ca_cert": "auth_serv/ca.pem"}
+            self.cred = iface.AddCred(dbus.Dictionary(args, signature='sv'))
+            iface.InterworkingSelect()
+            return False
+
+        def success(self):
+            return self.interworking_ap_seen and self.interworking_select_done
+
+    with TestDbusInterworking(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
index bfa49d65465943c4856f07db0548823b7dc5b2e7..9279ae4d58476072fc28eccf28c711e4c1989408 100644 (file)
@@ -937,6 +937,95 @@ void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_MESH */
 
 
+#ifdef CONFIG_INTERWORKING
+
+void wpas_dbus_signal_interworking_ap_added(struct wpa_supplicant *wpa_s,
+                                           struct wpa_bss *bss,
+                                           struct wpa_cred *cred,
+                                           const char *type,
+                                           int excluded,
+                                           int bh,
+                                           int bss_load,
+                                           int conn_capab)
+{
+       struct wpas_dbus_priv *iface;
+       DBusMessage *msg;
+       DBusMessageIter iter, dict_iter;
+       char bss_path[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path;
+       char cred_path[WPAS_DBUS_OBJECT_PATH_MAX], *cred_obj_path;
+
+       iface = wpa_s->global->dbus;
+
+       /* Do nothing if the control interface is not turned on */
+       if (!iface || !wpa_s->dbus_new_path)
+               return;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_INTERFACE,
+                                     "InterworkingAPAdded");
+       if (!msg)
+               return;
+
+       os_snprintf(bss_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
+                   wpa_s->dbus_new_path, bss->id);
+       bss_obj_path = bss_path;
+
+       os_snprintf(cred_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_CREDENTIALS_PART "/%u",
+                   wpa_s->dbus_new_path, cred->id);
+       cred_obj_path = cred_path;
+
+       dbus_message_iter_init_append(msg, &iter);
+       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                           &bss_obj_path) ||
+           !dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                           &cred_obj_path) ||
+           !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+           !wpa_dbus_dict_append_string(&dict_iter, "type", type) ||
+           !wpa_dbus_dict_append_int32(&dict_iter, "excluded", excluded) ||
+           !wpa_dbus_dict_append_int32(&dict_iter, "priority",
+                                       cred->priority) ||
+           !wpa_dbus_dict_append_int32(&dict_iter, "sp_priority",
+                                       cred->sp_priority) ||
+           !wpa_dbus_dict_append_int32(&dict_iter, "below_min_backhaul", bh) ||
+           !wpa_dbus_dict_append_int32(&dict_iter, "over_max_bss_load",
+                                       bss_load) ||
+           !wpa_dbus_dict_append_int32(&dict_iter, "conn_capab_missing",
+                                       conn_capab) ||
+           !wpa_dbus_dict_close_write(&iter, &dict_iter))
+               wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       else
+               dbus_connection_send(iface->con, msg, NULL);
+       dbus_message_unref(msg);
+}
+
+
+void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s)
+{
+       struct wpas_dbus_priv *iface;
+       DBusMessage *msg;
+
+       iface = wpa_s->global->dbus;
+
+       /* Do nothing if the control interface is not turned on */
+       if (!iface || !wpa_s->dbus_new_path)
+               return;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_INTERFACE,
+                                     "InterworkingSelectDone");
+       if (!msg)
+               return;
+
+       dbus_connection_send(iface->con, msg, NULL);
+
+       dbus_message_unref(msg);
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
 void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
                                    int depth, const char *subject,
                                    const char *altsubject[],
@@ -3592,6 +3681,12 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
                  END_ARGS
          }
        },
+       { "InterworkingSelect", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) wpas_dbus_handler_interworking_select,
+         {
+                 END_ARGS
+         }
+       },
 #endif /* CONFIG_INTERWORKING */
        { NULL, NULL, NULL, { END_ARGS } }
 };
@@ -4160,6 +4255,21 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
          }
        },
 #endif /* CONFIG_MESH */
+#ifdef CONFIG_INTERWORKING
+       { "InterworkingAPAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "bss", "o", ARG_OUT },
+                 { "cred", "o", ARG_OUT },
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "InterworkingSelectDone", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 END_ARGS
+         }
+       },
+#endif /* CONFIG_INTERWORKING */
        { NULL, NULL, { END_ARGS } }
 };
 
index 6cdd9dc166f0a23b84d7ed0b4f7ff2d31106879d..26bdcb548de85c888eac9fd3fe376cb137eab9fe 100644 (file)
@@ -16,6 +16,8 @@
 struct wpa_global;
 struct wpa_supplicant;
 struct wpa_ssid;
+struct wpa_cred;
+struct wpa_bss;
 struct wps_event_m2d;
 struct wps_event_fail;
 struct wps_credential;
@@ -267,6 +269,13 @@ void wpas_dbus_signal_mesh_peer_connected(struct wpa_supplicant *wpa_s,
                                          const u8 *peer_addr);
 void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
                                             const u8 *peer_addr, int reason);
+void wpas_dbus_signal_interworking_ap_added(struct wpa_supplicant *wpa_s,
+                                           struct wpa_bss *bss,
+                                           struct wpa_cred *cred,
+                                           const char *type, int excluded,
+                                           int bh, int bss_load,
+                                           int conn_capab);
+void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s);
 
 #else /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
@@ -619,6 +628,21 @@ void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
 {
 }
 
+static inline
+void wpas_dbus_signal_interworking_ap_added(struct wpa_supplicant *wpa_s,
+                                           struct wpa_bss *bss,
+                                           struct wpa_cred *cred,
+                                           const char *type, int excluded,
+                                           int bh, int bss_load,
+                                           int conn_capab)
+{
+}
+
+static inline
+void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s)
+{
+}
+
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
 #endif /* CTRL_IFACE_DBUS_H_NEW */
index ce6923e9527fe11ad47bbc8405de77d883e98bb5..545e9f64295aa2d82df7844f5d512811dd408c28 100644 (file)
@@ -26,6 +26,7 @@
 #include "../scan.h"
 #include "../autoscan.h"
 #include "../ap.h"
+#include "../interworking.h"
 #include "dbus_new_helpers.h"
 #include "dbus_new.h"
 #include "dbus_new_handlers.h"
@@ -1779,6 +1780,28 @@ DBusMessage * wpas_dbus_handler_remove_all_creds(DBusMessage *message,
 }
 
 
+DBusMessage *
+wpas_dbus_handler_interworking_select(DBusMessage *message,
+                                     struct wpa_supplicant *wpa_s)
+{
+       int result;
+       DBusMessage *reply = NULL;
+
+       /* Automatic selection is disabled and no constraint on channels */
+       result = interworking_select(wpa_s, 0, NULL);
+       if (result < 0) {
+               wpa_printf(MSG_ERROR,
+                          "%s[dbus]: failed to start Interworking selection",
+                          __func__);
+               reply = wpas_dbus_error_scan_error(
+                       message,
+                       "error starting Interworking selection.");
+       }
+
+       return reply;
+}
+
+
 /**
  * wpas_dbus_handler_signal_poll - Request immediate signal properties
  * @message: Pointer to incoming dbus message
index 1496f5535a862d434c2561f8aa048d89389d1c3e..a421083f7fe2334f95c169914a0eb74c7ad99762 100644 (file)
@@ -153,6 +153,10 @@ DBusMessage * wpas_dbus_handler_remove_cred(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_remove_all_creds(DBusMessage *message,
                                                 struct wpa_supplicant *wpa_s);
 
+DBusMessage *
+wpas_dbus_handler_interworking_select(DBusMessage *message,
+                                     struct wpa_supplicant *wpa_s);
+
 DECLARE_ACCESSOR(wpas_dbus_getter_capabilities);
 DECLARE_ACCESSOR(wpas_dbus_getter_state);
 DECLARE_ACCESSOR(wpas_dbus_getter_scanning);
index 5ae71ca1ca852ecdefeccae50d7ba9ed6a2c9da0..71a5c16510d44ff2a0c751c9e7295dbb3cc5d25a 100644 (file)
@@ -2502,13 +2502,9 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
                bh = cred_below_min_backhaul(wpa_s, cred, bss);
                bss_load = cred_over_max_bss_load(wpa_s, cred, bss);
                conn_capab = cred_conn_capab_missing(wpa_s, cred, bss);
-               wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d",
-                       excluded ? INTERWORKING_EXCLUDED : INTERWORKING_AP,
-                       MAC2STR(bss->bssid), type,
-                       bh ? " below_min_backhaul=1" : "",
-                       bss_load ? " over_max_bss_load=1" : "",
-                       conn_capab ? " conn_capab_missing=1" : "",
-                       cred->id, cred->priority, cred->sp_priority);
+               wpas_notify_interworking_ap_added(wpa_s, bss, cred, excluded,
+                                                 type, bh, bss_load,
+                                                 conn_capab);
                if (excluded)
                        continue;
                if (wpa_s->auto_select ||
@@ -2599,6 +2595,8 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
                        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
        }
 
+       wpas_notify_interworking_select_done(wpa_s);
+
        if (selected) {
                wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR,
                           MAC2STR(selected->bssid));
index fe5e072c24c284d7230bdd249f719fcbd0a05568..821c916c153f09bcaa8680196b7c65c74a105549 100644 (file)
@@ -19,6 +19,7 @@
 #include "rsn_supp/wpa.h"
 #include "fst/fst.h"
 #include "crypto/tls.h"
+#include "bss.h"
 #include "driver_i.h"
 #include "scan.h"
 #include "p2p_supplicant.h"
@@ -943,3 +944,32 @@ void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
 }
 
 #endif /* CONFIG_MESH */
+
+
+#ifdef CONFIG_INTERWORKING
+
+void wpas_notify_interworking_ap_added(struct wpa_supplicant *wpa_s,
+                                      struct wpa_bss *bss,
+                                      struct wpa_cred *cred, int excluded,
+                                      const char *type, int bh, int bss_load,
+                                      int conn_capab)
+{
+       wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d",
+               excluded ? INTERWORKING_EXCLUDED : INTERWORKING_AP,
+               MAC2STR(bss->bssid), type,
+               bh ? " below_min_backhaul=1" : "",
+               bss_load ? " over_max_bss_load=1" : "",
+               conn_capab ? " conn_capab_missing=1" : "",
+               cred->id, cred->priority, cred->sp_priority);
+
+       wpas_dbus_signal_interworking_ap_added(wpa_s, bss, cred, type, excluded,
+                                              bh, bss_load, conn_capab);
+}
+
+
+void wpas_notify_interworking_select_done(struct wpa_supplicant *wpa_s)
+{
+       wpas_dbus_signal_interworking_select_done(wpa_s);
+}
+
+#endif /* CONFIG_INTERWORKING */
index e843aa124b3945bbfe016ead29748f66579df25b..c46e7986e3b336e3b782c3840a28f5f39b8228b9 100644 (file)
@@ -15,6 +15,7 @@ struct wps_credential;
 struct wps_event_m2d;
 struct wps_event_fail;
 struct tls_cert_data;
+struct wpa_cred;
 
 int wpas_notify_supplicant_initialized(struct wpa_global *global);
 void wpas_notify_supplicant_deinitialized(struct wpa_global *global);
@@ -156,5 +157,11 @@ void wpas_notify_mesh_peer_connected(struct wpa_supplicant *wpa_s,
                                     const u8 *peer_addr);
 void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
                                        const u8 *peer_addr, u16 reason_code);
+void wpas_notify_interworking_ap_added(struct wpa_supplicant *wpa_s,
+                                      struct wpa_bss *bss,
+                                      struct wpa_cred *cred, int excluded,
+                                      const char *type, int bh, int bss_load,
+                                      int conn_capab);
+void wpas_notify_interworking_select_done(struct wpa_supplicant *wpa_s);
 
 #endif /* NOTIFY_H */