1
0
Fork 0
mirror of https://github.com/albfan/miraclecast.git synced 2025-03-09 23:38:56 +00:00

miracled: support managed wpa_supplicant

If miracled is spawned with --manage-wifi, we run our own copy of
wpa_supplicant on managed devices. This is meant for testing purposes
only. Hopefully, network-manages like NM or connman will provide a P2P API
at some time so we can switch. Until then, we allow the user to control
who is in charge of wpa_supplicant.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
This commit is contained in:
David Herrmann 2014-02-17 16:42:54 +01:00
parent 5fb83c9159
commit 6a37cbe6b8
6 changed files with 277 additions and 11 deletions

View file

@ -444,6 +444,25 @@ static int link_dbus_get_interface(sd_bus *bus,
return 1;
}
static int link_dbus_get_running(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, val;
val = l->running;
r = sd_bus_message_append_basic(reply, 'b', &val);
if (r < 0)
return r;
return 1;
}
static int link_dbus_get_name(sd_bus *bus,
const char *path,
const char *interface,
@ -503,6 +522,11 @@ static const sd_bus_vtable link_dbus_vtable[] = {
link_dbus_get_interface,
0,
SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Running",
"b",
link_dbus_get_running,
0,
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_WRITABLE_PROPERTY("Name",
"s",
link_dbus_get_name,

View file

@ -138,23 +138,17 @@ static void link_wifi_event_fn(struct wifi *w, void *data,
}
}
static int link_wifi_init(struct link *l)
static int link_wifi_start(struct link *l)
{
_shl_cleanup_free_ char *path = NULL;
struct wifi_dev *d;
int r;
char *path;
r = wifi_new(l->m->event, link_wifi_event_fn, l, &l->w);
if (r < 0)
return r;
path = shl_strcat("/run/wpa_supplicant/", l->interface);
path = shl_strjoin(arg_wpa_rundir, "/", l->interface, NULL);
if (!path)
return log_ENOMEM();
r = wifi_open(l->w, path);
free(path);
if (r < 0)
return r;
@ -168,8 +162,104 @@ static int link_wifi_init(struct link *l)
return 0;
}
static int link_wifi_child_fn(sd_event_source *source,
const siginfo_t *si,
void *data)
{
struct link *l = data;
log_error("wpa_supplicant died unexpectedly on link %s", l->name);
link_free(l);
return 0;
}
static int link_wifi_startup_fn(sd_event_source *source,
uint64_t usec,
void *data)
{
struct link *l = data;
int r;
r = link_wifi_start(l);
if (r < 0) {
if (wifi_is_open(l->w)) {
log_error("cannot start wifi on link %s", l->name);
link_free(l);
return 0;
}
/* reschedule timer */
sd_event_source_set_time(source,
now(CLOCK_MONOTONIC) + 200 * 1000);
sd_event_source_set_enabled(source, SD_EVENT_ON);
log_debug("wpa_supplicant startup still ongoing, reschedule..");
return 0;
}
log_debug("wpa_supplicant startup finished on link %s", l->name);
sd_event_source_set_enabled(source, SD_EVENT_OFF);
l->running = true;
link_dbus_properties_changed(l, "Running", NULL);
return 0;
}
static int link_wifi_init(struct link *l)
{
_shl_cleanup_free_ char *path = NULL;
int r;
r = wifi_new(l->m->event, link_wifi_event_fn, l, &l->w);
if (r < 0)
return r;
if (!arg_manage_wifi) {
r = link_wifi_start(l);
if (r < 0)
log_error("cannot open wpa_supplicant socket for link %s",
l->name);
else
l->running = true;
return r;
}
path = shl_strcat(arg_wpa_bindir, "/wpa_supplicant");
if (!path)
return log_ENOMEM();
r = wifi_spawn_supplicant(l->w, arg_wpa_rundir, path, l->interface);
if (r < 0)
return r;
r = sd_event_add_child(l->m->event,
wifi_get_supplicant_pid(l->w),
WEXITED,
link_wifi_child_fn,
l,
&l->wpa_child_source);
if (r < 0)
return r;
r = sd_event_add_monotonic(l->m->event,
now(CLOCK_MONOTONIC) + 200 * 1000,
0,
link_wifi_startup_fn,
l,
&l->wpa_startup_source);
if (r < 0)
return r;
return 0;
}
static void link_wifi_destroy(struct link *l)
{
sd_event_source_unref(l->wpa_startup_source);
sd_event_source_unref(l->wpa_child_source);
wifi_close(l->w);
wifi_free(l->w);
}
@ -227,6 +317,7 @@ int link_new(struct manager *m,
switch (l->type) {
case LINK_VIRTUAL:
l->running = true;
break;
case LINK_WIFI:
r = link_wifi_init(l);

View file

@ -76,6 +76,8 @@ struct wifi {
char *reply_buf;
size_t reply_buf_size;
pid_t wpa_pid;
struct wfd_wpa_ctrl *wpa;
sd_event_source *wpa_source;
struct shl_dlist devs;
@ -784,10 +786,27 @@ error:
void wifi_free(struct wifi *w)
{
int r;
pid_t rp;
if (!w)
return;
wifi_close(w);
if (w->wpa_pid > 0) {
log_debug("killing wpa_supplicant pid:%d and waiting for exit..",
w->wpa_pid);
r = kill(w->wpa_pid, SIGTERM);
if (r >= 0)
rp = waitpid(w->wpa_pid, NULL, 0);
if (r < 0 || rp != w->wpa_pid) {
r = kill(w->wpa_pid, SIGKILL);
if (r >= 0)
waitpid(w->wpa_pid, &r, 0);
}
}
sd_event_source_unref(w->wpa_source);
wfd_wpa_ctrl_unref(w->wpa);
free(w->reply_buf);
@ -832,6 +851,88 @@ static int wifi_read_all_peers(struct wifi *w)
return (r == -EAGAIN) ? 0 : r;
}
pid_t wifi_get_supplicant_pid(struct wifi *w)
{
if (!w)
return 0;
return w->wpa_pid;
}
static void wifi_run_supplicant(struct wifi *w,
const char *rundir,
const char *binary,
const char *ifname)
{
char *argv[64];
int i;
sigset_t mask;
sigemptyset(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL);
/* redirect stdout to stderr for wpa_supplicant */
dup2(2, 1);
/* initialize wpa_supplicant args */
i = 0;
argv[i++] = (char*)binary;
argv[i++] = "-Dnl80211";
argv[i++] = "-qq";
argv[i++] = "-C";
argv[i++] = (char*)rundir;
argv[i++] = "-i";
argv[i++] = (char*)ifname;
argv[i++] = "-p p2p_device=1";
argv[i] = NULL;
/* execute wpa_supplicant; if it fails, the caller issues exit(1) */
execve(argv[0], argv, environ);
}
int wifi_spawn_supplicant(struct wifi *w,
const char *rundir,
const char *binary,
const char *ifname)
{
pid_t pid;
if (!w)
return log_EINVAL();
if (w->wpa_pid > 0)
return 0;
if (access(binary, X_OK) < 0) {
log_error("execution of wpa_supplicant-binary (%s) not allowed: %m",
binary);
return -EINVAL;
}
pid = fork();
if (pid < 0) {
return log_ERRNO();
} else if (!pid) {
wifi_run_supplicant(w, rundir, binary, ifname);
exit(1);
}
w->wpa_pid = pid;
log_info("waiting for wpa_supplicant (pid: %d) startup on %s..",
(int)pid, ifname);
/* Ouh, yeah.. waiting for wpa_supplicant to start up is.. awful..
* We could use inotify on the ctrl-socket/dir, but these might be
* left-overs from previous runs and thus might get destroyed first.
* And there're some more races.. so lets just do nothing and fire
* a 100ms timer repeatedly in the parent. This gives wpa_supplicant
* enough time to start up and we can test the connection from time to
* time.
* We just need to make sure to catch SIGCHLD so we stop trying if
* wpa_supplicant dies.. All done in the parent. */
return 0;
}
int wifi_open(struct wifi *w, const char *wpa_path)
{
int r;
@ -845,7 +946,7 @@ int wifi_open(struct wifi *w, const char *wpa_path)
r = wfd_wpa_ctrl_open(w->wpa, wpa_path);
if (r < 0) {
log_error("cannot open wpa_supplicant socket %s: %d",
log_debug("cannot open wpa_supplicant socket %s: %d",
wpa_path, r);
goto error;
}
@ -880,7 +981,6 @@ void wifi_close(struct wifi *w)
}
wfd_wpa_ctrl_close(w->wpa);
w->wpa = NULL;
}
int wifi_set_discoverable(struct wifi *w, bool on)

View file

@ -97,6 +97,12 @@ void wifi_free(struct wifi *w);
void wifi_set_data(struct wifi *w, void *data);
void *wifi_get_data(struct wifi *w);
pid_t wifi_get_supplicant_pid(struct wifi *w);
int wifi_spawn_supplicant(struct wifi *w,
const char *rundir,
const char *binary,
const char *ifname);
bool wifi_is_open(struct wifi *w);
int wifi_open(struct wifi *w, const char *wpa_path);
void wifi_close(struct wifi *w);

View file

@ -44,6 +44,10 @@
#include "shl_log.h"
#include "shl_util.h"
bool arg_manage_wifi = false;
const char *arg_wpa_rundir = "/run/wpa_supplicant";
const char *arg_wpa_bindir = "/usr/bin";
/*
* Peer Handling
*/
@ -406,13 +410,26 @@ static int manager_run(struct manager *m)
static int help(void)
{
/*
* 80-char barrier:
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
*/
printf("%s [OPTIONS...] ...\n\n"
"Wifi-Display 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"
" --manage-wifi Enable internal wifi-management via wpa_supplicant if\n"
" they're not managed externally (like NetworkManager)\n"
" --wpa-rundir <dir> wpa_supplicant runtime dir [/run/wpa_supplicant]\n"
" --wpa-bindir <dir> wpa_supplicant binary dir [/usr/bin]\n"
, program_invocation_short_name);
/*
* 80-char barrier:
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
*/
return 0;
}
@ -423,12 +440,20 @@ static int parse_argv(int argc, char *argv[])
ARG_VERSION = 0x100,
ARG_LOG_LEVEL,
ARG_LOG_TIME,
ARG_MANAGE_WIFI,
ARG_WPA_RUNDIR,
ARG_WPA_BINDIR,
};
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 },
{ "manage-wifi", no_argument, NULL, ARG_MANAGE_WIFI },
{ "wpa-rundir", required_argument, NULL, ARG_WPA_RUNDIR },
{ "wpa-bindir", required_argument, NULL, ARG_WPA_BINDIR },
{}
};
int c;
@ -446,6 +471,16 @@ static int parse_argv(int argc, char *argv[])
case ARG_LOG_TIME:
log_init_time();
break;
case ARG_MANAGE_WIFI:
arg_manage_wifi = true;
break;
case ARG_WPA_RUNDIR:
arg_wpa_rundir = optarg;
break;
case ARG_WPA_BINDIR:
arg_wpa_bindir = optarg;
break;
case '?':
return -EINVAL;
}

View file

@ -95,6 +95,10 @@ struct link {
struct shl_dlist peers;
struct wifi *w;
sd_event_source *wpa_child_source;
sd_event_source *wpa_startup_source;
bool running : 1;
};
#define link_from_htable(_l) \
@ -166,4 +170,10 @@ void link_dbus_scan_stopped(struct link *l);
void link_dbus_added(struct link *l);
void link_dbus_removed(struct link *l);
/* cli arguments */
extern bool arg_manage_wifi;
extern const char *arg_wpa_rundir;
extern const char *arg_wpa_bindir;
#endif /* MIRACLED_H */