[connman] Added Tizen Wi-Fi Mesh
[platform/upstream/connman.git] / client / commands.c
old mode 100755 (executable)
new mode 100644 (file)
index 3f7e001..ce82791
 #include "commands.h"
 #include "agent.h"
 #include "vpnconnections.h"
+#if defined TIZEN_EXT_WIFI_MESH
+#include "mesh.h"
+#endif
 
 static DBusConnection *connection;
 static GHashTable *service_hash;
+static GHashTable *vpnconnection_hash;
 static GHashTable *peer_hash;
 static GHashTable *technology_hash;
 static char *session_notify_path;
@@ -265,6 +269,33 @@ static int cmd_state(char *args[], int num, struct connman_option *options)
                        state_print, NULL, NULL, NULL);
 }
 
+static int clock_print(DBusMessageIter *iter, const char *error,
+               void *user_data)
+{
+       DBusMessageIter entry;
+
+       if (error) {
+               fprintf(stderr, "Error: %s", 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, const char *error,
                void *user_data)
 {
@@ -495,8 +526,13 @@ struct tether_properties {
 
 static int tether_update(struct tether_properties *tether)
 {
-       if (tether->ssid_result == 0 && tether->passphrase_result == 0)
-               return tether_set("wifi", tether->set_tethering);
+       int ret;
+
+       if (tether->ssid_result == 0 && tether->passphrase_result == 0) {
+               ret = tether_set("wifi", tether->set_tethering);
+               g_free(tether);
+               return ret;
+       }
 
        if (tether->ssid_result != -EINPROGRESS &&
                        tether->passphrase_result != -EINPROGRESS) {
@@ -566,6 +602,578 @@ static int tether_set_ssid(char *ssid, char *passphrase, int set_tethering)
        return -EINPROGRESS;
 }
 
+#if defined TIZEN_EXT_WIFI_MESH
+struct mesh_if_prop {
+       char *ifname;
+       char *parent_ifname;
+       char *bridge_ifname;
+};
+
+struct mesh_create_network {
+       char *name;
+       unsigned int freq;
+       char *sec_type;
+};
+
+struct mesh_specific_scan_params {
+       char *name;
+       unsigned int freq;
+};
+
+struct mesh_gate_params {
+       bool gate_announce;
+       int hwmp_rootmode;
+       int stp;
+};
+
+static int mesh_return(DBusMessageIter *iter, const char *error,
+               void *user_data)
+{
+       char *method = user_data;
+
+       if (error)
+               fprintf(stderr, "Error %s: %s\n", method, error);
+       else
+               fprintf(stderr, "Success %s\n", method);
+
+       g_free(method);
+
+       return 0;
+}
+
+static void mesh_interface_add_append(DBusMessageIter *iter, void *user_data)
+{
+       struct mesh_if_prop *append = user_data;
+
+       /* Append Virtual Interface Name */
+               __connmanctl_dbus_append_dict_entry(iter, "Ifname",
+                               DBUS_TYPE_STRING, &append->ifname);
+
+       /* Append Parent WiFi Interface Name */
+               __connmanctl_dbus_append_dict_entry(iter, "ParentIfname",
+                               DBUS_TYPE_STRING, &append->parent_ifname);
+
+       /* Append Bridge Interface Name */
+               if (append->bridge_ifname)
+                       __connmanctl_dbus_append_dict_entry(iter, "BridgeIfname",
+                                               DBUS_TYPE_STRING, &append->bridge_ifname);
+}
+
+static void mesh_interface_remove_append(DBusMessageIter *iter, void *user_data)
+{
+       struct mesh_if_prop *append = user_data;
+
+       /* Append Virtual Interface Name */
+               __connmanctl_dbus_append_dict_entry(iter, "Ifname",
+                               DBUS_TYPE_STRING, &append->ifname);
+}
+
+static void mesh_create_network_append(DBusMessageIter *iter, void *user_data)
+{
+       struct mesh_create_network *append = user_data;
+
+       /* Append Mesh Network Name */
+               __connmanctl_dbus_append_dict_entry(iter, "Name",
+                               DBUS_TYPE_STRING, &append->name);
+
+       /* Append Mesh Network Frequency */
+               __connmanctl_dbus_append_dict_entry(iter, "Frequency",
+                               DBUS_TYPE_UINT16, &append->freq);
+
+       /* Append Mesh Network Security Type */
+               __connmanctl_dbus_append_dict_entry(iter, "Security",
+                               DBUS_TYPE_STRING, &append->sec_type);
+}
+
+static void mesh_specific_scan_append(DBusMessageIter *iter, void *user_data)
+{
+       struct mesh_specific_scan_params *append = user_data;
+
+       /* Append Mesh Network Name */
+               __connmanctl_dbus_append_dict_entry(iter, "Name",
+                               DBUS_TYPE_STRING, &append->name);
+
+       /* Append Mesh Network Frequency */
+               __connmanctl_dbus_append_dict_entry(iter, "Frequency",
+                               DBUS_TYPE_UINT16, &append->freq);
+}
+
+static void mesh_set_gate_append(DBusMessageIter *iter, void *user_data)
+{
+       struct mesh_gate_params *append = user_data;
+
+       /* Append Gate Announce Protocol */
+               __connmanctl_dbus_append_dict_entry(iter, "GateAnnounce",
+                               DBUS_TYPE_BOOLEAN, &append->gate_announce);
+
+       /* Append HWMP Root Mode */
+               __connmanctl_dbus_append_dict_entry(iter, "HWMPRootMode",
+                               DBUS_TYPE_UINT16, &append->hwmp_rootmode);
+
+       /* Append STP */
+               __connmanctl_dbus_append_dict_entry(iter, "STP", DBUS_TYPE_UINT16,
+                               &append->stp);
+}
+
+static void mesh_peer_append(DBusMessageIter *iter, void *user_data)
+{
+       char *peer_addr = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &peer_addr);
+
+       g_free(peer_addr);
+}
+
+static int mesh_peers_list(DBusMessageIter *iter,
+                                       const char *error, void *user_data)
+{
+       if (!error) {
+               __connmanctl_mesh_peers_list(iter);
+               fprintf(stdout, "\n");
+       } else
+               fprintf(stderr, "Error: %s\n", error);
+
+       return 0;
+}
+
+static int connected_mesh_peers_list(DBusMessageIter *iter,
+                                       const char *error, void *user_data)
+{
+       if (!error) {
+               __connmanctl_mesh_connected_peers_list(iter);
+               fprintf(stdout, "\n");
+       } else
+               fprintf(stderr, "Error: %s\n", error);
+
+       return 0;
+}
+
+static int disconnected_mesh_peers_list(DBusMessageIter *iter,
+                                       const char *error, void *user_data)
+{
+       if (!error) {
+               __connmanctl_mesh_disconnected_peers_list(iter);
+               fprintf(stdout, "\n");
+       } else
+               fprintf(stderr, "Error: %s\n", error);
+
+       return 0;
+}
+
+static int mesh_connect_return(DBusMessageIter *iter, const char *error,
+               void *user_data)
+{
+       char *path = user_data;
+
+       if (!error) {
+               char *str = strrchr(path, '/');
+               str++;
+               fprintf(stdout, "Connected %s\n", str);
+       } else
+               fprintf(stderr, "Error %s: %s\n", path, error);
+
+       g_free(user_data);
+
+       return 0;
+}
+
+static int mesh_disconnect_return(DBusMessageIter *iter, const char *error,
+               void *user_data)
+{
+       char *path = user_data;
+
+       if (!error) {
+               char *str = strrchr(path, '/');
+               str++;
+               fprintf(stdout, "Disconnected %s\n", str);
+       } else
+               fprintf(stderr, "Error %s: %s\n", path, error);
+
+       g_free(user_data);
+
+       return 0;
+}
+
+static int mesh_remove_return(DBusMessageIter *iter, const char *error,
+               void *user_data)
+{
+       char *path = user_data;
+
+       if (!error) {
+               char *str = strrchr(path, '/');
+               str++;
+               fprintf(stdout, "Removed %s\n", str);
+       } else
+               fprintf(stderr, "Error %s: %s\n", path, error);
+
+       g_free(user_data);
+
+       return 0;
+}
+
+static int mesh_config_return(DBusMessageIter *iter, const char *error,
+               void *user_data)
+{
+       char *path = user_data;
+       char *str = strrchr(path, '/');
+       str++;
+
+       if (error)
+               fprintf(stderr, "Error %s: %s\n", path, error);
+       else
+               fprintf(stdout, "Success SetProperty %s\n", str);
+
+       g_free(user_data);
+
+       return 0;
+}
+
+static int cmd_mesh(char *args[], int num, struct connman_option *options)
+{
+       int result = 0;
+       int c;
+       char *path = NULL;
+       char *method = NULL;
+       char *mesh_peer_name = NULL;
+       char *mesh_peer_path = NULL;
+       char *property = NULL;
+       char *value = NULL;
+       struct mesh_if_prop *append;
+       struct mesh_create_network *network;
+       struct mesh_specific_scan_params *scan_params;
+       struct mesh_gate_params *gate_params;
+       char *mesh_peer_addr = NULL;
+
+       c = parse_args(args[1], options);
+
+       switch (c) {
+       case 'a':
+               if (num < 4 || num > 5) {
+                       result = -EINVAL;
+                       break;
+               }
+               path = g_strdup_printf("/net/connman/technology/mesh");
+
+               append = dbus_malloc0(sizeof(struct mesh_if_prop));
+               append->ifname = g_strdup(args[2]);
+               append->parent_ifname = g_strdup(args[3]);
+               if (num == 5)
+                       append->bridge_ifname = g_strdup(args[4]);
+               method = g_strdup("MeshInterfaceAdd");
+               result = __connmanctl_dbus_mesh_dict(connection, path,
+                                                       "net.connman.Technology", mesh_return, method,
+                                                       "MeshInterfaceAdd", DBUS_TYPE_STRING,
+                                                       mesh_interface_add_append, append);
+               g_free(append->ifname);
+               g_free(append->parent_ifname);
+               g_free(append->bridge_ifname);
+               g_free(append);
+               break;
+
+       case 'r':
+               if (num != 3) {
+                       result = -EINVAL;
+                       break;
+               }
+               path = g_strdup_printf("/net/connman/technology/mesh");
+
+               append = dbus_malloc0(sizeof(struct mesh_if_prop));
+               append->ifname = g_strdup(args[2]);
+               method = g_strdup("MeshInterfaceRemove");
+               result = __connmanctl_dbus_mesh_dict(connection, path,
+                                                       "net.connman.Technology", mesh_return, method,
+                                                       "MeshInterfaceRemove", DBUS_TYPE_STRING,
+                                                       mesh_interface_remove_append, append);
+               g_free(append->ifname);
+               g_free(append);
+               break;
+
+       case 'p':
+               if (num > 3) {
+                       result = -E2BIG;
+                       break;
+               }
+
+               if (num == 3)
+                       mesh_peer_name = args[2];
+
+               if (!mesh_peer_name) {
+                       result = __connmanctl_dbus_method_call(connection,
+                                       CONNMAN_SERVICE, CONNMAN_PATH,
+                                       "net.connman.Manager", "GetMeshPeers",
+                                       mesh_peers_list, NULL, NULL, NULL);
+                       break;
+               }
+
+               if (check_dbus_name(mesh_peer_name) == false) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s",
+                                                                       mesh_peer_name);
+               result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
+                                               mesh_peer_path, "net.connman.Mesh", "GetProperties",
+                                               object_properties, mesh_peer_path, NULL, NULL);
+               break;
+
+       case 'c':
+               if (num < 3) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               if (num > 3) {
+                       result = -E2BIG;
+                       break;
+               }
+
+               mesh_peer_name = args[2];
+
+               if (check_dbus_name(mesh_peer_name) == false) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s",
+                                                                       mesh_peer_name);
+               result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
+                                               mesh_peer_path, "net.connman.Mesh", "Connect",
+                                               mesh_connect_return, mesh_peer_path, NULL, NULL);
+               break;
+
+       case 'd':
+               if (num < 3) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               if (num > 3) {
+                       result = -E2BIG;
+                       break;
+               }
+
+               mesh_peer_name = args[2];
+
+               if (check_dbus_name(mesh_peer_name) == false) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s",
+                                                                       mesh_peer_name);
+               result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
+                                               mesh_peer_path, "net.connman.Mesh", "Disconnect",
+                                               mesh_disconnect_return, mesh_peer_path, NULL, NULL);
+               break;
+
+       case 'f':
+               if (num < 3) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               if (num > 3) {
+                       result = -E2BIG;
+                       break;
+               }
+
+               mesh_peer_name = args[2];
+
+               if (check_dbus_name(mesh_peer_name) == false) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s",
+                                                                       mesh_peer_name);
+               result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE,
+                                               mesh_peer_path, "net.connman.Mesh", "Remove",
+                                               mesh_remove_return, mesh_peer_path, NULL, NULL);
+               break;
+
+       case 'C':
+               if (num > 2) {
+                       result = -E2BIG;
+                       break;
+               }
+
+               result = __connmanctl_dbus_method_call(connection,
+                                                               CONNMAN_SERVICE, CONNMAN_PATH,
+                                                               "net.connman.Manager", "GetConnectedMeshPeers",
+                                                               connected_mesh_peers_list, NULL, NULL, NULL);
+               break;
+
+       case 'D':
+               if (num > 2) {
+                       result = -E2BIG;
+                       break;
+               }
+
+               result = __connmanctl_dbus_method_call(connection,
+                                                               CONNMAN_SERVICE, CONNMAN_PATH,
+                                                               "net.connman.Manager",
+                                                               "GetDisconnectedMeshPeers",
+                                                               disconnected_mesh_peers_list, NULL, NULL, NULL);
+               break;
+
+       case 'n':
+               if (num != 5) {
+                       result = -EINVAL;
+                       break;
+               }
+               path = g_strdup_printf("/net/connman/technology/mesh");
+
+               network = dbus_malloc0(sizeof(struct mesh_create_network));
+               network->name = g_strdup(args[2]);
+               network->freq = atoi(args[3]);
+               network->sec_type = g_strdup(args[4]);
+               method = g_strdup("MeshCreateNetwork");
+               result = __connmanctl_dbus_mesh_dict(connection, path,
+                                                       "net.connman.Technology", mesh_return, method,
+                                                       "MeshCreateNetwork", DBUS_TYPE_STRING,
+                                                       mesh_create_network_append, network);
+               g_free(network->name);
+               g_free(network->sec_type);
+               g_free(network);
+               break;
+
+       case 'A':
+               if (num != 2) {
+                       result = -EINVAL;
+                       break;
+               }
+               path = g_strdup_printf("/net/connman/technology/mesh");
+
+               method = g_strdup("AbortScan");
+               result = __connmanctl_dbus_mesh_dict(connection, path,
+                                                       "net.connman.Technology", mesh_return, method,
+                                                       "AbortScan", DBUS_TYPE_STRING,
+                                                       NULL, NULL);
+               break;
+
+       case 'S':
+               if (num != 4) {
+                       result = -EINVAL;
+                       break;
+               }
+               path = g_strdup_printf("/net/connman/technology/mesh");
+
+               scan_params = dbus_malloc0(sizeof(struct mesh_specific_scan_params));
+               scan_params->name = g_strdup(args[2]);
+               scan_params->freq = atoi(args[3]);
+               method = g_strdup("MeshSpecificScan");
+               result = __connmanctl_dbus_mesh_dict(connection, path,
+                                                       "net.connman.Technology", mesh_return, method,
+                                                       "MeshSpecificScan", DBUS_TYPE_STRING,
+                                                       mesh_specific_scan_append, scan_params);
+               g_free(scan_params->name);
+               g_free(scan_params);
+               break;
+
+       case 'P':
+               if (num != 5) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               mesh_peer_name = args[2];
+               property = args[3];
+               value = args[4];
+
+               if (check_dbus_name(mesh_peer_name) == false) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s",
+                                                                       mesh_peer_name);
+
+               if (g_strcmp0(property, "Passphrase") == 0) {
+                       result = __connmanctl_dbus_set_property(connection,
+                                                               mesh_peer_path, "net.connman.Mesh",
+                                                               mesh_config_return, mesh_peer_path, property,
+                                                               DBUS_TYPE_STRING, &value);
+               } else {
+                       printf("Invalid property %s\n", property);
+                       result = -EINVAL;
+               }
+
+               break;
+
+       case 'G':
+               if (num != 5) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               path = g_strdup_printf("/net/connman/technology/mesh");
+
+               gate_params = dbus_malloc0(sizeof(struct mesh_gate_params));
+               gate_params->gate_announce = atoi(args[2]);
+               gate_params->hwmp_rootmode = atoi(args[3]);
+               gate_params->stp = atoi(args[4]);
+
+               method = g_strdup("SetMeshGate");
+
+               result = __connmanctl_dbus_mesh_dict(connection, path,
+                                                       "net.connman.Technology", mesh_return, method,
+                                                       "SetMeshGate", DBUS_TYPE_STRING,
+                                                       mesh_set_gate_append, gate_params);
+
+               break;
+
+       case 'z':
+               if (num != 3) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               mesh_peer_addr = g_strdup(args[2]);
+               method = g_strdup("MeshAddPeer");
+
+               result = __connmanctl_dbus_method_call(connection,
+                                                               CONNMAN_SERVICE, CONNMAN_PATH,
+                                                               "net.connman.Manager", "MeshAddPeer",
+                                                               mesh_return, method, mesh_peer_append,
+                                                               mesh_peer_addr);
+
+               break;
+
+       case 'y':
+               if (num != 3) {
+                       result = -EINVAL;
+                       break;
+               }
+
+               mesh_peer_addr = g_strdup(args[2]);
+               method = g_strdup("MeshRemovePeer");
+
+               result = __connmanctl_dbus_method_call(connection,
+                                                               CONNMAN_SERVICE, CONNMAN_PATH,
+                                                               "net.connman.Manager", "MeshRemovePeer",
+                                                               mesh_return, method, mesh_peer_append,
+                                                               mesh_peer_addr);
+
+               break;
+
+       default:
+               result = -EINVAL;
+               break;
+       }
+
+       g_free(path);
+
+       if (result < 0) {
+               if (result != -EINPROGRESS)
+                       printf("Error '%s': %s\n", args[1], strerror(-result));
+       }
+
+
+       return result;
+}
+#endif
+
 static int cmd_tether(char *args[], int num, struct connman_option *options)
 {
        char *ssid, *passphrase;
@@ -725,6 +1333,131 @@ static int cmd_disconnect(char *args[], int num, struct connman_option *options)
                                        disconnect_return, path, NULL, NULL);
 }
 
+struct move_service {
+       char *service;
+       char *target;
+};
+
+static int move_before_return(DBusMessageIter *iter, 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);
+
+       return;
+}
+
+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, 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);
+
+       return;
+}
+
+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, const char *error,
                void *user_data)
 {
@@ -1738,6 +2471,8 @@ static int session_config(char *args[], int num,
        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];
@@ -1764,6 +2499,41 @@ static int session_config(char *args[], int num,
                                        DBUS_TYPE_STRING, &args[index + 1]);
                        append.values = 2;
                        break;
+               case 'i':
+                       if (index + 1 < num)
+                               ifname = args[index + 1];
+                       else
+                               ifname = "";
+
+                       res = __connmanctl_dbus_session_change(connection,
+                                       session_path, session_config_return,
+                                       "AllowedInterface", "AllowedInterface",
+                                       DBUS_TYPE_STRING, &ifname);
+                       append.values = 2;
+                       break;
+               case 's':
+                       if (!args[index + 1]) {
+                               res = -EINVAL;
+                               break;
+                       }
+                       switch (parse_boolean(args[index + 1])) {
+                       case 1:
+                               source_ip_rule = TRUE;
+                               break;
+                       case 0:
+                               source_ip_rule = FALSE;
+                               break;
+                       default:
+                               res = -EINVAL;
+                               break;
+                       }
+
+                       res = __connmanctl_dbus_session_change(connection,
+                                       session_path, session_config_return,
+                                       "SourceIPRule", "SourceIPRule",
+                                       DBUS_TYPE_BOOLEAN, &source_ip_rule);
+                       append.values = 2;
+                       break;
 
                default:
                        res = -EINVAL;
@@ -1838,22 +2608,21 @@ static int cmd_exit(char *args[], int num, struct connman_option *options)
        return 1;
 }
 
-static char *lookup_service(const char *text, int state)
+static char *lookup_key_from_table(GHashTable *hash, const char *text,
+                                       int state)
 {
        static int len = 0;
        static GHashTableIter iter;
        gpointer key, value;
 
        if (state == 0) {
-               g_hash_table_iter_init(&iter, service_hash);
+               g_hash_table_iter_init(&iter, hash);
                len = strlen(text);
        }
 
-       while (g_hash_table_iter_next(&iter, &key, &value)) {
-               const char *service = key;
-               if (strncmp(text, service, len) == 0)
-                       return strdup(service);
-       }
+       while (g_hash_table_iter_next(&iter, &key, &value))
+               if (strncmp(text, key, len) == 0)
+                       return strdup(key);
 
        return NULL;
 }
@@ -1865,7 +2634,7 @@ static char *lookup_service_arg(const char *text, int state)
                return NULL;
        }
 
-       return lookup_service(text, state);
+       return lookup_key_from_table(service_hash, text, state);
 }
 
 static char *lookup_peer(const char *text, int state)
@@ -2009,6 +2778,16 @@ static char *lookup_agent(const char *text, int state)
        return lookup_on_off(text, state);
 }
 
+static char *lookup_vpnconnection_arg(const char *text, int state)
+{
+       if (__connmanctl_input_calc_level() > 1) {
+               __connmanctl_input_lookup_end();
+               return NULL;
+       }
+
+       return lookup_key_from_table(vpnconnection_hash, text, state);
+}
+
 static struct connman_option service_options[] = {
        {"properties", 'p', "[<service>]      (obsolete)"},
        { NULL, }
@@ -2042,9 +2821,43 @@ static struct connman_option monitor_options[] = {
 static struct connman_option session_options[] = {
        {"bearers", 'b', "<technology1> [<technology2> [...]]"},
        {"type", 't', "local|internet|any"},
+       {"ifname", 'i', "[<interface_name>]"},
+       {"srciprule", 's', "yes|no"},
        { NULL, }
 };
 
+#if defined TIZEN_EXT_WIFI_MESH
+static struct connman_option mesh_options[] = {
+       {"ifadd", 'a', "<ifname> <wifi_ifname>\n"
+               "                     [bridge_ifname]                Add Virtual Mesh "
+                       "interface"},
+       {"ifrmv", 'r', "<ifname>                       Remove Virtual Mesh "
+               "interface"},
+       {"peers", 'p', "[peer]                         Display Mesh peer "
+               "informations"},
+       {"connect", 'c', "<peer>                         Connect Mesh Peer"},
+       {"disconnect", 'd', "<peer>                         Disconnect Mesh Peer"},
+       {"remove", 'f', "<peer>                         Forget Mesh Peer"},
+       {"connected_peers", 'C', "[]                             Displays connected"
+               " Peer informations"},
+       {"disconnected_peers", 'D', "[]                           Displays "
+               "Disconnected Peer informations"},
+       {"create_network", 'n', "<name> <frequency> <sec_type>  Create New Mesh "
+               "Network"},
+       {"abort_scan", 'A', "                               Abort ongoing mesh "
+               "scan"},
+       {"specific_scan", 'S', "<name> <frequency>             Create New Mesh "
+               "Network"},
+       {"config", 'P', "<peer>                         Set Mesh Network "
+               "Configurations\n          Passphrase    <passphrase>"},
+       {"set_gate", 'G', "<gate_ann> <rootmode> <stp>    Set Mesh Gate "
+               "Option"},
+       {"add_peer", 'z', "<addr>                         Add Mesh Peer"},
+       {"remove_peer", 'y', "<addr>                         Remove Mesh Peer"},
+       { NULL, }
+};
+#endif
+
 static char *lookup_options(struct connman_option *options, const char *text,
                int state)
 {
@@ -2087,7 +2900,7 @@ static char *lookup_monitor(const char *text, int state)
 static char *lookup_config(const char *text, int state)
 {
        if (__connmanctl_input_calc_level() < 2)
-               return lookup_service(text, state);
+               return lookup_key_from_table(service_hash, text, state);
 
        return lookup_options(config_options, text, state);
 }
@@ -2097,6 +2910,13 @@ static char *lookup_session(const char *text, int state)
        return lookup_options(session_options, text, state);
 }
 
+#if defined TIZEN_EXT_WIFI_MESH
+static char *lookup_mesh(const char *text, int state)
+{
+       return lookup_options(mesh_options, text, state);
+}
+#endif
+
 static int peer_service_cb(DBusMessageIter *iter, const char *error,
                                                        void *user_data)
 {
@@ -2400,12 +3220,18 @@ static const struct {
          "Shows if the system is online or offline", NULL },
        { "technologies", NULL,           NULL,            cmd_technologies,
          "Display technologies", NULL },
+       { "clock",        NULL,           NULL,            cmd_clock,
+         "Get System Clock Properties", NULL },
        { "enable",       "<technology>|offline", NULL,    cmd_enable,
          "Enables given technology or offline mode",
          lookup_technology_offline },
        { "disable",      "<technology>|offline", NULL,    cmd_disable,
          "Disables given technology or offline mode",
          lookup_technology_offline },
+#if defined TIZEN_EXT_WIFI_MESH
+       { "mesh",      "", mesh_options, cmd_mesh, "Mesh specific commands",
+               lookup_mesh },
+#endif
        { "tether", "<technology> on|off\n"
                    "            wifi [on|off] <ssid> <passphrase> ",
                                          NULL,            cmd_tether,
@@ -2422,14 +3248,20 @@ static const struct {
          "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,
@@ -2633,6 +3465,72 @@ static int populate_service_hash(DBusMessageIter *iter, const char *error,
        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, 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));
@@ -2785,6 +3683,20 @@ static DBusHandlerResult monitor_completions_changed(
                return handled;
        }
 
+       if (dbus_message_is_signal(message, "net.connman.vpn.Manager",
+                                       "ConnectionAdded")) {
+               dbus_message_iter_init(message, &iter);
+               vpnconnection_added(&iter);
+               return handled;
+       }
+
+       if (dbus_message_is_signal(message, "net.connman.vpn.Manager",
+                                       "ConnectionRemoved")) {
+               dbus_message_iter_init(message, &iter);
+               vpnconnection_removed(&iter);
+               return handled;
+       }
+
        if (dbus_message_is_signal(message, "net.connman.Manager",
                                                "PeersChanged")) {
                dbus_message_iter_init(message, &iter);
@@ -2828,10 +3740,14 @@ void __connmanctl_monitor_completions(DBusConnection *dbus_conn)
 
        if (!dbus_conn) {
                g_hash_table_destroy(service_hash);
+               g_hash_table_destroy(vpnconnection_hash);
                g_hash_table_destroy(technology_hash);
 
                dbus_bus_remove_match(connection,
                        "type='signal',interface='net.connman.Manager'", NULL);
+               dbus_bus_remove_match(connection,
+                       "type='signal',interface='net.connman.vpn.Manager'",
+                       NULL);
                dbus_connection_remove_filter(connection,
                                        monitor_completions_changed,
                                        manager_enabled);
@@ -2843,6 +3759,9 @@ void __connmanctl_monitor_completions(DBusConnection *dbus_conn)
        service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                                g_free, NULL);
 
+       vpnconnection_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                               g_free, NULL);
+
        peer_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                                g_free, NULL);
 
@@ -2855,6 +3774,11 @@ void __connmanctl_monitor_completions(DBusConnection *dbus_conn)
                                populate_service_hash, NULL, NULL, NULL);
 
        __connmanctl_dbus_method_call(connection,
+                               VPN_SERVICE, CONNMAN_PATH,
+                               "net.connman.vpn.Manager", "GetConnections",
+                               populate_vpnconnection_hash, NULL, NULL, NULL);
+
+       __connmanctl_dbus_method_call(connection,
                                CONNMAN_SERVICE, CONNMAN_PATH,
                                "net.connman.Manager", "GetPeers",
                                populate_peer_hash, NULL, NULL, NULL);
@@ -2872,6 +3796,15 @@ void __connmanctl_monitor_completions(DBusConnection *dbus_conn)
        dbus_bus_add_match(connection,
                        "type='signal',interface='net.connman.Manager'", &err);
 
+       if (dbus_error_is_set(&err)) {
+               fprintf(stderr, "Error: %s\n", err.message);
+               return;
+       }
+
+       dbus_bus_add_match(connection,
+                       "type='signal',interface='net.connman.vpn.Manager'",
+                       &err);
+
        if (dbus_error_is_set(&err))
                fprintf(stderr, "Error: %s\n", err.message);
 }