5 * Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32 #include <sys/types.h>
39 #include "dbus_helpers.h"
42 #include "tethering.h"
46 #include "vpnconnections.h"
48 static DBusConnection *connection;
49 static GHashTable *service_hash;
50 static GHashTable *vpnconnection_hash;
51 static GHashTable *peer_hash;
52 static GHashTable *technology_hash;
53 static char *session_notify_path;
54 static char *session_path;
55 static bool session_connected;
57 struct connman_option {
63 static char *ipv4[] = {
71 static char *ipv6[] = {
79 static int cmd_help(char *args[], int num, struct connman_option *options);
81 static bool check_dbus_name(const char *name)
84 * Valid dbus chars should be [A-Z][a-z][0-9]_
85 * and should not start with number.
89 if (!name || name[0] == '\0')
92 for (i = 0; name[i] != '\0'; i++)
93 if (!((name[i] >= 'A' && name[i] <= 'Z') ||
94 (name[i] >= 'a' && name[i] <= 'z') ||
95 (name[i] >= '0' && name[i] <= '9') ||
102 static int parse_boolean(char *arg)
107 if (strcasecmp(arg, "no") == 0 ||
108 strcasecmp(arg, "false") == 0 ||
109 strcasecmp(arg, "off" ) == 0 ||
110 strcasecmp(arg, "disable" ) == 0 ||
111 strcasecmp(arg, "n") == 0 ||
112 strcasecmp(arg, "f") == 0 ||
113 strcasecmp(arg, "0") == 0)
116 if (strcasecmp(arg, "yes") == 0 ||
117 strcasecmp(arg, "true") == 0 ||
118 strcasecmp(arg, "on") == 0 ||
119 strcasecmp(arg, "enable" ) == 0 ||
120 strcasecmp(arg, "y") == 0 ||
121 strcasecmp(arg, "t") == 0 ||
122 strcasecmp(arg, "1") == 0)
128 static int parse_args(char *arg, struct connman_option *options)
135 for (i = 0; options[i].name; i++) {
136 if (strcmp(options[i].name, arg) == 0 ||
137 (strncmp(arg, "--", 2) == 0 &&
138 strcmp(&arg[2], options[i].name) == 0))
139 return options[i].val;
145 static int enable_return(DBusMessageIter *iter, const char *error,
148 char *tech = user_data;
151 str = strrchr(tech, '/');
158 fprintf(stdout, "Enabled %s\n", str);
160 fprintf(stderr, "Error %s: %s\n", str, error);
167 static int cmd_enable(char *args[], int num, struct connman_option *options)
170 dbus_bool_t b = TRUE;
178 if (check_dbus_name(args[1]) == false)
181 if (strcmp(args[1], "offline") == 0) {
182 tech = g_strdup(args[1]);
183 return __connmanctl_dbus_set_property(connection, "/",
184 "net.connman.Manager", enable_return, tech,
185 "OfflineMode", DBUS_TYPE_BOOLEAN, &b);
188 tech = g_strdup_printf("/net/connman/technology/%s", args[1]);
189 return __connmanctl_dbus_set_property(connection, tech,
190 "net.connman.Technology", enable_return, tech,
191 "Powered", DBUS_TYPE_BOOLEAN, &b);
194 static int disable_return(DBusMessageIter *iter, const char *error,
197 char *tech = user_data;
200 str = strrchr(tech, '/');
207 fprintf(stdout, "Disabled %s\n", str);
209 fprintf(stderr, "Error %s: %s\n", str, error);
216 static int cmd_disable(char *args[], int num, struct connman_option *options)
219 dbus_bool_t b = FALSE;
227 if (check_dbus_name(args[1]) == false)
230 if (strcmp(args[1], "offline") == 0) {
231 tech = g_strdup(args[1]);
232 return __connmanctl_dbus_set_property(connection, "/",
233 "net.connman.Manager", disable_return, tech,
234 "OfflineMode", DBUS_TYPE_BOOLEAN, &b);
237 tech = g_strdup_printf("/net/connman/technology/%s", args[1]);
238 return __connmanctl_dbus_set_property(connection, tech,
239 "net.connman.Technology", disable_return, tech,
240 "Powered", DBUS_TYPE_BOOLEAN, &b);
243 static int state_print(DBusMessageIter *iter, const char *error,
246 DBusMessageIter entry;
249 fprintf(stderr, "Error: %s\n", error);
253 dbus_message_iter_recurse(iter, &entry);
254 __connmanctl_dbus_print(&entry, " ", " = ", "\n");
255 fprintf(stdout, "\n");
260 static int cmd_state(char *args[], int num, struct connman_option *options)
265 return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
266 CONNMAN_PATH, "net.connman.Manager", "GetProperties",
267 state_print, NULL, NULL, NULL);
270 static int clock_print(DBusMessageIter *iter, const char *error,
273 DBusMessageIter entry;
276 fprintf(stderr, "Error: %s\n", error);
280 dbus_message_iter_recurse(iter, &entry);
281 __connmanctl_dbus_print(&entry, " ", " = ", "\n");
282 fprintf(stdout, "\n");
287 static int cmd_clock(char *args[], int num, struct connman_option *options)
292 return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
293 CONNMAN_PATH, "net.connman.Clock", "GetProperties",
294 clock_print, NULL, NULL, NULL);
297 static int services_list(DBusMessageIter *iter, const char *error,
301 __connmanctl_services_list(iter);
302 fprintf(stdout, "\n");
304 fprintf(stderr, "Error: %s\n", error);
310 static int peers_list(DBusMessageIter *iter,
311 const char *error, void *user_data)
314 __connmanctl_peers_list(iter);
315 fprintf(stdout, "\n");
317 fprintf(stderr, "Error: %s\n", error);
322 static int tethering_clients_list(DBusMessageIter *iter,
323 const char *error, void *user_data)
326 __connmanctl_tethering_clients_list(iter);
327 fprintf(stdout, "\n");
329 fprintf(stderr, "Error: %s\n", error);
334 static int object_properties(DBusMessageIter *iter,
335 const char *error, void *user_data)
337 char *path = user_data;
339 DBusMessageIter dict;
342 fprintf(stdout, "%s\n", path);
344 dbus_message_iter_recurse(iter, &dict);
345 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
347 fprintf(stdout, "\n");
350 str = strrchr(path, '/');
356 fprintf(stderr, "Error %s: %s\n", str, error);
364 static int cmd_services(char *args[], int num, struct connman_option *options)
366 char *service_name = NULL;
373 c = parse_args(args[1], options);
380 service_name = args[2];
385 service_name = args[1];
390 return __connmanctl_dbus_method_call(connection,
391 CONNMAN_SERVICE, CONNMAN_PATH,
392 "net.connman.Manager", "GetServices",
393 services_list, NULL, NULL, NULL);
396 if (check_dbus_name(service_name) == false)
399 path = g_strdup_printf("/net/connman/service/%s", service_name);
400 return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path,
401 "net.connman.Service", "GetProperties",
402 object_properties, path, NULL, NULL);
405 static int cmd_peers(char *args[], int num, struct connman_option *options)
407 char *peer_name = NULL;
417 return __connmanctl_dbus_method_call(connection,
418 CONNMAN_SERVICE, CONNMAN_PATH,
419 "net.connman.Manager", "GetPeers",
420 peers_list, NULL, NULL, NULL);
423 if (check_dbus_name(peer_name) == false)
426 path = g_strdup_printf("/net/connman/peer/%s", peer_name);
427 return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
428 path, "net.connman.Peer", "GetProperties",
429 object_properties, path, NULL, NULL);
432 static int technology_print(DBusMessageIter *iter, const char *error,
435 DBusMessageIter array;
438 fprintf(stderr, "Error: %s\n", error);
442 dbus_message_iter_recurse(iter, &array);
443 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
444 DBusMessageIter entry, dict;
447 dbus_message_iter_recurse(&array, &entry);
448 dbus_message_iter_get_basic(&entry, &path);
449 fprintf(stdout, "%s\n", path);
451 dbus_message_iter_next(&entry);
453 dbus_message_iter_recurse(&entry, &dict);
454 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
455 fprintf(stdout, "\n");
457 dbus_message_iter_next(&array);
463 static int cmd_technologies(char *args[], int num,
464 struct connman_option *options)
469 return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
470 CONNMAN_PATH, "net.connman.Manager", "GetTechnologies",
471 technology_print, NULL, NULL, NULL);
474 struct tether_enable {
479 static int tether_set_return(DBusMessageIter *iter, const char *error,
482 struct tether_enable *tether = user_data;
485 str = strrchr(tether->path, '/');
492 fprintf(stdout, "%s tethering for %s\n",
493 tether->enable ? "Enabled" : "Disabled",
496 fprintf(stderr, "Error %s %s tethering: %s\n",
498 "enabling" : "disabling", str, error);
500 g_free(tether->path);
506 static int tether_set(char *technology, int set_tethering)
508 struct tether_enable *tether = g_new(struct tether_enable, 1);
510 switch(set_tethering) {
512 tether->enable = TRUE;
515 tether->enable = FALSE;
522 tether->path = g_strdup_printf("/net/connman/technology/%s",
525 return __connmanctl_dbus_set_property(connection, tether->path,
526 "net.connman.Technology", tether_set_return,
527 tether, "Tethering", DBUS_TYPE_BOOLEAN,
531 struct tether_properties {
533 int passphrase_result;
537 static int tether_update(struct tether_properties *tether)
541 if (tether->ssid_result == 0 && tether->passphrase_result == 0) {
542 ret = tether_set("wifi", tether->set_tethering);
547 if (tether->ssid_result != -EINPROGRESS &&
548 tether->passphrase_result != -EINPROGRESS) {
556 static int tether_set_ssid_return(DBusMessageIter *iter, const char *error,
559 struct tether_properties *tether = user_data;
562 fprintf(stdout, "Wifi SSID set\n");
563 tether->ssid_result = 0;
565 fprintf(stderr, "Error setting wifi SSID: %s\n", error);
566 tether->ssid_result = -EINVAL;
569 return tether_update(tether);
572 static int tether_set_passphrase_return(DBusMessageIter *iter,
573 const char *error, void *user_data)
575 struct tether_properties *tether = user_data;
578 fprintf(stdout, "Wifi passphrase set\n");
579 tether->passphrase_result = 0;
581 fprintf(stderr, "Error setting wifi passphrase: %s\n", error);
582 tether->passphrase_result = -EINVAL;
585 return tether_update(tether);
588 static int tether_set_ssid(char *ssid, char *passphrase, int set_tethering)
590 struct tether_properties *tether = g_new(struct tether_properties, 1);
592 tether->set_tethering = set_tethering;
594 tether->ssid_result = __connmanctl_dbus_set_property(connection,
595 "/net/connman/technology/wifi",
596 "net.connman.Technology",
597 tether_set_ssid_return, tether,
598 "TetheringIdentifier", DBUS_TYPE_STRING, &ssid);
600 tether->passphrase_result =__connmanctl_dbus_set_property(connection,
601 "/net/connman/technology/wifi",
602 "net.connman.Technology",
603 tether_set_passphrase_return, tether,
604 "TetheringPassphrase", DBUS_TYPE_STRING, &passphrase);
606 if (tether->ssid_result != -EINPROGRESS &&
607 tether->passphrase_result != -EINPROGRESS) {
615 static int cmd_tether(char *args[], int num, struct connman_option *options)
617 char *ssid, *passphrase;
623 passphrase = args[num - 1];
624 ssid = args[num - 2];
626 set_tethering = parse_boolean(args[2]);
628 if (strcmp(args[1], "wifi") == 0) {
633 if (num == 5 && set_tethering == -1)
640 return tether_set_ssid(ssid, passphrase, set_tethering);
646 if (set_tethering == -1)
649 if (check_dbus_name(args[1]) == false)
652 return tether_set(args[1], set_tethering);
655 static int cmd_tethering_clients(char *args[], int num, struct connman_option *options)
660 return __connmanctl_dbus_method_call(connection,
661 CONNMAN_SERVICE, CONNMAN_PATH,
662 "net.connman.Manager", "GetTetheringClients",
663 tethering_clients_list, NULL, NULL, NULL);
666 static int scan_return(DBusMessageIter *iter, const char *error,
669 char *path = user_data;
672 char *str = strrchr(path, '/');
674 fprintf(stdout, "Scan completed for %s\n", str);
676 fprintf(stderr, "Error %s: %s\n", path, error);
683 static int cmd_scan(char *args[], int num, struct connman_option *options)
693 if (check_dbus_name(args[1]) == false)
696 path = g_strdup_printf("/net/connman/technology/%s", args[1]);
697 return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path,
698 "net.connman.Technology", "Scan",
699 scan_return, path, NULL, NULL);
702 static int connect_return(DBusMessageIter *iter, const char *error,
705 char *path = user_data;
708 char *str = strrchr(path, '/');
710 fprintf(stdout, "Connected %s\n", str);
712 fprintf(stderr, "Error %s: %s\n", path, error);
719 static int cmd_connect(char *args[], int num, struct connman_option *options)
721 const char *iface = "net.connman.Service";
730 if (check_dbus_name(args[1]) == false)
733 if (g_strstr_len(args[1], 5, "peer_") == args[1]) {
734 iface = "net.connman.Peer";
735 path = g_strdup_printf("/net/connman/peer/%s", args[1]);
737 path = g_strdup_printf("/net/connman/service/%s", args[1]);
739 return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, path,
740 iface, "Connect", connect_return, path, NULL, NULL);
743 static int disconnect_return(DBusMessageIter *iter, const char *error,
746 char *path = user_data;
749 char *str = strrchr(path, '/');
751 fprintf(stdout, "Disconnected %s\n", str);
753 fprintf(stderr, "Error %s: %s\n", path, error);
760 static int cmd_disconnect(char *args[], int num, struct connman_option *options)
762 const char *iface = "net.connman.Service";
771 if (check_dbus_name(args[1]) == false)
774 if (g_strstr_len(args[1], 5, "peer_") == args[1]) {
775 iface = "net.connman.Peer";
776 path = g_strdup_printf("/net/connman/peer/%s", args[1]);
778 path = g_strdup_printf("/net/connman/service/%s", args[1]);
780 return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
781 path, iface, "Disconnect",
782 disconnect_return, path, NULL, NULL);
785 struct move_service {
790 static int move_before_return(DBusMessageIter *iter, const char *error,
793 struct move_service *services = user_data;
798 service = strrchr(services->service, '/');
800 target = strrchr(services->target, '/');
802 fprintf(stdout, "Moved %s before %s\n", service, target);
804 fprintf(stderr, "Error %s: %s\n", services->service, error);
806 g_free(services->service);
807 g_free(services->target);
813 static void move_before_append_args(DBusMessageIter *iter, void *user_data)
815 char *path = user_data;
817 dbus_message_iter_append_basic(iter,
818 DBUS_TYPE_OBJECT_PATH, &path);
821 static int cmd_service_move_before(char *args[], int num,
822 struct connman_option *options)
824 const char *iface = "net.connman.Service";
825 struct move_service *services;
833 if (check_dbus_name(args[1]) == false)
836 services = g_new(struct move_service, 1);
838 services->service = g_strdup_printf("/net/connman/service/%s", args[1]);
839 services->target = g_strdup_printf("/net/connman/service/%s", args[2]);
841 return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
842 services->service, iface, "MoveBefore",
843 move_before_return, services,
844 move_before_append_args,
848 static int move_after_return(DBusMessageIter *iter, const char *error,
851 struct move_service *services = user_data;
856 service = strrchr(services->service, '/');
858 target = strrchr(services->target, '/');
860 fprintf(stdout, "Moved %s after %s\n", service, target);
862 fprintf(stderr, "Error %s: %s\n", services->service, error);
864 g_free(services->service);
865 g_free(services->target);
871 static void move_after_append_args(DBusMessageIter *iter, void *user_data)
873 char *path = user_data;
875 dbus_message_iter_append_basic(iter,
876 DBUS_TYPE_OBJECT_PATH, &path);
879 static int cmd_service_move_after(char *args[], int num,
880 struct connman_option *options)
882 const char *iface = "net.connman.Service";
883 struct move_service *services;
891 if (check_dbus_name(args[1]) == false)
894 services = g_new(struct move_service, 1);
896 services->service = g_strdup_printf("/net/connman/service/%s", args[1]);
897 services->target = g_strdup_printf("/net/connman/service/%s", args[2]);
899 return __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
900 services->service, iface, "MoveAfter",
901 move_after_return, services,
902 move_after_append_args,
906 static int config_return(DBusMessageIter *iter, const char *error,
909 char *service_name = user_data;
912 fprintf(stderr, "Error %s: %s\n", service_name, error);
919 struct config_append {
924 struct session_options {
928 struct connman_option *options;
931 static void config_append_ipv4(DBusMessageIter *iter,
934 struct config_append *append = user_data;
935 char **opts = append->opts;
941 while (opts[i] && ipv4[i]) {
942 __connmanctl_dbus_append_dict_entry(iter, ipv4[i],
943 DBUS_TYPE_STRING, &opts[i]);
950 static void config_append_ipv6(DBusMessageIter *iter, void *user_data)
952 struct config_append *append = user_data;
953 char **opts = append->opts;
960 if (g_strcmp0(opts[0], "auto") == 0) {
963 switch (parse_boolean(opts[1])) {
968 __connmanctl_dbus_append_dict_entry(iter, "Privacy",
969 DBUS_TYPE_STRING, &str);
976 __connmanctl_dbus_append_dict_entry(iter, "Privacy",
977 DBUS_TYPE_STRING, &str);
984 if (g_strcmp0(opts[1], "prefered") != 0 &&
987 fprintf(stderr, "Error %s: %s\n",
994 __connmanctl_dbus_append_dict_entry(iter,
995 "Privacy", DBUS_TYPE_STRING,
1000 } else if (g_strcmp0(opts[0], "manual") == 0) {
1003 while (opts[i] && ipv6[i]) {
1005 int value = atoi(opts[i]);
1006 __connmanctl_dbus_append_dict_entry(iter,
1007 ipv6[i], DBUS_TYPE_BYTE,
1010 __connmanctl_dbus_append_dict_entry(iter,
1011 ipv6[i], DBUS_TYPE_STRING,
1019 } else if (g_strcmp0(opts[0], "off") != 0) {
1020 fprintf(stderr, "Error %s: %s\n", opts[0], strerror(EINVAL));
1025 __connmanctl_dbus_append_dict_entry(iter, "Method", DBUS_TYPE_STRING,
1029 static void config_append_str(DBusMessageIter *iter, void *user_data)
1031 struct config_append *append = user_data;
1032 char **opts = append->opts;
1039 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
1047 static void append_servers(DBusMessageIter *iter, void *user_data)
1049 struct config_append *append = user_data;
1050 char **opts = append->opts;
1056 while (opts[i] && g_strcmp0(opts[i], "--excludes") != 0) {
1057 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
1065 static void append_excludes(DBusMessageIter *iter, void *user_data)
1067 struct config_append *append = user_data;
1068 char **opts = append->opts;
1069 int i = append->values;
1071 if (!opts || !opts[i] ||
1072 g_strcmp0(opts[i], "--excludes") != 0)
1077 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
1085 static void config_append_proxy(DBusMessageIter *iter, void *user_data)
1087 struct config_append *append = user_data;
1088 char **opts = append->opts;
1093 if (g_strcmp0(opts[0], "manual") == 0) {
1094 __connmanctl_dbus_append_dict_string_array(iter, "Servers",
1095 append_servers, append);
1097 __connmanctl_dbus_append_dict_string_array(iter, "Excludes",
1098 append_excludes, append);
1100 } else if (g_strcmp0(opts[0], "auto") == 0) {
1102 __connmanctl_dbus_append_dict_entry(iter, "URL",
1103 DBUS_TYPE_STRING, &opts[1]);
1107 } else if (g_strcmp0(opts[0], "direct") != 0)
1110 __connmanctl_dbus_append_dict_entry(iter, "Method",DBUS_TYPE_STRING,
1116 static int cmd_config(char *args[], int num, struct connman_option *options)
1118 int result = 0, res = 0, index = 2, oldindex = 0;
1120 char *service_name, *path;
1123 struct config_append append;
1125 service_name = args[1];
1129 if (check_dbus_name(service_name) == false)
1132 while (index < num && args[index]) {
1133 c = parse_args(args[index], options);
1134 opt_start = &args[index + 1];
1135 append.opts = opt_start;
1141 path = g_strdup_printf("/net/connman/service/%s", service_name);
1145 switch (parse_boolean(*opt_start)) {
1160 res = __connmanctl_dbus_set_property(connection,
1161 path, "net.connman.Service",
1163 g_strdup(service_name),
1165 DBUS_TYPE_BOOLEAN, &val);
1169 res = __connmanctl_dbus_set_property_dict(connection,
1170 path, "net.connman.Service",
1171 config_return, g_strdup(service_name),
1172 "IPv4.Configuration", DBUS_TYPE_STRING,
1173 config_append_ipv4, &append);
1174 index += append.values;
1178 res = __connmanctl_dbus_set_property_dict(connection,
1179 path, "net.connman.Service",
1180 config_return, g_strdup(service_name),
1181 "IPv6.Configuration", DBUS_TYPE_STRING,
1182 config_append_ipv6, &append);
1183 index += append.values;
1187 res = __connmanctl_dbus_set_property_array(connection,
1188 path, "net.connman.Service",
1189 config_return, g_strdup(service_name),
1190 "Nameservers.Configuration",
1191 DBUS_TYPE_STRING, config_append_str,
1193 index += append.values;
1197 res = __connmanctl_dbus_set_property_array(connection,
1198 path, "net.connman.Service",
1199 config_return, g_strdup(service_name),
1200 "Timeservers.Configuration",
1201 DBUS_TYPE_STRING, config_append_str,
1203 index += append.values;
1207 res = __connmanctl_dbus_set_property_array(connection,
1208 path, "net.connman.Service",
1209 config_return, g_strdup(service_name),
1210 "Domains.Configuration",
1211 DBUS_TYPE_STRING, config_append_str,
1213 index += append.values;
1217 res = __connmanctl_dbus_set_property_dict(connection,
1218 path, "net.connman.Service",
1219 config_return, g_strdup(service_name),
1220 "Proxy.Configuration",
1221 DBUS_TYPE_STRING, config_append_proxy,
1223 index += append.values;
1226 res = __connmanctl_dbus_method_call(connection,
1227 CONNMAN_SERVICE, path,
1228 "net.connman.Service", "Remove",
1229 config_return, g_strdup(service_name),
1234 switch (parse_boolean(*opt_start)) {
1246 res = __connmanctl_dbus_set_property(connection,
1247 path, "net.connman.Service",
1249 g_strdup(service_name),
1250 "mDNS.Configuration",
1251 DBUS_TYPE_BOOLEAN, &val);
1264 if (res == -EINPROGRESS)
1265 result = -EINPROGRESS;
1267 printf("Error '%s': %s\n", args[oldindex],
1278 static DBusHandlerResult monitor_changed(DBusConnection *connection,
1279 DBusMessage *message, void *user_data)
1281 DBusMessageIter iter;
1282 const char *interface, *path;
1284 interface = dbus_message_get_interface(message);
1286 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1288 if (strncmp(interface, "net.connman.", 12) != 0)
1289 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1291 if (!strcmp(interface, "net.connman.Agent") ||
1292 !strcmp(interface, "net.connman.vpn.Agent") ||
1293 !strcmp(interface, "net.connman.Session") ||
1294 !strcmp(interface, "net.connman.Notification"))
1295 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1297 interface = strrchr(interface, '.');
1298 if (interface && *interface != '\0')
1301 path = strrchr(dbus_message_get_path(message), '/');
1302 if (path && *path != '\0')
1305 __connmanctl_save_rl();
1307 if (dbus_message_is_signal(message, "net.connman.Manager",
1308 "ServicesChanged")) {
1310 fprintf(stdout, "%-12s %-20s = {\n", interface,
1312 dbus_message_iter_init(message, &iter);
1313 __connmanctl_services_list(&iter);
1314 fprintf(stdout, "\n}\n");
1316 __connmanctl_redraw_rl();
1318 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1319 } else if (dbus_message_is_signal(message, "net.connman.Manager",
1321 fprintf(stdout, "%-12s %-20s = {\n", interface,
1323 dbus_message_iter_init(message, &iter);
1324 __connmanctl_peers_list(&iter);
1325 fprintf(stdout, "\n}\n");
1327 __connmanctl_redraw_rl();
1329 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1330 } else if (dbus_message_is_signal(message, "net.connman.vpn.Manager",
1331 "ConnectionAdded") ||
1332 dbus_message_is_signal(message,
1333 "net.connman.vpn.Manager",
1334 "ConnectionRemoved")) {
1335 interface = "vpn.Manager";
1336 path = dbus_message_get_member(message);
1338 } else if (dbus_message_is_signal(message, "net.connman.Manager",
1339 "TechnologyAdded") ||
1340 dbus_message_is_signal(message, "net.connman.Manager",
1341 "TechnologyRemoved"))
1342 path = dbus_message_get_member(message);
1344 fprintf(stdout, "%-12s %-20s ", interface, path);
1345 dbus_message_iter_init(message, &iter);
1347 __connmanctl_dbus_print(&iter, "", " = ", " = ");
1348 fprintf(stdout, "\n");
1350 __connmanctl_redraw_rl();
1352 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1359 { "Service", false },
1360 { "Technology", false },
1361 { "Manager", false },
1362 { "vpn.Manager", false },
1363 { "vpn.Connection", false },
1367 static void monitor_add(char *interface)
1369 bool add_filter = true, found = false;
1374 for (i = 0; monitor[i].interface; i++) {
1375 if (monitor[i].enabled == true)
1378 if (g_strcmp0(interface, monitor[i].interface) == 0) {
1379 if (monitor[i].enabled == true)
1382 monitor[i].enabled = true;
1390 if (add_filter == true)
1391 dbus_connection_add_filter(connection, monitor_changed,
1394 dbus_error_init(&err);
1395 rule = g_strdup_printf("type='signal',interface='net.connman.%s'",
1397 dbus_bus_add_match(connection, rule, &err);
1400 if (dbus_error_is_set(&err))
1401 fprintf(stderr, "Error: %s\n", err.message);
1404 static void monitor_del(char *interface)
1406 bool del_filter = true, found = false;
1411 for (i = 0; monitor[i].interface; i++) {
1412 if (g_strcmp0(interface, monitor[i].interface) == 0) {
1413 if (monitor[i].enabled == false)
1416 monitor[i].enabled = false;
1420 if (monitor[i].enabled == true)
1427 rule = g_strdup_printf("type='signal',interface='net.connman.%s'",
1429 dbus_bus_remove_match(connection, rule, NULL);
1432 if (del_filter == true)
1433 dbus_connection_remove_filter(connection, monitor_changed,
1437 static int cmd_monitor(char *args[], int num, struct connman_option *options)
1446 switch (parse_boolean(args[2])) {
1456 c = parse_args(args[1], options);
1459 monitor_add("Service");
1460 monitor_add("Technology");
1461 monitor_add("Manager");
1462 monitor_add("vpn.Manager");
1463 monitor_add("vpn.Connection");
1468 monitor_add("Service");
1470 monitor_del("Service");
1475 monitor_add("Technology");
1477 monitor_del("Technology");
1482 monitor_add("Manager");
1484 monitor_del("Manager");
1489 monitor_add("vpn.Manager");
1491 monitor_del("vpn.Manager");
1496 monitor_add("vpn.Connection");
1498 monitor_del("vpn.Connection");
1502 switch(parse_boolean(args[1])) {
1504 monitor_del("Service");
1505 monitor_del("Technology");
1506 monitor_del("Manager");
1507 monitor_del("vpn.Manager");
1508 monitor_del("vpn.Connection");
1512 monitor_add("Service");
1513 monitor_add("Technology");
1514 monitor_add("Manager");
1515 monitor_add("vpn.Manager");
1516 monitor_add("vpn.Connection");
1525 return -EINPROGRESS;
1530 static int cmd_agent(char *args[], int num, struct connman_option *options)
1532 if (!__connmanctl_is_interactive()) {
1533 fprintf(stderr, "Error: Not supported in non-interactive "
1544 switch(parse_boolean(args[1])) {
1546 __connmanctl_agent_unregister(connection);
1550 if (__connmanctl_agent_register(connection) == -EINPROGRESS)
1551 return -EINPROGRESS;
1563 static int vpnconnections_properties(DBusMessageIter *iter, const char *error,
1566 char *path = user_data;
1568 DBusMessageIter dict;
1571 fprintf(stdout, "%s\n", path);
1573 dbus_message_iter_recurse(iter, &dict);
1574 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
1576 fprintf(stdout, "\n");
1579 str = strrchr(path, '/');
1585 fprintf(stderr, "Error %s: %s\n", str, error);
1593 static int vpnconnections_list(DBusMessageIter *iter, const char *error,
1597 __connmanctl_vpnconnections_list(iter);
1599 fprintf(stderr, "Error: %s\n", error);
1604 static int cmd_vpnconnections(char *args[], int num,
1605 struct connman_option *options)
1607 char *vpnconnection_name, *path;
1612 vpnconnection_name = args[1];
1614 if (!vpnconnection_name)
1615 return __connmanctl_dbus_method_call(connection,
1616 VPN_SERVICE, VPN_PATH,
1617 "net.connman.vpn.Manager", "GetConnections",
1618 vpnconnections_list, NULL,
1621 if (check_dbus_name(vpnconnection_name) == false)
1624 path = g_strdup_printf("/net/connman/vpn/connection/%s",
1625 vpnconnection_name);
1626 return __connmanctl_dbus_method_call(connection, VPN_SERVICE, path,
1627 "net.connman.vpn.Connection", "GetProperties",
1628 vpnconnections_properties, path, NULL, NULL);
1632 static int cmd_vpnagent(char *args[], int num, struct connman_option *options)
1634 if (!__connmanctl_is_interactive()) {
1635 fprintf(stderr, "Error: Not supported in non-interactive "
1646 switch(parse_boolean(args[1])) {
1648 __connmanctl_vpn_agent_unregister(connection);
1652 if (__connmanctl_vpn_agent_register(connection) ==
1654 return -EINPROGRESS;
1666 static DBusMessage *session_release(DBusConnection *connection,
1667 DBusMessage *message, void *user_data)
1669 __connmanctl_save_rl();
1671 fprintf(stdout, "Session %s released\n", session_path);
1673 __connmanctl_redraw_rl();
1675 g_free(session_path);
1676 session_path = NULL;
1677 session_connected = false;
1679 return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
1682 static DBusMessage *session_update(DBusConnection *connection,
1683 DBusMessage *message, void *user_data)
1685 DBusMessageIter iter, dict;
1687 __connmanctl_save_rl();
1689 fprintf(stdout, "Session Update = {\n");
1691 dbus_message_iter_init(message, &iter);
1692 dbus_message_iter_recurse(&iter, &dict);
1694 __connmanctl_dbus_print(&dict, "", " = ", "\n");
1695 fprintf(stdout, "\n}\n");
1697 dbus_message_iter_recurse(&iter, &dict);
1699 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1700 DBusMessageIter entry, variant;
1701 char *field, *state;
1703 dbus_message_iter_recurse(&dict, &entry);
1705 dbus_message_iter_get_basic(&entry, &field);
1707 if (dbus_message_iter_get_arg_type(&entry)
1709 && !strcmp(field, "State")) {
1711 dbus_message_iter_next(&entry);
1712 dbus_message_iter_recurse(&entry, &variant);
1713 if (dbus_message_iter_get_arg_type(&variant)
1714 != DBUS_TYPE_STRING)
1717 dbus_message_iter_get_basic(&variant, &state);
1719 if (!session_connected && (!strcmp(state, "connected")
1720 || !strcmp(state, "online"))) {
1722 fprintf(stdout, "Session %s connected\n",
1724 session_connected = true;
1729 if (!strcmp(state, "disconnected") &&
1730 session_connected) {
1732 fprintf(stdout, "Session %s disconnected\n",
1734 session_connected = false;
1739 dbus_message_iter_next(&dict);
1742 __connmanctl_redraw_rl();
1744 return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
1747 static const GDBusMethodTable notification_methods[] = {
1748 { GDBUS_METHOD("Release", NULL, NULL, session_release) },
1749 { GDBUS_METHOD("Update", GDBUS_ARGS({"settings", "a{sv}"}),
1750 NULL, session_update) },
1754 static int session_notify_add(const char *path)
1756 if (session_notify_path)
1759 if (!g_dbus_register_interface(connection, path,
1760 "net.connman.Notification",
1761 notification_methods, NULL, NULL,
1763 fprintf(stderr, "Error: Failed to register VPN Agent "
1768 session_notify_path = g_strdup(path);
1773 static void session_notify_remove(void)
1775 if (!session_notify_path)
1778 g_dbus_unregister_interface(connection, session_notify_path,
1779 "net.connman.Notification");
1781 g_free(session_notify_path);
1782 session_notify_path = NULL;
1785 static int session_connect_cb(DBusMessageIter *iter, const char *error,
1789 fprintf(stderr, "Error: %s\n", error);
1793 return -EINPROGRESS;
1797 static int session_connect(void)
1799 return __connmanctl_dbus_method_call(connection, "net.connman",
1800 session_path, "net.connman.Session", "Connect",
1801 session_connect_cb, NULL, NULL, NULL);
1804 static int session_disconnect_cb(DBusMessageIter *iter, const char *error,
1808 fprintf(stderr, "Error: %s\n", error);
1813 static int session_disconnect(void)
1815 return __connmanctl_dbus_method_call(connection, "net.connman",
1816 session_path, "net.connman.Session", "Disconnect",
1817 session_disconnect_cb, NULL, NULL, NULL);
1820 static int session_create_cb(DBusMessageIter *iter, const char *error,
1823 gboolean connect = GPOINTER_TO_INT(user_data);
1827 fprintf(stderr, "Error creating session: %s", error);
1828 session_notify_remove();
1832 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_OBJECT_PATH) {
1833 fprintf(stderr, "Error creating session: No session path\n");
1837 g_free(session_path);
1839 dbus_message_iter_get_basic(iter, &str);
1840 session_path = g_strdup(str);
1842 fprintf(stdout, "Session %s created\n", session_path);
1845 return session_connect();
1847 return -EINPROGRESS;
1850 static void session_config_append_array(DBusMessageIter *iter,
1853 struct config_append *append = user_data;
1854 char **opts = append->opts;
1860 while (opts[i] && strncmp(opts[i], "--", 2) != 0) {
1861 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
1869 static void session_create_append_dict(DBusMessageIter *iter, void *user_data)
1871 struct session_options *args_struct = user_data;
1872 int index = 0, res = 0;
1873 struct config_append append;
1876 dbus_bool_t source_ip_rule;
1878 while (index < args_struct->num && args_struct->args[index]) {
1879 append.opts = &args_struct->args[index];
1882 c = parse_args(args_struct->args[index], args_struct->options);
1886 __connmanctl_dbus_append_dict_string_array(iter, "AllowedBearers",
1887 session_config_append_array,
1891 if (! args_struct->args[index + 1]) {
1895 __connmanctl_dbus_append_dict_entry(iter, "ConnectionType",
1897 &args_struct->args[index + 1]);
1901 if (index + 1 < args_struct->num)
1902 ifname = args_struct->args[index + 1];
1905 __connmanctl_dbus_append_dict_entry(iter, "AllowedInterface",
1911 if (! args_struct->args[index + 1]) {
1915 switch (parse_boolean( args_struct->args[index + 1])) {
1917 source_ip_rule = TRUE;
1920 source_ip_rule = FALSE;
1926 __connmanctl_dbus_append_dict_entry(iter, "SourceIPRule",
1932 if (!args_struct->args[index + 1]) {
1936 __connmanctl_dbus_append_dict_entry(iter, "ContextIdentifier",
1938 &args_struct->args[index + 1]);
1945 if (res < 0 && res != -EINPROGRESS) {
1946 printf("Error '%s': %s\n", args_struct->args[index],
1951 index += append.values;
1955 static void session_create_append(DBusMessageIter *iter, void *user_data)
1957 struct session_options *args_struct = user_data;
1959 __connmanctl_dbus_append_dict(iter, session_create_append_dict,
1962 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
1963 &args_struct->notify_path);
1966 static int session_create(gboolean connect, char *args[], int num,
1967 struct connman_option *options)
1971 struct session_options args_struct;
1972 args_struct.args = args;
1973 args_struct.num = num;
1974 args_struct.options = options;
1976 notify_path = g_strdup_printf("/net/connman/connmanctl%d", getpid());
1977 session_notify_add(notify_path);
1978 args_struct.notify_path = notify_path;
1980 res = __connmanctl_dbus_method_call(connection, "net.connman", "/",
1981 "net.connman.Manager", "CreateSession",
1982 session_create_cb, GINT_TO_POINTER(connect),
1983 session_create_append, &args_struct);
1985 g_free(notify_path);
1987 if (res < 0 && res != -EINPROGRESS)
1988 session_notify_remove();
1993 static int session_destroy_cb(DBusMessageIter *iter, const char *error,
1997 fprintf(stderr, "Error destroying session: %s", error);
2001 fprintf(stdout, "Session %s ended\n", session_path);
2003 g_free(session_path);
2004 session_path = NULL;
2005 session_connected = false;
2010 static void session_destroy_append(DBusMessageIter *iter, void *user_data)
2012 const char *path = user_data;
2014 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
2017 static int session_destroy(void)
2019 return __connmanctl_dbus_method_call(connection, "net.connman", "/",
2020 "net.connman.Manager", "DestroySession",
2021 session_destroy_cb, NULL,
2022 session_destroy_append, session_path);
2025 static int session_config_return(DBusMessageIter *iter, const char *error,
2028 char *property_name = user_data;
2031 fprintf(stderr, "Error setting session %s: %s\n",
2032 property_name, error);
2037 static int session_config(char *args[], int num,
2038 struct connman_option *options)
2040 int index = 0, res = 0;
2041 struct config_append append;
2044 dbus_bool_t source_ip_rule;
2046 while (index < num && args[index]) {
2047 append.opts = &args[index];
2050 c = parse_args(args[index], options);
2054 res = __connmanctl_dbus_session_change_array(connection,
2055 session_path, session_config_return,
2056 "AllowedBearers", "AllowedBearers",
2057 session_config_append_array, &append);
2060 if (!args[index + 1]) {
2065 res = __connmanctl_dbus_session_change(connection,
2066 session_path, session_config_return,
2067 "ConnectionType", "ConnectionType",
2068 DBUS_TYPE_STRING, &args[index + 1]);
2072 if (index + 1 < num)
2073 ifname = args[index + 1];
2077 res = __connmanctl_dbus_session_change(connection,
2078 session_path, session_config_return,
2079 "AllowedInterface", "AllowedInterface",
2080 DBUS_TYPE_STRING, &ifname);
2084 if (!args[index + 1]) {
2088 switch (parse_boolean(args[index + 1])) {
2090 source_ip_rule = TRUE;
2093 source_ip_rule = FALSE;
2100 res = __connmanctl_dbus_session_change(connection,
2101 session_path, session_config_return,
2102 "SourceIPRule", "SourceIPRule",
2103 DBUS_TYPE_BOOLEAN, &source_ip_rule);
2107 if (!args[index + 1]) {
2112 res = __connmanctl_dbus_session_change(connection,
2113 session_path, session_config_return,
2114 "ctxid", "ctxid", DBUS_TYPE_STRING,
2123 if (res < 0 && res != -EINPROGRESS) {
2124 printf("Error '%s': %s\n", args[index],
2129 index += append.values;
2135 static int cmd_session(char *args[], int num, struct connman_option *options)
2144 switch(parse_boolean(command)) {
2148 return session_destroy();
2153 return session_create(FALSE, &args[2], num - 2, options);
2156 if (!strcmp(command, "connect")) {
2158 return session_create(TRUE, &args[2], num - 2,
2161 return session_connect();
2163 } else if (!strcmp(command, "disconnect")) {
2165 if (!session_path) {
2166 fprintf(stdout, "Session does not exist\n");
2170 return session_disconnect();
2171 } else if (!strcmp(command, "config")) {
2172 if (!session_path) {
2173 fprintf(stdout, "Session does not exist\n");
2180 return session_config(&args[2], num - 2, options);
2188 static int cmd_exit(char *args[], int num, struct connman_option *options)
2193 static char *lookup_key_from_table(GHashTable *hash, const char *text,
2197 static GHashTableIter iter;
2198 gpointer key, value;
2201 g_hash_table_iter_init(&iter, hash);
2205 while (g_hash_table_iter_next(&iter, &key, &value))
2206 if (strncmp(text, key, len) == 0)
2212 static char *lookup_service_arg(const char *text, int state)
2214 if (__connmanctl_input_calc_level() > 1) {
2215 __connmanctl_input_lookup_end();
2219 return lookup_key_from_table(service_hash, text, state);
2222 static char *lookup_peer(const char *text, int state)
2224 static GHashTableIter iter;
2225 gpointer key, value;
2229 g_hash_table_iter_init(&iter, peer_hash);
2233 while (g_hash_table_iter_next(&iter, &key, &value)) {
2234 const char *peer = key;
2235 if (strncmp(text, peer, len) == 0)
2236 return strdup(peer);
2242 static char *lookup_peer_arg(const char *text, int state)
2244 if (__connmanctl_input_calc_level() > 1) {
2245 __connmanctl_input_lookup_end();
2249 return lookup_peer(text, state);
2252 static char *lookup_technology(const char *text, int state)
2255 static GHashTableIter iter;
2256 gpointer key, value;
2259 g_hash_table_iter_init(&iter, technology_hash);
2263 while (g_hash_table_iter_next(&iter, &key, &value)) {
2264 const char *technology = key;
2265 if (strncmp(text, technology, len) == 0)
2266 return strdup(technology);
2272 static char *lookup_technology_arg(const char *text, int state)
2274 if (__connmanctl_input_calc_level() > 1) {
2275 __connmanctl_input_lookup_end();
2279 return lookup_technology(text, state);
2282 static char *lookup_technology_offline(const char *text, int state)
2285 static bool end = false;
2288 if (__connmanctl_input_calc_level() > 1) {
2289 __connmanctl_input_lookup_end();
2301 str = lookup_technology(text, state);
2307 if (strncmp(text, "offline", len) == 0)
2308 return strdup("offline");
2313 static char *lookup_on_off(const char *text, int state)
2315 char *onoff[] = { "on", "off", NULL };
2326 while (onoff[idx]) {
2330 if (!strncmp(text, str, len))
2337 static char *lookup_tether(const char *text, int state)
2341 level = __connmanctl_input_calc_level();
2343 return lookup_technology(text, state);
2346 return lookup_on_off(text, state);
2348 __connmanctl_input_lookup_end();
2353 static char *lookup_agent(const char *text, int state)
2355 if (__connmanctl_input_calc_level() > 1) {
2356 __connmanctl_input_lookup_end();
2360 return lookup_on_off(text, state);
2363 static char *lookup_vpnconnection_arg(const char *text, int state)
2365 if (__connmanctl_input_calc_level() > 1) {
2366 __connmanctl_input_lookup_end();
2370 return lookup_key_from_table(vpnconnection_hash, text, state);
2373 static struct connman_option service_options[] = {
2374 {"properties", 'p', "[<service>] (obsolete)"},
2378 static struct connman_option config_options[] = {
2379 {"nameservers", 'n', "<dns1> [<dns2>] [<dns3>]"},
2380 {"timeservers", 't', "<ntp1> [<ntp2>] [...]"},
2381 {"domains", 'd', "<domain1> [<domain2>] [...]"},
2382 {"mdns", 'm', "yes|no"},
2383 {"ipv6", 'v', "off|auto [enable|disable|preferred]|\n"
2384 "\t\t\tmanual <address> <prefixlength> <gateway>"},
2385 {"proxy", 'x', "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
2386 "\t\t\t[exclude <exclude1> [<exclude2>] [...]]"},
2387 {"autoconnect", 'a', "yes|no"},
2388 {"ipv4", 'i', "off|dhcp|manual <address> <netmask> <gateway>"},
2389 {"remove", 'r', " Remove service"},
2393 static struct connman_option monitor_options[] = {
2394 {"services", 's', "[off] Monitor only services"},
2395 {"tech", 'c', "[off] Monitor only technologies"},
2396 {"manager", 'm', "[off] Monitor only manager interface"},
2397 {"vpnmanager", 'M', "[off] Monitor only VPN manager "
2399 {"vpnconnection", 'C', "[off] Monitor only VPN "
2404 static struct connman_option session_options[] = {
2405 {"bearers", 'b', "<technology1> [<technology2> [...]]"},
2406 {"type", 't', "local|internet|any"},
2407 {"ifname", 'i', "[<interface_name>]"},
2408 {"srciprule", 's', "yes|no"},
2409 {"ctxid", 'c', "<context_identifier>"},
2413 static char *lookup_options(struct connman_option *options, const char *text,
2425 while (options[idx].name) {
2426 str = options[idx].name;
2429 if (str && strncmp(text, str, len) == 0)
2436 static char *lookup_monitor(const char *text, int state)
2440 level = __connmanctl_input_calc_level();
2443 return lookup_options(monitor_options, text, state);
2446 return lookup_on_off(text, state);
2448 __connmanctl_input_lookup_end();
2452 static char *lookup_config(const char *text, int state)
2454 if (__connmanctl_input_calc_level() < 2)
2455 return lookup_key_from_table(service_hash, text, state);
2457 return lookup_options(config_options, text, state);
2460 static char *lookup_session(const char *text, int state)
2462 return lookup_options(session_options, text, state);
2465 static int peer_service_cb(DBusMessageIter *iter, const char *error,
2468 bool registration = GPOINTER_TO_INT(user_data);
2471 fprintf(stderr, "Error %s peer service: %s\n",
2472 registration ? "registering" : "unregistering", error);
2474 fprintf(stdout, "Peer service %s\n",
2475 registration ? "registered" : "unregistered");
2480 struct _peer_service {
2481 unsigned char *bjr_query;
2483 unsigned char *bjr_response;
2484 int bjr_response_len;
2485 unsigned char *wfd_ies;
2492 static void append_dict_entry_fixed_array(DBusMessageIter *iter,
2493 const char *property, void *value, int length)
2495 DBusMessageIter dict_entry, variant, array;
2497 dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
2499 dbus_message_iter_append_basic(&dict_entry, DBUS_TYPE_STRING,
2501 dbus_message_iter_open_container(&dict_entry, DBUS_TYPE_VARIANT,
2502 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
2504 dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
2505 DBUS_TYPE_BYTE_AS_STRING, &array);
2506 dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
2508 dbus_message_iter_close_container(&variant, &array);
2509 dbus_message_iter_close_container(&dict_entry, &variant);
2510 dbus_message_iter_close_container(iter, &dict_entry);
2513 static void append_peer_service_dict(DBusMessageIter *iter, void *user_data)
2515 struct _peer_service *service = user_data;
2517 if (service->bjr_query && service->bjr_response) {
2518 append_dict_entry_fixed_array(iter, "BonjourQuery",
2519 &service->bjr_query, service->bjr_query_len);
2520 append_dict_entry_fixed_array(iter, "BonjourResponse",
2521 &service->bjr_response, service->bjr_response_len);
2522 } else if (service->upnp_service && service->version) {
2523 __connmanctl_dbus_append_dict_entry(iter, "UpnpVersion",
2524 DBUS_TYPE_INT32, &service->version);
2525 __connmanctl_dbus_append_dict_entry(iter, "UpnpService",
2526 DBUS_TYPE_STRING, &service->upnp_service);
2527 } else if (service->wfd_ies) {
2528 append_dict_entry_fixed_array(iter, "WiFiDisplayIEs",
2529 &service->wfd_ies, service->wfd_ies_len);
2533 static void peer_service_append(DBusMessageIter *iter, void *user_data)
2535 struct _peer_service *service = user_data;
2538 __connmanctl_dbus_append_dict(iter, append_peer_service_dict, service);
2540 if (service->master < 0)
2543 master = service->master == 1 ? TRUE : FALSE;
2544 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &master);
2547 static struct _peer_service *fill_in_peer_service(unsigned char *bjr_query,
2548 int bjr_query_len, unsigned char *bjr_response,
2549 int bjr_response_len, char *upnp_service,
2550 int version, unsigned char *wfd_ies,
2553 struct _peer_service *service;
2555 service = dbus_malloc0(sizeof(*service));
2557 if (bjr_query_len && bjr_response_len) {
2558 service->bjr_query = dbus_malloc0(bjr_query_len);
2559 memcpy(service->bjr_query, bjr_query, bjr_query_len);
2560 service->bjr_query_len = bjr_query_len;
2562 service->bjr_response = dbus_malloc0(bjr_response_len);
2563 memcpy(service->bjr_response, bjr_response, bjr_response_len);
2564 service->bjr_response_len = bjr_response_len;
2565 } else if (upnp_service && version) {
2566 service->upnp_service = strdup(upnp_service);
2567 service->version = version;
2568 } else if (wfd_ies && wfd_ies_len) {
2569 service->wfd_ies = dbus_malloc0(wfd_ies_len);
2570 memcpy(service->wfd_ies, wfd_ies, wfd_ies_len);
2571 service->wfd_ies_len = wfd_ies_len;
2580 static void free_peer_service(struct _peer_service *service)
2582 dbus_free(service->bjr_query);
2583 dbus_free(service->bjr_response);
2584 dbus_free(service->wfd_ies);
2585 free(service->upnp_service);
2589 static int peer_service_register(unsigned char *bjr_query, int bjr_query_len,
2590 unsigned char *bjr_response, int bjr_response_len,
2591 char *upnp_service, int version,
2592 unsigned char *wfd_ies, int wfd_ies_len, int master)
2594 struct _peer_service *service;
2595 bool registration = true;
2598 service = fill_in_peer_service(bjr_query, bjr_query_len, bjr_response,
2599 bjr_response_len, upnp_service, version,
2600 wfd_ies, wfd_ies_len);
2604 service->master = master;
2606 ret = __connmanctl_dbus_method_call(connection, "net.connman", "/",
2607 "net.connman.Manager", "RegisterPeerService",
2608 peer_service_cb, GINT_TO_POINTER(registration),
2609 peer_service_append, service);
2611 free_peer_service(service);
2616 static int peer_service_unregister(unsigned char *bjr_query, int bjr_query_len,
2617 unsigned char *bjr_response, int bjr_response_len,
2618 char *upnp_service, int version,
2619 unsigned char *wfd_ies, int wfd_ies_len)
2621 struct _peer_service *service;
2622 bool registration = false;
2625 service = fill_in_peer_service(bjr_query, bjr_query_len, bjr_response,
2626 bjr_response_len, upnp_service, version,
2627 wfd_ies, wfd_ies_len);
2631 service->master = -1;
2633 ret = __connmanctl_dbus_method_call(connection, "net.connman", "/",
2634 "net.connman.Manager", "UnregisterPeerService",
2635 peer_service_cb, GINT_TO_POINTER(registration),
2636 peer_service_append, service);
2638 free_peer_service(service);
2643 static int parse_spec_array(char *command, unsigned char spec[1024])
2645 int length, pos, end;
2649 end = strlen(command);
2650 for (e = NULL, length = pos = 0; command[pos] != '\0'; length++) {
2654 b[0] = command[pos];
2655 b[1] = command[pos+1];
2657 spec[length] = strtol(b, &e, 16);
2658 if (e && *e != '\0')
2667 static int cmd_peer_service(char *args[], int num,
2668 struct connman_option *options)
2670 unsigned char bjr_query[1024] = {};
2671 unsigned char bjr_response[1024] = {};
2672 unsigned char wfd_ies[1024] = {};
2673 char *upnp_service = NULL;
2674 int bjr_query_len = 0, bjr_response_len = 0;
2675 int version = 0, master = 0, wfd_ies_len = 0;
2681 if (!strcmp(args[2], "wfd_ies")) {
2682 wfd_ies_len = parse_spec_array(args[3], wfd_ies);
2683 if (wfd_ies_len == -EINVAL)
2693 if (!strcmp(args[2], "bjr_query")) {
2694 if (strcmp(args[4], "bjr_response"))
2696 bjr_query_len = parse_spec_array(args[3], bjr_query);
2697 bjr_response_len = parse_spec_array(args[5], bjr_response);
2699 if (bjr_query_len == -EINVAL || bjr_response_len == -EINVAL)
2701 } else if (!strcmp(args[2], "upnp_service")) {
2704 if (strcmp(args[4], "upnp_version"))
2706 upnp_service = args[3];
2707 version = strtol(args[5], &e, 10);
2714 master = parse_boolean(args[6]);
2719 if (!strcmp(args[1], "register")) {
2720 return peer_service_register(bjr_query, bjr_query_len,
2721 bjr_response, bjr_response_len, upnp_service,
2722 version, wfd_ies, wfd_ies_len, master);
2723 } else if (!strcmp(args[1], "unregister")) {
2724 return peer_service_unregister(bjr_query, bjr_query_len,
2725 bjr_response, bjr_response_len, upnp_service,
2726 version, wfd_ies, wfd_ies_len);
2732 static const struct {
2734 const char *argument;
2735 struct connman_option *options;
2736 int (*func) (char *args[], int num, struct connman_option *options);
2738 __connmanctl_lookup_cb cb;
2740 { "state", NULL, NULL, cmd_state,
2741 "Shows if the system is online or offline", NULL },
2742 { "technologies", NULL, NULL, cmd_technologies,
2743 "Display technologies", NULL },
2744 { "clock", NULL, NULL, cmd_clock,
2745 "Get System Clock Properties", NULL },
2746 { "enable", "<technology>|offline", NULL, cmd_enable,
2747 "Enables given technology or offline mode",
2748 lookup_technology_offline },
2749 { "disable", "<technology>|offline", NULL, cmd_disable,
2750 "Disables given technology or offline mode",
2751 lookup_technology_offline },
2752 { "tether", "<technology> on|off\n"
2753 " wifi [on|off] <ssid> <passphrase> ",
2755 "Enable, disable tethering, set SSID and passphrase for wifi",
2757 { "tethering_clients", NULL, NULL, cmd_tethering_clients,
2758 "Display tethering clients", NULL },
2759 { "services", "[<service>]", service_options, cmd_services,
2760 "Display services", lookup_service_arg },
2761 { "peers", "[peer]", NULL, cmd_peers,
2762 "Display peers", lookup_peer_arg },
2763 { "scan", "<technology>", NULL, cmd_scan,
2764 "Scans for new services for given technology",
2765 lookup_technology_arg },
2766 { "connect", "<service/peer>", NULL, cmd_connect,
2767 "Connect a given service or peer", lookup_service_arg },
2768 { "disconnect", "<service/peer>", NULL, cmd_disconnect,
2769 "Disconnect a given service or peer", lookup_service_arg },
2770 { "move-before", "<service> <target service> ", NULL,
2771 cmd_service_move_before, "Move <service> before <target service>",
2772 lookup_service_arg },
2773 { "move-after", "<service> <target service> ", NULL,
2774 cmd_service_move_after, "Move <service> after <target service>",
2775 lookup_service_arg },
2776 { "config", "<service>", config_options, cmd_config,
2777 "Set service configuration options", lookup_config },
2778 { "monitor", "[off]", monitor_options, cmd_monitor,
2779 "Monitor signals from interfaces", lookup_monitor },
2780 { "agent", "on|off", NULL, cmd_agent,
2781 "Agent mode", lookup_agent },
2782 { "vpnconnections", "[<connection>]", NULL, cmd_vpnconnections,
2783 "Display VPN connections", lookup_vpnconnection_arg },
2784 { "vpnagent", "on|off", NULL, cmd_vpnagent,
2785 "VPN Agent mode", lookup_agent },
2786 { "session", "on|off|connect|disconnect|config", session_options,
2787 cmd_session, "Enable or disable a session", lookup_session },
2788 { "peer_service", "register|unregister <specs> <master>\n"
2789 "Where specs are:\n"
2790 "\tbjr_query <query> bjr_response <response>\n"
2791 "\tupnp_service <service> upnp_version <version>\n"
2792 "\twfd_ies <ies>\n", NULL,
2793 cmd_peer_service, "(Un)Register a Peer Service", NULL },
2794 { "help", NULL, NULL, cmd_help,
2795 "Show help", NULL },
2796 { "exit", NULL, NULL, cmd_exit,
2798 { "quit", NULL, NULL, cmd_exit,
2803 static int cmd_help(char *args[], int num, struct connman_option *options)
2805 bool interactive = __connmanctl_is_interactive();
2808 if (interactive == false)
2809 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
2811 for (i = 0; cmd_table[i].cmd; i++) {
2812 const char *cmd = cmd_table[i].cmd;
2813 const char *argument = cmd_table[i].argument;
2814 const char *desc = cmd_table[i].desc;
2816 printf("%-16s%-22s%s\n", cmd? cmd: "",
2817 argument? argument: "",
2820 if (cmd_table[i].options) {
2821 for (j = 0; cmd_table[i].options[j].name;
2823 const char *options_desc =
2824 cmd_table[i].options[j].desc ?
2825 cmd_table[i].options[j].desc: "";
2827 printf(" --%-16s%s\n",
2828 cmd_table[i].options[j].name,
2834 if (interactive == false)
2835 fprintf(stdout, "\nNote: arguments and output are considered "
2836 "EXPERIMENTAL for now.\n");
2841 __connmanctl_lookup_cb __connmanctl_get_lookup_func(const char *text)
2843 int i, cmdlen, textlen;
2848 textlen = strlen(text);
2850 for (i = 0; cmd_table[i].cmd; i++) {
2851 cmdlen = strlen(cmd_table[i].cmd);
2853 if (textlen > cmdlen && text[cmdlen] != ' ')
2856 if (strncmp(cmd_table[i].cmd, text, cmdlen) == 0)
2857 return cmd_table[i].cb;
2863 int __connmanctl_commands(DBusConnection *dbus_conn, char *argv[], int argc)
2867 connection = dbus_conn;
2869 for (i = 0; cmd_table[i].cmd; i++) {
2870 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
2871 cmd_table[i].func) {
2872 result = cmd_table[i].func(argv, argc,
2873 cmd_table[i].options);
2874 if (result < 0 && result != -EINPROGRESS)
2875 fprintf(stderr, "Error '%s': %s\n", argv[0],
2881 fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);
2885 char *__connmanctl_lookup_command(const char *text, int state)
2895 while (cmd_table[i].cmd) {
2896 const char *command = cmd_table[i].cmd;
2900 if (strncmp(text, command, len) == 0)
2901 return strdup(command);
2907 static char *get_path(char *full_path)
2911 path = strrchr(full_path, '/');
2912 if (path && *path != '\0')
2920 static void add_service_id(const char *path)
2922 g_hash_table_replace(service_hash, g_strdup(path),
2923 GINT_TO_POINTER(TRUE));
2926 static void remove_service_id(const char *path)
2928 g_hash_table_remove(service_hash, path);
2931 static void services_added(DBusMessageIter *iter)
2933 DBusMessageIter array;
2936 while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRUCT) {
2938 dbus_message_iter_recurse(iter, &array);
2939 if (dbus_message_iter_get_arg_type(&array) !=
2940 DBUS_TYPE_OBJECT_PATH)
2943 dbus_message_iter_get_basic(&array, &path);
2944 add_service_id(get_path(path));
2946 dbus_message_iter_next(iter);
2950 static void update_services(DBusMessageIter *iter)
2952 DBusMessageIter array;
2955 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
2958 dbus_message_iter_recurse(iter, &array);
2959 services_added(&array);
2961 dbus_message_iter_next(iter);
2962 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
2965 dbus_message_iter_recurse(iter, &array);
2966 while (dbus_message_iter_get_arg_type(&array) ==
2967 DBUS_TYPE_OBJECT_PATH) {
2968 dbus_message_iter_get_basic(&array, &path);
2969 remove_service_id(get_path(path));
2971 dbus_message_iter_next(&array);
2975 static int populate_service_hash(DBusMessageIter *iter, const char *error,
2979 fprintf(stderr, "Error getting services: %s", error);
2983 update_services(iter);
2987 static void add_vpnconnection_id(const char *path)
2989 g_hash_table_replace(vpnconnection_hash, g_strdup(path),
2990 GINT_TO_POINTER(TRUE));
2993 static void remove_vpnconnection_id(const char *path)
2995 g_hash_table_remove(vpnconnection_hash, path);
2998 static void vpnconnection_added(DBusMessageIter *iter)
3002 dbus_message_iter_get_basic(iter, &path);
3003 add_vpnconnection_id(get_path(path));
3006 static void vpnconnection_removed(DBusMessageIter *iter)
3010 dbus_message_iter_get_basic(iter, &path);
3011 remove_vpnconnection_id(get_path(path));
3014 static void add_vpnconnections(DBusMessageIter *iter)
3016 DBusMessageIter array;
3019 while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRUCT) {
3021 dbus_message_iter_recurse(iter, &array);
3022 if (dbus_message_iter_get_arg_type(&array) !=
3023 DBUS_TYPE_OBJECT_PATH)
3026 dbus_message_iter_get_basic(&array, &path);
3027 add_vpnconnection_id(get_path(path));
3029 dbus_message_iter_next(iter);
3033 static int populate_vpnconnection_hash(DBusMessageIter *iter, const char *error,
3036 DBusMessageIter array;
3039 fprintf(stderr, "Error getting VPN connections: %s", error);
3043 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
3046 dbus_message_iter_recurse(iter, &array);
3048 add_vpnconnections(&array);
3053 static void add_peer_id(const char *path)
3055 g_hash_table_replace(peer_hash, g_strdup(path), GINT_TO_POINTER(TRUE));
3058 static void remove_peer_id(const char *path)
3060 g_hash_table_remove(peer_hash, path);
3063 static void peers_added(DBusMessageIter *iter)
3065 DBusMessageIter array;
3068 while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRUCT) {
3070 dbus_message_iter_recurse(iter, &array);
3071 if (dbus_message_iter_get_arg_type(&array) !=
3072 DBUS_TYPE_OBJECT_PATH)
3075 dbus_message_iter_get_basic(&array, &path);
3076 add_peer_id(get_path(path));
3078 dbus_message_iter_next(iter);
3082 static void update_peers(DBusMessageIter *iter)
3084 DBusMessageIter array;
3087 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
3090 dbus_message_iter_recurse(iter, &array);
3091 peers_added(&array);
3093 dbus_message_iter_next(iter);
3094 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
3097 dbus_message_iter_recurse(iter, &array);
3098 while (dbus_message_iter_get_arg_type(&array) ==
3099 DBUS_TYPE_OBJECT_PATH) {
3100 dbus_message_iter_get_basic(&array, &path);
3101 remove_peer_id(get_path(path));
3103 dbus_message_iter_next(&array);
3107 static int populate_peer_hash(DBusMessageIter *iter,
3108 const char *error, void *user_data)
3111 fprintf(stderr, "Error getting peers: %s", error);
3119 static void add_technology_id(const char *path)
3121 g_hash_table_replace(technology_hash, g_strdup(path),
3122 GINT_TO_POINTER(TRUE));
3125 static void remove_technology_id(const char *path)
3127 g_hash_table_remove(technology_hash, path);
3130 static void remove_technology(DBusMessageIter *iter)
3134 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_OBJECT_PATH)
3137 dbus_message_iter_get_basic(iter, &path);
3138 remove_technology_id(get_path(path));
3141 static void add_technology(DBusMessageIter *iter)
3145 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_OBJECT_PATH)
3148 dbus_message_iter_get_basic(iter, &path);
3149 add_technology_id(get_path(path));
3152 static void update_technologies(DBusMessageIter *iter)
3154 DBusMessageIter array;
3156 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
3159 dbus_message_iter_recurse(iter, &array);
3161 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
3162 DBusMessageIter object_path;
3164 dbus_message_iter_recurse(&array, &object_path);
3166 add_technology(&object_path);
3168 dbus_message_iter_next(&array);
3172 static int populate_technology_hash(DBusMessageIter *iter, const char *error,
3176 fprintf(stderr, "Error getting technologies: %s\n", error);
3180 update_technologies(iter);
3185 static DBusHandlerResult monitor_completions_changed(
3186 DBusConnection *connection,
3187 DBusMessage *message, void *user_data)
3189 bool *enabled = user_data;
3190 DBusMessageIter iter;
3191 DBusHandlerResult handled;
3194 handled = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3196 handled = DBUS_HANDLER_RESULT_HANDLED;
3198 if (dbus_message_is_signal(message, "net.connman.Manager",
3199 "ServicesChanged")) {
3200 dbus_message_iter_init(message, &iter);
3201 update_services(&iter);
3205 if (dbus_message_is_signal(message, "net.connman.vpn.Manager",
3206 "ConnectionAdded")) {
3207 dbus_message_iter_init(message, &iter);
3208 vpnconnection_added(&iter);
3212 if (dbus_message_is_signal(message, "net.connman.vpn.Manager",
3213 "ConnectionRemoved")) {
3214 dbus_message_iter_init(message, &iter);
3215 vpnconnection_removed(&iter);
3219 if (dbus_message_is_signal(message, "net.connman.Manager",
3221 dbus_message_iter_init(message, &iter);
3222 update_peers(&iter);
3226 if (dbus_message_is_signal(message, "net.connman.Manager",
3227 "TechnologyAdded")) {
3228 dbus_message_iter_init(message, &iter);
3229 add_technology(&iter);
3233 if (dbus_message_is_signal(message, "net.connman.Manager",
3234 "TechnologyRemoved")) {
3235 dbus_message_iter_init(message, &iter);
3236 remove_technology(&iter);
3240 if (!g_strcmp0(dbus_message_get_interface(message),
3241 "net.connman.Manager"))
3244 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3247 void __connmanctl_monitor_completions(DBusConnection *dbus_conn)
3249 bool *manager_enabled = NULL;
3253 for (i = 0; monitor[i].interface; i++) {
3254 if (!strcmp(monitor[i].interface, "Manager")) {
3255 manager_enabled = &monitor[i].enabled;
3261 g_hash_table_destroy(service_hash);
3262 g_hash_table_destroy(vpnconnection_hash);
3263 g_hash_table_destroy(technology_hash);
3265 dbus_bus_remove_match(connection,
3266 "type='signal',interface='net.connman.Manager'", NULL);
3267 dbus_bus_remove_match(connection,
3268 "type='signal',interface='net.connman.vpn.Manager'",
3270 dbus_connection_remove_filter(connection,
3271 monitor_completions_changed,
3276 connection = dbus_conn;
3278 service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
3281 vpnconnection_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
3284 peer_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
3287 technology_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
3290 __connmanctl_dbus_method_call(connection,
3291 CONNMAN_SERVICE, CONNMAN_PATH,
3292 "net.connman.Manager", "GetServices",
3293 populate_service_hash, NULL, NULL, NULL);
3295 __connmanctl_dbus_method_call(connection,
3296 VPN_SERVICE, CONNMAN_PATH,
3297 "net.connman.vpn.Manager", "GetConnections",
3298 populate_vpnconnection_hash, NULL, NULL, NULL);
3300 __connmanctl_dbus_method_call(connection,
3301 CONNMAN_SERVICE, CONNMAN_PATH,
3302 "net.connman.Manager", "GetPeers",
3303 populate_peer_hash, NULL, NULL, NULL);
3305 __connmanctl_dbus_method_call(connection,
3306 CONNMAN_SERVICE, CONNMAN_PATH,
3307 "net.connman.Manager", "GetTechnologies",
3308 populate_technology_hash, NULL, NULL, NULL);
3310 dbus_connection_add_filter(connection,
3311 monitor_completions_changed, manager_enabled,
3314 dbus_error_init(&err);
3315 dbus_bus_add_match(connection,
3316 "type='signal',interface='net.connman.Manager'", &err);
3318 if (dbus_error_is_set(&err)) {
3319 fprintf(stderr, "Error: %s\n", err.message);
3323 dbus_bus_add_match(connection,
3324 "type='signal',interface='net.connman.vpn.Manager'",
3327 if (dbus_error_is_set(&err))
3328 fprintf(stderr, "Error: %s\n", err.message);