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; 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, static int link_dbus_get_name(sd_bus *bus,
const char *path, const char *path,
const char *interface, const char *interface,
@ -503,6 +522,11 @@ static const sd_bus_vtable link_dbus_vtable[] = {
link_dbus_get_interface, link_dbus_get_interface,
0, 0,
SD_BUS_VTABLE_PROPERTY_CONST), 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", SD_BUS_WRITABLE_PROPERTY("Name",
"s", "s",
link_dbus_get_name, 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; struct wifi_dev *d;
int r; int r;
char *path;
r = wifi_new(l->m->event, link_wifi_event_fn, l, &l->w); path = shl_strjoin(arg_wpa_rundir, "/", l->interface, NULL);
if (r < 0)
return r;
path = shl_strcat("/run/wpa_supplicant/", l->interface);
if (!path) if (!path)
return log_ENOMEM(); return log_ENOMEM();
r = wifi_open(l->w, path); r = wifi_open(l->w, path);
free(path);
if (r < 0) if (r < 0)
return r; return r;
@ -168,8 +162,104 @@ static int link_wifi_init(struct link *l)
return 0; 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) 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_close(l->w);
wifi_free(l->w); wifi_free(l->w);
} }
@ -227,6 +317,7 @@ int link_new(struct manager *m,
switch (l->type) { switch (l->type) {
case LINK_VIRTUAL: case LINK_VIRTUAL:
l->running = true;
break; break;
case LINK_WIFI: case LINK_WIFI:
r = link_wifi_init(l); r = link_wifi_init(l);

View file

@ -76,6 +76,8 @@ struct wifi {
char *reply_buf; char *reply_buf;
size_t reply_buf_size; size_t reply_buf_size;
pid_t wpa_pid;
struct wfd_wpa_ctrl *wpa; struct wfd_wpa_ctrl *wpa;
sd_event_source *wpa_source; sd_event_source *wpa_source;
struct shl_dlist devs; struct shl_dlist devs;
@ -784,10 +786,27 @@ error:
void wifi_free(struct wifi *w) void wifi_free(struct wifi *w)
{ {
int r;
pid_t rp;
if (!w) if (!w)
return; return;
wifi_close(w); 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); sd_event_source_unref(w->wpa_source);
wfd_wpa_ctrl_unref(w->wpa); wfd_wpa_ctrl_unref(w->wpa);
free(w->reply_buf); free(w->reply_buf);
@ -832,6 +851,88 @@ static int wifi_read_all_peers(struct wifi *w)
return (r == -EAGAIN) ? 0 : r; 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 wifi_open(struct wifi *w, const char *wpa_path)
{ {
int r; 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); r = wfd_wpa_ctrl_open(w->wpa, wpa_path);
if (r < 0) { if (r < 0) {
log_error("cannot open wpa_supplicant socket %s: %d", log_debug("cannot open wpa_supplicant socket %s: %d",
wpa_path, r); wpa_path, r);
goto error; goto error;
} }
@ -880,7 +981,6 @@ void wifi_close(struct wifi *w)
} }
wfd_wpa_ctrl_close(w->wpa); wfd_wpa_ctrl_close(w->wpa);
w->wpa = NULL;
} }
int wifi_set_discoverable(struct wifi *w, bool on) 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_set_data(struct wifi *w, void *data);
void *wifi_get_data(struct wifi *w); 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); bool wifi_is_open(struct wifi *w);
int wifi_open(struct wifi *w, const char *wpa_path); int wifi_open(struct wifi *w, const char *wpa_path);
void wifi_close(struct wifi *w); void wifi_close(struct wifi *w);

View file

@ -44,6 +44,10 @@
#include "shl_log.h" #include "shl_log.h"
#include "shl_util.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 * Peer Handling
*/ */
@ -406,13 +410,26 @@ static int manager_run(struct manager *m)
static int help(void) static int help(void)
{ {
/*
* 80-char barrier:
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
*/
printf("%s [OPTIONS...] ...\n\n" printf("%s [OPTIONS...] ...\n\n"
"Wifi-Display Daemon.\n\n" "Wifi-Display Daemon.\n\n"
" -h --help Show this help\n" " -h --help Show this help\n"
" --version Show package version\n" " --version Show package version\n"
" --log-level <lvl> Maximum level for log messages\n" " --log-level <lvl> Maximum level for log messages\n"
" --log-time Prefix log-messages with timestamp\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); , program_invocation_short_name);
/*
* 80-char barrier:
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
*/
return 0; return 0;
} }
@ -423,12 +440,20 @@ static int parse_argv(int argc, char *argv[])
ARG_VERSION = 0x100, ARG_VERSION = 0x100,
ARG_LOG_LEVEL, ARG_LOG_LEVEL,
ARG_LOG_TIME, ARG_LOG_TIME,
ARG_MANAGE_WIFI,
ARG_WPA_RUNDIR,
ARG_WPA_BINDIR,
}; };
static const struct option options[] = { static const struct option options[] = {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION }, { "version", no_argument, NULL, ARG_VERSION },
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL }, { "log-level", required_argument, NULL, ARG_LOG_LEVEL },
{ "log-time", no_argument, NULL, ARG_LOG_TIME }, { "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; int c;
@ -446,6 +471,16 @@ static int parse_argv(int argc, char *argv[])
case ARG_LOG_TIME: case ARG_LOG_TIME:
log_init_time(); log_init_time();
break; 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 '?': case '?':
return -EINVAL; return -EINVAL;
} }

View file

@ -95,6 +95,10 @@ struct link {
struct shl_dlist peers; struct shl_dlist peers;
struct wifi *w; struct wifi *w;
sd_event_source *wpa_child_source;
sd_event_source *wpa_startup_source;
bool running : 1;
}; };
#define link_from_htable(_l) \ #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_added(struct link *l);
void link_dbus_removed(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 */ #endif /* MIRACLED_H */