mirror of
https://github.com/albfan/miraclecast.git
synced 2025-03-09 23:38:56 +00:00
978 lines
19 KiB
C
978 lines
19 KiB
C
/*
|
|
* MiracleCast - Wifi-Display/Miracast Implementation
|
|
*
|
|
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
|
*
|
|
* MiracleCast is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2.1 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* MiracleCast is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with MiracleCast; If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#define LOG_SUBSYSTEM "dbus"
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <systemd/sd-bus.h>
|
|
#include <systemd/sd-event.h>
|
|
#include "shl_log.h"
|
|
#include "shl_util.h"
|
|
#include "util.h"
|
|
#include "wifid.h"
|
|
|
|
static char *peer_dbus_get_path(struct peer *p)
|
|
{
|
|
char buf[128], *node;
|
|
int r;
|
|
|
|
sprintf(buf, "%s@%u", p->p2p_mac, p->l->ifindex);
|
|
|
|
r = sd_bus_path_encode("/org/freedesktop/miracle/wifi/peer",
|
|
buf,
|
|
&node);
|
|
if (r < 0) {
|
|
log_vERR(r);
|
|
return NULL;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
static char *link_dbus_get_path(struct link *l)
|
|
{
|
|
char buf[128], *node;
|
|
int r;
|
|
|
|
sprintf(buf, "%u", l->ifindex);
|
|
|
|
r = sd_bus_path_encode("/org/freedesktop/miracle/wifi/link",
|
|
buf,
|
|
&node);
|
|
if (r < 0) {
|
|
log_vERR(r);
|
|
return NULL;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/*
|
|
* Peer DBus
|
|
*/
|
|
|
|
static int peer_dbus_connect(sd_bus_message *msg,
|
|
void *data, sd_bus_error *err)
|
|
{
|
|
struct peer *p = data;
|
|
const char *prov, *pin;
|
|
int r;
|
|
|
|
r = sd_bus_message_read(msg, "ss", &prov, &pin);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
if (!*prov || !strcmp(prov, "auto"))
|
|
prov = NULL;
|
|
if (!*pin)
|
|
pin = NULL;
|
|
|
|
r = peer_connect(p, prov, pin);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return sd_bus_reply_method_return(msg, NULL);
|
|
}
|
|
|
|
static int peer_dbus_disconnect(sd_bus_message *msg,
|
|
void *data, sd_bus_error *err)
|
|
{
|
|
struct peer *p = data;
|
|
|
|
peer_disconnect(p);
|
|
return sd_bus_reply_method_return(msg, NULL);
|
|
}
|
|
|
|
static int peer_dbus_get_link(sd_bus *bus,
|
|
const char *path,
|
|
const char *interface,
|
|
const char *property,
|
|
sd_bus_message *reply,
|
|
void *data,
|
|
sd_bus_error *err)
|
|
{
|
|
_shl_free_ char *node = NULL;
|
|
struct peer *p = data;
|
|
int r;
|
|
|
|
node = link_dbus_get_path(p->l);
|
|
if (!node)
|
|
return -ENOMEM;
|
|
|
|
r = sd_bus_message_append_basic(reply, 'o', node);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int peer_dbus_get_p2p_mac(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_basic(reply, 's', p->p2p_mac);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int peer_dbus_get_friendly_name(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;
|
|
const char *name;
|
|
int r;
|
|
|
|
name = peer_get_friendly_name(p);
|
|
if (!name)
|
|
name = "<unknown>";
|
|
|
|
r = sd_bus_message_append_basic(reply, 's', name);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int peer_dbus_get_connected(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, "b", p->connected);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int peer_dbus_get_interface(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_interface(p));
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int peer_dbus_get_local_address(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_local_address(p));
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int peer_dbus_get_remote_address(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_remote_address(p));
|
|
if (r < 0)
|
|
return r;
|
|
|
|
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",
|
|
"ss",
|
|
NULL,
|
|
peer_dbus_connect,
|
|
0),
|
|
SD_BUS_METHOD("Disconnect",
|
|
NULL,
|
|
NULL,
|
|
peer_dbus_disconnect,
|
|
0),
|
|
SD_BUS_PROPERTY("Link",
|
|
"o",
|
|
peer_dbus_get_link,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_CONST),
|
|
SD_BUS_PROPERTY("P2PMac",
|
|
"s",
|
|
peer_dbus_get_p2p_mac,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_CONST),
|
|
SD_BUS_PROPERTY("FriendlyName",
|
|
"s",
|
|
peer_dbus_get_friendly_name,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
SD_BUS_PROPERTY("Connected",
|
|
"b",
|
|
peer_dbus_get_connected,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
SD_BUS_PROPERTY("Interface",
|
|
"s",
|
|
peer_dbus_get_interface,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
SD_BUS_PROPERTY("LocalAddress",
|
|
"s",
|
|
peer_dbus_get_local_address,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
SD_BUS_PROPERTY("RemoteAddress",
|
|
"s",
|
|
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_SIGNAL("GoNegRequest", "ss", 0),
|
|
SD_BUS_VTABLE_END
|
|
};
|
|
|
|
static int peer_dbus_find(sd_bus *bus,
|
|
const char *path,
|
|
const char *interface,
|
|
void *data,
|
|
void **found,
|
|
sd_bus_error *err)
|
|
{
|
|
_shl_free_ char *label = NULL;
|
|
struct manager *m = data;
|
|
struct link *l;
|
|
struct peer *p;
|
|
char *sep;
|
|
int r;
|
|
|
|
r = sd_bus_path_decode(path,
|
|
"/org/freedesktop/miracle/wifi/peer",
|
|
&label);
|
|
if (r <= 0)
|
|
return r;
|
|
|
|
sep = strchr(label, '@');
|
|
if (sep) {
|
|
*sep = 0;
|
|
l = manager_find_link_by_label(m, sep + 1);
|
|
if (!l || !l->public)
|
|
return 0;
|
|
|
|
p = link_find_peer_by_label(l, label);
|
|
if (!p || !p->public)
|
|
return 0;
|
|
} else {
|
|
p = NULL;
|
|
|
|
MANAGER_FOREACH_LINK(l, m) {
|
|
if (!l->public)
|
|
continue;
|
|
|
|
p = link_find_peer_by_label(l, label);
|
|
if (p)
|
|
break;
|
|
}
|
|
|
|
if (!p || !p->public)
|
|
return 0;
|
|
}
|
|
|
|
*found = p;
|
|
return 1;
|
|
}
|
|
|
|
void peer_dbus_properties_changed(struct peer *p, const char *prop, ...)
|
|
{
|
|
_shl_free_ char *node = NULL;
|
|
char **strv;
|
|
int r;
|
|
|
|
if (!p->public)
|
|
return;
|
|
|
|
node = peer_dbus_get_path(p);
|
|
if (!node)
|
|
return;
|
|
|
|
strv = strv_from_stdarg_alloca(prop);
|
|
r = sd_bus_emit_properties_changed_strv(p->l->m->bus,
|
|
node,
|
|
"org.freedesktop.miracle.wifi.Peer",
|
|
strv);
|
|
if (r < 0)
|
|
log_vERR(r);
|
|
}
|
|
|
|
void peer_dbus_provision_discovery(struct peer *p,
|
|
const char *type,
|
|
const char *pin)
|
|
{
|
|
_shl_free_ char *node = NULL;
|
|
int r;
|
|
|
|
if (!type)
|
|
return;
|
|
if (!pin)
|
|
pin = "";
|
|
|
|
node = peer_dbus_get_path(p);
|
|
if (!node)
|
|
return;
|
|
|
|
r = sd_bus_emit_signal(p->l->m->bus,
|
|
node,
|
|
"org.freedesktop.miracle.wifi.Peer",
|
|
"ProvisionDiscovery",
|
|
"ss", type, pin);
|
|
if (r < 0)
|
|
log_vERR(r);
|
|
}
|
|
|
|
void peer_dbus_go_neg_request(struct peer *p,
|
|
const char *type,
|
|
const char *pin)
|
|
{
|
|
_shl_free_ char *node = NULL;
|
|
int r;
|
|
|
|
if (!type)
|
|
return;
|
|
if (!pin)
|
|
pin = "";
|
|
|
|
node = peer_dbus_get_path(p);
|
|
if (!node)
|
|
return;
|
|
|
|
r = sd_bus_emit_signal(p->l->m->bus,
|
|
node,
|
|
"org.freedesktop.miracle.wifi.Peer",
|
|
"GoNegRequest",
|
|
"ss", type, pin);
|
|
if (r < 0)
|
|
log_vERR(r);
|
|
}
|
|
|
|
void peer_dbus_formation_failure(struct peer *p, const char *reason)
|
|
{
|
|
_shl_free_ char *node = NULL;
|
|
int r;
|
|
|
|
node = peer_dbus_get_path(p);
|
|
if (!node)
|
|
return;
|
|
|
|
r = sd_bus_emit_signal(p->l->m->bus,
|
|
node,
|
|
"org.freedesktop.miracle.wifi.Peer",
|
|
"FormationFailure",
|
|
"s", reason);
|
|
if (r < 0)
|
|
log_vERR(r);
|
|
}
|
|
|
|
void peer_dbus_added(struct peer *p)
|
|
{
|
|
_shl_free_ char *node = NULL;
|
|
int r;
|
|
|
|
node = peer_dbus_get_path(p);
|
|
if (!node)
|
|
return;
|
|
|
|
r = sd_bus_emit_interfaces_added(p->l->m->bus,
|
|
node,
|
|
"org.freedesktop.miracle.wifi.Peer",
|
|
NULL);
|
|
if (r < 0)
|
|
log_vERR(r);
|
|
}
|
|
|
|
void peer_dbus_removed(struct peer *p)
|
|
{
|
|
_shl_free_ char *node = NULL;
|
|
int r;
|
|
|
|
node = peer_dbus_get_path(p);
|
|
if (!node)
|
|
return;
|
|
|
|
r = sd_bus_emit_interfaces_removed(p->l->m->bus,
|
|
node,
|
|
/*
|
|
"org.freedesktop.DBus.Properties",
|
|
"org.freedesktop.DBus.Introspectable",
|
|
*/
|
|
"org.freedesktop.miracle.wifi.Peer",
|
|
NULL);
|
|
if (r < 0)
|
|
log_vERR(r);
|
|
}
|
|
|
|
/*
|
|
* Link DBus
|
|
*/
|
|
|
|
static int link_dbus_get_interface_index(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_basic(reply, 'u', &l->ifindex);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int link_dbus_get_mac_addr(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_basic(reply, 's', l->mac_addr);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int link_dbus_get_interface_name(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_basic(reply, 's', l->ifname);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int link_dbus_get_friendly_name(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_friendly_name(l));
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int link_dbus_set_friendly_name(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 *name;
|
|
int r;
|
|
|
|
r = sd_bus_message_read(value, "s", &name);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
if (!name || !*name)
|
|
return -EINVAL;
|
|
|
|
return link_set_friendly_name(l, name);
|
|
}
|
|
|
|
static int link_dbus_get_managed(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, "b", link_get_managed(l));
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int link_dbus_set_managed(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;
|
|
int val, r;
|
|
|
|
r = sd_bus_message_read(value, "b", &val);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return link_set_managed(l, val);
|
|
}
|
|
|
|
static int link_dbus_get_p2p_scanning(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, "b", link_get_p2p_scanning(l));
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int link_dbus_set_p2p_scanning(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;
|
|
int val, r;
|
|
|
|
r = sd_bus_message_read(value, "b", &val);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
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",
|
|
"u",
|
|
link_dbus_get_interface_index,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_CONST),
|
|
SD_BUS_PROPERTY("MACAddress",
|
|
"s",
|
|
link_dbus_get_mac_addr,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_CONST),
|
|
SD_BUS_PROPERTY("InterfaceName",
|
|
"s",
|
|
link_dbus_get_interface_name,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
SD_BUS_WRITABLE_PROPERTY("FriendlyName",
|
|
"s",
|
|
link_dbus_get_friendly_name,
|
|
link_dbus_set_friendly_name,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
SD_BUS_WRITABLE_PROPERTY("Managed",
|
|
"b",
|
|
link_dbus_get_managed,
|
|
link_dbus_set_managed,
|
|
0,
|
|
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
SD_BUS_WRITABLE_PROPERTY("P2PScanning",
|
|
"b",
|
|
link_dbus_get_p2p_scanning,
|
|
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
|
|
};
|
|
|
|
static int link_dbus_find(sd_bus *bus,
|
|
const char *path,
|
|
const char *interface,
|
|
void *data,
|
|
void **found,
|
|
sd_bus_error *err)
|
|
{
|
|
_shl_free_ char *label = NULL;
|
|
struct manager *m = data;
|
|
struct link *l;
|
|
int r;
|
|
|
|
r = sd_bus_path_decode(path,
|
|
"/org/freedesktop/miracle/wifi/link",
|
|
&label);
|
|
if (r <= 0)
|
|
return r;
|
|
|
|
l = manager_find_link_by_label(m, label);
|
|
if (!l || !l->public)
|
|
return 0;
|
|
|
|
*found = l;
|
|
return 1;
|
|
}
|
|
|
|
void link_dbus_properties_changed(struct link *l, const char *prop, ...)
|
|
{
|
|
_shl_free_ char *node = NULL;
|
|
char **strv;
|
|
int r;
|
|
|
|
if (!l->public)
|
|
return;
|
|
|
|
node = link_dbus_get_path(l);
|
|
if (!node)
|
|
return;
|
|
|
|
strv = strv_from_stdarg_alloca(prop);
|
|
r = sd_bus_emit_properties_changed_strv(l->m->bus,
|
|
node,
|
|
"org.freedesktop.miracle.wifi.Link",
|
|
strv);
|
|
if (r < 0)
|
|
log_vERR(r);
|
|
}
|
|
|
|
void link_dbus_added(struct link *l)
|
|
{
|
|
_shl_free_ char *node = NULL;
|
|
int r;
|
|
|
|
node = link_dbus_get_path(l);
|
|
if (!node)
|
|
return;
|
|
|
|
r = sd_bus_emit_interfaces_added(l->m->bus,
|
|
node,
|
|
/*
|
|
"org.freedesktop.DBus.Properties",
|
|
"org.freedesktop.DBus.Introspectable",
|
|
*/
|
|
"org.freedesktop.miracle.wifi.Link",
|
|
NULL);
|
|
if (r < 0)
|
|
log_vERR(r);
|
|
}
|
|
|
|
void link_dbus_removed(struct link *l)
|
|
{
|
|
_shl_free_ char *node = NULL;
|
|
int r;
|
|
|
|
node = link_dbus_get_path(l);
|
|
if (!node)
|
|
return;
|
|
|
|
r = sd_bus_emit_interfaces_removed(l->m->bus,
|
|
node,
|
|
/*
|
|
"org.freedesktop.DBus.Properties",
|
|
"org.freedesktop.DBus.Introspectable",
|
|
*/
|
|
"org.freedesktop.miracle.wifi.Link",
|
|
NULL);
|
|
if (r < 0)
|
|
log_vERR(r);
|
|
}
|
|
|
|
/*
|
|
* Manager DBus
|
|
*/
|
|
|
|
static const sd_bus_vtable manager_dbus_vtable[] = {
|
|
SD_BUS_VTABLE_START(0),
|
|
SD_BUS_VTABLE_END
|
|
};
|
|
|
|
static int manager_dbus_enumerate(sd_bus *bus,
|
|
const char *path,
|
|
void *data,
|
|
char ***out,
|
|
sd_bus_error *err)
|
|
{
|
|
struct manager *m = data;
|
|
struct link *l;
|
|
struct peer *p;
|
|
size_t i, peer_cnt;
|
|
char **nodes, *node;
|
|
|
|
if(strcmp("/org/freedesktop/miracle/wifi", path)) {
|
|
return 0;
|
|
}
|
|
|
|
peer_cnt = 0;
|
|
MANAGER_FOREACH_LINK(l, m)
|
|
if (l->public)
|
|
peer_cnt += l->peer_cnt;
|
|
|
|
nodes = malloc(sizeof(*nodes) * (m->link_cnt + peer_cnt + 1));
|
|
if (!nodes)
|
|
return log_ENOMEM();
|
|
|
|
i = 0;
|
|
MANAGER_FOREACH_LINK(l, m) {
|
|
if (i >= m->link_cnt + peer_cnt) {
|
|
log_warning("overflow: skipping link %s",
|
|
l->ifname);
|
|
continue;
|
|
}
|
|
|
|
if (!l->public)
|
|
continue;
|
|
|
|
node = link_dbus_get_path(l);
|
|
if (!node)
|
|
goto error;
|
|
|
|
nodes[i++] = node;
|
|
|
|
LINK_FOREACH_PEER(p, l) {
|
|
if (i >= m->link_cnt + peer_cnt) {
|
|
log_warning("overflow: skipping peer %s",
|
|
p->p2p_mac);
|
|
continue;
|
|
}
|
|
|
|
if (!p->public)
|
|
continue;
|
|
|
|
node = peer_dbus_get_path(p);
|
|
if (!node)
|
|
goto error;
|
|
|
|
nodes[i++] = node;
|
|
}
|
|
}
|
|
|
|
nodes[i] = NULL;
|
|
*out = nodes;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
while (i--)
|
|
free(nodes[i]);
|
|
free(nodes);
|
|
return log_ENOMEM();
|
|
}
|
|
|
|
int manager_dbus_connect(struct manager *m)
|
|
{
|
|
int r;
|
|
|
|
r = sd_bus_add_object_vtable(m->bus, NULL,
|
|
"/org/freedesktop/miracle/wifi",
|
|
"org.freedesktop.miracle.wifi.Manager",
|
|
manager_dbus_vtable,
|
|
m);
|
|
if (r < 0)
|
|
goto error;
|
|
|
|
r = sd_bus_add_node_enumerator(m->bus, NULL,
|
|
"/org/freedesktop/miracle/wifi",
|
|
manager_dbus_enumerate,
|
|
m);
|
|
if (r < 0)
|
|
goto error;
|
|
|
|
r = sd_bus_add_fallback_vtable(m->bus, NULL,
|
|
"/org/freedesktop/miracle/wifi/link",
|
|
"org.freedesktop.miracle.wifi.Link",
|
|
link_dbus_vtable,
|
|
link_dbus_find,
|
|
m);
|
|
if (r < 0)
|
|
goto error;
|
|
|
|
r = sd_bus_add_fallback_vtable(m->bus, NULL,
|
|
"/org/freedesktop/miracle/wifi/peer",
|
|
"org.freedesktop.miracle.wifi.Peer",
|
|
peer_dbus_vtable,
|
|
peer_dbus_find,
|
|
m);
|
|
if (r < 0)
|
|
goto error;
|
|
|
|
r = sd_bus_add_object_manager(m->bus, NULL, "/org/freedesktop/miracle/wifi");
|
|
if (r < 0)
|
|
goto error;
|
|
|
|
r = sd_bus_request_name(m->bus, "org.freedesktop.miracle.wifi", 0);
|
|
if (r < 0) {
|
|
log_error("cannot claim org.freedesktop.miracle.wifi bus-name: %d",
|
|
r);
|
|
goto error_silent;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error:
|
|
log_vERR(r);
|
|
error_silent:
|
|
manager_dbus_disconnect(m);
|
|
return r;
|
|
}
|
|
|
|
void manager_dbus_disconnect(struct manager *m)
|
|
{
|
|
if (!m || !m->bus)
|
|
return;
|
|
|
|
sd_bus_release_name(m->bus, "org.freedesktop.miracle.wifi");
|
|
}
|