1
0
Fork 0
mirror of https://github.com/albfan/miraclecast.git synced 2025-02-12 16:11:54 +00:00

Add new miracle-wifid daemon

The miracle-wifid daemon is a rewrite of the wifi-related parts of
miracled. Unlike miracled, we no longer integrate the wifi-part directly
into the core daemon. This way, we can easily replace the wifi-bridge with
other network managers once they gain P2P capabilities.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
This commit is contained in:
David Herrmann 2014-03-19 13:08:25 +01:00
parent b0b53f986c
commit 18a5094bc0
9 changed files with 4512 additions and 0 deletions

1
.gitignore vendored
View file

@ -22,6 +22,7 @@ configure
libtool
m4/
miracle-dhcp
miracle-wifid
miraclectl
miracled
stamp-h1

View file

@ -86,6 +86,27 @@ libmiracle_shared_la_CPPFLAGS = $(AM_CPPFLAGS)
libmiracle_shared_la_LDFLAGS = $(AM_LDFLAGS)
libmiracle_shared_la_LIBADD = $(AM_LIBADD)
#
# miracle-wifid
#
bin_PROGRAMS += miracle-wifid
miracle_wifid_SOURCES = \
src/wifi/wifid.h \
src/wifi/wifid.c \
src/wifi/wifid-dbus.c \
src/wifi/wifid-link.c \
src/wifi/wifid-peer.c \
src/wifi/wifid-supplicant.c
miracle_wifid_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(DEPS_CFLAGS)
miracle_wifid_LDADD = \
libmiracle-shared.la \
$(DEPS_LIBS)
miracle_wifid_LDFLAGS = $(AM_LDFLAGS)
#
# miraclectl
#

View file

@ -10,31 +10,48 @@
<policy user="root">
<allow own="org.freedesktop.miracle"/>
<allow own="org.freedesktop.miracle.wifi"/>
<allow send_destination="org.freedesktop.miracle"/>
<allow send_destination="org.freedesktop.miracle.wifi"/>
<allow receive_sender="org.freedesktop.miracle"/>
<allow receive_sender="org.freedesktop.miracle.wifi"/>
</policy>
<policy context="default">
<deny send_destination="org.freedesktop.miracle"/>
<deny send_destination="org.freedesktop.miracle.wifi"/>
<allow send_destination="org.freedesktop.miracle"
send_interface="org.freedesktop.DBus.Introspectable"/>
<allow send_destination="org.freedesktop.miracle.wifi"
send_interface="org.freedesktop.DBus.Introspectable"/>
<allow send_destination="org.freedesktop.miracle"
send_interface="org.freedesktop.DBus.Peer"/>
<allow send_destination="org.freedesktop.miracle.wifi"
send_interface="org.freedesktop.DBus.Peer"/>
<allow send_destination="org.freedesktop.miracle"
send_interface="org.freedesktop.DBus.ObjectManager"/>
<allow send_destination="org.freedesktop.miracle.wifi"
send_interface="org.freedesktop.DBus.ObjectManager"/>
<allow send_destination="org.freedesktop.miracle"
send_interface="org.freedesktop.DBus.Properties"
send_member="Get"/>
<allow send_destination="org.freedesktop.miracle.wifi"
send_interface="org.freedesktop.DBus.Properties"
send_member="Get"/>
<allow send_destination="org.freedesktop.miracle"
send_interface="org.freedesktop.DBus.Properties"
send_member="GetAll"/>
<allow send_destination="org.freedesktop.miracle.wifi"
send_interface="org.freedesktop.DBus.Properties"
send_member="GetAll"/>
<allow receive_sender="org.freedesktop.miracle"/>
<allow receive_sender="org.freedesktop.miracle.wifi"/>
</policy>
</busconfig>

835
src/wifi/wifid-dbus.c Normal file
View file

@ -0,0 +1,835 @@
/*
* 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 <stdbool.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 *bus, 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 *bus, 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 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_SIGNAL("ProvisionDiscovery", "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_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.DBus.Properties",
"org.freedesktop.DBus.Introspectable",
*/
"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_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_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;
bool val;
int r;
r = sd_bus_message_read(value, "b", &val);
if (r < 0)
return r;
return link_set_p2p_scanning(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("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("P2PScanning",
"b",
link_dbus_get_p2p_scanning,
link_dbus_set_p2p_scanning,
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;
int r;
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 + 2));
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;
}
}
node = strdup("/org/freedesktop/miracle/wifi");
if (!node) {
r = log_ENOMEM();
goto error;
}
nodes[i++] = node;
nodes[i] = NULL;
*out = nodes;
return 0;
error:
while (i--)
free(nodes[i]);
free(nodes);
return r;
}
int manager_dbus_connect(struct manager *m)
{
int r;
r = sd_bus_add_object_vtable(m->bus,
"/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,
"/org/freedesktop/miracle/wifi",
manager_dbus_enumerate,
m);
if (r < 0)
goto error;
r = sd_bus_add_fallback_vtable(m->bus,
"/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,
"/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, "/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_ERR(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");
sd_bus_remove_object_manager(m->bus, "/org/freedesktop/miracle/wifi");
sd_bus_remove_fallback_vtable(m->bus,
"/org/freedesktop/miracle/wifi/peer",
"org.freedesktop.miracle.wifi.Peer",
peer_dbus_vtable,
peer_dbus_find,
m);
sd_bus_remove_fallback_vtable(m->bus,
"/org/freedesktop/miracle/wifi/link",
"org.freedesktop.miracle.wifi.Link",
link_dbus_vtable,
link_dbus_find,
m);
sd_bus_remove_node_enumerator(m->bus,
"/org/freedesktop/miracle/wifi",
manager_dbus_enumerate,
m);
sd_bus_remove_object_vtable(m->bus,
"/org/freedesktop/miracle/wifi",
"org.freedesktop.miracle.wifi.Manager",
manager_dbus_vtable,
m);
}

262
src/wifi/wifid-link.c Normal file
View file

@ -0,0 +1,262 @@
/*
* 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 "link"
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include "shl_dlist.h"
#include "shl_log.h"
#include "shl_util.h"
#include "util.h"
#include "wifid.h"
/*
* Link Handling
*/
struct peer *link_find_peer(struct link *l, const char *p2p_mac)
{
char **elem;
bool res;
res = shl_htable_lookup_str(&l->peers, p2p_mac, NULL, &elem);
if (!res)
return NULL;
return peer_from_htable(elem);
}
struct peer *link_find_peer_by_label(struct link *l, const char *label)
{
char mac[MAC_STRLEN];
reformat_mac(mac, label);
return link_find_peer(l, mac);
}
int link_new(struct manager *m,
unsigned int ifindex,
const char *ifname,
struct link **out)
{
struct link *l;
int r;
if (!m || !ifindex || !ifname)
return log_EINVAL();
if (shl_htable_lookup_uint(&m->links, ifindex, NULL))
return -EALREADY;
log_debug("new link: %s (%u)", ifname, ifindex);
l = calloc(1, sizeof(*l));
if (!l)
return log_ENOMEM();
l->m = m;
l->ifindex = ifindex;
shl_htable_init_str(&l->peers);
l->ifname = strdup(ifname);
if (!l->ifname) {
r = log_ENOMEM();
goto error;
}
r = supplicant_new(l, &l->s);
if (r < 0)
goto error;
r = shl_htable_insert_uint(&m->links, &l->ifindex);
if (r < 0) {
log_vERR(r);
goto error;
}
++m->link_cnt;
log_info("add link: %s", l->ifname);
if (out)
*out = l;
return 0;
error:
link_free(l);
return r;
}
void link_free(struct link *l)
{
if (!l)
return;
log_debug("free link: %s (%u)", l->ifname, l->ifindex);
link_set_managed(l, false);
if (shl_htable_remove_uint(&l->m->links, l->ifindex, NULL)) {
log_info("remove link: %s", l->ifname);
--l->m->link_cnt;
}
supplicant_free(l->s);
/* link_set_managed(l, false) already removed all peers */
shl_htable_clear_str(&l->peers, NULL, NULL);
free(l->friendly_name);
free(l->ifname);
free(l);
}
void link_set_managed(struct link *l, bool set)
{
int r;
if (!l)
return log_vEINVAL();
if (l->managed == set)
return;
if (set) {
log_info("manage link %s", l->ifname);
r = supplicant_start(l->s);
if (r < 0) {
log_error("cannot start supplicant on %s", l->ifname);
return;
}
} else {
log_info("link %s no longer managed", l->ifname);
supplicant_stop(l->s);
}
l->managed = set;
}
int link_renamed(struct link *l, const char *ifname)
{
char *t;
if (!l || !ifname)
return log_EINVAL();
if (!strcmp(l->ifname, ifname))
return 0;
log_info("link %s (%u) was renamed to %s",
l->ifname, l->ifindex, ifname);
t = strdup(ifname);
if (!t)
return log_ENOMEM();
free(l->ifname);
l->ifname = t;
link_dbus_properties_changed(l, "InterfaceName", NULL);
return 0;
}
int link_set_friendly_name(struct link *l, const char *name)
{
char *t;
int r;
if (!l || !name || !*name)
return log_EINVAL();
t = strdup(name);
if (!t)
return log_ENOMEM();
if (supplicant_is_ready(l->s)) {
r = supplicant_set_friendly_name(l->s, name);
if (r < 0) {
free(t);
return r;
}
}
free(l->friendly_name);
l->friendly_name = t;
link_dbus_properties_changed(l, "FriendlyName", NULL);
return 0;
}
const char *link_get_friendly_name(struct link *l)
{
if (!l)
return NULL;
return l->friendly_name;
}
int link_set_p2p_scanning(struct link *l, bool set)
{
if (!l)
return log_EINVAL();
if (set) {
return supplicant_p2p_start_scan(l->s);
} else {
supplicant_p2p_stop_scan(l->s);
return 0;
}
}
bool link_get_p2p_scanning(struct link *l)
{
return l && supplicant_p2p_scanning(l->s);
}
void link_supplicant_started(struct link *l)
{
if (!l || l->public)
return;
log_debug("link %s started", l->ifname);
l->public = true;
link_dbus_added(l);
}
void link_supplicant_stopped(struct link *l)
{
if (!l || !l->public)
return;
log_debug("link %s stopped", l->ifname);
link_dbus_removed(l);
l->public = false;
}
void link_supplicant_p2p_scan_changed(struct link *l, bool new_value)
{
if (!l)
return;
link_dbus_properties_changed(l, "P2PScanning", NULL);
}

198
src/wifi/wifid-peer.c Normal file
View file

@ -0,0 +1,198 @@
/*
* 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 "peer"
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include "shl_dlist.h"
#include "shl_log.h"
#include "shl_util.h"
#include "util.h"
#include "wifid.h"
/*
* Peer Handling
*/
int peer_new(struct link *l,
const char *p2p_mac,
struct peer **out)
{
char mac[MAC_STRLEN];
struct peer *p;
int r;
if (!l || !p2p_mac)
return log_EINVAL();
reformat_mac(mac, p2p_mac);
if (shl_htable_lookup_str(&l->peers, mac, NULL, NULL))
return -EALREADY;
log_debug("new peer: %s @ %s", mac, l->ifname);
p = calloc(1, sizeof(*p));
if (!p)
return log_ENOMEM();
p->l = l;
p->p2p_mac = calloc(1, MAC_STRLEN);
if (!p->p2p_mac) {
r = log_ENOMEM();
goto error;
}
strncpy(p->p2p_mac, mac, MAC_STRLEN - 1);
r = shl_htable_insert_str(&l->peers, &p->p2p_mac, NULL);
if (r < 0) {
log_vERR(r);
goto error;
}
++l->peer_cnt;
log_info("add peer: %s", p->p2p_mac);
if (out)
*out = p;
return 0;
error:
peer_free(p);
return r;
}
void peer_free(struct peer *p)
{
if (!p)
return;
log_debug("free peer: %s @ %s", p->p2p_mac, p->l->ifname);
if (shl_htable_remove_str(&p->l->peers, p->p2p_mac, NULL, NULL)) {
log_info("remove peer: %s", p->p2p_mac);
--p->l->peer_cnt;
}
free(p->p2p_mac);
free(p);
}
const char *peer_get_friendly_name(struct peer *p)
{
if (!p)
return NULL;
return supplicant_peer_get_friendly_name(p->sp);
}
const char *peer_get_interface(struct peer *p)
{
if (!p || !p->connected)
return NULL;
return supplicant_peer_get_interface(p->sp);
}
const char *peer_get_local_address(struct peer *p)
{
if (!p || !p->connected)
return NULL;
return supplicant_peer_get_local_address(p->sp);
}
const char *peer_get_remote_address(struct peer *p)
{
if (!p || !p->connected)
return NULL;
return supplicant_peer_get_remote_address(p->sp);
}
int peer_connect(struct peer *p, const char *prov, const char *pin)
{
if (!p)
return log_EINVAL();
return supplicant_peer_connect(p->sp, prov, pin);
}
void peer_disconnect(struct peer *p)
{
if (!p)
return log_vEINVAL();
supplicant_peer_disconnect(p->sp);
}
void peer_supplicant_started(struct peer *p)
{
if (!p || p->public)
return;
log_debug("peer %s @ %s started", p->p2p_mac, p->l->ifname);
p->public = true;
peer_dbus_added(p);
}
void peer_supplicant_stopped(struct peer *p)
{
if (!p || !p->public)
return;
log_debug("peer %s @ %s stopped", p->p2p_mac, p->l->ifname);
peer_dbus_removed(p);
p->public = false;
}
void peer_supplicant_friendly_name_changed(struct peer *p)
{
if (!p || !p->public)
return;
peer_dbus_properties_changed(p, "FriendlyName", NULL);
}
void peer_supplicant_provision_discovery(struct peer *p,
const char *prov,
const char *pin)
{
if (!p || !p->public)
return;
peer_dbus_provision_discovery(p, prov, pin);
}
void peer_supplicant_connected_changed(struct peer *p, bool connected)
{
if (!p || p->connected == connected)
return;
p->connected = connected;
peer_dbus_properties_changed(p, "Connected",
"Interface",
"LocalAddress",
"RemoteAddress",
NULL);
}

2440
src/wifi/wifid-supplicant.c Normal file

File diff suppressed because it is too large Load diff

544
src/wifi/wifid.c Normal file
View file

@ -0,0 +1,544 @@
/*
* 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/>.
*/
#include <errno.h>
#include <getopt.h>
#include <libudev.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/signalfd.h>
#include <sys/wait.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-daemon.h>
#include <systemd/sd-event.h>
#include <time.h>
#include <unistd.h>
#include "shl_htable.h"
#include "shl_macro.h"
#include "shl_log.h"
#include "shl_util.h"
#include "util.h"
#include "wifid.h"
const char *arg_wpa_bindir = "/usr/bin";
unsigned int arg_wpa_loglevel = LOG_NOTICE;
/*
* Manager Handling
*/
struct link *manager_find_link(struct manager *m, unsigned int ifindex)
{
unsigned int *elem;
bool res;
res = shl_htable_lookup_uint(&m->links, ifindex, &elem);
if (!res)
return NULL;
return link_from_htable(elem);
}
struct link *manager_find_link_by_label(struct manager *m, const char *label)
{
const char *next;
unsigned int idx;
int r;
r = shl_atoi_u(label, 10, &next, &idx);
if (r < 0 || *next)
return NULL;
return manager_find_link(m, idx);
}
static void manager_add_udev_link(struct manager *m,
struct udev_device *d)
{
struct link *l;
unsigned int ifindex;
const char *ifname;
int r;
ifindex = ifindex_from_udev_device(d);
if (!ifindex)
return;
ifname = udev_device_get_property_value(d, "INTERFACE");
if (!ifname)
return;
/* ignore dynamic p2p interfaces */
if (shl_startswith(ifname, "p2p-"))
return;
r = link_new(m, ifindex, ifname, &l);
if (r < 0)
return;
link_set_friendly_name(l, m->friendly_name);
if (udev_device_has_tag(d, "miracle"))
link_set_managed(l, true);
}
static int manager_udev_fn(sd_event_source *source,
int fd,
uint32_t mask,
void *data)
{
_cleanup_udev_device_ struct udev_device *d = NULL;
struct manager *m = data;
const char *action, *ifname;
unsigned int ifindex;
struct link *l;
d = udev_monitor_receive_device(m->udev_mon);
if (!d)
return 0;
ifindex = ifindex_from_udev_device(d);
if (!ifindex)
return 0;
l = manager_find_link(m, ifindex);
action = udev_device_get_action(d);
if (action && !strcmp(action, "remove")) {
if (l)
link_free(l);
} else if (l) {
if (action && !strcmp(action, "move")) {
ifname = udev_device_get_property_value(d, "INTERFACE");
if (ifname)
link_renamed(l, ifname);
}
if (udev_device_has_tag(d, "miracle"))
link_set_managed(l, true);
else
link_set_managed(l, false);
} else {
manager_add_udev_link(m, d);
}
return 0;
}
static int manager_signal_fn(sd_event_source *source,
const struct signalfd_siginfo *ssi,
void *data)
{
struct manager *m = data;
if (ssi->ssi_signo == SIGCHLD) {
log_debug("caught SIGCHLD for %ld, reaping child", (long)ssi->ssi_pid);
waitid(P_PID, ssi->ssi_pid, NULL, WNOHANG|WEXITED);
return 0;
} else if (ssi->ssi_signo == SIGPIPE) {
/* ignore SIGPIPE */
return 0;
}
log_notice("caught signal %d, exiting..", (int)ssi->ssi_signo);
sd_event_exit(m->event, 0);
return 0;
}
static void manager_free(struct manager *m)
{
unsigned int i;
struct link *l;
if (!m)
return;
while ((l = MANAGER_FIRST_LINK(m)))
link_free(l);
manager_dbus_disconnect(m);
shl_htable_clear_uint(&m->links, NULL, NULL);
sd_event_source_unref(m->udev_mon_source);
udev_monitor_unref(m->udev_mon);
udev_unref(m->udev);
for (i = 0; m->sigs[i]; ++i)
sd_event_source_unref(m->sigs[i]);
sd_bus_unref(m->bus);
sd_event_unref(m->event);
free(m->friendly_name);
free(m);
}
static int manager_new(struct manager **out)
{
struct manager *m;
static const int sigs[] = {
SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGPIPE, SIGCHLD, 0
};
unsigned int i;
sigset_t mask;
int r;
m = calloc(1, sizeof(*m));
if (!m)
return log_ENOMEM();
shl_htable_init_uint(&m->links);
r = sd_event_default(&m->event);
if (r < 0) {
log_vERR(r);
goto error;
}
r = sd_event_set_watchdog(m->event, true);
if (r < 0) {
log_vERR(r);
goto error;
}
r = sd_bus_default_system(&m->bus);
if (r < 0) {
log_error("cannot connect to system bus: %d", r);
goto error;
}
r = sd_bus_attach_event(m->bus, m->event, 0);
if (r < 0) {
log_vERR(r);
goto error;
}
for (i = 0; sigs[i]; ++i) {
sigemptyset(&mask);
sigaddset(&mask, sigs[i]);
sigprocmask(SIG_BLOCK, &mask, NULL);
r = sd_event_add_signal(m->event,
&m->sigs[i],
sigs[i],
manager_signal_fn,
m);
if (r < 0) {
log_vERR(r);
goto error;
}
/* low-priority to allow others to handle it first */
sd_event_source_set_priority(m->sigs[i], 100);
}
m->udev = udev_new();
if (!m->udev) {
r = log_ENOMEM();
goto error;
}
m->udev_mon = udev_monitor_new_from_netlink(m->udev, "udev");
if (!m->udev_mon) {
r = log_ENOMEM();
goto error;
}
r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_mon,
"net",
"wlan");
if (r < 0) {
log_vERR(r);
goto error;
}
r = udev_monitor_enable_receiving(m->udev_mon);
if (r < 0) {
log_vERR(r);
goto error;
}
r = sd_event_add_io(m->event,
&m->udev_mon_source,
udev_monitor_get_fd(m->udev_mon),
EPOLLHUP | EPOLLERR | EPOLLIN,
manager_udev_fn,
m);
if (r < 0) {
log_vERR(r);
goto error;
}
r = manager_dbus_connect(m);
if (r < 0)
goto error;
if (out)
*out = m;
return 0;
error:
manager_free(m);
return r;
}
static void manager_read_name(struct manager *m)
{
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
_cleanup_sd_bus_message_ sd_bus_message *rep = NULL;
const char *name;
char *str;
int r;
r = sd_bus_call_method(m->bus,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
"org.freedesktop.DBus.Properties",
"Get",
&err,
&rep,
"ss", "org.freedesktop.hostname1", "Hostname");
if (r < 0)
goto error;
r = sd_bus_message_enter_container(rep, 'v', "s");
if (r < 0)
goto error;
r = sd_bus_message_read(rep, "s", &name);
if (r < 0)
goto error;
if (shl_isempty(name)) {
log_warning("no hostname set on systemd.hostname1, using: %s",
m->friendly_name);
return;
}
str = strdup(name);
if (!str)
return log_vENOMEM();
free(m->friendly_name);
m->friendly_name = str;
log_debug("friendly-name from local hostname: %s", str);
return;
error:
log_warning("cannot read hostname from systemd.hostname1: %s",
bus_error_message(&err, r));
}
static void manager_read_links(struct manager *m)
{
_cleanup_udev_enumerate_ struct udev_enumerate *e = NULL;
struct udev_list_entry *l;
struct udev_device *d;
int r;
e = udev_enumerate_new(m->udev);
if (!e)
goto error;
r = udev_enumerate_add_match_subsystem(e, "net");
if (r < 0)
goto error;
r = udev_enumerate_add_match_property(e, "DEVTYPE", "wlan");
if (r < 0)
goto error;
r = udev_enumerate_add_match_is_initialized(e);
if (r < 0)
goto error;
r = udev_enumerate_scan_devices(e);
if (r < 0)
goto error;
udev_list_entry_foreach(l, udev_enumerate_get_list_entry(e)) {
d = udev_device_new_from_syspath(m->udev,
udev_list_entry_get_name(l));
if (!d)
goto error;
manager_add_udev_link(m, d);
udev_device_unref(d);
}
return;
error:
log_warning("cannot enumerate links via udev");
}
static int manager_startup(struct manager *m)
{
int r;
r = shl_mkdir_p_prefix("/run", "/run/miracle", 0755);
if (r >= 0)
r = shl_mkdir_p_prefix("/run/miracle",
"/run/miracle/wifi",
0700);
if (r < 0) {
log_error("cannot create maintenance directories in /run: %d",
r);
return r;
}
manager_read_name(m);
manager_read_links(m);
return 0;
}
static int manager_run(struct manager *m)
{
return sd_event_loop(m->event);
}
static int help(void)
{
/*
* 80-char barrier:
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
*/
printf("%s [OPTIONS...] ...\n\n"
"Wifi Management Daemon.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --log-level <lvl> Maximum level for log messages\n"
" --log-time Prefix log-messages with timestamp\n"
"\n"
" --wpa-bindir <dir> wpa_supplicant binary dir [/usr/bin]\n"
" --wpa-loglevel <lvl> wpa_supplicant log-level\n"
, program_invocation_short_name);
/*
* 80-char barrier:
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
*/
return 0;
}
static int parse_argv(int argc, char *argv[])
{
enum {
ARG_VERSION = 0x100,
ARG_LOG_LEVEL,
ARG_LOG_TIME,
ARG_WPA_BINDIR,
ARG_WPA_LOGLEVEL,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
{ "log-time", no_argument, NULL, ARG_LOG_TIME },
{ "wpa-bindir", required_argument, NULL, ARG_WPA_BINDIR },
{ "wpa-loglevel", required_argument, NULL, ARG_WPA_LOGLEVEL },
{}
};
int c;
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
switch (c) {
case 'h':
return help();
case ARG_VERSION:
puts(PACKAGE_STRING);
return 0;
case ARG_LOG_LEVEL:
log_max_sev = atoi(optarg);
break;
case ARG_LOG_TIME:
log_init_time();
break;
case ARG_WPA_BINDIR:
arg_wpa_bindir = optarg;
break;
case ARG_WPA_LOGLEVEL:
arg_wpa_loglevel = atoi(optarg);
break;
case '?':
return -EINVAL;
}
}
if (optind < argc) {
log_error("unparsed remaining arguments starting with: %s",
argv[optind]);
return -EINVAL;
}
log_format(LOG_DEFAULT_BASE, NULL, LOG_INFO,
"miracle-wifid - revision %s %s %s",
"some-rev-TODO-xyz", __DATE__, __TIME__);
return 1;
}
int main(int argc, char **argv)
{
struct manager *m = NULL;
int r;
srand(time(NULL));
r = parse_argv(argc, argv);
if (r < 0)
return EXIT_FAILURE;
if (!r)
return EXIT_SUCCESS;
r = manager_new(&m);
if (r < 0)
goto finish;
r = manager_startup(m);
if (r < 0)
goto finish;
r = sd_notify(false, "READY=1\n"
"STATUS=Running..");
if (r < 0) {
log_vERR(r);
goto finish;
}
r = manager_run(m);
finish:
sd_notify(false, "STATUS=Exiting..");
manager_free(m);
log_debug("exiting..");
return abs(r);
}

194
src/wifi/wifid.h Normal file
View file

@ -0,0 +1,194 @@
/*
* 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/>.
*/
#include <errno.h>
#include <libudev.h>
#include <stdbool.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include "shl_dlist.h"
#include "shl_htable.h"
#ifndef WIFID_H
#define WIFID_H
struct manager;
struct link;
struct peer;
struct supplicant;
struct supplicant_peer;
/* supplicant */
int supplicant_new(struct link *l,
struct supplicant **out);
void supplicant_free(struct supplicant *s);
int supplicant_start(struct supplicant *s);
void supplicant_stop(struct supplicant *s);
bool supplicant_is_running(struct supplicant *s);
bool supplicant_is_ready(struct supplicant *s);
int supplicant_set_friendly_name(struct supplicant *s, const char *name);
int supplicant_p2p_start_scan(struct supplicant *s);
void supplicant_p2p_stop_scan(struct supplicant *s);
bool supplicant_p2p_scanning(struct supplicant *s);
/* supplicant peer */
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);
int supplicant_peer_connect(struct supplicant_peer *sp,
const char *prov_type,
const char *pin);
void supplicant_peer_disconnect(struct supplicant_peer *sp);
/* peer */
struct peer {
struct link *l;
char *p2p_mac;
struct supplicant_peer *sp;
bool public : 1;
bool connected : 1;
};
#define peer_from_htable(_p) \
shl_htable_offsetof((_p), struct peer, p2p_mac)
int peer_new(struct link *l,
const char *p2p_mac,
struct peer **out);
void peer_free(struct peer *p);
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);
int peer_connect(struct peer *p, const char *prov, const char *pin);
void peer_disconnect(struct peer *p);
int peer_allow(struct peer *p);
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_provision_discovery(struct peer *p,
const char *prov,
const char *pin);
void peer_supplicant_connected_changed(struct peer *p, bool connected);
_shl_sentinel_
void peer_dbus_properties_changed(struct peer *p, const char *prop, ...);
void peer_dbus_provision_discovery(struct peer *p,
const char *prov,
const char *pin);
void peer_dbus_added(struct peer *p);
void peer_dbus_removed(struct peer *p);
/* link */
struct link {
struct manager *m;
unsigned int ifindex;
struct supplicant *s;
char *ifname;
char *friendly_name;
size_t peer_cnt;
struct shl_htable peers;
bool managed : 1;
bool public : 1;
};
#define link_from_htable(_l) \
shl_htable_offsetof((_l), struct link, ifindex)
#define LINK_FIRST_PEER(_l) \
SHL_HTABLE_FIRST_MACRO(&(_l)->peers, peer_from_htable)
#define LINK_FOREACH_PEER(_i, _l) \
SHL_HTABLE_FOREACH_MACRO(_i, &(_l)->peers, peer_from_htable)
struct peer *link_find_peer(struct link *l, const char *p2p_mac);
struct peer *link_find_peer_by_label(struct link *l, const char *label);
int link_new(struct manager *m,
unsigned int ifindex,
const char *ifname,
struct link **out);
void link_free(struct link *l);
void link_set_managed(struct link *l, bool set);
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_p2p_scanning(struct link *l, bool set);
bool link_get_p2p_scanning(struct link *l);
void link_supplicant_started(struct link *l);
void link_supplicant_stopped(struct link *l);
void link_supplicant_p2p_scan_changed(struct link *l, bool new_value);
_shl_sentinel_
void link_dbus_properties_changed(struct link *l, const char *prop, ...);
void link_dbus_added(struct link *l);
void link_dbus_removed(struct link *l);
/* manager */
struct manager {
sd_event *event;
sd_bus *bus;
sd_event_source *sigs[_NSIG];
struct udev *udev;
struct udev_monitor *udev_mon;
sd_event_source *udev_mon_source;
char *friendly_name;
size_t link_cnt;
struct shl_htable links;
};
#define MANAGER_FIRST_LINK(_m) \
SHL_HTABLE_FIRST_MACRO(&(_m)->links, link_from_htable)
#define MANAGER_FOREACH_LINK(_i, _m) \
SHL_HTABLE_FOREACH_MACRO(_i, &(_m)->links, link_from_htable)
struct link *manager_find_link(struct manager *m, unsigned int ifindex);
struct link *manager_find_link_by_label(struct manager *m, const char *label);
/* dbus */
int manager_dbus_connect(struct manager *m);
void manager_dbus_disconnect(struct manager *m);
/* cli arguments */
extern const char *arg_wpa_bindir;
extern unsigned int arg_wpa_loglevel;
#endif /* WIFID_H */