diff --git a/src/wifi/wifid-dbus.c b/src/wifi/wifid-dbus.c index 0c9eba1..c3fa983 100644 --- a/src/wifi/wifid-dbus.c +++ b/src/wifi/wifid-dbus.c @@ -238,6 +238,24 @@ static int peer_dbus_get_remote_address(sd_bus *bus, return 1; } +static int peer_dbus_get_wfd_subelements(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *data, + sd_bus_error *err) +{ + struct peer *p = data; + int r; + + r = sd_bus_message_append(reply, "s", peer_get_wfd_subelements(p)); + if (r < 0) + return r; + + return 1; +} + static const sd_bus_vtable peer_dbus_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_METHOD("Connect", @@ -285,6 +303,11 @@ static const sd_bus_vtable peer_dbus_vtable[] = { peer_dbus_get_remote_address, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("WfdSubelements", + "s", + peer_dbus_get_wfd_subelements, + 0, + SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_SIGNAL("ProvisionDiscovery", "ss", 0), SD_BUS_VTABLE_END }; @@ -545,6 +568,43 @@ static int link_dbus_set_p2p_scanning(sd_bus *bus, return link_set_p2p_scanning(l, val); } +static int link_dbus_get_wfd_subelements(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *data, + sd_bus_error *err) +{ + struct link *l = data; + int r; + + r = sd_bus_message_append(reply, "s", link_get_wfd_subelements(l)); + if (r < 0) + return r; + + return 1; +} + +static int link_dbus_set_wfd_subelements(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *value, + void *data, + sd_bus_error *err) +{ + struct link *l = data; + const char *val; + int r; + + r = sd_bus_message_read(value, "s", &val); + if (r < 0) + return r; + + return link_set_wfd_subelements(l, val); +} + static const sd_bus_vtable link_dbus_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("InterfaceIndex", @@ -569,6 +629,12 @@ static const sd_bus_vtable link_dbus_vtable[] = { link_dbus_set_p2p_scanning, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_WRITABLE_PROPERTY("WfdSubelements", + "s", + link_dbus_get_wfd_subelements, + link_dbus_set_wfd_subelements, + 0, + SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_VTABLE_END }; diff --git a/src/wifi/wifid-link.c b/src/wifi/wifid-link.c index 139195a..ff9eb62 100644 --- a/src/wifi/wifid-link.c +++ b/src/wifi/wifid-link.c @@ -126,6 +126,7 @@ void link_free(struct link *l) /* link_set_managed(l, false) already removed all peers */ shl_htable_clear_str(&l->peers, NULL, NULL); + free(l->wfd_subelements); free(l->friendly_name); free(l->ifname); free(l); @@ -215,6 +216,41 @@ const char *link_get_friendly_name(struct link *l) return l->friendly_name; } +int link_set_wfd_subelements(struct link *l, const char *val) +{ + char *t; + int r; + + if (!l || !val) + return log_EINVAL(); + + t = strdup(val); + if (!t) + return log_ENOMEM(); + + if (supplicant_is_ready(l->s)) { + r = supplicant_set_wfd_subelements(l->s, val); + if (r < 0) { + free(t); + return r; + } + } + + free(l->wfd_subelements); + l->wfd_subelements = t; + link_dbus_properties_changed(l, "WfdSubelements", NULL); + + return 0; +} + +const char *link_get_wfd_subelements(struct link *l) +{ + if (!l) + return NULL; + + return l->wfd_subelements; +} + int link_set_p2p_scanning(struct link *l, bool set) { if (!l) diff --git a/src/wifi/wifid-peer.c b/src/wifi/wifid-peer.c index 6022ca9..12101bf 100644 --- a/src/wifi/wifid-peer.c +++ b/src/wifi/wifid-peer.c @@ -130,6 +130,14 @@ const char *peer_get_remote_address(struct peer *p) return supplicant_peer_get_remote_address(p->sp); } +const char *peer_get_wfd_subelements(struct peer *p) +{ + if (!p) + return NULL; + + return supplicant_peer_get_wfd_subelements(p->sp); +} + int peer_connect(struct peer *p, const char *prov, const char *pin) { if (!p) @@ -174,6 +182,14 @@ void peer_supplicant_friendly_name_changed(struct peer *p) peer_dbus_properties_changed(p, "FriendlyName", NULL); } +void peer_supplicant_wfd_subelements_changed(struct peer *p) +{ + if (!p || !p->public) + return; + + peer_dbus_properties_changed(p, "WfdSubelements", NULL); +} + void peer_supplicant_provision_discovery(struct peer *p, const char *prov, const char *pin) diff --git a/src/wifi/wifid-supplicant.c b/src/wifi/wifid-supplicant.c index 1c2e992..8b7fb30 100644 --- a/src/wifi/wifid-supplicant.c +++ b/src/wifi/wifid-supplicant.c @@ -60,6 +60,7 @@ struct supplicant_peer { char *friendly_name; char *remote_addr; + char *wfd_subelements; char *prov; char *pin; char *sta_mac; @@ -647,6 +648,7 @@ static void supplicant_peer_free(struct supplicant_peer *sp) free(sp->pin); free(sp->prov); free(sp->friendly_name); + free(sp->wfd_subelements); free(sp); } @@ -682,6 +684,14 @@ const char *supplicant_peer_get_remote_address(struct supplicant_peer *sp) return sp->remote_addr; } +const char *supplicant_peer_get_wfd_subelements(struct supplicant_peer *sp) +{ + if (!sp) + return NULL; + + return sp->wfd_subelements; +} + int supplicant_peer_connect(struct supplicant_peer *sp, const char *prov_type, const char *pin) @@ -779,7 +789,7 @@ static void supplicant_parse_peer(struct supplicant *s, struct wpas_message *m) { struct supplicant_peer *sp; - const char *mac, *name; + const char *mac, *name, *val; char *t; int r; @@ -812,6 +822,18 @@ static void supplicant_parse_peer(struct supplicant *s, wpas_message_get_raw(m)); } + r = wpas_message_dict_read(m, "wfd_subelems", 's', &val); + if (r >= 0) { + t = strdup(val); + if (!t) { + log_vENOMEM(); + } else { + free(sp->wfd_subelements); + sp->wfd_subelements = t; + peer_supplicant_wfd_subelements_changed(sp->p); + } + } + if (s->running) peer_supplicant_started(sp->p); } @@ -1454,7 +1476,9 @@ static int supplicant_set_wifi_display_fn(struct wpas *w, struct wpas_message *reply, void *data) { + _wpas_message_unref_ struct wpas_message *m = NULL; struct supplicant *s = data; + int r; /* SET received */ --s->setup_cnt; @@ -1464,8 +1488,49 @@ static int supplicant_set_wifi_display_fn(struct wpas *w, s->has_wfd = false; } + if (s->has_wfd) { + /* update subelements */ + + r = wpas_message_new_request(s->bus_global, + "WFD_SUBELEM_SET", + &m); + if (r < 0) { + log_vERR(r); + goto error; + } + + r = wpas_message_append(m, "s", "0"); + if (r < 0) { + log_vERR(r); + goto error; + } + + if (!shl_isempty(s->l->wfd_subelements)) { + r = wpas_message_append(m, "s", s->l->wfd_subelements); + if (r < 0) { + log_vERR(r); + goto error; + } + } + + r = wpas_call_async(s->bus_global, + m, + NULL, + NULL, + 0, + NULL); + if (r < 0) { + log_vERR(r); + goto error; + } + } + supplicant_try_ready(s); return 0; + +error: + supplicant_failed(s); + return 0; } static int supplicant_status_fn(struct wpas *w, @@ -1718,7 +1783,7 @@ int supplicant_set_friendly_name(struct supplicant *s, const char *name) int r; if (!s->running || !name || !*name) - return log_EINVAL();; + return log_EINVAL(); r = wpas_message_new_request(s->bus_global, "SET", @@ -1745,6 +1810,45 @@ int supplicant_set_friendly_name(struct supplicant *s, const char *name) return 0; } +int supplicant_set_wfd_subelements(struct supplicant *s, const char *val) +{ + _wpas_message_unref_ struct wpas_message *m = NULL; + int r; + + if (!s->running || !val) + return log_EINVAL(); + + r = wpas_message_new_request(s->bus_global, + "WFD_SUBELEM_SET", + &m); + if (r < 0) + return log_ERR(r); + + r = wpas_message_append(m, "s", "0"); + if (r < 0) + return log_ERR(r); + + if (!shl_isempty(val)) { + r = wpas_message_append(m, "s", val); + if (r < 0) + return log_ERR(r); + } + + r = wpas_call_async(s->bus_global, + m, + NULL, + NULL, + 0, + NULL); + if (r < 0) + return log_ERR(r); + + log_debug("send 'WFD_SUBELEM_SET 0 %s' to wpas on %s", + val, s->l->ifname); + + return 0; +} + int supplicant_p2p_start_scan(struct supplicant *s) { _wpas_message_unref_ struct wpas_message *m = NULL; diff --git a/src/wifi/wifid.h b/src/wifi/wifid.h index 0f3e661..8867cc8 100644 --- a/src/wifi/wifid.h +++ b/src/wifi/wifid.h @@ -57,6 +57,7 @@ const char *supplicant_peer_get_friendly_name(struct supplicant_peer *sp); const char *supplicant_peer_get_interface(struct supplicant_peer *sp); const char *supplicant_peer_get_local_address(struct supplicant_peer *sp); const char *supplicant_peer_get_remote_address(struct supplicant_peer *sp); +const char *supplicant_peer_get_wfd_subelements(struct supplicant_peer *sp); int supplicant_peer_connect(struct supplicant_peer *sp, const char *prov_type, const char *pin); @@ -85,6 +86,7 @@ const char *peer_get_friendly_name(struct peer *p); const char *peer_get_interface(struct peer *p); const char *peer_get_local_address(struct peer *p); const char *peer_get_remote_address(struct peer *p); +const char *peer_get_wfd_subelements(struct peer *p); int peer_connect(struct peer *p, const char *prov, const char *pin); void peer_disconnect(struct peer *p); @@ -94,6 +96,7 @@ void peer_reject(struct peer *p); void peer_supplicant_started(struct peer *p); void peer_supplicant_stopped(struct peer *p); void peer_supplicant_friendly_name_changed(struct peer *p); +void peer_supplicant_wfd_subelements_changed(struct peer *p); void peer_supplicant_provision_discovery(struct peer *p, const char *prov, const char *pin); @@ -116,6 +119,7 @@ struct link { char *ifname; char *friendly_name; + char *wfd_subelements; size_t peer_cnt; struct shl_htable peers; @@ -145,6 +149,8 @@ int link_renamed(struct link *l, const char *ifname); int link_set_friendly_name(struct link *l, const char *name); const char *link_get_friendly_name(struct link *l); +int link_set_wfd_subelements(struct link *l, const char *val); +const char *link_get_wfd_subelements(struct link *l); int link_set_p2p_scanning(struct link *l, bool set); bool link_get_p2p_scanning(struct link *l);