]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DBus: Add ANQP fields to BSS properties
authorDamien Dejean <damiendejean@chromium.org>
Mon, 26 Feb 2024 16:32:41 +0000 (16:32 +0000)
committerJouni Malinen <j@w1.fi>
Sat, 9 Mar 2024 15:59:22 +0000 (17:59 +0200)
Add ANQP fields to the BSS properties to allow DBus clients to be
notified and obtain the values when it changes.

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 61d67dca18bec809ca77c36df0cc46dc1b94ccc6..9f72614d42604a2fe989af9f3c3cbc932a718057 100644 (file)
@@ -2214,6 +2214,30 @@ scan results.
        <h3>Age - u - (read)</h3>
        <p>Number of seconds since the BSS was last seen.</p>
       </li>
+      <li>
+       <h3>ANQP - a{sv} - (read)</h3>
+       <p>ANQP information of the BSS. Empty dictionary indicates no ANQP field. Named dictionary entries are:</p>
+       <table>
+         <tr><td>CapabilityList</td><td>ay</td></tr>
+         <tr><td>VenueName</td><td>ay</td></tr>
+         <tr><td>NetworkAuthType</td><td>ay</td></tr>
+         <tr><td>RoamingConsortium</td><td>ay</td></tr>
+         <tr><td>IPAddrTypeAvailability</td><td>ay</td></tr>
+         <tr><td>NAIRealm</td><td>ay</td></tr>
+         <tr><td>3GPP</td><td>ay</td></tr>
+         <tr><td>DomainName</td><td>ay</td></tr>
+         <tr><td>FilsRealmInfo</td><td>ay</td></tr>
+         <tr><td>HS20CapabilityList</td><td>ay</td></tr>
+         <tr><td>HS20OperatorFriendlyName</td><td>ay</td></tr>
+         <tr><td>HS20WanMetrics</td><td>ay</td></tr>
+         <tr><td>HS20ConnectionCapability</td><td>ay</td></tr>
+         <tr><td>HS20OperatingClass</td><td>ay</td></tr>
+         <tr><td>HS20OSUProvidersList</td><td>ay</td></tr>
+         <tr><td>HS20OperatorIconMetadata</td><td>ay</td></tr>
+         <tr><td>HS20OSUProvidersNAIList</td><td>ay</td></tr>
+       </table>
+       <p>Unnamed ANQP elements have a generic entry name 'anqp[id]' where 'id' is the InfoID of the ANQP element as described in IEEE Std 802.11-2020, Table 9-331 (ANQP-element definitions).</p>
+      </li>
     </ul>
 
 \subsection dbus_bss_signals Signals
index 97baa8f2c668e0a9bd18a8bf0840b543597529a3..f5cfecbd65b4119d2a8965458fee6d8007e4303d 100644 (file)
@@ -6353,3 +6353,55 @@ def test_dbus_anqp_query_done(dev, apdev):
     with TestDbusANQPGet(bus) as t:
         if not t.success():
             raise Exception("Expected signals not seen")
+
+def test_dbus_bss_anqp_properties(dev, apdev):
+    """D-Bus ANQP BSS properties changed"""
+    (bus, wpa_obj, path, if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params(ssid="test-anqp")
+    params["hessid"] = bssid
+    params['mbo'] = '1'
+    params['mbo_cell_data_conn_pref'] = '1'
+    params['hs20_oper_friendly_name'] = ["eng:Example operator",
+                                         "fin:Esimerkkioperaattori"]
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    class TestDbusANQPBSSPropertiesChanged(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.capability_list = False
+            self.venue_name = False
+            self.roaming_consortium = False
+            self.nai_realm = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_query)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.propertiesChanged, WPAS_DBUS_BSS,
+                            "PropertiesChanged")
+            self.loop.run()
+            return self
+
+        def propertiesChanged(self, properties):
+            logger.debug("propertiesChanged: %s" % str(properties))
+            if 'ANQP' in properties:
+                anqp_properties = properties['ANQP']
+                self.capability_list = 'CapabilityList' in anqp_properties
+                self.venue_name = 'VenueName' in anqp_properties
+                self.roaming_consortium = 'RoamingConsortium' in anqp_properties
+                self.nai_realm = 'NAIRealm' in anqp_properties
+
+        def run_query(self, *args):
+            dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+            iface.ANQPGet({"addr": bssid,
+                           "ids": dbus.Array([257,258,261,263], dbus.Signature("q"))})
+            return False
+
+        def success(self):
+            return self.capability_list and self.venue_name and self.roaming_consortium and self.nai_realm
+
+    with TestDbusANQPBSSPropertiesChanged(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
index 7c5e42c47209ddabb0aae34da066d17f81241933..8bd6a9a43bbae2b749b10d776ea504a1a1d04a53 100644 (file)
@@ -2473,6 +2473,9 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
        case WPAS_DBUS_BSS_PROP_AGE:
                prop = "Age";
                break;
+       case WPAS_DBUS_BSS_PROP_ANQP:
+               prop = "ANQP";
+               break;
        default:
                wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
                           __func__, property);
@@ -3011,6 +3014,11 @@ static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
          NULL,
          NULL
        },
+       {"ANQP", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+         wpas_dbus_getter_bss_anqp,
+         NULL,
+         NULL,
+       },
        { NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
index 7148eaaad5661427694ff73a60bc1f6ce1243add..952bb422a6d618eadc1d5ac3673672e6cd12afc2 100644 (file)
@@ -53,6 +53,7 @@ enum wpas_dbus_bss_prop {
        WPAS_DBUS_BSS_PROP_WPS,
        WPAS_DBUS_BSS_PROP_IES,
        WPAS_DBUS_BSS_PROP_AGE,
+       WPAS_DBUS_BSS_PROP_ANQP,
 };
 
 enum wpas_dbus_sta_prop {
index 815a5a83aeefdc649e8f8769b5821edc840dd49e..3897d98f4e297f9802dce548b2d502268bbc6afc 100644 (file)
@@ -5757,6 +5757,177 @@ dbus_bool_t wpas_dbus_getter_bss_age(
 }
 
 
+/**
+ * wpas_dbus_getter_bss_anqp - Return all the ANQP fields of a BSS
+ * @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 for "ANQP" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_anqp(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+       DBusMessageIter iter_dict, variant_iter;
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *bss;
+       struct wpa_bss_anqp *anqp;
+       struct wpa_bss_anqp_elem *elem;
+
+       bss = get_bss_helper(args, error, __func__);
+       if (!bss)
+               return FALSE;
+
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             "a{sv}", &variant_iter) ||
+           !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+               goto nomem;
+
+       anqp = bss->anqp;
+       if (anqp) {
+#ifdef CONFIG_INTERWORKING
+               if (anqp->capability_list &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "CapabilityList",
+                           wpabuf_head(anqp->capability_list),
+                           wpabuf_len(anqp->capability_list)))
+                       goto nomem;
+               if (anqp->venue_name &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "VenueName",
+                           wpabuf_head(anqp->venue_name),
+                           wpabuf_len(anqp->venue_name)))
+                       goto nomem;
+               if (anqp->network_auth_type &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "NetworkAuthType",
+                           wpabuf_head(anqp->network_auth_type),
+                           wpabuf_len(anqp->network_auth_type)))
+                       goto nomem;
+               if (anqp->roaming_consortium &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "RoamingConsortium",
+                           wpabuf_head(anqp->roaming_consortium),
+                           wpabuf_len(anqp->roaming_consortium)))
+                       goto nomem;
+               if (anqp->ip_addr_type_availability &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "IPAddrTypeAvailability",
+                           wpabuf_head(anqp->ip_addr_type_availability),
+                           wpabuf_len(anqp->ip_addr_type_availability)))
+                       goto nomem;
+               if (anqp->nai_realm &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "NAIRealm",
+                           wpabuf_head(anqp->nai_realm),
+                           wpabuf_len(anqp->nai_realm)))
+                       goto nomem;
+               if (anqp->anqp_3gpp &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "3GPP",
+                           wpabuf_head(anqp->anqp_3gpp),
+                           wpabuf_len(anqp->anqp_3gpp)))
+                       goto nomem;
+               if (anqp->domain_name &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "DomainName",
+                           wpabuf_head(anqp->domain_name),
+                           wpabuf_len(anqp->domain_name)))
+                       goto nomem;
+               if (anqp->fils_realm_info &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "FilsRealmInfo",
+                           wpabuf_head(anqp->fils_realm_info),
+                           wpabuf_len(anqp->fils_realm_info)))
+                       goto nomem;
+
+#ifdef CONFIG_HS20
+               if (anqp->hs20_capability_list &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "HS20CapabilityList",
+                           wpabuf_head(anqp->hs20_capability_list),
+                           wpabuf_len(anqp->hs20_capability_list)))
+                       goto nomem;
+               if (anqp->hs20_operator_friendly_name &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "HS20OperatorFriendlyName",
+                           wpabuf_head(anqp->hs20_operator_friendly_name),
+                           wpabuf_len(anqp->hs20_operator_friendly_name)))
+                       goto nomem;
+               if (anqp->hs20_wan_metrics &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "HS20WanMetrics",
+                           wpabuf_head(anqp->hs20_wan_metrics),
+                           wpabuf_len(anqp->hs20_wan_metrics)))
+                       goto nomem;
+               if (anqp->hs20_connection_capability &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "HS20ConnectionCapability",
+                           wpabuf_head(anqp->hs20_connection_capability),
+                           wpabuf_len(anqp->hs20_connection_capability)))
+                       goto nomem;
+               if (anqp->hs20_operating_class &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "HS20OperatingClass",
+                           wpabuf_head(anqp->hs20_operating_class),
+                           wpabuf_len(anqp->hs20_operating_class)))
+                       goto nomem;
+               if (anqp->hs20_osu_providers_list &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "HS20OSUProvidersList",
+                           wpabuf_head(anqp->hs20_osu_providers_list),
+                           wpabuf_len(anqp->hs20_osu_providers_list)))
+                       goto nomem;
+               if (anqp->hs20_operator_icon_metadata &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "HS20OperatorIconMetadata",
+                           wpabuf_head(anqp->hs20_operator_icon_metadata),
+                           wpabuf_len(anqp->hs20_operator_icon_metadata)))
+                       goto nomem;
+               if (anqp->hs20_osu_providers_nai_list &&
+                   !wpa_dbus_dict_append_byte_array(
+                           &iter_dict, "HS20OSUProvidersNAIList",
+                           wpabuf_head(anqp->hs20_osu_providers_nai_list),
+                           wpabuf_len(anqp->hs20_osu_providers_nai_list)))
+                       goto nomem;
+#endif /* CONFIG_HS20 */
+
+               dl_list_for_each(elem, &anqp->anqp_elems,
+                                struct wpa_bss_anqp_elem, list) {
+                       char title[32];
+
+                       os_snprintf(title, sizeof(title), "anqp[%u]",
+                                   elem->infoid);
+                       if (!wpa_dbus_dict_append_byte_array(
+                                   &iter_dict, title,
+                                   wpabuf_head(elem->payload),
+                                   wpabuf_len(elem->payload)))
+                               goto nomem;
+
+                       os_snprintf(title, sizeof(title),
+                                   "protected-anqp-info[%u]", elem->infoid);
+                       if (!wpa_dbus_dict_append_bool(
+                                   &iter_dict, title,
+                                   elem->protected_response))
+                               goto nomem;
+               }
+#endif /* CONFIG_INTERWORKING */
+       }
+
+       if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+           !dbus_message_iter_close_container(iter, &variant_iter))
+               goto nomem;
+
+       return TRUE;
+
+nomem:
+       dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       return FALSE;
+}
+
+
 /**
  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
  * @iter: Pointer to incoming dbus message iter
index 48f9d3483e51425eb02a5340b44f483fbe469dd2..acd6af7ffa38b65b01d475d80f393d17510ac62c 100644 (file)
@@ -219,6 +219,7 @@ DECLARE_ACCESSOR(wpas_dbus_getter_bss_rsn);
 DECLARE_ACCESSOR(wpas_dbus_getter_bss_wps);
 DECLARE_ACCESSOR(wpas_dbus_getter_bss_ies);
 DECLARE_ACCESSOR(wpas_dbus_getter_bss_age);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_anqp);
 DECLARE_ACCESSOR(wpas_dbus_getter_enabled);
 DECLARE_ACCESSOR(wpas_dbus_setter_enabled);
 DECLARE_ACCESSOR(wpas_dbus_getter_network_properties);
index 06b4d111601c41e3f9f777ab3065dd61c048351e..a085d226071a848b519f8d2f4e1e6b286a3f1466 100644 (file)
@@ -3198,6 +3198,8 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
        }
 
 out_parse_done:
+       if (bss)
+               wpas_notify_bss_anqp_changed(wpa_s, bss->id);
 #ifdef CONFIG_HS20
        hs20_notify_parse_done(wpa_s);
 #endif /* CONFIG_HS20 */
index 57b1e5fc3c54f205b846b940c8a2212f606d499c..6d5dbcc298f2d62556176fa93117ed26872e19cb 100644 (file)
@@ -559,6 +559,15 @@ void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id)
 }
 
 
+void wpas_notify_bss_anqp_changed(struct wpa_supplicant *wpa_s, unsigned int id)
+{
+       if (wpa_s->p2p_mgmt)
+               return;
+
+       wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_ANQP, id);
+}
+
+
 void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name)
 {
        if (wpa_s->p2p_mgmt)
index 0c249a77ef3d8d6c1ca0f404dc1259244e398ae2..f6c7ac4e2d3b73ef4289159662cba44b5008433a 100644 (file)
@@ -83,6 +83,8 @@ void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
 void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
                                   unsigned int id);
 void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id);
+void wpas_notify_bss_anqp_changed(struct wpa_supplicant *wpa_s,
+                                 unsigned int id);
 void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name);
 void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name);