X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=client%2Fcommands.c;h=94c375dd198d0f445d88ecff29d191da24efd567;hb=dd3cccc5e67548dcc2dd6c6254ed6c97859085d5;hp=9c01fd534b04a3513865bd51e13a0bb4f6b8881a;hpb=1b9d0a62f59bb48c8deb2f0b98d9acdffdd9abe7;p=platform%2Fupstream%2Fconnman.git diff --git a/client/commands.c b/client/commands.c index 9c01fd5..94c375d 100644 --- a/client/commands.c +++ b/client/commands.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,7 @@ #include "dbus_helpers.h" #include "input.h" #include "services.h" +#include "tethering.h" #include "peers.h" #include "commands.h" #include "agent.h" @@ -45,6 +47,7 @@ static DBusConnection *connection; static GHashTable *service_hash; +static GHashTable *vpnconnection_hash; static GHashTable *peer_hash; static GHashTable *technology_hash; static char *session_notify_path; @@ -139,7 +142,7 @@ static int parse_args(char *arg, struct connman_option *options) return '?'; } -static int enable_return(DBusMessageIter *iter, const char *error, +static int enable_return(DBusMessageIter *iter, int errnum, const char *error, void *user_data) { char *tech = user_data; @@ -151,10 +154,19 @@ static int enable_return(DBusMessageIter *iter, const char *error, else str = tech; - if (!error) + switch (errnum) { + case 0: fprintf(stdout, "Enabled %s\n", str); - else + break; + case -ENODEV: + fprintf(stderr, "%s is not available\n", str); + break; + case -EALREADY: + fprintf(stderr, "%s is already enabled\n", str); + break; + default: fprintf(stderr, "Error %s: %s\n", str, error); + } g_free(user_data); @@ -188,7 +200,7 @@ static int cmd_enable(char *args[], int num, struct connman_option *options) "Powered", DBUS_TYPE_BOOLEAN, &b); } -static int disable_return(DBusMessageIter *iter, const char *error, +static int disable_return(DBusMessageIter *iter, int errnum, const char *error, void *user_data) { char *tech = user_data; @@ -200,10 +212,19 @@ static int disable_return(DBusMessageIter *iter, const char *error, else str = tech; - if (!error) - fprintf(stdout, "Disabled %s\n", str); - else + switch (errnum) { + case 0: + fprintf(stdout, "Disable %s\n", str); + break; + case -ENODEV: + fprintf(stderr, "%s is not available\n", str); + break; + case -EALREADY: + fprintf(stderr, "%s is already disabled\n", str); + break; + default: fprintf(stderr, "Error %s: %s\n", str, error); + } g_free(user_data); @@ -237,13 +258,13 @@ static int cmd_disable(char *args[], int num, struct connman_option *options) "Powered", DBUS_TYPE_BOOLEAN, &b); } -static int state_print(DBusMessageIter *iter, const char *error, +static int state_print(DBusMessageIter *iter, int errnum, const char *error, void *user_data) { DBusMessageIter entry; if (error) { - fprintf(stderr, "Error: %s", error); + fprintf(stderr, "Error: %s\n", error); return 0; } @@ -264,7 +285,34 @@ static int cmd_state(char *args[], int num, struct connman_option *options) state_print, NULL, NULL, NULL); } -static int services_list(DBusMessageIter *iter, const char *error, +static int clock_print(DBusMessageIter *iter, int errnum, const char *error, + void *user_data) +{ + DBusMessageIter entry; + + if (error) { + fprintf(stderr, "Error: %s\n", error); + return 0; + } + + dbus_message_iter_recurse(iter, &entry); + __connmanctl_dbus_print(&entry, " ", " = ", "\n"); + fprintf(stdout, "\n"); + + return 0; +} + +static int cmd_clock(char *args[], int num, struct connman_option *options) +{ + if (num > 1) + return -E2BIG; + + return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, + CONNMAN_PATH, "net.connman.Clock", "GetProperties", + clock_print, NULL, NULL, NULL); +} + +static int services_list(DBusMessageIter *iter, int errnum, const char *error, void *user_data) { if (!error) { @@ -277,7 +325,7 @@ static int services_list(DBusMessageIter *iter, const char *error, return 0; } -static int peers_list(DBusMessageIter *iter, +static int peers_list(DBusMessageIter *iter, int errnum, const char *error, void *user_data) { if (!error) { @@ -289,7 +337,19 @@ static int peers_list(DBusMessageIter *iter, return 0; } -static int object_properties(DBusMessageIter *iter, +static int tethering_clients_list(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) +{ + if (!error) { + __connmanctl_tethering_clients_list(iter); + fprintf(stdout, "\n"); + } else + fprintf(stderr, "Error: %s\n", error); + + return 0; +} + +static int object_properties(DBusMessageIter *iter, int errnum, const char *error, void *user_data) { char *path = user_data; @@ -387,7 +447,7 @@ static int cmd_peers(char *args[], int num, struct connman_option *options) object_properties, path, NULL, NULL); } -static int technology_print(DBusMessageIter *iter, const char *error, +static int technology_print(DBusMessageIter *iter, int errnum, const char *error, void *user_data) { DBusMessageIter array; @@ -434,8 +494,8 @@ struct tether_enable { dbus_bool_t enable; }; -static int tether_set_return(DBusMessageIter *iter, const char *error, - void *user_data) +static int tether_set_return(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { struct tether_enable *tether = user_data; char *str; @@ -494,8 +554,13 @@ struct tether_properties { static int tether_update(struct tether_properties *tether) { - if (tether->ssid_result == 0 && tether->passphrase_result == 0) - return tether_set("wifi", tether->set_tethering); + int ret; + + if (tether->ssid_result == 0 && tether->passphrase_result == 0) { + ret = tether_set("wifi", tether->set_tethering); + g_free(tether); + return ret; + } if (tether->ssid_result != -EINPROGRESS && tether->passphrase_result != -EINPROGRESS) { @@ -506,8 +571,8 @@ static int tether_update(struct tether_properties *tether) return -EINPROGRESS; } -static int tether_set_ssid_return(DBusMessageIter *iter, const char *error, - void *user_data) +static int tether_set_ssid_return(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { struct tether_properties *tether = user_data; @@ -522,8 +587,8 @@ static int tether_set_ssid_return(DBusMessageIter *iter, const char *error, return tether_update(tether); } -static int tether_set_passphrase_return(DBusMessageIter *iter, - const char *error, void *user_data) +static int tether_set_passphrase_return(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { struct tether_properties *tether = user_data; @@ -605,7 +670,18 @@ static int cmd_tether(char *args[], int num, struct connman_option *options) return tether_set(args[1], set_tethering); } -static int scan_return(DBusMessageIter *iter, const char *error, +static int cmd_tethering_clients(char *args[], int num, struct connman_option *options) +{ + if (num > 1) + return -E2BIG; + + return __connmanctl_dbus_method_call(connection, + CONNMAN_SERVICE, CONNMAN_PATH, + "net.connman.Manager", "GetTetheringClients", + tethering_clients_list, NULL, NULL, NULL); +} + +static int scan_return(DBusMessageIter *iter, int ernnum, const char *error, void *user_data) { char *path = user_data; @@ -641,8 +717,8 @@ static int cmd_scan(char *args[], int num, struct connman_option *options) scan_return, path, NULL, NULL); } -static int connect_return(DBusMessageIter *iter, const char *error, - void *user_data) +static int connect_return(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { char *path = user_data; @@ -660,6 +736,7 @@ static int connect_return(DBusMessageIter *iter, const char *error, static int cmd_connect(char *args[], int num, struct connman_option *options) { + const char *iface = "net.connman.Service"; char *path; if (num > 2) @@ -671,14 +748,18 @@ static int cmd_connect(char *args[], int num, struct connman_option *options) if (check_dbus_name(args[1]) == false) return -EINVAL; - path = g_strdup_printf("/net/connman/service/%s", args[1]); + if (g_strstr_len(args[1], 5, "peer_") == args[1]) { + iface = "net.connman.Peer"; + path = g_strdup_printf("/net/connman/peer/%s", args[1]); + } else + path = g_strdup_printf("/net/connman/service/%s", args[1]); + return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path, - "net.connman.Service", "Connect", - connect_return, path, NULL, NULL); + iface, "Connect", connect_return, path, NULL, NULL); } -static int disconnect_return(DBusMessageIter *iter, const char *error, - void *user_data) +static int disconnect_return(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { char *path = user_data; @@ -696,6 +777,7 @@ static int disconnect_return(DBusMessageIter *iter, const char *error, static int cmd_disconnect(char *args[], int num, struct connman_option *options) { + const char *iface = "net.connman.Service"; char *path; if (num > 2) @@ -707,14 +789,140 @@ static int cmd_disconnect(char *args[], int num, struct connman_option *options) if (check_dbus_name(args[1]) == false) return -EINVAL; - path = g_strdup_printf("/net/connman/service/%s", args[1]); - return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path, - "net.connman.Service", "Disconnect", - disconnect_return, path, NULL, NULL); + if (g_strstr_len(args[1], 5, "peer_") == args[1]) { + iface = "net.connman.Peer"; + path = g_strdup_printf("/net/connman/peer/%s", args[1]); + } else + path = g_strdup_printf("/net/connman/service/%s", args[1]); + + return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, + path, iface, "Disconnect", + disconnect_return, path, NULL, NULL); } -static int config_return(DBusMessageIter *iter, const char *error, - void *user_data) +struct move_service { + char *service; + char *target; +}; + +static int move_before_return(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) +{ + struct move_service *services = user_data; + char *service; + char *target; + + if (!error) { + service = strrchr(services->service, '/'); + service++; + target = strrchr(services->target, '/'); + target++; + fprintf(stdout, "Moved %s before %s\n", service, target); + } else + fprintf(stderr, "Error %s: %s\n", services->service, error); + + g_free(services->service); + g_free(services->target); + g_free(user_data); + + return 0; +} + +static void move_before_append_args(DBusMessageIter *iter, void *user_data) +{ + char *path = user_data; + + dbus_message_iter_append_basic(iter, + DBUS_TYPE_OBJECT_PATH, &path); +} + +static int cmd_service_move_before(char *args[], int num, + struct connman_option *options) +{ + const char *iface = "net.connman.Service"; + struct move_service *services; + + if (num > 3) + return -E2BIG; + + if (num < 3) + return -EINVAL; + + if (check_dbus_name(args[1]) == false) + return -EINVAL; + + services = g_new(struct move_service, 1); + + services->service = g_strdup_printf("/net/connman/service/%s", args[1]); + services->target = g_strdup_printf("/net/connman/service/%s", args[2]); + + return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, + services->service, iface, "MoveBefore", + move_before_return, services, + move_before_append_args, + services->target); +} + +static int move_after_return(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) +{ + struct move_service *services = user_data; + char *service; + char *target; + + if (!error) { + service = strrchr(services->service, '/'); + service++; + target = strrchr(services->target, '/'); + target++; + fprintf(stdout, "Moved %s after %s\n", service, target); + } else + fprintf(stderr, "Error %s: %s\n", services->service, error); + + g_free(services->service); + g_free(services->target); + g_free(user_data); + + return 0; +} + +static void move_after_append_args(DBusMessageIter *iter, void *user_data) +{ + char *path = user_data; + + dbus_message_iter_append_basic(iter, + DBUS_TYPE_OBJECT_PATH, &path); +} + +static int cmd_service_move_after(char *args[], int num, + struct connman_option *options) +{ + const char *iface = "net.connman.Service"; + struct move_service *services; + + if (num > 3) + return -E2BIG; + + if (num < 3) + return -EINVAL; + + if (check_dbus_name(args[1]) == false) + return -EINVAL; + + services = g_new(struct move_service, 1); + + services->service = g_strdup_printf("/net/connman/service/%s", args[1]); + services->target = g_strdup_printf("/net/connman/service/%s", args[2]); + + return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, + services->service, iface, "MoveAfter", + move_after_return, services, + move_after_append_args, + services->target); +} + +static int config_return(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { char *service_name = user_data; @@ -731,6 +939,13 @@ struct config_append { int values; }; +struct session_options { + char **args; + int num; + char *notify_path; + struct connman_option *options; +}; + static void config_append_ipv4(DBusMessageIter *iter, void *user_data) { @@ -1032,6 +1247,30 @@ static int cmd_config(char *args[], int num, struct connman_option *options) config_return, g_strdup(service_name), NULL, NULL); break; + + case 'm': + switch (parse_boolean(*opt_start)) { + case 1: + val = TRUE; + break; + case 0: + val = FALSE; + break; + default: + res = -EINVAL; + break; + } + if (res == 0) { + res = __connmanctl_dbus_set_property(connection, + path, "net.connman.Service", + config_return, + g_strdup(service_name), + "mDNS.Configuration", + DBUS_TYPE_BOOLEAN, &val); + } + index++; + break; + default: res = -EINVAL; break; @@ -1339,8 +1578,8 @@ static int cmd_agent(char *args[], int num, struct connman_option *options) return 0; } -static int vpnconnections_properties(DBusMessageIter *iter, const char *error, - void *user_data) +static int vpnconnections_properties(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { char *path = user_data; char *str; @@ -1369,8 +1608,8 @@ static int vpnconnections_properties(DBusMessageIter *iter, const char *error, return 0; } -static int vpnconnections_list(DBusMessageIter *iter, const char *error, - void *user_data) +static int vpnconnections_list(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { if (!error) __connmanctl_vpnconnections_list(iter); @@ -1561,11 +1800,11 @@ static void session_notify_remove(void) session_notify_path = NULL; } -static int session_connect_cb(DBusMessageIter *iter, const char *error, - void *user_data) +static int session_connect_cb(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { if (error) { - fprintf(stderr, "Error: %s", error); + fprintf(stderr, "Error: %s\n", error); return 0; } @@ -1580,11 +1819,11 @@ static int session_connect(void) session_connect_cb, NULL, NULL, NULL); } -static int session_disconnect_cb(DBusMessageIter *iter, const char *error, - void *user_data) +static int session_disconnect_cb(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { if (error) - fprintf(stderr, "Error: %s", error); + fprintf(stderr, "Error: %s\n", error); return 0; } @@ -1596,8 +1835,8 @@ static int session_disconnect(void) session_disconnect_cb, NULL, NULL, NULL); } -static int session_create_cb(DBusMessageIter *iter, const char *error, - void *user_data) +static int session_create_cb(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { gboolean connect = GPOINTER_TO_INT(user_data); char *str; @@ -1626,28 +1865,140 @@ static int session_create_cb(DBusMessageIter *iter, const char *error, return -EINPROGRESS; } +static void session_config_append_array(DBusMessageIter *iter, + void *user_data) +{ + struct config_append *append = user_data; + char **opts = append->opts; + int i = 1; + + if (!opts) + return; + + while (opts[i] && strncmp(opts[i], "--", 2) != 0) { + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, + &opts[i]); + i++; + } + + append->values = i; +} + +static void session_create_append_dict(DBusMessageIter *iter, void *user_data) +{ + struct session_options *args_struct = user_data; + int index = 0, res = 0; + struct config_append append; + char c; + char *ifname; + dbus_bool_t source_ip_rule; + + while (index < args_struct->num && args_struct->args[index]) { + append.opts = &args_struct->args[index]; + append.values = 0; + + c = parse_args(args_struct->args[index], args_struct->options); + + switch (c) { + case 'b': + __connmanctl_dbus_append_dict_string_array(iter, "AllowedBearers", + session_config_append_array, + &append); + break; + case 't': + if (! args_struct->args[index + 1]) { + res = -EINVAL; + break; + } + __connmanctl_dbus_append_dict_entry(iter, "ConnectionType", + DBUS_TYPE_STRING, + &args_struct->args[index + 1]); + append.values = 2; + break; + case 'i': + if (index + 1 < args_struct->num) + ifname = args_struct->args[index + 1]; + else + ifname = ""; + __connmanctl_dbus_append_dict_entry(iter, "AllowedInterface", + DBUS_TYPE_STRING, + &ifname); + append.values = 2; + break; + case 's': + if (! args_struct->args[index + 1]) { + res = -EINVAL; + break; + } + switch (parse_boolean( args_struct->args[index + 1])) { + case 1: + source_ip_rule = TRUE; + break; + case 0: + source_ip_rule = FALSE; + break; + default: + res = -EINVAL; + break; + } + __connmanctl_dbus_append_dict_entry(iter, "SourceIPRule", + DBUS_TYPE_BOOLEAN, + &source_ip_rule); + append.values = 2; + break; + case 'c': + if (!args_struct->args[index + 1]) { + res = -EINVAL; + break; + } + __connmanctl_dbus_append_dict_entry(iter, "ContextIdentifier", + DBUS_TYPE_STRING, + &args_struct->args[index + 1]); + append.values = 2; + break; + default: + res = -EINVAL; + } + + if (res < 0 && res != -EINPROGRESS) { + printf("Error '%s': %s\n", args_struct->args[index], + strerror(-res)); + return; + } + + index += append.values; + } +} + static void session_create_append(DBusMessageIter *iter, void *user_data) { - const char *notify_path = user_data; + struct session_options *args_struct = user_data; - __connmanctl_dbus_append_dict(iter, NULL, NULL); + __connmanctl_dbus_append_dict(iter, session_create_append_dict, + args_struct); dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, - ¬ify_path); + &args_struct->notify_path); } -static int session_create(gboolean connect) +static int session_create(gboolean connect, char *args[], int num, + struct connman_option *options) { int res; char *notify_path; + struct session_options args_struct; + args_struct.args = args; + args_struct.num = num; + args_struct.options = options; notify_path = g_strdup_printf("/net/connman/connmanctl%d", getpid()); session_notify_add(notify_path); + args_struct.notify_path = notify_path; res = __connmanctl_dbus_method_call(connection, "net.connman", "/", "net.connman.Manager", "CreateSession", session_create_cb, GINT_TO_POINTER(connect), - session_create_append, notify_path); + session_create_append, &args_struct); g_free(notify_path); @@ -1657,8 +2008,8 @@ static int session_create(gboolean connect) return res; } -static int session_destroy_cb(DBusMessageIter *iter, const char *error, - void *user_data) +static int session_destroy_cb(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { if (error) { fprintf(stderr, "Error destroying session: %s", error); @@ -1689,8 +2040,8 @@ static int session_destroy(void) session_destroy_append, session_path); } -static int session_config_return(DBusMessageIter *iter, const char *error, - void *user_data) +static int session_config_return(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { char *property_name = user_data; @@ -1701,31 +2052,14 @@ static int session_config_return(DBusMessageIter *iter, const char *error, return 0; } -static void session_config_append_array(DBusMessageIter *iter, - void *user_data) -{ - struct config_append *append = user_data; - char **opts = append->opts; - int i = 1; - - if (!opts) - return; - - while (opts[i] && strncmp(opts[i], "--", 2) != 0) { - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, - &opts[i]); - i++; - } - - append->values = i; -} - static int session_config(char *args[], int num, struct connman_option *options) { int index = 0, res = 0; struct config_append append; char c; + char *ifname; + dbus_bool_t source_ip_rule; while (index < num && args[index]) { append.opts = &args[index]; @@ -1752,6 +2086,53 @@ static int session_config(char *args[], int num, DBUS_TYPE_STRING, &args[index + 1]); append.values = 2; break; + case 'i': + if (index + 1 < num) + ifname = args[index + 1]; + else + ifname = ""; + + res = __connmanctl_dbus_session_change(connection, + session_path, session_config_return, + "AllowedInterface", "AllowedInterface", + DBUS_TYPE_STRING, &ifname); + append.values = 2; + break; + case 's': + if (!args[index + 1]) { + res = -EINVAL; + break; + } + switch (parse_boolean(args[index + 1])) { + case 1: + source_ip_rule = TRUE; + break; + case 0: + source_ip_rule = FALSE; + break; + default: + res = -EINVAL; + break; + } + + res = __connmanctl_dbus_session_change(connection, + session_path, session_config_return, + "SourceIPRule", "SourceIPRule", + DBUS_TYPE_BOOLEAN, &source_ip_rule); + append.values = 2; + break; + case 'c': + if (!args[index + 1]) { + res = -EINVAL; + break; + } + + res = __connmanctl_dbus_session_change(connection, + session_path, session_config_return, + "ctxid", "ctxid", DBUS_TYPE_STRING, + &args[index + 1]); + append.values = 2; + break; default: res = -EINVAL; @@ -1787,12 +2168,13 @@ static int cmd_session(char *args[], int num, struct connman_option *options) case 1: if (session_path) return -EALREADY; - return session_create(FALSE); + return session_create(FALSE, &args[2], num - 2, options); default: if (!strcmp(command, "connect")) { if (!session_path) - return session_create(TRUE); + return session_create(TRUE, &args[2], num - 2, + options); return session_connect(); @@ -1826,22 +2208,21 @@ static int cmd_exit(char *args[], int num, struct connman_option *options) return 1; } -static char *lookup_service(const char *text, int state) +static char *lookup_key_from_table(GHashTable *hash, const char *text, + int state) { static int len = 0; static GHashTableIter iter; gpointer key, value; if (state == 0) { - g_hash_table_iter_init(&iter, service_hash); + g_hash_table_iter_init(&iter, hash); len = strlen(text); } - while (g_hash_table_iter_next(&iter, &key, &value)) { - const char *service = key; - if (strncmp(text, service, len) == 0) - return strdup(service); - } + while (g_hash_table_iter_next(&iter, &key, &value)) + if (strncmp(text, key, len) == 0) + return strdup(key); return NULL; } @@ -1853,7 +2234,7 @@ static char *lookup_service_arg(const char *text, int state) return NULL; } - return lookup_service(text, state); + return lookup_key_from_table(service_hash, text, state); } static char *lookup_peer(const char *text, int state) @@ -1997,6 +2378,16 @@ static char *lookup_agent(const char *text, int state) return lookup_on_off(text, state); } +static char *lookup_vpnconnection_arg(const char *text, int state) +{ + if (__connmanctl_input_calc_level() > 1) { + __connmanctl_input_lookup_end(); + return NULL; + } + + return lookup_key_from_table(vpnconnection_hash, text, state); +} + static struct connman_option service_options[] = { {"properties", 'p', "[] (obsolete)"}, { NULL, } @@ -2006,6 +2397,7 @@ static struct connman_option config_options[] = { {"nameservers", 'n', " [] []"}, {"timeservers", 't', " [] [...]"}, {"domains", 'd', " [] [...]"}, + {"mdns", 'm', "yes|no"}, {"ipv6", 'v', "off|auto [enable|disable|preferred]|\n" "\t\t\tmanual
"}, {"proxy", 'x', "direct|auto |manual [] [...]\n" @@ -2030,6 +2422,9 @@ static struct connman_option monitor_options[] = { static struct connman_option session_options[] = { {"bearers", 'b', " [ [...]]"}, {"type", 't', "local|internet|any"}, + {"ifname", 'i', "[]"}, + {"srciprule", 's', "yes|no"}, + {"ctxid", 'c', ""}, { NULL, } }; @@ -2075,7 +2470,7 @@ static char *lookup_monitor(const char *text, int state) static char *lookup_config(const char *text, int state) { if (__connmanctl_input_calc_level() < 2) - return lookup_service(text, state); + return lookup_key_from_table(service_hash, text, state); return lookup_options(config_options, text, state); } @@ -2085,6 +2480,273 @@ static char *lookup_session(const char *text, int state) return lookup_options(session_options, text, state); } +static int peer_service_cb(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) +{ + bool registration = GPOINTER_TO_INT(user_data); + + if (error) + fprintf(stderr, "Error %s peer service: %s\n", + registration ? "registering" : "unregistering", error); + else + fprintf(stdout, "Peer service %s\n", + registration ? "registered" : "unregistered"); + + return 0; +} + +struct _peer_service { + unsigned char *bjr_query; + int bjr_query_len; + unsigned char *bjr_response; + int bjr_response_len; + unsigned char *wfd_ies; + int wfd_ies_len; + char *upnp_service; + int version; + int master; +}; + +static void append_dict_entry_fixed_array(DBusMessageIter *iter, + const char *property, void *value, int length) +{ + DBusMessageIter dict_entry, variant, array; + + dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, + NULL, &dict_entry); + dbus_message_iter_append_basic(&dict_entry, DBUS_TYPE_STRING, + &property); + dbus_message_iter_open_container(&dict_entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, + &variant); + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + value, length); + dbus_message_iter_close_container(&variant, &array); + dbus_message_iter_close_container(&dict_entry, &variant); + dbus_message_iter_close_container(iter, &dict_entry); +} + +static void append_peer_service_dict(DBusMessageIter *iter, void *user_data) +{ + struct _peer_service *service = user_data; + + if (service->bjr_query && service->bjr_response) { + append_dict_entry_fixed_array(iter, "BonjourQuery", + &service->bjr_query, service->bjr_query_len); + append_dict_entry_fixed_array(iter, "BonjourResponse", + &service->bjr_response, service->bjr_response_len); + } else if (service->upnp_service && service->version) { + __connmanctl_dbus_append_dict_entry(iter, "UpnpVersion", + DBUS_TYPE_INT32, &service->version); + __connmanctl_dbus_append_dict_entry(iter, "UpnpService", + DBUS_TYPE_STRING, &service->upnp_service); + } else if (service->wfd_ies) { + append_dict_entry_fixed_array(iter, "WiFiDisplayIEs", + &service->wfd_ies, service->wfd_ies_len); + } +} + +static void peer_service_append(DBusMessageIter *iter, void *user_data) +{ + struct _peer_service *service = user_data; + dbus_bool_t master; + + __connmanctl_dbus_append_dict(iter, append_peer_service_dict, service); + + if (service->master < 0) + return; + + master = service->master == 1 ? TRUE : FALSE; + dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &master); +} + +static struct _peer_service *fill_in_peer_service(unsigned char *bjr_query, + int bjr_query_len, unsigned char *bjr_response, + int bjr_response_len, char *upnp_service, + int version, unsigned char *wfd_ies, + int wfd_ies_len) +{ + struct _peer_service *service; + + service = dbus_malloc0(sizeof(*service)); + + if (bjr_query_len && bjr_response_len) { + service->bjr_query = dbus_malloc0(bjr_query_len); + memcpy(service->bjr_query, bjr_query, bjr_query_len); + service->bjr_query_len = bjr_query_len; + + service->bjr_response = dbus_malloc0(bjr_response_len); + memcpy(service->bjr_response, bjr_response, bjr_response_len); + service->bjr_response_len = bjr_response_len; + } else if (upnp_service && version) { + service->upnp_service = strdup(upnp_service); + service->version = version; + } else if (wfd_ies && wfd_ies_len) { + service->wfd_ies = dbus_malloc0(wfd_ies_len); + memcpy(service->wfd_ies, wfd_ies, wfd_ies_len); + service->wfd_ies_len = wfd_ies_len; + } else { + dbus_free(service); + service = NULL; + } + + return service; +} + +static void free_peer_service(struct _peer_service *service) +{ + dbus_free(service->bjr_query); + dbus_free(service->bjr_response); + dbus_free(service->wfd_ies); + free(service->upnp_service); + dbus_free(service); +} + +static int peer_service_register(unsigned char *bjr_query, int bjr_query_len, + unsigned char *bjr_response, int bjr_response_len, + char *upnp_service, int version, + unsigned char *wfd_ies, int wfd_ies_len, int master) +{ + struct _peer_service *service; + bool registration = true; + int ret; + + service = fill_in_peer_service(bjr_query, bjr_query_len, bjr_response, + bjr_response_len, upnp_service, version, + wfd_ies, wfd_ies_len); + if (!service) + return -EINVAL; + + service->master = master; + + ret = __connmanctl_dbus_method_call(connection, "net.connman", "/", + "net.connman.Manager", "RegisterPeerService", + peer_service_cb, GINT_TO_POINTER(registration), + peer_service_append, service); + + free_peer_service(service); + + return ret; +} + +static int peer_service_unregister(unsigned char *bjr_query, int bjr_query_len, + unsigned char *bjr_response, int bjr_response_len, + char *upnp_service, int version, + unsigned char *wfd_ies, int wfd_ies_len) +{ + struct _peer_service *service; + bool registration = false; + int ret; + + service = fill_in_peer_service(bjr_query, bjr_query_len, bjr_response, + bjr_response_len, upnp_service, version, + wfd_ies, wfd_ies_len); + if (!service) + return -EINVAL; + + service->master = -1; + + ret = __connmanctl_dbus_method_call(connection, "net.connman", "/", + "net.connman.Manager", "UnregisterPeerService", + peer_service_cb, GINT_TO_POINTER(registration), + peer_service_append, service); + + free_peer_service(service); + + return ret; +} + +static int parse_spec_array(char *command, unsigned char spec[1024]) +{ + int length, pos, end; + char b[3] = {}; + char *e; + + end = strlen(command); + for (e = NULL, length = pos = 0; command[pos] != '\0'; length++) { + if (pos+2 > end) + return -EINVAL; + + b[0] = command[pos]; + b[1] = command[pos+1]; + + spec[length] = strtol(b, &e, 16); + if (e && *e != '\0') + return -EINVAL; + + pos += 2; + } + + return length; +} + +static int cmd_peer_service(char *args[], int num, + struct connman_option *options) +{ + unsigned char bjr_query[1024] = {}; + unsigned char bjr_response[1024] = {}; + unsigned char wfd_ies[1024] = {}; + char *upnp_service = NULL; + int bjr_query_len = 0, bjr_response_len = 0; + int version = 0, master = 0, wfd_ies_len = 0; + int limit; + + if (num < 4) + return -EINVAL; + + if (!strcmp(args[2], "wfd_ies")) { + wfd_ies_len = parse_spec_array(args[3], wfd_ies); + if (wfd_ies_len == -EINVAL) + return -EINVAL; + limit = 5; + goto master; + } + + if (num < 6) + return -EINVAL; + + limit = 7; + if (!strcmp(args[2], "bjr_query")) { + if (strcmp(args[4], "bjr_response")) + return -EINVAL; + bjr_query_len = parse_spec_array(args[3], bjr_query); + bjr_response_len = parse_spec_array(args[5], bjr_response); + + if (bjr_query_len == -EINVAL || bjr_response_len == -EINVAL) + return -EINVAL; + } else if (!strcmp(args[2], "upnp_service")) { + char *e = NULL; + + if (strcmp(args[4], "upnp_version")) + return -EINVAL; + upnp_service = args[3]; + version = strtol(args[5], &e, 10); + if (*e != '\0') + return -EINVAL; + } + +master: + if (num == limit) { + master = parse_boolean(args[6]); + if (master < 0) + return -EINVAL; + } + + if (!strcmp(args[1], "register")) { + return peer_service_register(bjr_query, bjr_query_len, + bjr_response, bjr_response_len, upnp_service, + version, wfd_ies, wfd_ies_len, master); + } else if (!strcmp(args[1], "unregister")) { + return peer_service_unregister(bjr_query, bjr_query_len, + bjr_response, bjr_response_len, upnp_service, + version, wfd_ies, wfd_ies_len); + } + + return -EINVAL; +} + static const struct { const char *cmd; const char *argument; @@ -2097,6 +2759,8 @@ static const struct { "Shows if the system is online or offline", NULL }, { "technologies", NULL, NULL, cmd_technologies, "Display technologies", NULL }, + { "clock", NULL, NULL, cmd_clock, + "Get System Clock Properties", NULL }, { "enable", "|offline", NULL, cmd_enable, "Enables given technology or offline mode", lookup_technology_offline }, @@ -2108,6 +2772,8 @@ static const struct { NULL, cmd_tether, "Enable, disable tethering, set SSID and passphrase for wifi", lookup_tether }, + { "tethering_clients", NULL, NULL, cmd_tethering_clients, + "Display tethering clients", NULL }, { "services", "[]", service_options, cmd_services, "Display services", lookup_service_arg }, { "peers", "[peer]", NULL, cmd_peers, @@ -2115,22 +2781,34 @@ static const struct { { "scan", "", NULL, cmd_scan, "Scans for new services for given technology", lookup_technology_arg }, - { "connect", "", NULL, cmd_connect, - "Connect a given service", lookup_service_arg }, - { "disconnect", "", NULL, cmd_disconnect, - "Disconnect a given service", lookup_service_arg }, + { "connect", "", NULL, cmd_connect, + "Connect a given service or peer", lookup_service_arg }, + { "disconnect", "", NULL, cmd_disconnect, + "Disconnect a given service or peer", lookup_service_arg }, + { "move-before", " ", NULL, + cmd_service_move_before, "Move before ", + lookup_service_arg }, + { "move-after", " ", NULL, + cmd_service_move_after, "Move after ", + lookup_service_arg }, { "config", "", config_options, cmd_config, "Set service configuration options", lookup_config }, { "monitor", "[off]", monitor_options, cmd_monitor, "Monitor signals from interfaces", lookup_monitor }, { "agent", "on|off", NULL, cmd_agent, "Agent mode", lookup_agent }, - {"vpnconnections", "[]", NULL, cmd_vpnconnections, - "Display VPN connections", NULL }, + { "vpnconnections", "[]", NULL, cmd_vpnconnections, + "Display VPN connections", lookup_vpnconnection_arg }, { "vpnagent", "on|off", NULL, cmd_vpnagent, "VPN Agent mode", lookup_agent }, { "session", "on|off|connect|disconnect|config", session_options, cmd_session, "Enable or disable a session", lookup_session }, + { "peer_service", "register|unregister \n" + "Where specs are:\n" + "\tbjr_query bjr_response \n" + "\tupnp_service upnp_version \n" + "\twfd_ies \n", NULL, + cmd_peer_service, "(Un)Register a Peer Service", NULL }, { "help", NULL, NULL, cmd_help, "Show help", NULL }, { "exit", NULL, NULL, cmd_exit, @@ -2312,13 +2990,84 @@ static void update_services(DBusMessageIter *iter) } } -static int populate_service_hash(DBusMessageIter *iter, const char *error, - void *user_data) +static int populate_service_hash(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { + if (error) { + fprintf(stderr, "Error getting services: %s", error); + return 0; + } + update_services(iter); return 0; } +static void add_vpnconnection_id(const char *path) +{ + g_hash_table_replace(vpnconnection_hash, g_strdup(path), + GINT_TO_POINTER(TRUE)); +} + +static void remove_vpnconnection_id(const char *path) +{ + g_hash_table_remove(vpnconnection_hash, path); +} + +static void vpnconnection_added(DBusMessageIter *iter) +{ + char *path = NULL; + + dbus_message_iter_get_basic(iter, &path); + add_vpnconnection_id(get_path(path)); +} + +static void vpnconnection_removed(DBusMessageIter *iter) +{ + char *path = NULL; + + dbus_message_iter_get_basic(iter, &path); + remove_vpnconnection_id(get_path(path)); +} + +static void add_vpnconnections(DBusMessageIter *iter) +{ + DBusMessageIter array; + char *path = NULL; + + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRUCT) { + + dbus_message_iter_recurse(iter, &array); + if (dbus_message_iter_get_arg_type(&array) != + DBUS_TYPE_OBJECT_PATH) + return; + + dbus_message_iter_get_basic(&array, &path); + add_vpnconnection_id(get_path(path)); + + dbus_message_iter_next(iter); + } +} + +static int populate_vpnconnection_hash(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) +{ + DBusMessageIter array; + + if (error) { + fprintf(stderr, "Error getting VPN connections: %s", error); + return 0; + } + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) + return 0; + + dbus_message_iter_recurse(iter, &array); + + add_vpnconnections(&array); + + return 0; +} + static void add_peer_id(const char *path) { g_hash_table_replace(peer_hash, g_strdup(path), GINT_TO_POINTER(TRUE)); @@ -2373,9 +3122,14 @@ static void update_peers(DBusMessageIter *iter) } } -static int populate_peer_hash(DBusMessageIter *iter, - const char *error, void *user_data) +static int populate_peer_hash(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { + if (error) { + fprintf(stderr, "Error getting peers: %s", error); + return 0; + } + update_peers(iter); return 0; } @@ -2433,9 +3187,14 @@ static void update_technologies(DBusMessageIter *iter) } } -static int populate_technology_hash(DBusMessageIter *iter, const char *error, - void *user_data) +static int populate_technology_hash(DBusMessageIter *iter, int errnum, + const char *error, void *user_data) { + if (error) { + fprintf(stderr, "Error getting technologies: %s\n", error); + return 0; + } + update_technologies(iter); return 0; @@ -2461,6 +3220,20 @@ static DBusHandlerResult monitor_completions_changed( return handled; } + if (dbus_message_is_signal(message, "net.connman.vpn.Manager", + "ConnectionAdded")) { + dbus_message_iter_init(message, &iter); + vpnconnection_added(&iter); + return handled; + } + + if (dbus_message_is_signal(message, "net.connman.vpn.Manager", + "ConnectionRemoved")) { + dbus_message_iter_init(message, &iter); + vpnconnection_removed(&iter); + return handled; + } + if (dbus_message_is_signal(message, "net.connman.Manager", "PeersChanged")) { dbus_message_iter_init(message, &iter); @@ -2504,10 +3277,14 @@ void __connmanctl_monitor_completions(DBusConnection *dbus_conn) if (!dbus_conn) { g_hash_table_destroy(service_hash); + g_hash_table_destroy(vpnconnection_hash); g_hash_table_destroy(technology_hash); dbus_bus_remove_match(connection, "type='signal',interface='net.connman.Manager'", NULL); + dbus_bus_remove_match(connection, + "type='signal',interface='net.connman.vpn.Manager'", + NULL); dbus_connection_remove_filter(connection, monitor_completions_changed, manager_enabled); @@ -2519,6 +3296,9 @@ void __connmanctl_monitor_completions(DBusConnection *dbus_conn) service_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + vpnconnection_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, NULL); + peer_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); @@ -2531,6 +3311,11 @@ void __connmanctl_monitor_completions(DBusConnection *dbus_conn) populate_service_hash, NULL, NULL, NULL); __connmanctl_dbus_method_call(connection, + VPN_SERVICE, CONNMAN_PATH, + "net.connman.vpn.Manager", "GetConnections", + populate_vpnconnection_hash, NULL, NULL, NULL); + + __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, CONNMAN_PATH, "net.connman.Manager", "GetPeers", populate_peer_hash, NULL, NULL, NULL); @@ -2548,6 +3333,15 @@ void __connmanctl_monitor_completions(DBusConnection *dbus_conn) dbus_bus_add_match(connection, "type='signal',interface='net.connman.Manager'", &err); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "Error: %s\n", err.message); + return; + } + + dbus_bus_add_match(connection, + "type='signal',interface='net.connman.vpn.Manager'", + &err); + if (dbus_error_is_set(&err)) fprintf(stderr, "Error: %s\n", err.message); }