diff --git a/src/ctl/ctl-wifi.c b/src/ctl/ctl-wifi.c index 6efca2c..130c031 100644 --- a/src/ctl/ctl-wifi.c +++ b/src/ctl/ctl-wifi.c @@ -414,6 +414,8 @@ static int ctl_link_parse_properties(struct ctl_link *l, bool p2p_scanning_set = false; char *tmp; int p2p_scanning, r; + bool managed_set = false; + int managed; if (!l || !m) return cli_EINVAL(); @@ -444,6 +446,13 @@ static int ctl_link_parse_properties(struct ctl_link *l, &friendly_name); if (r < 0) return cli_log_parser(r); + } else if (!strcmp(t, "Managed")) { + r = bus_message_read_basic_variant(m, "b", + &managed); + if (r < 0) + return cli_log_parser(r); + + managed_set = true; } else if (!strcmp(t, "P2PScanning")) { r = bus_message_read_basic_variant(m, "b", &p2p_scanning); @@ -494,6 +503,9 @@ static int ctl_link_parse_properties(struct ctl_link *l, } } + if (managed_set) + l->managed = managed; + if (p2p_scanning_set) l->p2p_scanning = p2p_scanning; @@ -620,6 +632,63 @@ int ctl_link_set_wfd_subelements(struct ctl_link *l, const char *val) return 0; } +int ctl_link_set_managed(struct ctl_link *l, bool val) +{ + _sd_bus_message_unref_ sd_bus_message *m = NULL; + _sd_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL; + _shl_free_ char *node = NULL; + int r; + + if (!l) + return cli_EINVAL(); + if (l->managed == val) + return 0; + + r = sd_bus_path_encode("/org/freedesktop/miracle/wifi/link", + l->label, + &node); + if (r < 0) + return cli_ERR(r); + + r = sd_bus_message_new_method_call(l->w->bus, + &m, + "org.freedesktop.miracle.wifi", + node, + "org.freedesktop.DBus.Properties", + "Set"); + if (r < 0) + return cli_log_create(r); + + r = sd_bus_message_append(m, "ss", + "org.freedesktop.miracle.wifi.Link", + "Managed"); + if (r < 0) + return cli_log_create(r); + + r = sd_bus_message_open_container(m, 'v', "b"); + if (r < 0) + return cli_log_create(r); + + r = sd_bus_message_append(m, "b", val); + if (r < 0) + return cli_log_create(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return cli_log_create(r); + + r = sd_bus_call(l->w->bus, m, 0, &err, NULL); + if (r < 0) { + cli_error("cannot change managed state on link %s to %d: %s", + l->label, val, bus_error_message(&err, r)); + return r; + } + + l->managed = val; + + return 0; +} + int ctl_link_set_p2p_scanning(struct ctl_link *l, bool val) { _sd_bus_message_unref_ sd_bus_message *m = NULL; diff --git a/src/ctl/ctl.h b/src/ctl/ctl.h index 1d0bd9a..02220bc 100644 --- a/src/ctl/ctl.h +++ b/src/ctl/ctl.h @@ -71,6 +71,7 @@ struct ctl_link { unsigned int ifindex; char *ifname; char *friendly_name; + bool managed; char *wfd_subelements; bool p2p_scanning; }; @@ -78,6 +79,7 @@ struct ctl_link { #define link_from_dlist(_l) shl_dlist_entry((_l), struct ctl_link, list); int ctl_link_set_friendly_name(struct ctl_link *l, const char *name); +int ctl_link_set_managed(struct ctl_link *l, bool val); int ctl_link_set_wfd_subelements(struct ctl_link *l, const char *val); int ctl_link_set_p2p_scanning(struct ctl_link *l, bool val); diff --git a/src/ctl/sinkctl.c b/src/ctl/sinkctl.c index 029407c..9a6489d 100644 --- a/src/ctl/sinkctl.c +++ b/src/ctl/sinkctl.c @@ -84,19 +84,20 @@ static int cmd_list(char **args, unsigned int n) /* list links */ - cli_printf("%6s %-24s %-30s\n", - "LINK", "INTERFACE", "FRIENDLY-NAME"); + cli_printf("%6s %-24s %-30s %-10s\n", + "LINK", "INTERFACE", "FRIENDLY-NAME", "MANAGED"); shl_dlist_for_each(i, &wifi->links) { l = link_from_dlist(i); ++link_cnt; - cli_printf("%6s %-24s %-30s\n", + cli_printf("%6s %-24s %-30s %-10s\n", l->label, shl_isempty(l->ifname) ? "" : l->ifname, shl_isempty(l->friendly_name) ? - "" : l->friendly_name); + "" : l->friendly_name, + l->managed ? "yes": "no"); } cli_printf("\n"); @@ -157,6 +158,7 @@ static int cmd_show(char **args, unsigned int n) cli_printf("P2PScanning=%d\n", l->p2p_scanning); if (l->wfd_subelements && *l->wfd_subelements) cli_printf("WfdSubelements=%s\n", l->wfd_subelements); + cli_printf("Managed=%d\n", l->managed); } else if (p) { cli_printf("Peer=%s\n", p->label); if (p->p2p_mac && *p->p2p_mac) @@ -210,6 +212,11 @@ static int cmd_run(char **args, unsigned int n) return 0; } + if (!l->managed) { + cli_printf("link %s not managed\n", l->label); + return 0; + } + run_on(l); return 0; @@ -240,11 +247,37 @@ static int cmd_bind(char **args, unsigned int n) if (!l) return 0; + if (!l->managed) { + cli_printf("link %s not managed\n", l->label); + return 0; + } + run_on(l); return 0; } +/* + * cmd: set-managed + */ + +static int cmd_set_managed(char **args, unsigned int n) +{ + struct ctl_link *l = NULL; + bool managed = true; + + l = ctl_wifi_search_link(wifi, args[0]); + if (!l) { + cli_error("unknown link %s", args[0]); + return 0; + } + + if (!strcmp(args[1], "no")) { + managed = false; + } + return ctl_link_set_managed(l, managed); +} + /* * cmd: quit/exit */ @@ -341,6 +374,7 @@ static const struct cli_cmd cli_cmds[] = { { "show", "", CLI_M, CLI_LESS, 1, cmd_show, "Show detailed object information" }, { "run", "", CLI_M, CLI_EQUAL, 1, cmd_run, "Run sink on given link" }, { "bind", "", CLI_M, CLI_EQUAL, 1, cmd_bind, "Like 'run' but bind the link name to run when it is hotplugged" }, + { "set-managed", " ", CLI_M, CLI_EQUAL, 2, cmd_set_managed, "Manage or unmnage a link" }, { "quit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, "Quit program" }, { "exit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, NULL }, { "help", NULL, CLI_M, CLI_MORE, 0, NULL, "Print help" }, diff --git a/src/ctl/wifictl.c b/src/ctl/wifictl.c index d3ad7f3..8823f73 100644 --- a/src/ctl/wifictl.c +++ b/src/ctl/wifictl.c @@ -52,19 +52,20 @@ static int cmd_list(char **args, unsigned int n) /* list links */ - cli_printf("%6s %-24s %-30s\n", - "LINK", "INTERFACE", "FRIENDLY-NAME"); + cli_printf("%6s %-24s %-30s %-10s\n", + "LINK", "INTERFACE", "FRIENDLY-NAME", "MANAGED"); shl_dlist_for_each(i, &wifi->links) { l = link_from_dlist(i); ++link_cnt; - cli_printf("%6s %-24s %-30s\n", + cli_printf("%6s %-24s %-30s %-10s\n", l->label, shl_isempty(l->ifname) ? "" : l->ifname, shl_isempty(l->friendly_name) ? - "" : l->friendly_name); + "" : l->friendly_name, + l->managed ? "yes": "no"); } cli_printf("\n"); @@ -157,6 +158,7 @@ static int cmd_show(char **args, unsigned int n) cli_printf("P2PScanning=%d\n", l->p2p_scanning); if (l->wfd_subelements && *l->wfd_subelements) cli_printf("WfdSubelements=%s\n", l->wfd_subelements); + cli_printf("Managed=%d\n", l->managed); } else if (p) { cli_printf("Peer=%s\n", p->label); if (p->p2p_mac && *p->p2p_mac) @@ -212,9 +214,53 @@ static int cmd_set_friendly_name(char **args, unsigned int n) return 0; } + if (!l->managed) { + cli_printf("link %s not managed\n", l->label); + return 0; + } + return ctl_link_set_friendly_name(l, name); } +/* + * cmd: set-managed + */ + +static int cmd_set_managed(char **args, unsigned int n) +{ + struct ctl_link *l = NULL; + const char *value; + bool managed = true; + + if (n < 1) { + cli_printf("To what?\n"); + return 0; + } + + if (n > 1) { + l = ctl_wifi_search_link(wifi, args[0]); + if (!l) { + cli_error("unknown link %s", args[0]); + return 0; + } + + value = args[1]; + } else { + value = args[0]; + } + + l = l ? : selected_link; + if (!l) { + cli_error("no link selected"); + return 0; + } + + if (!strcmp(value, "no")) { + managed = false; + } + return ctl_link_set_managed(l, managed); +} + /* * cmd: p2p-scan */ @@ -243,6 +289,11 @@ static int cmd_p2p_scan(char **args, unsigned int n) return 0; } + if (!l->managed) { + cli_printf("link %s not managed\n", l->label); + return 0; + } + return ctl_link_set_p2p_scanning(l, !stop); } @@ -290,6 +341,11 @@ static int cmd_connect(char **args, unsigned int n) pin = ""; } + if (!p->l->managed) { + cli_printf("link %s not managed\n", p->l->label); + return 0; + } + return ctl_peer_connect(p, prov, pin); } @@ -312,6 +368,11 @@ static int cmd_disconnect(char **args, unsigned int n) return 0; } + if (!p->l->managed) { + cli_printf("link %s not managed\n", p->l->label); + return 0; + } + return ctl_peer_disconnect(p); } @@ -334,6 +395,7 @@ static const struct cli_cmd cli_cmds[] = { { "select", "[link]", CLI_Y, CLI_LESS, 1, cmd_select, "Select default link" }, { "show", "[link|peer]", CLI_M, CLI_LESS, 1, cmd_show, "Show detailed object information" }, { "set-friendly-name", "[link] ", CLI_M, CLI_LESS, 2, cmd_set_friendly_name, "Set friendly name of an object" }, + { "set-managed", "[link] ", CLI_M, CLI_LESS, 2, cmd_set_managed, "Manage or unmnage a link" }, { "p2p-scan", "[link] [stop]", CLI_Y, CLI_LESS, 2, cmd_p2p_scan, "Control neighborhood P2P scanning" }, { "connect", " [provision] [pin]", CLI_M, CLI_LESS, 3, cmd_connect, "Connect to peer" }, { "disconnect", "", CLI_M, CLI_EQUAL, 1, cmd_disconnect, "Disconnect from peer" }, diff --git a/src/shared/shl_log.h b/src/shared/shl_log.h index bd08601..43e972b 100644 --- a/src/shared/shl_log.h +++ b/src/shared/shl_log.h @@ -231,4 +231,9 @@ extern const char *LOG_SUBSYSTEM; #define log_vERR(_r) \ ((void)log_ERR(_r)) +#define log_EUNMANAGED() \ + (log_error("interface unmanaged"), -EFAULT) +#define log_vEUNMANAGED() \ + ((void)log_EUNMANAGED()) + #endif /* SHL_LOG_H */ diff --git a/src/wifi/wifid-dbus.c b/src/wifi/wifid-dbus.c index e7f73ec..c45dc89 100644 --- a/src/wifi/wifid-dbus.c +++ b/src/wifi/wifid-dbus.c @@ -571,6 +571,42 @@ static int link_dbus_set_friendly_name(sd_bus *bus, 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, @@ -662,6 +698,12 @@ static const sd_bus_vtable link_dbus_vtable[] = { 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, diff --git a/src/wifi/wifid-link.c b/src/wifi/wifid-link.c index bc69557..81cef73 100644 --- a/src/wifi/wifid-link.c +++ b/src/wifi/wifid-link.c @@ -100,6 +100,8 @@ int link_new(struct manager *m, if (out) *out = l; + l->public = true; + link_dbus_added(l); return 0; error: @@ -116,6 +118,9 @@ void link_free(struct link *l) link_set_managed(l, false); + link_dbus_removed(l); + l->public = false; + if (shl_htable_remove_uint(&l->m->links, l->ifindex, NULL)) { log_info("remove link: %s", l->ifname); --l->m->link_cnt; @@ -159,14 +164,19 @@ int link_set_config_methods(struct link *l, char *config_methods) return 0; } -void link_set_managed(struct link *l, bool set) +bool link_get_managed(struct link *l) +{ + return l->managed; +} + +int link_set_managed(struct link *l, bool set) { int r; if (!l) - return log_vEINVAL(); + return log_EINVAL(); if (l->managed == set) - return; + return 0; if (set) { log_info("manage link %s", l->ifname); @@ -174,7 +184,7 @@ void link_set_managed(struct link *l, bool set) r = supplicant_start(l->s); if (r < 0) { log_error("cannot start supplicant on %s", l->ifname); - return; + return -EFAULT; } } else { log_info("link %s no longer managed", l->ifname); @@ -182,6 +192,7 @@ void link_set_managed(struct link *l, bool set) } l->managed = set; + return 0; } int link_renamed(struct link *l, const char *ifname) @@ -216,6 +227,9 @@ int link_set_friendly_name(struct link *l, const char *name) if (!l || !name || !*name) return log_EINVAL(); + if (!l->managed) + return log_EUNMANAGED(); + t = strdup(name); if (!t) return log_ENOMEM(); @@ -251,6 +265,9 @@ int link_set_wfd_subelements(struct link *l, const char *val) if (!l || !val) return log_EINVAL(); + if (!l->managed) + return log_EUNMANAGED(); + t = strdup(val); if (!t) return log_ENOMEM(); @@ -283,6 +300,9 @@ int link_set_p2p_scanning(struct link *l, bool set) if (!l) return log_EINVAL(); + if (!l->managed) + return log_EUNMANAGED(); + if (set) { return supplicant_p2p_start_scan(l->s); } else { @@ -293,7 +313,16 @@ int link_set_p2p_scanning(struct link *l, bool set) bool link_get_p2p_scanning(struct link *l) { - return l && supplicant_p2p_scanning(l->s); + if (!l) { + log_vEINVAL(); + return false; + } + + if (!l->managed) { + return false; + } + + return supplicant_p2p_scanning(l->s); } void link_supplicant_started(struct link *l) @@ -301,9 +330,8 @@ 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); + link_set_friendly_name(l, l->m->friendly_name); + log_info("link %s managed", l->ifname); } void link_supplicant_stopped(struct link *l) @@ -311,9 +339,7 @@ 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; + log_info("link %s unmanaged", l->ifname); } void link_supplicant_p2p_scan_changed(struct link *l, bool new_value) diff --git a/src/wifi/wifid.c b/src/wifi/wifid.c index 4c0f02c..72209f4 100644 --- a/src/wifi/wifid.c +++ b/src/wifi/wifid.c @@ -44,6 +44,7 @@ const char *interface_name = NULL; const char *config_methods = NULL; unsigned int arg_wpa_loglevel = LOG_NOTICE; bool use_dev = false; +bool lazy_managed = false; /* * Manager Handling @@ -109,9 +110,9 @@ static void manager_add_udev_link(struct manager *m, link_use_dev(l); #ifdef RELY_UDEV - if (udev_device_has_tag(d, "miracle")) { + if (udev_device_has_tag(d, "miracle") && !lazy_managed) { #else - if (!interface_name || !strcmp(interface_name, ifname)) { + if ((!interface_name || !strcmp(interface_name, ifname)) && !lazy_managed) { #endif link_set_managed(l, true); } else { @@ -152,12 +153,12 @@ static int manager_udev_fn(sd_event_source *source, } #ifdef RELY_UDEV - if (udev_device_has_tag(d, "miracle")) + if (udev_device_has_tag(d, "miracle") && !lazy_managed) link_set_managed(l, true); else link_set_managed(l, false); #else - if (!interface_name || !strcmp(interface_name, ifname)) { + if ((!interface_name || !strcmp(interface_name, ifname)) && !lazy_managed) { link_set_managed(l, true); } else { log_debug("ignored device: %s", ifname); @@ -230,7 +231,7 @@ static int manager_new(struct manager **out) unsigned int i; sigset_t mask; int r; - char *cm; + char *cm; m = calloc(1, sizeof(*m)); if (!m) @@ -477,6 +478,7 @@ static int help(void) "\n" " --wpa-loglevel