#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
+#include <ctype.h>
#include <glib.h>
#include <gdbus.h>
#include "dbus_helpers.h"
#include "input.h"
#include "services.h"
+#include "tethering.h"
#include "peers.h"
#include "commands.h"
#include "agent.h"
static DBusConnection *connection;
static GHashTable *service_hash;
+static GHashTable *vpnconnection_hash;
static GHashTable *peer_hash;
static GHashTable *technology_hash;
static char *session_notify_path;
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;
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);
"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;
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);
"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;
}
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) {
return 0;
}
-static int peers_list(DBusMessageIter *iter,
+static int peers_list(DBusMessageIter *iter, int errnum,
const char *error, void *user_data)
{
if (!error) {
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;
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;
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;
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) {
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;
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;
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;
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;
static int cmd_connect(char *args[], int num, struct connman_option *options)
{
+ const char *iface = "net.connman.Service";
char *path;
if (num > 2)
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;
static int cmd_disconnect(char *args[], int num, struct connman_option *options)
{
+ const char *iface = "net.connman.Service";
char *path;
if (num > 2)
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;
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)
{
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;
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;
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);
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;
}
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;
}
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;
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);
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);
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;
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];
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;
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();
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;
}
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)
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', "[<service>] (obsolete)"},
{ NULL, }
{"nameservers", 'n', "<dns1> [<dns2>] [<dns3>]"},
{"timeservers", 't', "<ntp1> [<ntp2>] [...]"},
{"domains", 'd', "<domain1> [<domain2>] [...]"},
+ {"mdns", 'm', "yes|no"},
{"ipv6", 'v', "off|auto [enable|disable|preferred]|\n"
"\t\t\tmanual <address> <prefixlength> <gateway>"},
{"proxy", 'x', "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
static struct connman_option session_options[] = {
{"bearers", 'b', "<technology1> [<technology2> [...]]"},
{"type", 't', "local|internet|any"},
+ {"ifname", 'i', "[<interface_name>]"},
+ {"srciprule", 's', "yes|no"},
+ {"ctxid", 'c', "<context_identifier>"},
{ NULL, }
};
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);
}
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;
"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", "<technology>|offline", NULL, cmd_enable,
"Enables given technology or offline mode",
lookup_technology_offline },
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>]", service_options, cmd_services,
"Display services", lookup_service_arg },
{ "peers", "[peer]", NULL, cmd_peers,
{ "scan", "<technology>", NULL, cmd_scan,
"Scans for new services for given technology",
lookup_technology_arg },
- { "connect", "<service>", NULL, cmd_connect,
- "Connect a given service", lookup_service_arg },
- { "disconnect", "<service>", NULL, cmd_disconnect,
- "Disconnect a given service", lookup_service_arg },
+ { "connect", "<service/peer>", NULL, cmd_connect,
+ "Connect a given service or peer", lookup_service_arg },
+ { "disconnect", "<service/peer>", NULL, cmd_disconnect,
+ "Disconnect a given service or peer", lookup_service_arg },
+ { "move-before", "<service> <target service> ", NULL,
+ cmd_service_move_before, "Move <service> before <target service>",
+ lookup_service_arg },
+ { "move-after", "<service> <target service> ", NULL,
+ cmd_service_move_after, "Move <service> after <target service>",
+ lookup_service_arg },
{ "config", "<service>", 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", "[<connection>]", NULL, cmd_vpnconnections,
- "Display VPN connections", NULL },
+ { "vpnconnections", "[<connection>]", 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 <specs> <master>\n"
+ "Where specs are:\n"
+ "\tbjr_query <query> bjr_response <response>\n"
+ "\tupnp_service <service> upnp_version <version>\n"
+ "\twfd_ies <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,
}
}
-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));
}
}
-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;
}
}
}
-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;
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);
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);
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);
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);
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);
}