summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--[-rwxr-xr-x]Makefile.am24
-rw-r--r--[-rwxr-xr-x]client/commands.c618
-rw-r--r--[-rwxr-xr-x]client/dbus_helpers.c49
-rw-r--r--[-rwxr-xr-x]client/dbus_helpers.h9
-rw-r--r--client/mesh.c166
-rw-r--r--client/mesh.h40
-rw-r--r--configure.ac5
-rw-r--r--[-rwxr-xr-x]gsupplicant/gsupplicant.h53
-rw-r--r--gsupplicant/supplicant.c526
-rw-r--r--[-rwxr-xr-x]include/dbus.h3
-rw-r--r--[-rwxr-xr-x]include/device.h7
-rw-r--r--[-rwxr-xr-x]include/inet.h5
-rw-r--r--include/mesh-netlink.h58
-rw-r--r--include/mesh.h155
-rw-r--r--[-rwxr-xr-x]include/service.h7
-rw-r--r--[-rwxr-xr-x]packaging/connman.spec21
-rw-r--r--[-rwxr-xr-x]plugins/ethernet.c65
-rw-r--r--[-rwxr-xr-x]plugins/wifi.c805
-rw-r--r--[-rwxr-xr-x]src/config.c3
-rw-r--r--[-rwxr-xr-x]src/connman.h28
-rw-r--r--[-rwxr-xr-x]src/device.c110
-rw-r--r--[-rwxr-xr-x]src/dhcp.c35
-rw-r--r--[-rwxr-xr-x]src/error.c14
-rw-r--r--[-rwxr-xr-x]src/inet.c93
-rw-r--r--[-rwxr-xr-x]src/main.c6
-rw-r--r--[-rwxr-xr-x]src/manager.c123
-rw-r--r--src/mesh-netlink.c187
-rw-r--r--src/mesh.c1660
-rw-r--r--[-rwxr-xr-x]src/notifier.c6
-rw-r--r--[-rwxr-xr-x]src/rtnl.c14
-rw-r--r--[-rwxr-xr-x]src/service.c37
-rw-r--r--[-rwxr-xr-x]src/session.c3
-rw-r--r--[-rwxr-xr-x]src/technology.c531
-rw-r--r--[-rwxr-xr-x]src/wispr.c3
34 files changed, 5437 insertions, 32 deletions
diff --git a/Makefile.am b/Makefile.am
index 76c5419..94c6e9d 100755..100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,6 +13,10 @@ include_HEADERS = include/log.h include/plugin.h \
include/session.h include/ipaddress.h include/agent.h \
include/inotify.h include/peer.h include/machine.h
+if TIZEN_EXT_WIFI_MESH
+include_HEADERS += include/mesh.h include/mesh-netlink.h
+endif
+
nodist_include_HEADERS = include/version.h
noinst_HEADERS = include/rtnl.h include/task.h \
@@ -129,10 +133,18 @@ src_connmand_SOURCES = $(gdhcp_sources) $(gweb_sources) \
src/inotify.c src/ipv6pd.c src/peer.c \
src/peer_service.c src/machine.c src/util.c
+if TIZEN_EXT_WIFI_MESH
+src_connmand_SOURCES += src/mesh.c src/mesh-netlink.c
+endif
+
src_connmand_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ @GNUTLS_LIBS@ @LIBSYSTEMD_LIBS@ \
-lresolv -ldl -lrt
+if TIZEN_EXT_WIFI_MESH
+src_connmand_LDADD += -lnl -lnl-genl
+endif
+
src_connmand_LDFLAGS = -Wl,--export-dynamic -pie \
-Wl,--version-script=$(srcdir)/src/connman.ver
@@ -190,11 +202,19 @@ vpn_connman_vpnd_SOURCES = $(gdhcp_sources) $(builtin_vpn_sources) \
vpn/vpn-agent.c vpn/vpn-agent.h \
vpn/vpn-config.c
+if TIZEN_EXT_WIFI_MESH
+vpn_connman_vpnd_SOURCES += src/mesh.c src/mesh-netlink.c
+endif
+
vpn_connman_vpnd_LDADD = gdbus/libgdbus-internal.la $(builtin_vpn_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ @XTABLES_LIBS@ @GNUTLS_LIBS@ \
@LIBSYSTEMD_LIBS@ \
-lresolv -ldl
+if TIZEN_EXT_WIFI_MESH
+vpn_connman_vpnd_LDADD += -lnl -lnl-genl
+endif
+
vpn_connman_vpnd_LDFLAGS = -Wl,--export-dynamic \
-Wl,--version-script=$(srcdir)/vpn/vpn.ver
endif
@@ -314,6 +334,10 @@ client_connmanctl_SOURCES = client/dbus_helpers.h client/dbus_helpers.c \
client/vpnconnections.h client/vpnconnections.c \
client/main.c
+if TIZEN_EXT_WIFI_MESH
+client_connmanctl_SOURCES += client/mesh.c client/mesh.h
+endif
+
client_connmanctl_LDADD = gdbus/libgdbus-internal.la @DBUS_LIBS@ @GLIB_LIBS@ \
-lreadline -ldl -lncurses
endif
diff --git a/client/commands.c b/client/commands.c
index 746e158..ce82791 100755..100644
--- a/client/commands.c
+++ b/client/commands.c
@@ -43,6 +43,9 @@
#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;
@@ -599,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;
@@ -2251,6 +2826,38 @@ static struct connman_option session_options[] = {
{ 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)
{
@@ -2303,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)
{
@@ -2614,6 +3228,10 @@ static const struct {
{ "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,
diff --git a/client/dbus_helpers.c b/client/dbus_helpers.c
index 6ca407d..8c6bdbb 100755..100644
--- a/client/dbus_helpers.c
+++ b/client/dbus_helpers.c
@@ -224,6 +224,11 @@ static int append_variant(DBusMessageIter *iter, const char *property,
case DBUS_TYPE_INT32:
type_str = DBUS_TYPE_INT32_AS_STRING;
break;
+#if defined TIZEN_EXT_WIFI_MESH
+ case DBUS_TYPE_UINT16:
+ type_str = DBUS_TYPE_UINT16_AS_STRING;
+ break;
+#endif
default:
return -EOPNOTSUPP;
}
@@ -354,6 +359,50 @@ int __connmanctl_dbus_set_property_dict(DBusConnection *connection,
return send_method_call(connection, message, cb, user_data);
}
+#if defined TIZEN_EXT_WIFI_MESH
+int __connmanctl_dbus_mesh_dict(DBusConnection *connection,
+ const char *path, const char *interface,
+ connmanctl_dbus_method_return_func_t cb, void *user_data,
+ const char *property, int type,
+ connmanctl_dbus_append_func_t append_fn,
+ void *append_user_data)
+{
+ DBusMessage *message;
+ DBusMessageIter iter, variant, dict;
+
+ message = dbus_message_new_method_call(CONNMAN_SERVICE, path,
+ interface, "MeshCommands");
+
+ if (!message)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &variant);
+
+ dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &dict);
+
+ if (append_fn)
+ append_fn(&dict, append_user_data);
+
+ dbus_message_iter_close_container(&variant, &dict);
+ dbus_message_iter_close_container(&iter, &variant);
+
+ return send_method_call(connection, message, cb, user_data);
+}
+#endif
+
static void append_variant_array(DBusMessageIter *iter, const char *property,
connmanctl_dbus_append_func_t append_fn,
void *append_user_data)
diff --git a/client/dbus_helpers.h b/client/dbus_helpers.h
index 395808a..6945839 100755..100644
--- a/client/dbus_helpers.h
+++ b/client/dbus_helpers.h
@@ -67,6 +67,15 @@ int __connmanctl_dbus_set_property_dict(DBusConnection *connection,
connmanctl_dbus_append_func_t append_fn,
void *append_user_data);
+#if defined TIZEN_EXT_WIFI_MESH
+int __connmanctl_dbus_mesh_dict(DBusConnection *connection,
+ const char *path, const char *interface,
+ connmanctl_dbus_method_return_func_t cb, void *user_data,
+ const char *property, int type,
+ connmanctl_dbus_append_func_t append_fn,
+ void *append_user_data);
+#endif
+
void __connmanctl_dbus_append_dict_string_array(DBusMessageIter *iter,
const char *property, connmanctl_dbus_append_func_t append_fn,
void *append_user_data);
diff --git a/client/mesh.c b/client/mesh.c
new file mode 100644
index 0000000..6e57793
--- /dev/null
+++ b/client/mesh.c
@@ -0,0 +1,166 @@
+/*
+ *
+ * Connection Manager
+ *
+ *
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "mesh.h"
+#include "dbus_helpers.h"
+
+static void print_mesh_peer(char *path, DBusMessageIter *iter)
+{
+ char *name = "";
+ char state = ' ';
+ char *str, *property;
+ DBusMessageIter entry, val;
+ int count = 0, favorite = 0;
+
+ while (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
+ dbus_message_iter_recurse(iter, &entry);
+ dbus_message_iter_get_basic(&entry, &property);
+
+ if (strcmp(property, "Name") == 0) {
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &val);
+ dbus_message_iter_get_basic(&val, &name);
+ } else if (strcmp(property, "State") == 0) {
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &val);
+ dbus_message_iter_get_basic(&val, &str);
+
+ if (str) {
+ if (strcmp(str, "online") == 0)
+ state = 'O';
+ else if (strcmp(str, "ready") == 0)
+ state = 'R';
+ else if (!strcmp(str, "association"))
+ state = 'a';
+ else if (!strcmp(str, "configuration"))
+ state = 'c';
+ else if (!strcmp(str, "disconnect"))
+ state = 'd';
+ }
+ } else if (strcmp(property, "Favorite") == 0) {
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &val);
+ dbus_message_iter_get_basic(&val, &favorite);
+ }
+
+ dbus_message_iter_next(iter);
+ count++;
+ }
+
+ str = strrchr(path, '/');
+ if (str)
+ str++;
+ else
+ str = path;
+
+ if (count > 0)
+ fprintf(stdout, "%c%c %-20s %s", favorite != 0 ? 'A' : ' ',
+ state, name, str);
+ else
+ fprintf(stdout, "%s %s", "unchanged", str);
+}
+
+static void list_mesh_peer_array(DBusMessageIter *iter)
+{
+ DBusMessageIter array, dict;
+ 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);
+
+ dbus_message_iter_next(&array);
+ if (dbus_message_iter_get_arg_type(&array)
+ == DBUS_TYPE_ARRAY) {
+ dbus_message_iter_recurse(&array, &dict);
+ print_mesh_peer(path, &dict);
+ }
+
+ if (dbus_message_iter_has_next(iter))
+ fprintf(stdout, "\n");
+
+ dbus_message_iter_next(iter);
+ }
+}
+
+void __connmanctl_mesh_peers_list(DBusMessageIter *iter)
+{
+ DBusMessageIter array;
+ char *path;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return;
+
+ dbus_message_iter_recurse(iter, &array);
+ list_mesh_peer_array(&array);
+
+ dbus_message_iter_next(iter);
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return;
+
+ fprintf(stdout, "\n}, {");
+
+ dbus_message_iter_recurse(iter, &array);
+ while (dbus_message_iter_get_arg_type(&array)
+ == DBUS_TYPE_OBJECT_PATH) {
+ dbus_message_iter_get_basic(&array, &path);
+ fprintf(stdout, "\n%s %s", "removed", path);
+
+ dbus_message_iter_next(&array);
+ }
+
+}
+
+void __connmanctl_mesh_connected_peers_list(DBusMessageIter *iter)
+{
+ DBusMessageIter array;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return;
+
+ dbus_message_iter_recurse(iter, &array);
+ __connmanctl_dbus_print(&array, " ", " = ", "\n");
+ fprintf(stdout, "\n");
+}
+
+void __connmanctl_mesh_disconnected_peers_list(DBusMessageIter *iter)
+{
+ DBusMessageIter array;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return;
+
+ dbus_message_iter_recurse(iter, &array);
+ __connmanctl_dbus_print(&array, " ", " = ", "\n");
+ fprintf(stdout, "\n");
+}
diff --git a/client/mesh.h b/client/mesh.h
new file mode 100644
index 0000000..8dd413d
--- /dev/null
+++ b/client/mesh.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Connection Manager
+ *
+ *
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __CONNMANCTL_MESH_H
+#define __CONNMANCTL_MESH_H
+
+#include <dbus/dbus.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void __connmanctl_mesh_peers_list(DBusMessageIter *iter);
+void __connmanctl_mesh_connected_peers_list(DBusMessageIter *iter);
+void __connmanctl_mesh_disconnected_peers_list(DBusMessageIter *iter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMANCTL_MESH_H */
diff --git a/configure.ac b/configure.ac
index 01ecd95..3a569d4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -79,6 +79,11 @@ AC_ARG_ENABLE(tizen-ext,
fi])
AM_CONDITIONAL(TIZEN_EXT, test "${enable-tizen-ext}" != "no")
+AC_ARG_ENABLE(tizen-ext-wifi-mesh,
+ AC_HELP_STRING([--enable-tizen-ext-wifi-mesh], [enable TIZEN extensions for Wi-Fi Mesh]),
+ [CFLAGS="$CFLAGS -DTIZEN_EXT_WIFI_MESH"], [enable_tizen_ext_wifi_mesh="no"])
+AM_CONDITIONAL(TIZEN_EXT_WIFI_MESH, test "${enable_tizen_ext_wifi_mesh}" != "no")
+
AC_ARG_WITH(openconnect, AC_HELP_STRING([--with-openconnect=PROGRAM],
[specify location of openconnect binary]), [path_openconnect=${withval}])
diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index 648ee57..7e94711 100755..100644
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -50,6 +50,9 @@ extern "C" {
#define G_SUPPLICANT_CAPABILITY_MODE_IBSS (1 << 1)
#define G_SUPPLICANT_CAPABILITY_MODE_AP (1 << 2)
#define G_SUPPLICANT_CAPABILITY_MODE_P2P (1 << 3)
+#if defined TIZEN_EXT_WIFI_MESH
+#define G_SUPPLICANT_CAPABILITY_MODE_MESH (1 << 4)
+#endif
#define G_SUPPLICANT_KEYMGMT_NONE (1 << 0)
#define G_SUPPLICANT_KEYMGMT_IEEE8021X (1 << 1)
@@ -66,6 +69,9 @@ extern "C" {
#define G_SUPPLICANT_KEYMGMT_WPA_EAP (1 << 7)
#define G_SUPPLICANT_KEYMGMT_WPA_EAP_256 (1 << 8)
#define G_SUPPLICANT_KEYMGMT_WPS (1 << 9)
+#if defined TIZEN_EXT_WIFI_MESH
+#define G_SUPPLICANT_KEYMGMT_SAE (1 << 10)
+#endif
#define G_SUPPLICANT_PROTO_WPA (1 << 0)
#define G_SUPPLICANT_PROTO_RSN (1 << 1)
@@ -94,8 +100,19 @@ typedef enum {
G_SUPPLICANT_MODE_INFRA,
G_SUPPLICANT_MODE_IBSS,
G_SUPPLICANT_MODE_MASTER,
+#if defined TIZEN_EXT_WIFI_MESH
+ G_SUPPLICANT_MODE_MESH,
+#endif
} GSupplicantMode;
+#if defined TIZEN_EXT_WIFI_MESH
+typedef enum {
+ G_SUPPLICANT_IEEE80211W_UNKNOWN,
+ G_SUPPLICANT_IEEE80211W_OPTIONAL,
+ G_SUPPLICANT_IEEE80211W_REQUIRED,
+} GSupplicantPmf;
+#endif
+
typedef enum {
G_SUPPLICANT_SECURITY_UNKNOWN,
G_SUPPLICANT_SECURITY_NONE,
@@ -106,6 +123,9 @@ typedef enum {
G_SUPPLICANT_SECURITY_FT_PSK,
G_SUPPLICANT_SECURITY_FT_IEEE8021X,
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ G_SUPPLICANT_SECURITY_SAE,
+#endif
} GSupplicantSecurity;
#if defined TIZEN_EXT
@@ -192,6 +212,9 @@ struct _GSupplicantSSID {
const char *phase1;
const char *pac_file;
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ uint16_t ieee80211w;
+#endif
};
typedef struct _GSupplicantSSID GSupplicantSSID;
@@ -257,6 +280,9 @@ struct _GSupplicantPeer;
typedef struct _GSupplicantInterface GSupplicantInterface;
typedef struct _GSupplicantPeer GSupplicantPeer;
+#if defined TIZEN_EXT_WIFI_MESH
+typedef struct _GSupplicantMeshPeer GSupplicantMeshPeer;
+#endif
typedef void (*GSupplicantInterfaceCallback) (int result,
GSupplicantInterface *interface,
@@ -346,6 +372,26 @@ GSupplicantPeer *g_supplicant_interface_peer_lookup(GSupplicantInterface *interf
const char *identifier);
bool g_supplicant_interface_is_p2p_finding(GSupplicantInterface *interface);
+#if defined TIZEN_EXT_WIFI_MESH
+bool g_supplicant_interface_has_mesh(GSupplicantInterface *interface);
+int g_supplicant_mesh_interface_create(const char *ifname, const char *driver,
+ const char *bridge, const char *parent_ifname,
+ GSupplicantInterfaceCallback callback, void *user_data);
+const void *g_supplicant_interface_get_mesh_group_ssid(
+ GSupplicantInterface *interface,
+ unsigned int *ssid_len);
+int g_supplicant_mesh_get_disconnect_reason(GSupplicantInterface *interface);
+const char *g_supplicant_mesh_peer_get_address(GSupplicantMeshPeer *mesh_peer);
+int g_supplicant_mesh_peer_get_disconnect_reason(
+ GSupplicantMeshPeer *mesh_peer);
+int g_supplicant_interface_abort_scan(GSupplicantInterface *interface,
+ GSupplicantInterfaceCallback callback, void *user_data);
+int g_supplicant_interface_mesh_peer_change_status(
+ GSupplicantInterface *interface,
+ GSupplicantInterfaceCallback callback, const char *peer_address,
+ const char *method, void *user_data);
+#endif
+
/* Network and Peer API */
struct _GSupplicantNetwork;
struct _GSupplicantGroup;
@@ -437,6 +483,13 @@ struct _GSupplicantCallbacks {
int reasoncode);
void (*assoc_status_code)(GSupplicantInterface *interface,
int reasoncode);
+#if defined TIZEN_EXT_WIFI_MESH
+ void (*mesh_support) (GSupplicantInterface *interface);
+ void (*mesh_group_started) (GSupplicantInterface *interface);
+ void (*mesh_group_removed) (GSupplicantInterface *interface);
+ void (*mesh_peer_connected) (GSupplicantMeshPeer *mesh_peer);
+ void (*mesh_peer_disconnected) (GSupplicantMeshPeer *mesh_peer);
+#endif
};
typedef struct _GSupplicantCallbacks GSupplicantCallbacks;
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index bbaad04..4f6957b 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -96,6 +96,9 @@ static struct strvalmap keymgmt_map[] = {
{ "wpa-eap", G_SUPPLICANT_KEYMGMT_WPA_EAP },
{ "wpa-eap-sha256", G_SUPPLICANT_KEYMGMT_WPA_EAP_256 },
{ "wps", G_SUPPLICANT_KEYMGMT_WPS },
+#if defined TIZEN_EXT_WIFI_MESH
+ { "sae", G_SUPPLICANT_KEYMGMT_SAE },
+#endif
{ }
};
@@ -139,6 +142,9 @@ static struct strvalmap mode_capa_map[] = {
{ "ad-hoc", G_SUPPLICANT_CAPABILITY_MODE_IBSS },
{ "ap", G_SUPPLICANT_CAPABILITY_MODE_AP },
{ "p2p", G_SUPPLICANT_CAPABILITY_MODE_P2P },
+#if defined TIZEN_EXT_WIFI_MESH
+ { "mesh", G_SUPPLICANT_CAPABILITY_MODE_MESH },
+#endif
{ }
};
@@ -162,6 +168,14 @@ struct added_network_information {
char * private_passphrase;
};
+#if defined TIZEN_EXT_WIFI_MESH
+struct _GSupplicantMeshGroupInfo {
+ unsigned char ssid[32];
+ unsigned int ssid_len;
+ int disconnect_reason;
+};
+#endif
+
struct _GSupplicantInterface {
char *path;
char *network_path;
@@ -198,6 +212,10 @@ struct _GSupplicantInterface {
#if defined TIZEN_EXT
int disconnect_reason;
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ bool mesh_support;
+ struct _GSupplicantMeshGroupInfo group_info;
+#endif
};
struct g_supplicant_bss {
@@ -230,6 +248,9 @@ struct g_supplicant_bss {
unsigned char country_code[COUNTRY_CODE_LENGTH];
#endif
unsigned int wps_capabilities;
+#if defined TIZEN_EXT_WIFI_MESH
+ dbus_bool_t sae;
+#endif
};
struct _GSupplicantNetwork {
@@ -297,6 +318,10 @@ struct interface_create_data {
char *ifname;
char *driver;
char *bridge;
+#if defined TIZEN_EXT_WIFI_MESH
+ char *parent_ifname;
+ bool is_mesh_interface;
+#endif
GSupplicantInterface *interface;
GSupplicantInterfaceCallback callback;
void *user_data;
@@ -331,6 +356,14 @@ struct g_connman_bssids {
static int network_remove(struct interface_data *data);
+#if defined TIZEN_EXT_WIFI_MESH
+struct _GSupplicantMeshPeer {
+ GSupplicantInterface *interface;
+ char *peer_address;
+ int disconnect_reason;
+};
+#endif
+
static inline void debug(const char *format, ...)
{
char str[256];
@@ -359,6 +392,10 @@ static GSupplicantMode string2mode(const char *mode)
return G_SUPPLICANT_MODE_INFRA;
else if (g_str_equal(mode, "ad-hoc"))
return G_SUPPLICANT_MODE_IBSS;
+#if defined TIZEN_EXT_WIFI_MESH
+ else if (g_str_equal(mode, "mesh"))
+ return G_SUPPLICANT_MODE_MESH;
+#endif
return G_SUPPLICANT_MODE_UNKNOWN;
}
@@ -374,6 +411,10 @@ static const char *mode2string(GSupplicantMode mode)
return "adhoc";
case G_SUPPLICANT_MODE_MASTER:
return "ap";
+#if defined TIZEN_EXT_WIFI_MESH
+ case G_SUPPLICANT_MODE_MESH:
+ return "mesh";
+#endif
}
return NULL;
@@ -398,6 +439,10 @@ static const char *security2string(GSupplicantSecurity security)
case G_SUPPLICANT_SECURITY_FT_IEEE8021X:
return "ft_ieee8021x";
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ case G_SUPPLICANT_SECURITY_SAE:
+ return "sae";
+#endif
}
return NULL;
@@ -580,6 +625,27 @@ static void callback_p2p_support(GSupplicantInterface *interface)
}
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+static void callback_mesh_support(GSupplicantInterface *interface)
+{
+ SUPPLICANT_DBG("");
+
+ if (!interface->mesh_support)
+ return;
+
+ if (callbacks_pointer && callbacks_pointer->mesh_support)
+ callbacks_pointer->mesh_support(interface);
+}
+
+bool g_supplicant_interface_has_mesh(GSupplicantInterface *interface)
+{
+ if (!interface)
+ return false;
+
+ return interface->mesh_support;
+}
+#endif
+
static void callback_scan_started(GSupplicantInterface *interface)
{
if (!callbacks_pointer)
@@ -1698,6 +1764,10 @@ static void merge_network(GSupplicantNetwork *network)
g_string_append_printf(str, "_managed");
else if (g_strcmp0(mode, "1") == 0)
g_string_append_printf(str, "_adhoc");
+#if defined TIZEN_EXT_WIFI_MESH
+ else if (g_strcmp0(mode, "5") == 0)
+ g_string_append_printf(str, "_mesh");
+#endif
if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
g_string_append_printf(str, "_psk");
@@ -2266,6 +2336,11 @@ static void bss_compute_security(struct g_supplicant_bss *bss)
bss->psk = TRUE;
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_SAE)
+ bss->sae = TRUE;
+#endif
+
if (bss->ieee8021x)
bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
else if (bss->psk)
@@ -2276,6 +2351,10 @@ static void bss_compute_security(struct g_supplicant_bss *bss)
else if (bss->ft_ieee8021x == TRUE)
bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ else if (bss->sae)
+ bss->security = G_SUPPLICANT_SECURITY_SAE;
+#endif
else if (bss->privacy)
bss->security = G_SUPPLICANT_SECURITY_WEP;
else
@@ -2672,6 +2751,10 @@ static void interface_property(const char *key, DBusMessageIter *iter,
if (interface->mode_capa & G_SUPPLICANT_CAPABILITY_MODE_P2P)
interface->p2p_support = true;
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ if (interface->mode_capa & G_SUPPLICANT_CAPABILITY_MODE_MESH)
+ interface->mesh_support = true;
+#endif
} else if (g_strcmp0(key, "State") == 0) {
const char *str = NULL;
@@ -3969,6 +4052,214 @@ static void signal_group_peer_disconnected(const char *path, DBusMessageIter *it
peer->connection_requested = false;
}
+#if defined TIZEN_EXT_WIFI_MESH
+const void *g_supplicant_interface_get_mesh_group_ssid(
+ GSupplicantInterface *interface,
+ unsigned int *ssid_len)
+{
+ if (!ssid_len)
+ return NULL;
+
+ if (!interface || interface->group_info.ssid_len == 0) {
+ *ssid_len = 0;
+ return NULL;
+ }
+
+ *ssid_len = interface->group_info.ssid_len;
+ return interface->group_info.ssid;
+}
+
+int g_supplicant_mesh_get_disconnect_reason(GSupplicantInterface *interface)
+{
+ if (!interface)
+ return -EINVAL;
+
+ return interface->group_info.disconnect_reason;
+}
+
+const char *g_supplicant_mesh_peer_get_address(GSupplicantMeshPeer *mesh_peer)
+{
+ if (!mesh_peer || !mesh_peer->peer_address)
+ return NULL;
+
+ return mesh_peer->peer_address;
+}
+
+int g_supplicant_mesh_peer_get_disconnect_reason(GSupplicantMeshPeer *mesh_peer)
+{
+ if (!mesh_peer)
+ return -EINVAL;
+
+ return mesh_peer->disconnect_reason;
+}
+
+static void callback_mesh_group_started(GSupplicantInterface *interface)
+{
+ if (!callbacks_pointer)
+ return;
+
+ if (!callbacks_pointer->mesh_group_started)
+ return;
+
+ callbacks_pointer->mesh_group_started(interface);
+}
+
+static void callback_mesh_group_removed(GSupplicantInterface *interface)
+{
+ if (!callbacks_pointer)
+ return;
+
+ if (!callbacks_pointer->mesh_group_removed)
+ return;
+
+ callbacks_pointer->mesh_group_removed(interface);
+}
+
+static void mesh_group_info(const char *key, DBusMessageIter *iter,
+ void *user_data)
+{
+ GSupplicantInterface *interface = user_data;
+ if (!key)
+ return;
+
+ if (g_strcmp0(key, "SSID") == 0) {
+ DBusMessageIter array;
+ unsigned char *ssid;
+ int ssid_len;
+
+ dbus_message_iter_recurse(iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
+
+ if (ssid_len > 0 && ssid_len < 33) {
+ memcpy(interface->group_info.ssid, ssid, ssid_len);
+ interface->group_info.ssid_len = ssid_len;
+ } else {
+ memset(interface->group_info.ssid, 0, 32);
+ interface->group_info.ssid_len = 0;
+ }
+ } else if (g_strcmp0(key, "DisconnectReason") == 0) {
+ int disconnect_reason = 0;
+ dbus_message_iter_get_basic(iter, &disconnect_reason);
+ interface->group_info.disconnect_reason = disconnect_reason;
+ }
+}
+
+static void signal_mesh_group_started(const char *path, DBusMessageIter *iter)
+{
+ GSupplicantInterface *interface;
+
+ interface = g_hash_table_lookup(interface_table, path);
+ if (!interface)
+ return;
+
+ supplicant_dbus_property_foreach(iter, mesh_group_info, interface);
+
+ callback_mesh_group_started(interface);
+}
+
+static void signal_mesh_group_removed(const char *path, DBusMessageIter *iter)
+{
+ GSupplicantInterface *interface;
+
+ interface = g_hash_table_lookup(interface_table, path);
+ if (!interface)
+ return;
+
+ supplicant_dbus_property_foreach(iter, mesh_group_info, interface);
+
+ callback_mesh_group_removed(interface);
+}
+
+static void callback_mesh_peer_connected(GSupplicantMeshPeer *mesh_peer)
+{
+ if (!callbacks_pointer)
+ return;
+
+ if (!callbacks_pointer->mesh_peer_connected)
+ return;
+
+ callbacks_pointer->mesh_peer_connected(mesh_peer);
+}
+
+static void callback_mesh_peer_disconnected(GSupplicantMeshPeer *mesh_peer)
+{
+ if (!callbacks_pointer)
+ return;
+
+ if (!callbacks_pointer->mesh_peer_disconnected)
+ return;
+
+ callbacks_pointer->mesh_peer_disconnected(mesh_peer);
+}
+
+static void mesh_peer_info(const char *key, DBusMessageIter *iter,
+ void *user_data)
+{
+ GSupplicantMeshPeer *mesh_peer = user_data;
+ if (!key)
+ return;
+
+ if (g_strcmp0(key, "PeerAddress") == 0) {
+ DBusMessageIter array;
+ unsigned char *addr;
+ int addr_len;
+
+ dbus_message_iter_recurse(iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
+
+ if (addr_len == 6) {
+ mesh_peer->peer_address = g_malloc0(19);
+ snprintf(mesh_peer->peer_address, 19,
+ "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1],
+ addr[2], addr[3], addr[4], addr[5]);
+ }
+ } else if (g_strcmp0(key, "DisconnectReason") == 0) {
+ int disconnect_reason = 0;
+ dbus_message_iter_get_basic(iter, &disconnect_reason);
+ mesh_peer->disconnect_reason = disconnect_reason;
+ }
+}
+
+static void signal_mesh_peer_connected(const char *path, DBusMessageIter *iter)
+{
+ GSupplicantInterface *interface;
+ GSupplicantMeshPeer *mesh_peer;
+
+ interface = g_hash_table_lookup(interface_table, path);
+ if (!interface)
+ return;
+
+ mesh_peer = dbus_malloc0(sizeof(GSupplicantMeshPeer));
+ mesh_peer->interface = interface;
+
+ supplicant_dbus_property_foreach(iter, mesh_peer_info, mesh_peer);
+
+ callback_mesh_peer_connected(mesh_peer);
+ g_free(mesh_peer->peer_address);
+ g_free(mesh_peer);
+}
+
+static void signal_mesh_peer_disconnected(const char *path,
+ DBusMessageIter *iter)
+{
+ GSupplicantInterface *interface;
+ GSupplicantMeshPeer *mesh_peer;
+
+ interface = g_hash_table_lookup(interface_table, path);
+ if (!interface)
+ return;
+
+ mesh_peer = dbus_malloc0(sizeof(GSupplicantMeshPeer));
+ mesh_peer->interface = interface;
+
+ supplicant_dbus_property_foreach(iter, mesh_peer_info, mesh_peer);
+
+ callback_mesh_peer_disconnected(mesh_peer);
+ g_free(mesh_peer->peer_address);
+ g_free(mesh_peer);
+}
+#endif
+
static struct {
const char *interface;
const char *member;
@@ -4012,6 +4303,16 @@ static struct {
{ SUPPLICANT_INTERFACE ".Group", "PeerJoined", signal_group_peer_joined },
{ SUPPLICANT_INTERFACE ".Group", "PeerDisconnected", signal_group_peer_disconnected },
+#if defined TIZEN_EXT_WIFI_MESH
+ { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshGroupStarted",
+ signal_mesh_group_started },
+ { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshGroupRemoved",
+ signal_mesh_group_removed },
+ { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshPeerConnected",
+ signal_mesh_peer_connected },
+ { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshPeerDisconnected",
+ signal_mesh_peer_disconnected },
+#endif
{ }
};
@@ -4290,6 +4591,9 @@ static void interface_create_data_free(struct interface_create_data *data)
g_free(data->ifname);
g_free(data->driver);
g_free(data->bridge);
+#if defined TIZEN_EXT_WIFI_MESH
+ g_free(data->parent_ifname);
+#endif
dbus_free(data);
}
@@ -4317,6 +4621,9 @@ static void interface_create_property(const char *key, DBusMessageIter *iter,
#if !defined TIZEN_EXT
callback_p2p_support(interface);
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ callback_mesh_support(interface);
+#endif
}
interface_create_data_free(data);
@@ -4403,6 +4710,17 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data)
DBUS_TYPE_STRING, &config_file);
}
+#if defined TIZEN_EXT_WIFI_MESH
+ if (data->is_mesh_interface) {
+ if (data->parent_ifname)
+ supplicant_dbus_dict_append_basic(&dict, "ParentIfname",
+ DBUS_TYPE_STRING, &data->parent_ifname);
+
+ supplicant_dbus_dict_append_basic(&dict, "IsMeshInterface",
+ DBUS_TYPE_BOOLEAN, &data->is_mesh_interface);
+ }
+#endif
+
supplicant_dbus_dict_close(iter, &dict);
}
@@ -4438,6 +4756,9 @@ static void interface_get_result(const char *error,
#if !defined TIZEN_EXT
callback_p2p_support(interface);
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ callback_mesh_support(interface);
+#endif
}
interface_create_data_free(data);
@@ -4477,6 +4798,117 @@ static void interface_get_params(DBusMessageIter *iter, void *user_data)
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
}
+#if defined TIZEN_EXT_WIFI_MESH
+int g_supplicant_mesh_interface_create(const char *ifname, const char *driver,
+ const char *bridge, const char *parent_ifname,
+ GSupplicantInterfaceCallback callback, void *user_data)
+{
+ struct interface_create_data *data;
+ int ret;
+
+ SUPPLICANT_DBG("ifname %s", ifname);
+
+ if (!ifname || !parent_ifname)
+ return -EINVAL;
+
+ if (!system_available)
+ return -EFAULT;
+
+ data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
+ data->ifname = g_strdup(ifname);
+ data->driver = g_strdup(driver);
+ data->bridge = g_strdup(bridge);
+ data->is_mesh_interface = true;
+ data->parent_ifname = g_strdup(parent_ifname);
+ data->callback = callback;
+ data->user_data = user_data;
+
+ ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
+ SUPPLICANT_INTERFACE,
+ "CreateInterface",
+ interface_create_params,
+ interface_create_result, data,
+ NULL);
+ return ret;
+}
+
+struct interface_mesh_peer_data {
+ char *peer_address;
+ char *method;
+ GSupplicantInterface *interface;
+ GSupplicantInterfaceCallback callback;
+ void *user_data;
+};
+
+static void interface_mesh_change_peer_params(DBusMessageIter *iter,
+ void *user_data)
+{
+ struct interface_mesh_peer_data *data = user_data;
+
+ SUPPLICANT_DBG("");
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->peer_address);
+}
+
+static void interface_mesh_change_peer_result(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct interface_mesh_peer_data *data = user_data;
+ int err = 0;
+
+ SUPPLICANT_DBG("%s", data->method);
+
+ if (error) {
+ err = -EIO;
+ SUPPLICANT_DBG("error %s", error);
+ }
+
+ if (data->callback)
+ data->callback(err, data->interface, data->user_data);
+
+ g_free(data->peer_address);
+ g_free(data->method);
+ dbus_free(data);
+}
+
+int g_supplicant_interface_mesh_peer_change_status(
+ GSupplicantInterface *interface,
+ GSupplicantInterfaceCallback callback, const char *peer_address,
+ const char *method, void *user_data)
+{
+ struct interface_mesh_peer_data *data;
+ int ret;
+
+ if (!peer_address)
+ return -EINVAL;
+
+ data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
+ data->peer_address = g_strdup(peer_address);
+ data->method = g_strdup(method);
+ data->interface = interface;
+ data->callback = callback;
+ data->user_data = user_data;
+
+ ret = supplicant_dbus_method_call(interface->path,
+ SUPPLICANT_INTERFACE ".Interface.Mesh",
+ method, interface_mesh_change_peer_params,
+ interface_mesh_change_peer_result, data, NULL);
+ if (ret < 0) {
+ g_free(data->peer_address);
+ g_free(data->method);
+ dbus_free(data);
+ }
+
+ return ret;
+}
+#endif
+
int g_supplicant_interface_create(const char *ifname, const char *driver,
const char *bridge,
GSupplicantInterfaceCallback callback,
@@ -4787,6 +5219,57 @@ static int interface_ready_to_scan(GSupplicantInterface *interface)
return 0;
}
+#if defined TIZEN_EXT_WIFI_MESH
+static void interface_abort_scan_result(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct interface_scan_data *data = user_data;
+ int err = 0;
+
+ if (error) {
+ SUPPLICANT_DBG("error %s", error);
+ err = -EIO;
+ }
+
+ g_free(data->path);
+
+ if (data->callback)
+ data->callback(err, data->interface, data->user_data);
+
+ dbus_free(data);
+}
+
+int g_supplicant_interface_abort_scan(GSupplicantInterface *interface,
+ GSupplicantInterfaceCallback callback, void *user_data)
+{
+ struct interface_scan_data *data;
+ int ret;
+
+ if (!interface->scanning)
+ return -EEXIST;
+
+ data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
+ data->interface = interface;
+ data->path = g_strdup(interface->path);
+ data->callback = callback;
+ data->user_data = user_data;
+
+ ret = supplicant_dbus_method_call(interface->path,
+ SUPPLICANT_INTERFACE ".Interface", "AbortScan", NULL,
+ interface_abort_scan_result, data, interface);
+
+ if (ret < 0) {
+ g_free(data->path);
+ dbus_free(data);
+ }
+
+ return ret;
+}
+#endif
+
int g_supplicant_interface_scan(GSupplicantInterface *interface,
GSupplicantScanParams *scan_data,
GSupplicantInterfaceCallback callback,
@@ -5429,6 +5912,17 @@ static void add_network_security_proto(DBusMessageIter *dict,
g_free(proto);
}
+#if defined TIZEN_EXT_WIFI_MESH
+static void add_network_ieee80211w(DBusMessageIter *dict, GSupplicantSSID *ssid)
+{
+ if (ssid->security != G_SUPPLICANT_SECURITY_SAE)
+ return;
+
+ supplicant_dbus_dict_append_basic(dict, "ieee80211w", DBUS_TYPE_UINT32,
+ &ssid->ieee80211w);
+}
+#endif
+
static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
{
char *key_mgmt;
@@ -5471,6 +5965,12 @@ static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
add_network_security_proto(dict, ssid);
break;
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ case G_SUPPLICANT_SECURITY_SAE:
+ key_mgmt = "SAE";
+ add_network_security_psk(dict, ssid);
+ break;
+#endif
}
supplicant_dbus_dict_append_basic(dict, "key_mgmt",
@@ -5492,6 +5992,11 @@ static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid)
case G_SUPPLICANT_MODE_MASTER:
mode = 2;
break;
+#if defined TIZEN_EXT_WIFI_MESH
+ case G_SUPPLICANT_MODE_MESH:
+ mode = 5;
+ break;
+#endif
}
supplicant_dbus_dict_append_basic(dict, "mode",
@@ -5522,6 +6027,10 @@ static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
add_network_security(&dict, ssid);
+#if defined TIZEN_EXT_WIFI_MESH
+ add_network_ieee80211w(&dict, ssid);
+#endif
+
supplicant_dbus_dict_append_fixed_array(&dict, "ssid",
DBUS_TYPE_BYTE, &ssid->ssid,
ssid->ssid_len);
@@ -5865,7 +6374,12 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface,
network_remove(intf_data);
} else
#if defined TIZEN_EXT
- if (ssid->passphrase && g_strcmp0(ssid->passphrase, "") != 0 && !ssid->eap) {
+ if (ssid->passphrase &&
+ g_strcmp0(ssid->passphrase, "") != 0 &&
+#if defined TIZEN_EXT_WIFI_MESH
+ ssid->mode != G_SUPPLICANT_MODE_MESH &&
+#endif
+ !ssid->eap) {
ret = send_decryption_request(ssid->passphrase, data);
if (ret < 0)
SUPPLICANT_DBG("Decryption request failed %d", ret);
@@ -6549,6 +7063,10 @@ static const char *g_supplicant_rule7 = "type=signal,"
static const char *g_supplicant_rule8 = "type=signal,"
"interface=" SUPPLICANT_INTERFACE ".Group";
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+static const char *g_supplicant_rule9 = "type=signal,"
+ "interface=" SUPPLICANT_INTERFACE ".Interface.Mesh";
+#endif
static void invoke_introspect_method(void)
{
@@ -6615,6 +7133,9 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks)
dbus_bus_add_match(connection, g_supplicant_rule7, NULL);
dbus_bus_add_match(connection, g_supplicant_rule8, NULL);
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ dbus_bus_add_match(connection, g_supplicant_rule9, NULL);
+#endif
dbus_connection_flush(connection);
if (dbus_bus_name_has_owner(connection,
@@ -6656,6 +7177,9 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
SUPPLICANT_DBG("");
if (connection) {
+#if defined TIZEN_EXT_WIFI_MESH
+ dbus_bus_remove_match(connection, g_supplicant_rule9, NULL);
+#endif
#if !defined TIZEN_EXT
dbus_bus_remove_match(connection, g_supplicant_rule8, NULL);
dbus_bus_remove_match(connection, g_supplicant_rule7, NULL);
diff --git a/include/dbus.h b/include/dbus.h
index 3087fe4..19e4938 100755..100644
--- a/include/dbus.h
+++ b/include/dbus.h
@@ -47,6 +47,9 @@ extern "C" {
#define CONNMAN_SESSION_INTERFACE CONNMAN_SERVICE ".Session"
#define CONNMAN_NOTIFICATION_INTERFACE CONNMAN_SERVICE ".Notification"
#define CONNMAN_PEER_INTERFACE CONNMAN_SERVICE ".Peer"
+#if defined TIZEN_EXT_WIFI_MESH
+#define CONNMAN_MESH_INTERFACE CONNMAN_SERVICE ".Mesh"
+#endif
#define CONNMAN_PRIVILEGE_MODIFY 1
#define CONNMAN_PRIVILEGE_SECRET 2
diff --git a/include/device.h b/include/device.h
index 36b2f55..852207d 100755..100644
--- a/include/device.h
+++ b/include/device.h
@@ -131,6 +131,13 @@ struct connman_device_driver {
struct connman_device *device, int scan_type,
GSList *specific_scan_list, void *user_data);
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ int (*abort_scan) (enum connman_service_type type,
+ struct connman_device *device);
+ int (*mesh_specific_scan) (enum connman_service_type type,
+ struct connman_device *device, const char *ssid, unsigned int freq,
+ void *user_data);
+#endif
};
int connman_device_driver_register(struct connman_device_driver *driver);
diff --git a/include/inet.h b/include/inet.h
index 0742730..ef61af9 100755..100644
--- a/include/inet.h
+++ b/include/inet.h
@@ -81,6 +81,11 @@ int connman_inet_check_ipaddress(const char *host);
bool connman_inet_check_hostname(const char *ptr, size_t len);
bool connman_inet_is_ipv6_supported();
+#if defined TIZEN_EXT_WIFI_MESH
+char *connman_inet_ifaddr(const char *name);
+char *connman_inet_ifname2addr(const char *name);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/include/mesh-netlink.h b/include/mesh-netlink.h
new file mode 100644
index 0000000..78b3e36
--- /dev/null
+++ b/include/mesh-netlink.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Connection Manager
+ *
+ *
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __CONNMAN_MESH_NETLINK_H
+#define __CONNMAN_MESH_NETLINK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ int id;
+ struct nl_sock *nl_socket;
+ struct nl_cb *cb;
+} mesh_nl80211_global;
+
+#define MESH_HWMP_ROOTMODE_NO_ROOT 0
+#define MESH_HWMP_ROOTMODE_PROACTIVE_PREQ_NO_PREP 2
+#define MESH_HWMP_ROOTMODE_PROACTIVE_PREQ_WITH_PREP 3
+#define MESH_HWMP_ROOTMODE_RANN 4
+
+#define NL80211_ATTR_IFINDEX 3
+#define NL80211_CMD_SET_MESH_CONFIG 29
+#define NL80211_ATTR_MESH_CONFIG 35
+
+#define NL80211_MESHCONF_HWMP_ROOTMODE 14
+#define NL80211_MESHCONF_GATE_ANNOUNCEMENTS 17
+
+int __connman_mesh_netlink_set_gate_announce(mesh_nl80211_global *global,
+ int mesh_if_index, bool gate_announce, int hwmp_rootmode);
+
+mesh_nl80211_global *__connman_mesh_nl80211_global_init(void);
+void __connman_mesh_nl80211_global_deinit(mesh_nl80211_global *global);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_MESH_NETLINK_H */
diff --git a/include/mesh.h b/include/mesh.h
new file mode 100644
index 0000000..547c237
--- /dev/null
+++ b/include/mesh.h
@@ -0,0 +1,155 @@
+/*
+ *
+ * Connection Manager
+ *
+ *
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __CONNMAN_MESH_H
+#define __CONNMAN_MESH_H
+
+#include <gdbus.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct connman_mesh;
+
+enum connman_mesh_security {
+ CONNMAN_MESH_SECURITY_UNKNOWN = 0,
+ CONNMAN_MESH_SECURITY_NONE = 1,
+ CONNMAN_MESH_SECURITY_SAE = 2,
+};
+
+enum connman_mesh_state {
+ CONNMAN_MESH_STATE_UNKNOWN = 0,
+ CONNMAN_MESH_STATE_IDLE = 1,
+ CONNMAN_MESH_STATE_ASSOCIATION = 2,
+ CONNMAN_MESH_STATE_CONFIGURATION = 3,
+ CONNMAN_MESH_STATE_READY = 4,
+ CONNMAN_MESH_STATE_DISCONNECT = 5,
+ CONNMAN_MESH_STATE_FAILURE = 6,
+};
+
+enum connman_mesh_peer_type {
+ CONNMAN_MESH_PEER_TYPE_CREATED = 0,
+ CONNMAN_MESH_PEER_TYPE_DISCOVERED = 1,
+};
+
+enum connman_mesh_peer_disconnect_reason {
+ CONNMAN_MESH_REASON_UNKNOWN = 0,
+ CONNMAN_MESH_DEAUTH_LEAVING = 1,
+ CONNMAN_MESH_PEERING_CANCELLED = 2,
+ CONNMAN_MESH_MAX_PEERS = 3,
+ CONNMAN_MESH_CONFIG_POLICY_VIOLATION = 4,
+ CONNMAN_MESH_CLOSE_RCVD = 5,
+ CONNMAN_MESH_MAX_RETRIES = 6,
+ CONNMAN_MESH_CONFIRM_TIMEOUT = 7,
+ CONNMAN_MESH_INVALID_GTK = 8,
+ CONNMAN_MESH_INCONSISTENT_PARAMS = 9,
+ CONNMAN_MESH_INVALID_SECURITY_CAP = 10,
+};
+
+enum connman_mesh_peer_status {
+ CONNMAN_MESH_PEER_ADD = 0,
+ CONNMAN_MESH_PEER_REMOVE = 1,
+};
+
+struct connman_mesh *connman_mesh_create(const char *interface_addr,
+ const char *identifier);
+
+void connman_mesh_set_name(struct connman_mesh *mesh, const char *name);
+const char *connman_mesh_get_name(struct connman_mesh *mesh);
+void connman_mesh_set_passphrase(struct connman_mesh *mesh,
+ const char *passphrase);
+const char *connman_mesh_get_passphrase(struct connman_mesh *mesh);
+void connman_mesh_set_address(struct connman_mesh *mesh, const char *address);
+void connman_mesh_set_security(struct connman_mesh *mesh, const char *security);
+const char *connman_mesh_get_security(struct connman_mesh *mesh);
+void connman_mesh_set_frequency(struct connman_mesh *mesh, uint16_t frequency);
+uint16_t connman_mesh_get_frequency(struct connman_mesh *mesh);
+void connman_mesh_set_ieee80211w(struct connman_mesh *mesh, uint16_t ieee80211w);
+uint16_t connman_mesh_get_ieee80211w(struct connman_mesh *mesh);
+int connman_mesh_peer_set_state(struct connman_mesh *mesh,
+ enum connman_mesh_state new_state);
+void connman_mesh_set_peer_type(struct connman_mesh *mesh,
+ enum connman_mesh_peer_type type);
+bool connman_mesh_peer_is_connected_state(struct connman_mesh *mesh);
+struct connman_mesh *connman_get_connected_mesh_from_name(char *name);
+struct connman_mesh *connman_get_connecting_mesh_from_name(char *name);
+void connman_mesh_set_index(struct connman_mesh *mesh, int index);
+void connman_mesh_set_strength(struct connman_mesh *mesh, uint8_t strength);
+void connman_mesh_peer_set_disconnect_reason(struct connman_mesh *mesh,
+ int disconnect_reason);
+void __connman_mesh_add_ethernet_to_bridge(void);
+void __connman_mesh_remove_ethernet_from_bridge(void);
+int __connman_mesh_change_peer_status(DBusMessage *msg,
+ const char *peer_address,
+ enum connman_mesh_peer_status status);
+
+int connman_mesh_register(struct connman_mesh *mesh);
+void connman_mesh_unregister(struct connman_mesh *mesh);
+
+int __connman_mesh_add_virtual_interface(const char *ifname,
+ const char *parent_ifname, const char *bridge_ifname);
+
+int __connman_mesh_remove_virtual_interface(const char *ifname);
+int __connman_mesh_set_stp_gate_announce(bool gate_announce, int hwmp_rootmode,
+ int stp);
+
+const char *connman_mesh_get_interface_name(void);
+bool connman_mesh_is_interface_created(void);
+
+struct connman_mesh *connman_mesh_get(const char *interface_addr,
+ const char *identifier);
+
+int connman_mesh_notify_interface_create(bool success);
+int connman_mesh_notify_interface_remove(bool success);
+
+int connman_mesh_add_connected_peer(const char *peer_address);
+int connman_mesh_remove_connected_peer(const char *peer_address, int reason);
+
+typedef void (*mesh_change_peer_status_cb_t) (int result, void *user_data);
+
+struct connman_mesh_driver {
+ int (*add_interface) (const char *ifname, const char *parent_ifname);
+ int (*remove_interface) (const char *ifname);
+ int (*connect) (struct connman_mesh *mesh);
+ int (*disconnect) (struct connman_mesh *mesh);
+ int (*change_peer_status) (const char *peer_address,
+ enum connman_mesh_peer_status status,
+ mesh_change_peer_status_cb_t callback, void *user_data);
+};
+
+int connman_mesh_driver_register(struct connman_mesh_driver *driver);
+void connman_mesh_driver_unregister(struct connman_mesh_driver *driver);
+
+struct connman_mesh_eth_driver {
+ int (*add_to_bridge) (const char *bridge);
+ int (*remove_from_bridge) (const char *bridge);
+};
+
+int connman_mesh_eth_driver_register(struct connman_mesh_eth_driver *driver);
+void connman_mesh_eth_driver_unregister(struct connman_mesh_eth_driver *driver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_MESH_H */
diff --git a/include/service.h b/include/service.h
index 3055023..961b594 100755..100644
--- a/include/service.h
+++ b/include/service.h
@@ -49,8 +49,15 @@ enum connman_service_type {
CONNMAN_SERVICE_TYPE_VPN = 7,
CONNMAN_SERVICE_TYPE_GADGET = 8,
CONNMAN_SERVICE_TYPE_P2P = 9,
+#if defined TIZEN_EXT_WIFI_MESH
+ CONNMAN_SERVICE_TYPE_MESH = 10,
+#endif
};
+#if defined TIZEN_EXT_WIFI_MESH
+#define MAX_CONNMAN_SERVICE_TYPES 11
+#else
#define MAX_CONNMAN_SERVICE_TYPES 10
+#endif
enum connman_service_security {
diff --git a/packaging/connman.spec b/packaging/connman.spec
index 411a651..fd69829 100755..100644
--- a/packaging/connman.spec
+++ b/packaging/connman.spec
@@ -5,7 +5,7 @@
Name: connman
Version: 1.35
-Release: 27
+Release: 28
License: GPL-2.0+
Summary: Connection Manager
Url: http://connman.net
@@ -18,6 +18,7 @@ BuildRequires: pkgconfig(gio-2.0)
BuildRequires: pkgconfig(libiptc)
BuildRequires: pkgconfig(xtables)
BuildRequires: pkgconfig(libsmack)
+BuildRequires: pkgconfig(libnl-2.0)
BuildRequires: pkgconfig(libsystemd-daemon)
%if %{with connman_openconnect}
BuildRequires: openconnect
@@ -141,8 +142,6 @@ This overwrites conf file of %{name}.
%build
-#CFLAGS+=" -DTIZEN_EXT -lsmack -Werror"
-
%if %{with connman_vpnd}
VPN_CFLAGS+=" -DTIZEN_EXT -lsmack -Werror"
%endif
@@ -151,9 +150,9 @@ chmod +x bootstrap
./bootstrap
%configure \
--sysconfdir=/etc \
- --enable-client \
- --enable-tizen-ext \
- --enable-pacrunner \
+ --enable-client \
+ --enable-tizen-ext \
+ --enable-pacrunner \
--enable-wifi=builtin \
%if %{with connman_openconnect}
--enable-openconnect \
@@ -170,11 +169,11 @@ chmod +x bootstrap
--disable-ofono \
--enable-telephony=builtin \
--enable-test \
- --enable-loopback \
- --enable-ethernet \
- --with-systemdunitdir=%{_libdir}/systemd/system \
- --enable-pie \
- --disable-wispr
+ --enable-loopback \
+ --enable-ethernet \
+ --with-systemdunitdir=%{_libdir}/systemd/system \
+ --enable-pie \
+ --disable-wispr
make %{?_smp_mflags}
diff --git a/plugins/ethernet.c b/plugins/ethernet.c
index 9a4d741..aadfe89 100755..100644
--- a/plugins/ethernet.c
+++ b/plugins/ethernet.c
@@ -48,6 +48,9 @@
#include <connman/rtnl.h>
#include <connman/log.h>
#include <connman/setting.h>
+#if defined TIZEN_EXT_WIFI_MESH
+#include <connman/mesh.h>
+#endif
static bool eth_tethering = false;
@@ -252,6 +255,10 @@ static void ethernet_newlink(unsigned flags, unsigned change, void *user_data)
} else {
DBG("carrier off");
remove_network(device, ethernet);
+#if defined TIZEN_EXT_WIFI_MESH
+ /* Remove ethernet from mesh bridge */
+ __connman_mesh_remove_ethernet_from_bridge();
+#endif
}
}
@@ -430,6 +437,54 @@ static struct connman_technology_driver eth_tech_driver = {
.set_tethering = eth_tech_set_tethering,
};
+#if defined TIZEN_EXT_WIFI_MESH
+static int eth_mesh_add_to_bridge(const char *bridge)
+{
+ GList *list;
+ struct ethernet_data *ethernet;
+
+ DBG("Add ethernet to bridge %s", bridge);
+
+ for (list = eth_interface_list; list; list = list->next) {
+ int index = GPOINTER_TO_INT(list->data);
+ struct connman_device *device =
+ connman_device_find_by_index(index);
+
+ if (device) {
+ ethernet = connman_device_get_data(device);
+ if (ethernet)
+ remove_network(device, ethernet);
+ }
+
+ connman_inet_ifup(index);
+
+ connman_inet_add_to_bridge(index, bridge);
+ }
+
+ return 0;
+}
+
+static int eth_mesh_remove_from_bridge(const char *bridge)
+{
+ GList *list;
+
+ DBG("Remove ethernet from bridge %s", bridge);
+
+ for (list = eth_interface_list; list; list = list->next) {
+ int index = GPOINTER_TO_INT(list->data);
+
+ connman_inet_remove_from_bridge(index, bridge);
+ }
+
+ return 0;
+}
+
+static struct connman_mesh_eth_driver eth_mesh_driver = {
+ .add_to_bridge = eth_mesh_add_to_bridge,
+ .remove_from_bridge = eth_mesh_remove_from_bridge,
+};
+#endif
+
static int ethernet_init(void)
{
int err;
@@ -438,6 +493,12 @@ static int ethernet_init(void)
if (err < 0)
return err;
+#if defined TIZEN_EXT_WIFI_MESH
+ err = connman_mesh_eth_driver_register(&eth_mesh_driver);
+ if (err < 0)
+ return err;
+#endif
+
err = connman_network_driver_register(&eth_network_driver);
if (err < 0)
return err;
@@ -455,6 +516,10 @@ static void ethernet_exit(void)
{
connman_technology_driver_unregister(&eth_tech_driver);
+#if defined TIZEN_EXT_WIFI_MESH
+ connman_mesh_eth_driver_unregister(&eth_mesh_driver);
+#endif
+
connman_network_driver_unregister(&eth_network_driver);
connman_device_driver_unregister(&eth_dev_driver);
diff --git a/plugins/wifi.c b/plugins/wifi.c
index 6103dc8..8e8017d 100755..100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -163,6 +163,10 @@ struct wifi_data {
#endif
int disconnect_code;
int assoc_code;
+#if defined TIZEN_EXT_WIFI_MESH
+ bool mesh_interface;
+ struct wifi_mesh_info *mesh_info;
+#endif
};
#if defined TIZEN_EXT
@@ -347,6 +351,506 @@ static void add_pending_wifi_device(struct wifi_data *wifi)
pending_wifi_device = g_list_append(pending_wifi_device, wifi);
}
+#if defined TIZEN_EXT_WIFI_MESH
+struct wifi_mesh_info {
+ struct wifi_data *wifi;
+ GSupplicantInterface *interface;
+ struct connman_mesh *mesh;
+ char *parent_ifname;
+ char *ifname;
+ char *identifier;
+ int index;
+};
+
+struct mesh_change_peer_status_info {
+ char *peer_address;
+ enum connman_mesh_peer_status peer_status;
+ mesh_change_peer_status_cb_t callback;
+ void *user_data;
+};
+
+static struct connman_technology_driver mesh_tech_driver = {
+ .name = "mesh",
+ .type = CONNMAN_SERVICE_TYPE_MESH,
+};
+
+static void mesh_interface_create_callback(int result,
+ GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct wifi_mesh_info *mesh_info = user_data;
+ struct wifi_data *wifi;
+ bool success = false;
+
+ DBG("result %d ifname %s, mesh_info %p", result,
+ g_supplicant_interface_get_ifname(interface),
+ mesh_info);
+
+ if (result < 0 || !mesh_info)
+ goto done;
+
+ wifi = mesh_info->wifi;
+
+ mesh_info->interface = interface;
+ mesh_info->identifier = connman_inet_ifaddr(mesh_info->ifname);
+ mesh_info->index = connman_inet_ifindex(mesh_info->ifname);
+ DBG("Mesh Interface identifier %s", mesh_info->identifier);
+ wifi->mesh_interface = true;
+ wifi->mesh_info = mesh_info;
+ g_supplicant_interface_set_data(interface, wifi);
+ success = true;
+
+done:
+ connman_mesh_notify_interface_create(success);
+}
+
+static int add_mesh_interface(const char *ifname, const char *parent_ifname)
+{
+ GList *list;
+ struct wifi_data *wifi;
+ struct wifi_mesh_info *mesh_info;
+ const char *wifi_ifname;
+ bool parent_found = false;
+ const char *driver = "nl80211";
+
+ for (list = iface_list; list; list = list->next) {
+ wifi = list->data;
+
+ if (!g_supplicant_interface_has_mesh(wifi->interface))
+ continue;
+
+ wifi_ifname = g_supplicant_interface_get_ifname(wifi->interface);
+ if (!wifi_ifname)
+ continue;
+
+ if (!g_strcmp0(wifi_ifname, parent_ifname)) {
+ parent_found = true;
+ break;
+ }
+ }
+
+ if (!parent_found) {
+ DBG("Parent interface %s doesn't exist", parent_ifname);
+ return -ENODEV;
+ }
+
+ mesh_info = g_try_malloc0(sizeof(struct wifi_mesh_info));
+ if (!mesh_info)
+ return -ENOMEM;
+
+ mesh_info->wifi = wifi;
+ mesh_info->ifname = g_strdup(ifname);
+ mesh_info->parent_ifname = g_strdup(parent_ifname);
+
+ g_supplicant_mesh_interface_create(ifname, driver, NULL, parent_ifname,
+ mesh_interface_create_callback, mesh_info);
+ return -EINPROGRESS;
+}
+
+static void mesh_interface_remove_callback(int result,
+ GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct wifi_data *wifi = user_data;
+ struct wifi_mesh_info *mesh_info = wifi->mesh_info;
+ bool success = false;
+
+ DBG("result %d mesh_info %p", result, mesh_info);
+
+ if (result < 0 || !mesh_info)
+ goto done;
+
+ mesh_info->interface = NULL;
+ g_free(mesh_info->parent_ifname);
+ g_free(mesh_info->ifname);
+ g_free(mesh_info->identifier);
+ g_free(mesh_info);
+ wifi->mesh_interface = false;
+ wifi->mesh_info = NULL;
+ success = true;
+
+done:
+ connman_mesh_notify_interface_remove(success);
+}
+
+static int remove_mesh_interface(const char *ifname)
+{
+ GList *list;
+ struct wifi_data *wifi;
+ struct wifi_mesh_info *mesh_info;
+ bool mesh_if_found = false;
+ int ret;
+
+ for (list = iface_list; list; list = list->next) {
+ wifi = list->data;
+
+ if (wifi->mesh_interface) {
+ mesh_if_found = true;
+ break;
+ }
+ }
+
+ if (!mesh_if_found) {
+ DBG("Mesh interface %s doesn't exist", ifname);
+ return -ENODEV;
+ }
+
+ mesh_info = wifi->mesh_info;
+ ret = g_supplicant_interface_remove(mesh_info->interface,
+ mesh_interface_remove_callback, wifi);
+ if (ret < 0)
+ return ret;
+
+ return -EINPROGRESS;
+}
+
+static void mesh_disconnect_callback(int result,
+ GSupplicantInterface *interface, void *user_data)
+{
+ struct connman_mesh *mesh = user_data;
+
+ DBG("result %d interface %p mesh %p", result, interface, mesh);
+}
+
+static int mesh_peer_disconnect(struct connman_mesh *mesh)
+{
+ GList *list;
+ struct wifi_data *wifi;
+ struct wifi_mesh_info *mesh_info;
+ bool mesh_if_found = false;
+ GSupplicantInterface *interface;
+
+ for (list = iface_list; list; list = list->next) {
+ wifi = list->data;
+
+ if (wifi->mesh_interface) {
+ mesh_if_found = true;
+ break;
+ }
+ }
+
+ if (!mesh_if_found) {
+ DBG("Mesh interface is not created");
+ return -ENODEV;
+ }
+
+ mesh_info = wifi->mesh_info;
+
+ interface = mesh_info->interface;
+ return g_supplicant_interface_disconnect(interface,
+ mesh_disconnect_callback, mesh);
+}
+
+static void mesh_connect_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct connman_mesh *mesh = user_data;
+ DBG("mesh %p result %d", mesh, result);
+
+ if (result < 0)
+ connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_FAILURE);
+ else
+ connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_ASSOCIATION);
+}
+
+static GSupplicantSecurity mesh_network_security(const char *security)
+{
+ if (g_str_equal(security, "none"))
+ return G_SUPPLICANT_SECURITY_NONE;
+ else if (g_str_equal(security, "sae"))
+ return G_SUPPLICANT_SECURITY_SAE;
+
+ return G_SUPPLICANT_SECURITY_UNKNOWN;
+}
+
+static void mesh_ssid_init(GSupplicantSSID *ssid, struct connman_mesh *mesh)
+{
+ const char *name;
+ const char *security;
+
+ if (ssid->ssid)
+ g_free(ssid->ssid);
+
+ memset(ssid, 0, sizeof(*ssid));
+ ssid->mode = G_SUPPLICANT_MODE_MESH;
+
+ security = connman_mesh_get_security(mesh);
+ ssid->security = mesh_network_security(security);
+
+ if (ssid->security == G_SUPPLICANT_SECURITY_SAE)
+ ssid->passphrase = connman_mesh_get_passphrase(mesh);
+
+ ssid->freq = connman_mesh_get_frequency(mesh);
+ name = connman_mesh_get_name(mesh);
+ if (name) {
+ ssid->ssid_len = strlen(name);
+ ssid->ssid = g_malloc0(ssid->ssid_len + 1);
+ memcpy(ssid->ssid, name, ssid->ssid_len);
+ ssid->scan_ssid = 1;
+ }
+}
+
+static int mesh_peer_connect(struct connman_mesh *mesh)
+{
+ GList *list;
+ struct wifi_data *wifi;
+ struct wifi_mesh_info *mesh_info;
+ bool mesh_if_found = false;
+ GSupplicantInterface *interface;
+ GSupplicantSSID *ssid;
+
+ for (list = iface_list; list; list = list->next) {
+ wifi = list->data;
+
+ if (wifi->mesh_interface) {
+ mesh_if_found = true;
+ break;
+ }
+ }
+
+ if (!mesh_if_found) {
+ DBG("Mesh interface is not created");
+ return -ENODEV;
+ }
+
+ mesh_info = wifi->mesh_info;
+
+ interface = mesh_info->interface;
+
+ ssid = g_try_malloc0(sizeof(GSupplicantSSID));
+ if (!ssid)
+ return -ENOMEM;
+
+ mesh_info->mesh = mesh;
+
+ mesh_ssid_init(ssid, mesh);
+ return g_supplicant_interface_connect(interface, ssid,
+ mesh_connect_callback, mesh);
+}
+
+static void mesh_peer_change_status_callback(int result,
+ GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct mesh_change_peer_status_info *data = user_data;
+
+ DBG("result %d Peer Status %d", result, data->peer_status);
+
+ if (result == 0 && data->peer_status == CONNMAN_MESH_PEER_REMOVE) {
+ /* WLAN_REASON_MESH_PEERING_CANCELLED = 52 */
+ connman_mesh_remove_connected_peer(data->peer_address, 52);
+ }
+
+ if (data->callback)
+ data->callback(result, data->user_data);
+
+ g_free(data->peer_address);
+ g_free(data);
+ return;
+}
+
+static int mesh_change_peer_status(const char *peer_address,
+ enum connman_mesh_peer_status status,
+ mesh_change_peer_status_cb_t callback, void *user_data)
+{
+ GList *list;
+ struct wifi_data *wifi;
+ struct wifi_mesh_info *mesh_info;
+ bool mesh_if_found = false;
+ GSupplicantInterface *interface;
+ struct mesh_change_peer_status_info *data;
+ const char *method;
+
+ for (list = iface_list; list; list = list->next) {
+ wifi = list->data;
+
+ if (wifi->mesh_interface) {
+ mesh_if_found = true;
+ break;
+ }
+ }
+
+ if (!mesh_if_found) {
+ DBG("Mesh interface is not created");
+ return -ENODEV;
+ }
+
+ mesh_info = wifi->mesh_info;
+
+ interface = mesh_info->interface;
+
+ switch (status) {
+ case CONNMAN_MESH_PEER_ADD:
+ method = "MeshPeerAdd";
+ break;
+ case CONNMAN_MESH_PEER_REMOVE:
+ method = "MeshPeerRemove";
+ break;
+ default:
+ DBG("Invalid method");
+ return -EINVAL;
+ }
+
+ data = g_try_malloc0(sizeof(struct mesh_change_peer_status_info));
+ if (data == NULL) {
+ DBG("Memory allocation failed");
+ return -ENOMEM;
+ }
+
+ data->peer_address = g_strdup(peer_address);
+ data->peer_status = status;
+ data->callback = callback;
+ data->user_data = user_data;
+
+ return g_supplicant_interface_mesh_peer_change_status(interface,
+ mesh_peer_change_status_callback, peer_address, method,
+ data);
+}
+
+static struct connman_mesh_driver mesh_driver = {
+ .add_interface = add_mesh_interface,
+ .remove_interface = remove_mesh_interface,
+ .connect = mesh_peer_connect,
+ .disconnect = mesh_peer_disconnect,
+ .change_peer_status = mesh_change_peer_status,
+};
+
+static void mesh_support(GSupplicantInterface *interface)
+{
+ DBG("");
+
+ if (!g_supplicant_interface_has_mesh(interface))
+ return;
+
+ if (connman_technology_driver_register(&mesh_tech_driver) < 0) {
+ DBG("Could not register Mesh technology driver");
+ return;
+ }
+
+ connman_mesh_driver_register(&mesh_driver);
+}
+
+static void check_mesh_technology(void)
+{
+ bool mesh_exists = false;
+ GList *list;
+
+ for (list = iface_list; list; list = list->next) {
+ struct wifi_data *w = list->data;
+
+ if (w->interface &&
+ g_supplicant_interface_has_mesh(w->interface))
+ mesh_exists = true;
+ }
+
+ if (!mesh_exists) {
+ connman_technology_driver_unregister(&mesh_tech_driver);
+ connman_mesh_driver_unregister(&mesh_driver);
+ }
+}
+
+static void mesh_group_started(GSupplicantInterface *interface)
+{
+ struct wifi_data *wifi;
+ struct wifi_mesh_info *mesh_info;
+ struct connman_mesh *mesh;
+ const unsigned char *ssid;
+ unsigned int ssid_len;
+ char name[33];
+
+ ssid = g_supplicant_interface_get_mesh_group_ssid(interface, &ssid_len);
+ memcpy(name, ssid, ssid_len);
+ name[ssid_len] = '\0';
+ DBG("name %s", name);
+ wifi = g_supplicant_interface_get_data(interface);
+ DBG("wifi %p", wifi);
+
+ if (!wifi)
+ return;
+
+ mesh_info = wifi->mesh_info;
+ if (!mesh_info)
+ return;
+
+ mesh = mesh_info->mesh;
+ if (!mesh)
+ return;
+
+ connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_CONFIGURATION);
+}
+
+static void mesh_group_removed(GSupplicantInterface *interface)
+{
+ struct wifi_data *wifi;
+ struct wifi_mesh_info *mesh_info;
+ struct connman_mesh *mesh;
+ const unsigned char *ssid;
+ unsigned int ssid_len;
+ int disconnect_reason;
+ char name[33];
+
+ ssid = g_supplicant_interface_get_mesh_group_ssid(interface, &ssid_len);
+ memcpy(name, ssid, ssid_len);
+ name[ssid_len] = '\0';
+ DBG("name %s", name);
+
+ disconnect_reason = g_supplicant_mesh_get_disconnect_reason(interface);
+ DBG("Disconnect Reason %d", disconnect_reason);
+
+ wifi = g_supplicant_interface_get_data(interface);
+ DBG("wifi %p", wifi);
+
+ if (!wifi)
+ return;
+
+ mesh_info = wifi->mesh_info;
+ if (!mesh_info)
+ return;
+
+ mesh = connman_get_connected_mesh_from_name(name);
+ if (!mesh) {
+ DBG("%s is not connected", name);
+ mesh = connman_get_connecting_mesh_from_name(name);
+ if (!mesh) {
+ DBG("%s is not connecting", name);
+ return;
+ }
+ }
+
+ connman_mesh_peer_set_disconnect_reason(mesh, disconnect_reason);
+ connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_DISCONNECT);
+}
+
+static void mesh_peer_connected(GSupplicantMeshPeer *mesh_peer)
+{
+ const char *peer_address;
+
+ peer_address = g_supplicant_mesh_peer_get_address(mesh_peer);
+
+ if (!peer_address)
+ return;
+
+ DBG("Peer %s connected", peer_address);
+ connman_mesh_add_connected_peer(peer_address);
+}
+
+static void mesh_peer_disconnected(GSupplicantMeshPeer *mesh_peer)
+{
+ const char *peer_address;
+ int reason;
+
+ peer_address = g_supplicant_mesh_peer_get_address(mesh_peer);
+
+ if (!peer_address)
+ return;
+
+ reason = g_supplicant_mesh_peer_get_disconnect_reason(mesh_peer);
+
+ DBG("Peer %s disconnected with reason %d", peer_address, reason);
+ connman_mesh_remove_connected_peer(peer_address, reason);
+}
+#endif
+
static struct wifi_data *get_pending_wifi_data(const char *ifname)
{
GList *list;
@@ -1034,6 +1538,9 @@ static void wifi_remove(struct connman_device *device)
iface_list = g_list_remove(iface_list, wifi);
check_p2p_technology();
+#if defined TIZEN_EXT_WIFI_MESH
+ check_mesh_technology();
+#endif
remove_pending_wifi_device(wifi);
@@ -2094,7 +2601,7 @@ static int wifi_specific_scan(enum connman_service_type type,
}
memcpy(scan_ssid->ssid, ssid, (ssid_len + 1));
- DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len);
+ /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */
scan_ssid->ssid_len = ssid_len;
scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
count++;
@@ -2160,7 +2667,7 @@ static int wifi_specific_scan(enum connman_service_type type,
}
memcpy(scan_ssid->ssid, ssid, (ssid_len + 1));
- DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len);
+ /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */
scan_ssid->ssid_len = ssid_len;
scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
ap_count++;
@@ -2197,6 +2704,159 @@ static int wifi_specific_scan(enum connman_service_type type,
}
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+static void mesh_scan_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct connman_device *device = user_data;
+ struct wifi_data *wifi = connman_device_get_data(device);
+ bool scanning;
+
+ DBG("result %d wifi %p", result, wifi);
+
+ scanning = connman_device_get_scanning(device);
+ if (scanning)
+ connman_device_set_scanning(device,
+ CONNMAN_SERVICE_TYPE_MESH, false);
+
+ if (scanning)
+ connman_device_unref(device);
+}
+
+static int mesh_scan(struct connman_device *device)
+{
+ struct wifi_data *wifi;
+ struct wifi_mesh_info *mesh_info;
+ int ret;
+
+ DBG("");
+
+ wifi = connman_device_get_data(device);
+
+ if (!wifi->mesh_interface)
+ return -ENOTSUP;
+
+ mesh_info = wifi->mesh_info;
+ reset_autoscan(device);
+ connman_device_ref(device);
+
+ ret = g_supplicant_interface_scan(mesh_info->interface, NULL,
+ mesh_scan_callback, device);
+ if (ret)
+ connman_device_unref(device);
+ else
+ connman_device_set_scanning(device,
+ CONNMAN_SERVICE_TYPE_MESH, true);
+
+ return ret;
+}
+
+static void abort_scan_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct connman_device *device = user_data;
+ struct wifi_data *wifi = connman_device_get_data(device);
+
+ DBG("result %d wifi %p", result, wifi);
+
+ __connman_technology_notify_abort_scan(CONNMAN_SERVICE_TYPE_MESH, result);
+}
+
+static int mesh_abort_scan(enum connman_service_type type,
+ struct connman_device *device)
+{
+ struct wifi_data *wifi = connman_device_get_data(device);
+ struct wifi_mesh_info *mesh_info;
+ bool scanning;
+ int ret;
+
+ if (!wifi || !wifi->mesh_interface)
+ return -ENODEV;
+
+ if (type != CONNMAN_SERVICE_TYPE_MESH)
+ return -EINVAL;
+
+ mesh_info = wifi->mesh_info;
+
+ scanning = connman_device_get_scanning(device);
+ if (!scanning)
+ return -EEXIST;
+
+ ret = g_supplicant_interface_abort_scan(mesh_info->interface,
+ abort_scan_callback, device);
+
+ return ret;
+}
+
+static int mesh_specific_scan(enum connman_service_type type,
+ struct connman_device *device, const char *ssid,
+ unsigned int freq, void *user_data)
+{
+ struct wifi_data *wifi = connman_device_get_data(device);
+ GSupplicantScanParams *scan_params = NULL;
+ struct wifi_mesh_info *mesh_info;
+ struct scan_ssid *scan_ssid;
+ bool scanning;
+ int ret;
+
+ if (!wifi || !wifi->mesh_interface)
+ return -ENODEV;
+
+ if (type != CONNMAN_SERVICE_TYPE_MESH)
+ return -EINVAL;
+
+ if (wifi->p2p_device)
+ return 0;
+
+ mesh_info = wifi->mesh_info;
+
+ scanning = connman_device_get_scanning(device);
+ if (scanning)
+ return -EALREADY;
+
+ scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
+ if (!scan_params)
+ return -ENOMEM;
+
+ scan_ssid = g_try_new(struct scan_ssid, 1);
+ if (!scan_ssid) {
+ g_free(scan_params);
+ return -ENOMEM;
+ }
+
+ scan_ssid->ssid_len = strlen(ssid);
+ memcpy(scan_ssid->ssid, ssid, scan_ssid->ssid_len);
+ scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
+ scan_params->num_ssids = 1;
+
+ scan_params->freqs = g_try_new(uint16_t, 1);
+ if (!scan_params->freqs) {
+ g_slist_free_full(scan_params->ssids, g_free);
+ g_free(scan_params);
+ return -ENOMEM;
+ }
+
+ scan_params->freqs[0] = freq;
+ scan_params->num_freqs = 1;
+
+ reset_autoscan(device);
+ connman_device_ref(device);
+
+ ret = g_supplicant_interface_scan(mesh_info->interface, scan_params,
+ mesh_scan_callback, device);
+
+ if (ret == 0) {
+ connman_device_set_scanning(device,
+ CONNMAN_SERVICE_TYPE_MESH, true);
+ } else {
+ g_supplicant_free_scan_params(scan_params);
+ connman_device_unref(device);
+ }
+
+ return ret;
+}
+#endif
+
/*
* Note that the hidden scan is only used when connecting to this specific
* hidden AP first time. It is not used when system autoconnects to hidden AP.
@@ -2228,6 +2888,11 @@ static int wifi_scan(enum connman_service_type type,
if (type == CONNMAN_SERVICE_TYPE_P2P)
return p2p_find(device);
+#if defined TIZEN_EXT_WIFI_MESH
+ if (type == CONNMAN_SERVICE_TYPE_MESH)
+ return mesh_scan(device);
+#endif
+
DBG("device %p wifi %p hidden ssid %s", device, wifi->interface, ssid);
scanning = connman_device_get_scanning(device);
@@ -2379,6 +3044,10 @@ static struct connman_device_driver wifi_ng_driver = {
#if defined TIZEN_EXT
.specific_scan = wifi_specific_scan,
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ .abort_scan = mesh_abort_scan,
+ .mesh_specific_scan = mesh_specific_scan,
+#endif
};
static void system_ready(void)
@@ -3238,6 +3907,21 @@ static void interface_removed(GSupplicantInterface *interface)
wifi = g_supplicant_interface_get_data(interface);
+#if defined TIZEN_EXT_WIFI_MESH
+ if (wifi && wifi->mesh_interface) {
+ DBG("Notify mesh interface remove");
+ connman_mesh_notify_interface_remove(true);
+ struct wifi_mesh_info *mesh_info = wifi->mesh_info;
+ g_free(mesh_info->parent_ifname);
+ g_free(mesh_info->ifname);
+ g_free(mesh_info->identifier);
+ g_free(mesh_info);
+ wifi->mesh_interface = false;
+ wifi->mesh_info = NULL;
+ return;
+ }
+#endif
+
if (wifi)
wifi->interface = NULL;
@@ -3252,6 +3936,9 @@ static void interface_removed(GSupplicantInterface *interface)
connman_device_set_powered(wifi->device, false);
check_p2p_technology();
+#if defined TIZEN_EXT_WIFI_MESH
+ check_mesh_technology();
+#endif
}
static void set_device_type(const char *type, char dev_type[17])
@@ -3391,6 +4078,97 @@ static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
return strength;
}
+#if defined TIZEN_EXT_WIFI_MESH
+static void mesh_peer_added(GSupplicantNetwork *supplicant_network)
+{
+ GSupplicantInterface *interface;
+ struct wifi_data *wifi;
+ const char *name, *security;
+ struct connman_mesh *connman_mesh;
+ struct wifi_mesh_info *mesh_info;
+ const unsigned char *bssid;
+ const char *identifier;
+ char *address;
+ uint16_t frequency;
+ int ret;
+
+ interface = g_supplicant_network_get_interface(supplicant_network);
+ wifi = g_supplicant_interface_get_data(interface);
+ if (!wifi || !wifi->mesh_interface) {
+ DBG("Virtual Mesh interface not created");
+ return;
+ }
+
+ bssid = g_supplicant_network_get_bssid(supplicant_network);
+ address = g_malloc0(19);
+ snprintf(address, 19, "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1],
+ bssid[2], bssid[3], bssid[4], bssid[5]);
+
+ identifier = g_supplicant_network_get_identifier(supplicant_network);
+ name = g_supplicant_network_get_name(supplicant_network);
+ security = g_supplicant_network_get_security(supplicant_network);
+ frequency = g_supplicant_network_get_frequency(supplicant_network);
+
+ mesh_info = wifi->mesh_info;
+ connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
+ if (connman_mesh)
+ goto done;
+
+ DBG("Mesh Peer name %s identifier %s security %s added", name, identifier,
+ security);
+ connman_mesh = connman_mesh_create(mesh_info->identifier, identifier);
+ connman_mesh_set_name(connman_mesh, name);
+ connman_mesh_set_security(connman_mesh, security);
+ connman_mesh_set_frequency(connman_mesh, frequency);
+ connman_mesh_set_address(connman_mesh, address);
+ connman_mesh_set_index(connman_mesh, mesh_info->index);
+ connman_mesh_set_strength(connman_mesh,
+ calculate_strength(supplicant_network));
+ connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_DISCOVERED);
+
+ ret = connman_mesh_register(connman_mesh);
+ if (ret == -EALREADY)
+ DBG("Mesh Peer is already registered");
+
+done:
+ g_free(address);
+}
+
+static void mesh_peer_removed(GSupplicantNetwork *supplicant_network)
+{
+ GSupplicantInterface *interface;
+ struct wifi_data *wifi;
+ struct connman_mesh *connman_mesh;
+ struct wifi_mesh_info *mesh_info;
+ const char *identifier;
+
+ interface = g_supplicant_network_get_interface(supplicant_network);
+ wifi = g_supplicant_interface_get_data(interface);
+ if (!wifi || !wifi->mesh_interface) {
+ DBG("Virtual Mesh interface not created");
+ return;
+ }
+
+ identifier = g_supplicant_network_get_identifier(supplicant_network);
+ if (!identifier) {
+ DBG("Failed to get Mesh Peer identifier");
+ return;
+ }
+
+ mesh_info = wifi->mesh_info;
+ connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
+ if (connman_mesh) {
+ /* Do not unregister connected mesh peer */
+ if (connman_mesh_peer_is_connected_state(connman_mesh)) {
+ DBG("Mesh Peer %s is connected", identifier);
+ return;
+ }
+ DBG("Mesh Peer identifier %s removed", identifier);
+ connman_mesh_unregister(connman_mesh);
+ }
+}
+#endif
+
static void network_added(GSupplicantNetwork *supplicant_network)
{
struct connman_network *network;
@@ -3417,6 +4195,13 @@ static void network_added(GSupplicantNetwork *supplicant_network)
if (!g_strcmp0(mode, "adhoc"))
return;
+#if defined TIZEN_EXT_WIFI_MESH
+ if (!g_strcmp0(mode, "mesh")) {
+ mesh_peer_added(supplicant_network);
+ return;
+ }
+#endif
+
interface = g_supplicant_network_get_interface(supplicant_network);
wifi = g_supplicant_interface_get_data(interface);
name = g_supplicant_network_get_name(supplicant_network);
@@ -3543,6 +4328,15 @@ static void network_removed(GSupplicantNetwork *network)
const char *name, *identifier;
struct connman_network *connman_network;
+#if defined TIZEN_EXT_WIFI_MESH
+ const char *mode;
+ mode = g_supplicant_network_get_mode(network);
+ if (!g_strcmp0(mode, "mesh")) {
+ mesh_peer_removed(network);
+ return;
+ }
+#endif
+
interface = g_supplicant_network_get_interface(network);
wifi = g_supplicant_interface_get_data(interface);
identifier = g_supplicant_network_get_identifier(network);
@@ -4026,6 +4820,13 @@ static const GSupplicantCallbacks callbacks = {
.debug = debug,
.disconnect_reasoncode = disconnect_reasoncode,
.assoc_status_code = assoc_status_code,
+#if defined TIZEN_EXT_WIFI_MESH
+ .mesh_support = mesh_support,
+ .mesh_group_started = mesh_group_started,
+ .mesh_group_removed = mesh_group_removed,
+ .mesh_peer_connected = mesh_peer_connected,
+ .mesh_peer_disconnected = mesh_peer_disconnected,
+#endif
};
diff --git a/src/config.c b/src/config.c
index 75cd717..0126711 100755..100644
--- a/src/config.c
+++ b/src/config.c
@@ -1257,6 +1257,9 @@ static int try_provision_service(struct connman_config_service *config,
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_VPN:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
return -ENOENT;
}
diff --git a/src/connman.h b/src/connman.h
index d1069b9..905467e 100755..100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -57,6 +57,10 @@ DBusMessage *__connman_error_operation_aborted(DBusMessage *msg);
DBusMessage *__connman_error_operation_timeout(DBusMessage *msg);
DBusMessage *__connman_error_invalid_service(DBusMessage *msg);
DBusMessage *__connman_error_invalid_property(DBusMessage *msg);
+#if defined TIZEN_EXT_WIFI_MESH
+DBusMessage *__connman_error_invalid_command(DBusMessage *msg);
+DBusMessage *__connman_error_scan_abort_failed(DBusMessage *msg);
+#endif
int __connman_manager_init(void);
void __connman_manager_cleanup(void);
@@ -920,6 +924,30 @@ int __connman_peer_service_unregister(const char *owner,
const unsigned char *query,
int query_length, int version);
+#if defined TIZEN_EXT_WIFI_MESH
+#include <connman/mesh.h>
+
+int __connman_mesh_init(void);
+void __connman_mesh_cleanup(void);
+bool __connman_technology_get_connected(enum connman_service_type type);
+void __connman_technology_mesh_interface_create_finished(
+ enum connman_service_type type, bool success,
+ const char *error);
+void __connman_technology_mesh_interface_remove_finished(
+ enum connman_service_type type, bool success);
+void __connman_mesh_peer_list_struct(DBusMessageIter *array);
+void __connman_mesh_connected_peer_list_struct(DBusMessageIter *array);
+void __connman_mesh_disconnected_peer_list_struct(DBusMessageIter *array);
+int __connman_mesh_dhcp_start(struct connman_ipconfig *ipconfig,
+ dhcp_cb callback, gpointer user_data);
+int __connman_device_abort_scan(enum connman_service_type type);
+void __connman_technology_notify_abort_scan(enum connman_service_type type,
+ int result);
+int __connman_device_request_mesh_specific_scan(enum connman_service_type type,
+ const char *name, unsigned int freq);
+void __connman_mesh_auto_connect(void);
+#endif /* TIZEN_EXT_WIFI_MESH */
+
#include <connman/session.h>
typedef void (* service_iterate_cb) (struct connman_service *service,
diff --git a/src/device.c b/src/device.c
index 3ec8f71..8b77021 100755..100644
--- a/src/device.c
+++ b/src/device.c
@@ -743,6 +743,11 @@ int connman_device_set_scanning(struct connman_device *device,
__connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+#if defined TIZEN_EXT_WIFI_MESH
+ if (type == CONNMAN_SERVICE_TYPE_MESH)
+ __connman_mesh_auto_connect();
+#endif
+
return 0;
}
@@ -1077,6 +1082,9 @@ int __connman_device_request_specific_scan(enum connman_service_type type,
return -EOPNOTSUPP;
case CONNMAN_SERVICE_TYPE_WIFI:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
}
@@ -1107,6 +1115,100 @@ int __connman_device_request_specific_scan(enum connman_service_type type,
return last_err;
}
+
+#if defined TIZEN_EXT_WIFI_MESH
+static int device_abort_scan(enum connman_service_type type,
+ struct connman_device *device)
+{
+ if (!device->driver || !device->driver->scan)
+ return -EOPNOTSUPP;
+
+ if (!device->powered)
+ return -ENOLINK;
+
+ return device->driver->abort_scan(type, device);
+}
+
+int __connman_device_abort_scan(enum connman_service_type type)
+{
+ GSList *list;
+ int err = -EINVAL;
+
+ if (type != CONNMAN_SERVICE_TYPE_MESH)
+ return -EINVAL;
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+ enum connman_service_type service_type =
+ __connman_device_get_service_type(device);
+
+ if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
+ if (type == CONNMAN_SERVICE_TYPE_MESH)
+ if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
+ continue;
+
+ if (!device->scanning) {
+ err = -EEXIST;
+ continue;
+ }
+
+ err = device_abort_scan(type, device);
+ }
+ }
+ return err;
+}
+
+static int device_mesh_specific_scan(enum connman_service_type type,
+ struct connman_device *device, const char *name,
+ unsigned int freq)
+{
+ if (!device->driver || !device->driver->mesh_specific_scan)
+ return -EOPNOTSUPP;
+
+ if (!device->powered)
+ return -ENOLINK;
+
+ return device->driver->mesh_specific_scan(type, device, name, freq, NULL);
+}
+
+int __connman_device_request_mesh_specific_scan(enum connman_service_type type,
+ const char *name,
+ unsigned int freq)
+{
+ bool success = false;
+ int last_err = -ENOSYS;
+ GSList *list;
+ int err;
+
+ if (type != CONNMAN_SERVICE_TYPE_MESH)
+ return -EINVAL;
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+ enum connman_service_type service_type =
+ __connman_device_get_service_type(device);
+
+ if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
+ if (type == CONNMAN_SERVICE_TYPE_MESH)
+ if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
+ continue;
+ }
+
+ err = device_mesh_specific_scan(type, device, name, freq);
+ if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
+ success = true;
+ } else {
+ last_err = err;
+ DBG("device %p err %d", device, err);
+ }
+ }
+
+ if (success)
+ return 0;
+
+ return last_err;
+}
+#endif /* TIZEN_EXT_WIFI_MESH */
#endif
int __connman_device_request_scan(enum connman_service_type type)
@@ -1128,6 +1230,9 @@ int __connman_device_request_scan(enum connman_service_type type)
return -EOPNOTSUPP;
case CONNMAN_SERVICE_TYPE_WIFI:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
}
@@ -1140,6 +1245,11 @@ int __connman_device_request_scan(enum connman_service_type type)
if (type == CONNMAN_SERVICE_TYPE_P2P) {
if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
continue;
+#if defined TIZEN_EXT_WIFI_MESH
+ } else if (type == CONNMAN_SERVICE_TYPE_MESH) {
+ if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
+ continue;
+#endif
} else if (service_type != type)
continue;
}
diff --git a/src/dhcp.c b/src/dhcp.c
index c428c1d..26a350b 100755..100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -730,6 +730,41 @@ char *__connman_dhcp_get_server_address(struct connman_ipconfig *ipconfig)
return g_dhcp_client_get_server_address(dhcp->dhcp_client);
}
+#if defined TIZEN_EXT_WIFI_MESH
+int __connman_mesh_dhcp_start(struct connman_ipconfig *ipconfig,
+ dhcp_cb callback, gpointer user_data)
+{
+ struct connman_dhcp *dhcp;
+ int err;
+
+ DBG("");
+
+ dhcp = g_hash_table_lookup(ipconfig_table, ipconfig);
+ if (!dhcp) {
+
+ dhcp = g_try_new0(struct connman_dhcp, 1);
+ if (!dhcp)
+ return -ENOMEM;
+
+ dhcp->ipconfig = ipconfig;
+ __connman_ipconfig_ref(ipconfig);
+
+ err = dhcp_initialize(dhcp);
+
+ if (err < 0) {
+ g_free(dhcp);
+ return err;
+ }
+
+ g_hash_table_insert(ipconfig_table, ipconfig, dhcp);
+ }
+
+ dhcp->callback = callback;
+ dhcp->user_data = user_data;
+ return g_dhcp_client_start(dhcp->dhcp_client, NULL);
+}
+#endif
+
int __connman_dhcp_start(struct connman_ipconfig *ipconfig,
struct connman_network *network, dhcp_cb callback,
gpointer user_data)
diff --git a/src/error.c b/src/error.c
index 4f24ae2..1a05920 100755..100644
--- a/src/error.c
+++ b/src/error.c
@@ -185,3 +185,17 @@ DBusMessage *__connman_error_invalid_property(DBusMessage *msg)
return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
".InvalidProperty", "Invalid property");
}
+
+#if defined TIZEN_EXT_WIFI_MESH
+DBusMessage *__connman_error_invalid_command(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".InvalidCommand", "Invalid Mesh Command");
+}
+
+DBusMessage *__connman_error_scan_abort_failed(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".ScanAbortFailed", "Scan Abort Failed");
+}
+#endif
diff --git a/src/inet.c b/src/inet.c
index 93be1e7..25e5372 100755..100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -190,6 +190,78 @@ done:
return err;
}
+#if defined TIZEN_EXT_WIFI_MESH
+char *connman_inet_ifaddr(const char *name)
+{
+ struct ifreq ifr;
+ struct ether_addr eth;
+ char *str;
+ int sk, err;
+
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return NULL;
+
+ strncpy(ifr.ifr_name, name, IFNAMSIZ-1);
+
+ err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+ close(sk);
+
+ if (err < 0)
+ return NULL;
+
+ str = g_malloc(18);
+ if (!str)
+ return NULL;
+
+ memcpy(&eth, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
+ snprintf(str, 13, "%02x%02x%02x%02x%02x%02x",
+ eth.ether_addr_octet[0],
+ eth.ether_addr_octet[1],
+ eth.ether_addr_octet[2],
+ eth.ether_addr_octet[3],
+ eth.ether_addr_octet[4],
+ eth.ether_addr_octet[5]);
+
+ return str;
+}
+
+char *connman_inet_ifname2addr(const char *name)
+{
+ struct ifreq ifr;
+ struct ether_addr eth;
+ char *str;
+ int sk, err;
+
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return NULL;
+
+ strncpy(ifr.ifr_name, name, IFNAMSIZ-1);
+
+ err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+ close(sk);
+
+ if (err < 0)
+ return NULL;
+
+ str = g_malloc(18);
+ if (!str)
+ return NULL;
+
+ memcpy(&eth, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
+ snprintf(str, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
+ eth.ether_addr_octet[0],
+ eth.ether_addr_octet[1],
+ eth.ether_addr_octet[2],
+ eth.ether_addr_octet[3],
+ eth.ether_addr_octet[4],
+ eth.ether_addr_octet[5]);
+
+ return str;
+}
+#endif
+
int connman_inet_ifindex(const char *name)
{
struct ifreq ifr;
@@ -347,29 +419,14 @@ void connman_inet_update_device_ident(struct connman_device *device)
case CONNMAN_DEVICE_TYPE_GADGET:
case CONNMAN_DEVICE_TYPE_WIFI:
addr = index2addr(index);
- break;
- case CONNMAN_DEVICE_TYPE_BLUETOOTH:
- case CONNMAN_DEVICE_TYPE_CELLULAR:
- case CONNMAN_DEVICE_TYPE_GPS:
- case CONNMAN_DEVICE_TYPE_VENDOR:
- break;
- }
-
- switch (type) {
- case CONNMAN_DEVICE_TYPE_VENDOR:
- case CONNMAN_DEVICE_TYPE_GPS:
- break;
- case CONNMAN_DEVICE_TYPE_ETHERNET:
- case CONNMAN_DEVICE_TYPE_GADGET:
ident = index2ident(index, NULL);
break;
- case CONNMAN_DEVICE_TYPE_WIFI:
+ case CONNMAN_DEVICE_TYPE_CELLULAR:
ident = index2ident(index, NULL);
break;
case CONNMAN_DEVICE_TYPE_BLUETOOTH:
- break;
- case CONNMAN_DEVICE_TYPE_CELLULAR:
- ident = index2ident(index, NULL);
+ case CONNMAN_DEVICE_TYPE_GPS:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
break;
}
diff --git a/src/main.c b/src/main.c
index 4bc2266..7a6d802 100755..100644
--- a/src/main.c
+++ b/src/main.c
@@ -806,6 +806,9 @@ int main(int argc, char *argv[])
__connman_service_init();
__connman_peer_service_init();
__connman_peer_init();
+#if defined TIZEN_EXT_WIFI_MESH
+ __connman_mesh_init();
+#endif /* TIZEN_EXT_WIFI_MESH */
__connman_provider_init();
__connman_network_init();
__connman_config_init();
@@ -880,6 +883,9 @@ int main(int argc, char *argv[])
__connman_firewall_cleanup();
__connman_peer_service_cleanup();
__connman_peer_cleanup();
+#if defined TIZEN_EXT_WIFI_MESH
+ __connman_mesh_cleanup();
+#endif /* TIZEN_EXT_WIFI_MESH */
__connman_ippool_cleanup();
__connman_device_cleanup();
__connman_network_cleanup();
diff --git a/src/manager.c b/src/manager.c
index 2e1367f..bd44fea 100755..100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -537,6 +537,114 @@ error:
}
+#if defined TIZEN_EXT_WIFI_MESH
+static void append_mesh_peer_structs(DBusMessageIter *iter, void *user_data)
+{
+ __connman_mesh_peer_list_struct(iter);
+}
+
+static DBusMessage *get_mesh_peers(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ __connman_dbus_append_objpath_dict_array(reply,
+ append_mesh_peer_structs, NULL);
+ return reply;
+}
+
+static DBusMessage *get_connected_mesh_peers(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, array;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING, &array);
+
+ __connman_mesh_connected_peer_list_struct(&array);
+ dbus_message_iter_close_container(&iter, &array);
+ return reply;
+}
+
+static DBusMessage *get_disconnected_mesh_peers(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, array;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING, &array);
+
+ __connman_mesh_disconnected_peer_list_struct(&array);
+ dbus_message_iter_close_container(&iter, &array);
+ return reply;
+}
+
+static DBusMessage *mesh_add_peer(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ const char *addr;
+ int err;
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID);
+
+ DBG("Address %s", addr);
+
+ err = __connman_mesh_change_peer_status(msg, addr, CONNMAN_MESH_PEER_ADD);
+ if (err < 0)
+ return __connman_error_failed(msg, -err);
+
+ return NULL;
+}
+
+static DBusMessage *mesh_remove_peer(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ const char *addr;
+ int err;
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID);
+
+ DBG("Address %s", addr);
+
+ err = __connman_mesh_change_peer_status(msg, addr,
+ CONNMAN_MESH_PEER_REMOVE);
+ if (err < 0)
+ return __connman_error_failed(msg, -err);
+
+ return NULL;
+}
+#endif
+
static const GDBusMethodTable manager_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
@@ -596,6 +704,21 @@ static const GDBusMethodTable manager_methods[] = {
{ GDBUS_METHOD("UnregisterPeerService",
GDBUS_ARGS({ "specification", "a{sv}" }), NULL,
unregister_peer_service) },
+#if defined TIZEN_EXT_WIFI_MESH
+ { GDBUS_METHOD("GetMeshPeers",
+ NULL, GDBUS_ARGS({ "peers", "a(oa{sv})" }),
+ get_mesh_peers) },
+ { GDBUS_METHOD("GetConnectedMeshPeers",
+ NULL, GDBUS_ARGS({ "peers", "a(a{sv})" }),
+ get_connected_mesh_peers) },
+ { GDBUS_METHOD("GetDisconnectedMeshPeers",
+ NULL, GDBUS_ARGS({ "peers", "a(a{sv})" }),
+ get_disconnected_mesh_peers) },
+ { GDBUS_ASYNC_METHOD("MeshAddPeer", GDBUS_ARGS({ "address", "s" }), NULL,
+ mesh_add_peer) },
+ { GDBUS_ASYNC_METHOD("MeshRemovePeer", GDBUS_ARGS({ "address", "s" }), NULL,
+ mesh_remove_peer) },
+#endif
{ },
};
diff --git a/src/mesh-netlink.c b/src/mesh-netlink.c
new file mode 100644
index 0000000..22d6925
--- /dev/null
+++ b/src/mesh-netlink.c
@@ -0,0 +1,187 @@
+/*
+ *
+ * Connection Manager
+ *
+ *
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "connman.h"
+#include <connman/mesh-netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+#include <netlink/netlink.h>
+
+static int seq_check_cb(struct nl_msg *msg, void *arg)
+{
+ DBG("");
+
+ return NL_OK;
+}
+
+static int finish_cb(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+
+ DBG("");
+
+ *ret = 0;
+
+ return NL_SKIP;
+}
+
+static int ack_cb(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+
+ DBG("");
+
+ *ret = 0;
+
+ return NL_STOP;
+}
+
+static int valid_cb(struct nl_msg *msg, void *arg)
+{
+ DBG("");
+
+ return NL_SKIP;
+}
+
+static int error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
+{
+ int *ret = arg;
+
+ *ret = err->error;
+
+ DBG("error %d", *ret);
+
+ return NL_STOP;
+}
+
+int __connman_mesh_netlink_set_gate_announce(mesh_nl80211_global *global,
+ int mesh_if_index, bool gate_announce, int hwmp_rootmode)
+{
+ struct nl_msg *msg;
+ struct nlattr *container;
+ struct nl_cb *cb;
+ int err = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ cb = nl_cb_clone(global->cb);
+ if (!cb)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, global->id, 0, 0, NL80211_CMD_SET_MESH_CONFIG, 0);
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, mesh_if_index);
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+
+ nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE, hwmp_rootmode);
+
+ nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS, gate_announce);
+
+ nla_nest_end(msg, container);
+
+ err = nl_send_auto_complete(global->nl_socket, msg);
+ if (err < 0) {
+ DBG("Failed to send msg");
+ goto out;
+ }
+
+ err = 1;
+
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_cb, &err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_cb, &err);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, &err);
+ nl_cb_err(cb, NL_CB_CUSTOM, error_cb, &err);
+
+ while (err > 0) {
+ int res = nl_recvmsgs(global->nl_socket, cb);
+ if (res < 0)
+ DBG("nl_recvmsgs failed: %d", res);
+ }
+
+out:
+ nl_cb_put(cb);
+ nlmsg_free(msg);
+ return err;
+}
+
+mesh_nl80211_global *__connman_mesh_nl80211_global_init(void)
+{
+ mesh_nl80211_global *global;
+
+ DBG("");
+
+ global = g_malloc0(sizeof(mesh_nl80211_global));
+
+ global->nl_socket = nl_socket_alloc();
+ if (!global->nl_socket) {
+ DBG("Failed to allocate netlink socket");
+ g_free(global);
+ return NULL;
+ }
+
+ if (genl_connect(global->nl_socket)) {
+ DBG("Failed to connect to generic netlink");
+ nl_socket_free(global->nl_socket);
+ g_free(global);
+ return NULL;
+ }
+
+ nl_socket_set_buffer_size(global->nl_socket, 8192, 8192);
+
+ global->id = genl_ctrl_resolve(global->nl_socket, "nl80211");
+ if (global->id < 0) {
+ DBG("nl80211 generic netlink not found");
+ nl_socket_free(global->nl_socket);
+ g_free(global);
+ return NULL;
+ }
+
+ global->cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!global->cb) {
+ DBG("Failed to allocate netwlink callbacks");
+ nl_socket_free(global->nl_socket);
+ g_free(global);
+ return NULL;
+ }
+
+ nl_cb_set(global->cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, seq_check_cb, NULL);
+
+ return global;
+}
+
+void __connman_mesh_nl80211_global_deinit(mesh_nl80211_global *global)
+{
+ DBG("");
+
+ nl_cb_put(global->cb);
+ nl_socket_free(global->nl_socket);
+ g_free(global);
+}
diff --git a/src/mesh.c b/src/mesh.c
new file mode 100644
index 0000000..b902934
--- /dev/null
+++ b/src/mesh.c
@@ -0,0 +1,1660 @@
+/*
+ *
+ * Connection Manager
+ *
+ *
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <gdbus.h>
+
+#include <connman/storage.h>
+#include "connman.h"
+#include <sys/types.h>
+#include <dirent.h>
+#include <linux/if_bridge.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <unistd.h>
+#include "mesh-netlink.h"
+
+static DBusConnection *connection;
+
+static GHashTable *mesh_table;
+static GHashTable *connected_peer_table;
+static GHashTable *disconnected_peer_table;
+
+static struct connman_mesh_driver *mesh_driver;
+static struct connman_mesh_eth_driver *mesh_eth_driver;
+
+char *mesh_ifname;
+char *bridge_interface;
+static unsigned int mesh_autoconnect_timeout;
+static bool is_mesh_if_created;
+bool eth_if_bridged;
+mesh_nl80211_global *nl80211_global;
+
+struct connman_mesh {
+ int refcount;
+ char *identifier;
+ char *name;
+ char *path;
+ char *address;
+ char *interface_addr;
+ enum connman_mesh_security security;
+ char *passphrase;
+ enum connman_mesh_state state;
+ enum connman_mesh_peer_type peer_type;
+ enum connman_mesh_peer_disconnect_reason disconnect_reason;
+ uint16_t frequency;
+ uint8_t strength;
+ bool registered;
+ bool favorite;
+ DBusMessage *pending;
+ int index;
+ int br_index;
+ uint16_t ieee80211w;
+ struct connman_ipconfig *ipconfig;
+};
+
+struct connman_mesh_connected_peer {
+ char *peer_address;
+};
+
+struct connman_mesh_disconnected_peer {
+ char *peer_address;
+ enum connman_mesh_peer_disconnect_reason disconnect_reason;
+};
+
+struct connman_mesh_change_peer_data {
+ DBusMessage *pending;
+ char *peer_address;
+ enum connman_mesh_peer_status status;
+};
+
+static void mesh_dhcp_callback(struct connman_ipconfig *ipconfig,
+ struct connman_network *network, bool success, gpointer data);
+
+static void mesh_free(gpointer data)
+{
+ struct connman_mesh *mesh = data;
+
+ connman_mesh_unregister(mesh);
+
+ g_free(mesh->path);
+
+ if (mesh->state == CONNMAN_MESH_STATE_CONFIGURATION ||
+ mesh->state == CONNMAN_MESH_STATE_READY)
+ __connman_dhcp_stop(mesh->ipconfig);
+
+ if (mesh->ipconfig) {
+ __connman_ipconfig_set_ops(mesh->ipconfig, NULL);
+ __connman_ipconfig_set_data(mesh->ipconfig, NULL);
+ __connman_ipconfig_unref(mesh->ipconfig);
+ mesh->ipconfig = NULL;
+ }
+ g_free(mesh->identifier);
+ g_free(mesh->name);
+ g_free(mesh->passphrase);
+ g_free(mesh->interface_addr);
+ g_free(mesh->address);
+ g_free(mesh);
+}
+
+static void mesh_connected_peer_free(gpointer data)
+{
+ struct connman_mesh_connected_peer *peer = data;
+
+ g_free(peer->peer_address);
+ g_free(peer);
+}
+
+static void mesh_disconnected_peer_free(gpointer data)
+{
+ struct connman_mesh_disconnected_peer *peer = data;
+
+ g_free(peer->peer_address);
+ g_free(peer);
+}
+
+static void __mesh_load_and_create_network(char *mesh_id)
+{
+ GKeyFile *keyfile;
+ GString *str;
+ struct connman_mesh *connman_mesh;
+ gchar *name, *passphrase, *peer_type;
+ char *identifier, *group, *address;
+ const char *sec_type, *mesh_ifname;
+ int freq, i;
+
+ keyfile = connman_storage_load_service(mesh_id);
+ if (!keyfile) {
+ DBG("Mesh profile doesn't exist");
+ return;
+ }
+
+ peer_type = g_key_file_get_string(keyfile, mesh_id, "PeerType", NULL);
+ if (g_strcmp0(peer_type, "created")) {
+ DBG("Mesh Profile was not created");
+ goto done;
+ }
+
+ name = g_key_file_get_string(keyfile, mesh_id, "Name", NULL);
+ if (!name) {
+ DBG("Failed to get Mesh Profile Name");
+ goto done;
+ }
+
+ passphrase = g_key_file_get_string(keyfile, mesh_id, "Passphrase", NULL);
+ if (passphrase)
+ sec_type = "sae";
+ else
+ sec_type = "none";
+
+ freq = g_key_file_get_integer(keyfile, mesh_id, "Frequency", NULL);
+
+ mesh_ifname = connman_mesh_get_interface_name();
+
+ str = g_string_sized_new((strlen(name) * 2) + 24);
+
+ for (i = 0; name[i]; i++)
+ g_string_append_printf(str, "%02x", name[i]);
+
+ g_string_append_printf(str, "_mesh");
+
+ if (g_strcmp0(sec_type, "none") == 0)
+ g_string_append_printf(str, "_none");
+ else if (g_strcmp0(sec_type, "sae") == 0)
+ g_string_append_printf(str, "_sae");
+
+ group = g_string_free(str, FALSE);
+
+ identifier = connman_inet_ifaddr(mesh_ifname);
+ address = connman_inet_ifname2addr(mesh_ifname);
+
+ connman_mesh = connman_mesh_create(identifier, group);
+ connman_mesh_set_name(connman_mesh, name);
+ connman_mesh_set_address(connman_mesh, address);
+ connman_mesh_set_security(connman_mesh, sec_type);
+ connman_mesh_set_frequency(connman_mesh, freq);
+ connman_mesh_set_index(connman_mesh, connman_inet_ifindex(mesh_ifname));
+ connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_CREATED);
+
+ connman_mesh_register(connman_mesh);
+ g_free(group);
+ g_free(identifier);
+ g_free(address);
+done:
+ g_key_file_free(keyfile);
+}
+
+static bool is_connected(struct connman_mesh *mesh)
+{
+ if (mesh->state == CONNMAN_MESH_STATE_READY)
+ return true;
+
+ return false;
+}
+
+static void mesh_peer_dhcp_refresh(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct connman_mesh *mesh = value;
+
+ DBG("mesh %p state %d", mesh, mesh->state);
+
+ if (is_connected(mesh))
+ __connman_mesh_dhcp_start(mesh->ipconfig, mesh_dhcp_callback, mesh);
+}
+
+int connman_inet_set_stp(int stp)
+{
+ int sk, err = 0;
+ struct ifreq ifr;
+ unsigned long args[4];
+
+ if (!bridge_interface)
+ return -EINVAL;
+
+ sk = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (sk < 0) {
+ err = -errno;
+ goto out;
+ }
+
+ args[0] = BRCTL_SET_BRIDGE_STP_STATE;
+ args[1] = stp;
+ args[2] = args[3] = 0;
+ memset(&ifr, 0, sizeof(struct ifreq));
+ strncpy(ifr.ifr_name, bridge_interface, sizeof(ifr.ifr_name) - 1);
+ ifr.ifr_data = (char *)args;
+
+ if (ioctl(sk, SIOCDEVPRIVATE, &ifr) < 0)
+ err = -errno;
+
+ close(sk);
+
+out:
+ if (err < 0)
+ DBG("Set STP Failed error %s", strerror(-err));
+
+ return err;
+}
+
+int __connman_mesh_set_stp_gate_announce(bool gate_announce, int hwmp_rootmode,
+ int stp)
+{
+ int err;
+
+ if (!mesh_ifname)
+ return -EINVAL;
+
+ err = connman_inet_set_stp(stp);
+ if (err < 0)
+ return err;
+
+ err = __connman_mesh_netlink_set_gate_announce(nl80211_global,
+ connman_inet_ifindex(mesh_ifname), gate_announce,
+ hwmp_rootmode);
+
+ return err;
+}
+
+void __connman_mesh_add_ethernet_to_bridge(void)
+{
+ if (is_mesh_if_created) {
+ DBG("");
+ mesh_eth_driver->add_to_bridge(bridge_interface);
+ eth_if_bridged = true;
+ g_hash_table_foreach(mesh_table, mesh_peer_dhcp_refresh, NULL);
+ connman_inet_set_stp(1);
+ __connman_mesh_netlink_set_gate_announce(nl80211_global,
+ connman_inet_ifindex(mesh_ifname), true,
+ MESH_HWMP_ROOTMODE_RANN);
+ }
+}
+
+void __connman_mesh_remove_ethernet_from_bridge(void)
+{
+ if (eth_if_bridged) {
+ DBG("");
+ mesh_eth_driver->remove_from_bridge(bridge_interface);
+ eth_if_bridged = false;
+ g_hash_table_foreach(mesh_table, mesh_peer_dhcp_refresh, NULL);
+ connman_inet_set_stp(0);
+ __connman_mesh_netlink_set_gate_announce(nl80211_global,
+ connman_inet_ifindex(mesh_ifname), false,
+ MESH_HWMP_ROOTMODE_NO_ROOT);
+ }
+}
+
+int connman_mesh_notify_interface_create(bool success)
+{
+ int ret;
+ int index;
+ const char *error = NULL;
+ DIR *dir;
+ struct dirent *d;
+
+ if (!success) {
+ error = "Operation Failed";
+ goto done;
+ }
+
+ if (!bridge_interface) {
+ DBG("Don't create bridge interface");
+ goto done;
+ }
+
+ DBG("Creating bridge [%s]", bridge_interface);
+
+ /* Create bridge interface */
+ ret = __connman_bridge_create(bridge_interface);
+ if (0 != ret) {
+ DBG("Failed to create bridge [%s] : [%s]", bridge_interface,
+ strerror(-ret));
+ error = "Bridge Creation";
+ success = false;
+ goto done;
+ }
+
+ /* Get Mesh Interface Index */
+ index = connman_inet_ifindex(mesh_ifname);
+ if (index < 0) {
+ DBG("Failed to get interface index for %s", mesh_ifname);
+ error = "Operation Failed";
+ success = false;
+ goto done;
+ }
+
+ /* Add mesh interface into bridge */
+ ret = connman_inet_add_to_bridge(index, bridge_interface);
+ if (0 != ret) {
+ DBG("Failed to add interface[%s] into bridge[%s]", mesh_ifname,
+ bridge_interface);
+ error = "Add Mesh into bridge";
+ success = false;
+ goto done;
+ }
+
+ if (__connman_technology_get_connected(CONNMAN_SERVICE_TYPE_ETHERNET)) {
+ mesh_eth_driver->add_to_bridge(bridge_interface);
+ eth_if_bridged = true;
+ }
+
+ index = connman_inet_ifindex(bridge_interface);
+ if (index < 0) {
+ DBG("Failed to get interface index for %s", bridge_interface);
+ error = "Operation Failed";
+ success = false;
+ goto done;
+ }
+
+ /* Make bridge interface UP */
+ ret = connman_inet_ifup(index);
+ if (0 != ret) {
+ DBG("Failed to change bridge interface state");
+ error = "Make bridge interface UP";
+ success = false;
+ }
+
+done:
+ if (success) {
+ is_mesh_if_created = true;
+
+ /* Load previously created mesh profiles */
+ dir = opendir(STORAGEDIR);
+ if (!dir) {
+ DBG("Failed to open %s directory", STORAGEDIR);
+ __connman_technology_mesh_interface_create_finished(
+ CONNMAN_SERVICE_TYPE_MESH, success, error);
+ return 0;
+ }
+
+ while ((d = readdir(dir))) {
+ if (g_str_has_prefix(d->d_name, "mesh_")) {
+ DBG("%s is a mesh profile", d->d_name);
+ __mesh_load_and_create_network(d->d_name);
+ __connman_mesh_auto_connect();
+ }
+ }
+
+ closedir(dir);
+
+ } else {
+ if (eth_if_bridged)
+ mesh_eth_driver->remove_from_bridge(bridge_interface);
+
+ __connman_bridge_disable(bridge_interface);
+
+ __connman_bridge_remove(bridge_interface);
+
+ mesh_driver->remove_interface(mesh_ifname);
+ }
+ __connman_technology_mesh_interface_create_finished(
+ CONNMAN_SERVICE_TYPE_MESH, success, error);
+ return 0;
+}
+
+int __connman_mesh_add_virtual_interface(const char *ifname,
+ const char *parent_ifname, const char *bridge_ifname)
+{
+ int ret;
+
+ if (!ifname || !parent_ifname)
+ return -EINVAL;
+
+ ret = mesh_driver->add_interface(ifname, parent_ifname);
+ if (ret != -EINPROGRESS) {
+ DBG("Failed to add virtual mesh interface");
+ return ret;
+ }
+
+ mesh_ifname = g_strdup(ifname);
+ bridge_interface = g_strdup(bridge_ifname);
+ DBG("Success adding virtual mesh interface");
+ return 0;
+}
+
+int connman_mesh_notify_interface_remove(bool success)
+{
+ struct connman_device *device;
+ int index;
+ if (success) {
+ g_free(mesh_ifname);
+ mesh_ifname = NULL;
+ g_hash_table_remove_all(mesh_table);
+ is_mesh_if_created = false;
+
+ if (eth_if_bridged) {
+ if (bridge_interface)
+ mesh_eth_driver->remove_from_bridge(bridge_interface);
+
+ device = __connman_device_find_device(
+ CONNMAN_SERVICE_TYPE_ETHERNET);
+ if (device) {
+ index = connman_device_get_index(device);
+ connman_inet_ifup(index);
+ }
+ eth_if_bridged = false;
+ }
+
+ if (bridge_interface) {
+ __connman_bridge_disable(bridge_interface);
+ if (__connman_bridge_remove(bridge_interface))
+ DBG("Failed to remove bridge [%s]", bridge_interface);
+
+ g_free(bridge_interface);
+ bridge_interface = NULL;
+ }
+ }
+
+ __connman_technology_mesh_interface_remove_finished(
+ CONNMAN_SERVICE_TYPE_MESH, success);
+ return 0;
+}
+
+int __connman_mesh_remove_virtual_interface(const char *ifname)
+{
+ int ret;
+ int index;
+
+ if (!ifname)
+ return -EINVAL;
+
+ if (bridge_interface) {
+ index = connman_inet_ifindex(mesh_ifname);
+ if (index < 0) {
+ DBG("Failed to get interface index for %s", mesh_ifname);
+ return -EINVAL;
+ }
+
+ ret = connman_inet_remove_from_bridge(index, bridge_interface);
+ if (0 != ret) {
+ DBG("Failed to remove interface[%s] freom bridge[%s]", mesh_ifname,
+ bridge_interface);
+ return -EINVAL;
+ }
+
+ if (eth_if_bridged)
+ mesh_eth_driver->remove_from_bridge(bridge_interface);
+
+ __connman_bridge_disable(bridge_interface);
+
+ ret = __connman_bridge_remove(bridge_interface);
+ if (0 != ret) {
+ DBG("Failed to remove bridge [%s]", bridge_interface);
+ return -EINVAL;
+ }
+
+ g_free(bridge_interface);
+ bridge_interface = NULL;
+ }
+
+ ret = mesh_driver->remove_interface(ifname);
+ if (ret != -EINPROGRESS) {
+ DBG("Failed to remove virtual mesh interface");
+ return ret;
+ }
+
+ DBG("Success removing virtual mesh interface");
+ return 0;
+}
+
+const char *connman_mesh_get_interface_name(void)
+{
+ return mesh_ifname;
+}
+
+bool connman_mesh_is_interface_created(void)
+{
+ DBG("Mesh interface is %screated", is_mesh_if_created ? "" : "not ");
+ return is_mesh_if_created;
+}
+
+struct connman_mesh *connman_mesh_create(const char *interface_addr,
+ const char *identifier)
+{
+ struct connman_mesh *mesh;
+
+ mesh = g_malloc0(sizeof(struct connman_mesh));
+ mesh->identifier = g_strdup_printf("mesh_%s_%s", interface_addr,
+ identifier);
+ mesh->interface_addr = g_strdup(interface_addr);
+ mesh->state = CONNMAN_MESH_STATE_IDLE;
+
+ mesh->refcount = 1;
+
+ return mesh;
+}
+
+void connman_mesh_set_name(struct connman_mesh *mesh, const char *name)
+{
+ g_free(mesh->name);
+ mesh->name = g_strdup(name);
+}
+
+const char *connman_mesh_get_name(struct connman_mesh *mesh)
+{
+ return mesh->name;
+}
+
+void connman_mesh_set_passphrase(struct connman_mesh *mesh,
+ const char *passphrase)
+{
+ g_free(mesh->passphrase);
+ mesh->passphrase = g_strdup(passphrase);
+}
+
+const char *connman_mesh_get_passphrase(struct connman_mesh *mesh)
+{
+ return mesh->passphrase;
+}
+
+void connman_mesh_set_address(struct connman_mesh *mesh, const char *address)
+{
+ g_free(mesh->address);
+ mesh->address = g_strdup(address);
+}
+
+void connman_mesh_set_security(struct connman_mesh *mesh, const char *security)
+{
+ if (!g_strcmp0(security, "none"))
+ mesh->security = CONNMAN_MESH_SECURITY_NONE;
+ else if (!g_strcmp0(security, "sae"))
+ mesh->security = CONNMAN_MESH_SECURITY_SAE;
+ else
+ mesh->security = CONNMAN_MESH_SECURITY_UNKNOWN;
+}
+
+static const char *security2string(enum connman_mesh_security security)
+{
+ switch (security) {
+ case CONNMAN_MESH_SECURITY_UNKNOWN:
+ break;
+ case CONNMAN_MESH_SECURITY_NONE:
+ return "none";
+ case CONNMAN_MESH_SECURITY_SAE:
+ return "sae";
+ }
+
+ return NULL;
+}
+
+const char *connman_mesh_get_security(struct connman_mesh *mesh)
+{
+ return security2string(mesh->security);
+}
+
+void connman_mesh_set_frequency(struct connman_mesh *mesh, uint16_t frequency)
+{
+ mesh->frequency = frequency;
+}
+
+uint16_t connman_mesh_get_frequency(struct connman_mesh *mesh)
+{
+ return mesh->frequency;
+}
+
+void connman_mesh_set_ieee80211w(struct connman_mesh *mesh, uint16_t ieee80211w)
+{
+ mesh->ieee80211w = ieee80211w;
+}
+
+uint16_t connman_mesh_get_ieee80211w(struct connman_mesh *mesh)
+{
+ return mesh->ieee80211w;
+}
+
+void connman_mesh_set_index(struct connman_mesh *mesh, int index)
+{
+ mesh->index = index;
+
+ if (bridge_interface)
+ mesh->br_index = connman_inet_ifindex(bridge_interface);
+}
+
+void connman_mesh_set_strength(struct connman_mesh *mesh, uint8_t strength)
+{
+ mesh->strength = strength;
+}
+
+static const char *peertype2string(enum connman_mesh_peer_type type)
+{
+ switch (type) {
+ case CONNMAN_MESH_PEER_TYPE_CREATED:
+ return "created";
+ case CONNMAN_MESH_PEER_TYPE_DISCOVERED:
+ return "discovered";
+ }
+
+ return NULL;
+}
+
+void connman_mesh_set_peer_type(struct connman_mesh *mesh,
+ enum connman_mesh_peer_type type)
+{
+ mesh->peer_type = type;
+}
+
+static const char *state2string(enum connman_mesh_state state)
+{
+ switch (state) {
+ case CONNMAN_MESH_STATE_UNKNOWN:
+ break;
+ case CONNMAN_MESH_STATE_IDLE:
+ return "idle";
+ case CONNMAN_MESH_STATE_ASSOCIATION:
+ return "association";
+ case CONNMAN_MESH_STATE_CONFIGURATION:
+ return "configuration";
+ case CONNMAN_MESH_STATE_READY:
+ return "ready";
+ case CONNMAN_MESH_STATE_DISCONNECT:
+ return "disconnect";
+ case CONNMAN_MESH_STATE_FAILURE:
+ return "failure";
+ }
+
+ return NULL;
+}
+
+static enum connman_mesh_peer_disconnect_reason convert_to_disconnect_reason(
+ int reason)
+{
+ switch (reason) {
+ case 3:
+ return CONNMAN_MESH_DEAUTH_LEAVING;
+ case 52:
+ return CONNMAN_MESH_PEERING_CANCELLED;
+ case 53:
+ return CONNMAN_MESH_MAX_PEERS;
+ case 54:
+ return CONNMAN_MESH_CONFIG_POLICY_VIOLATION;
+ case 55:
+ return CONNMAN_MESH_CLOSE_RCVD;
+ case 56:
+ return CONNMAN_MESH_MAX_RETRIES;
+ case 57:
+ return CONNMAN_MESH_CONFIRM_TIMEOUT;
+ case 58:
+ return CONNMAN_MESH_INVALID_GTK;
+ case 59:
+ return CONNMAN_MESH_INCONSISTENT_PARAMS;
+ case 60:
+ return CONNMAN_MESH_INVALID_SECURITY_CAP;
+ }
+
+ return CONNMAN_MESH_REASON_UNKNOWN;
+}
+
+void connman_mesh_peer_set_disconnect_reason(struct connman_mesh *mesh,
+ int disconnect_reason)
+{
+ mesh->disconnect_reason = convert_to_disconnect_reason(disconnect_reason);
+}
+
+static bool is_connecting(struct connman_mesh *mesh)
+{
+ if (mesh->state == CONNMAN_MESH_STATE_ASSOCIATION ||
+ mesh->state == CONNMAN_MESH_STATE_CONFIGURATION)
+ return true;
+
+ return false;
+}
+
+static int mesh_load(struct connman_mesh *mesh)
+{
+ GKeyFile *keyfile;
+ bool favorite;
+ GError *error = NULL;
+ gchar *str;
+
+ keyfile = connman_storage_load_service(mesh->identifier);
+ if (!keyfile) {
+ DBG("Mesh profile is new");
+ return -EIO;
+ }
+
+ favorite = g_key_file_get_boolean(keyfile,
+ mesh->identifier, "Favorite", &error);
+
+ if (!error)
+ mesh->favorite = favorite;
+
+ g_clear_error(&error);
+
+ str = g_key_file_get_string(keyfile, mesh->identifier, "Passphrase", NULL);
+
+ if (str) {
+ g_free(mesh->passphrase);
+ mesh->passphrase = str;
+ }
+
+ return 0;
+}
+
+static int mesh_save(struct connman_mesh *mesh)
+{
+ GKeyFile *keyfile;
+
+ keyfile = __connman_storage_open_service(mesh->identifier);
+ if (!keyfile)
+ return -EIO;
+
+ g_key_file_set_string(keyfile, mesh->identifier, "Name", mesh->name);
+ g_key_file_set_integer(keyfile, mesh->identifier, "Frequency",
+ mesh->frequency);
+ g_key_file_set_boolean(keyfile, mesh->identifier, "Favorite",
+ mesh->favorite);
+
+ if (mesh->passphrase)
+ g_key_file_set_string(keyfile, mesh->identifier, "Passphrase",
+ mesh->passphrase);
+
+ g_key_file_set_string(keyfile, mesh->identifier, "PeerType",
+ peertype2string(mesh->peer_type));
+
+ __connman_storage_save_service(keyfile, mesh->identifier);
+
+ g_key_file_free(keyfile);
+
+ return 0;
+}
+
+static void reply_pending(struct connman_mesh *mesh, int error)
+{
+ if (!mesh->pending)
+ return;
+
+ connman_dbus_reply_pending(mesh->pending, error, NULL);
+ mesh->pending = NULL;
+}
+
+static void state_changed(struct connman_mesh *mesh)
+{
+ const char *state;
+
+ state = state2string(mesh->state);
+ if (!state)
+ return;
+
+ connman_dbus_property_changed_basic(mesh->path,
+ CONNMAN_MESH_INTERFACE, "State",
+ DBUS_TYPE_STRING, &state);
+}
+
+static void mesh_dhcp_callback(struct connman_ipconfig *ipconfig,
+ struct connman_network *network, bool success, gpointer data)
+{
+ struct connman_mesh *mesh = data;
+ int err;
+
+ if (!success)
+ goto error;
+
+ err = __connman_ipconfig_address_add(ipconfig);
+ if (err < 0)
+ goto error;
+
+ return;
+
+error:
+ connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_FAILURE);
+}
+
+static int mesh_start_dhcp_client(struct connman_mesh *mesh)
+{
+ DBG("");
+
+ __connman_ipconfig_enable(mesh->ipconfig);
+
+ return __connman_mesh_dhcp_start(mesh->ipconfig, mesh_dhcp_callback, mesh);
+}
+
+static void mesh_remove_connected_peer(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct connman_mesh_connected_peer *peer = value;
+
+ DBG("Remove Peer %s", peer->peer_address);
+ g_hash_table_remove(connected_peer_table, key);
+}
+
+static void mesh_remove_disconnected_peer(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct connman_mesh_disconnected_peer *peer = value;
+
+ DBG("Remove Peer %s", peer->peer_address);
+ g_hash_table_remove(disconnected_peer_table, key);
+}
+
+int connman_mesh_peer_set_state(struct connman_mesh *mesh,
+ enum connman_mesh_state new_state)
+{
+ enum connman_mesh_state old_state = mesh->state;
+
+ DBG("mesh peer %s old state %s new state %s", mesh->name,
+ state2string(old_state), state2string(new_state));
+
+ if (old_state == new_state)
+ return -EALREADY;
+
+ switch (new_state) {
+ case CONNMAN_MESH_STATE_UNKNOWN:
+ return -EINVAL;
+ case CONNMAN_MESH_STATE_IDLE:
+ case CONNMAN_MESH_STATE_ASSOCIATION:
+ break;
+ case CONNMAN_MESH_STATE_CONFIGURATION:
+ /* Start Link Local IP Address */
+ mesh_start_dhcp_client(mesh);
+ break;
+ case CONNMAN_MESH_STATE_READY:
+ reply_pending(mesh, 0);
+ mesh->favorite = true;
+ __connman_notifier_connect(CONNMAN_SERVICE_TYPE_MESH);
+
+ /* Set Gate Announce option */
+ if (eth_if_bridged) {
+ connman_inet_set_stp(1);
+ __connman_mesh_netlink_set_gate_announce(nl80211_global,
+ connman_inet_ifindex(mesh_ifname), true,
+ MESH_HWMP_ROOTMODE_RANN);
+ }
+
+ mesh_save(mesh);
+ break;
+ case CONNMAN_MESH_STATE_DISCONNECT:
+ __connman_dhcp_stop(mesh->ipconfig);
+ g_hash_table_foreach(connected_peer_table, mesh_remove_connected_peer,
+ NULL);
+ g_hash_table_foreach(disconnected_peer_table,
+ mesh_remove_disconnected_peer, NULL);
+ __connman_notifier_disconnect(CONNMAN_SERVICE_TYPE_MESH);
+ break;
+ case CONNMAN_MESH_STATE_FAILURE:
+ reply_pending(mesh, ECONNABORTED);
+ break;
+ }
+
+ mesh->state = new_state;
+ state_changed(mesh);
+
+ return 0;
+}
+
+bool connman_mesh_peer_is_connected_state(struct connman_mesh *mesh)
+{
+ switch (mesh->state) {
+ case CONNMAN_MESH_STATE_UNKNOWN:
+ case CONNMAN_MESH_STATE_IDLE:
+ case CONNMAN_MESH_STATE_ASSOCIATION:
+ case CONNMAN_MESH_STATE_CONFIGURATION:
+ case CONNMAN_MESH_STATE_DISCONNECT:
+ case CONNMAN_MESH_STATE_FAILURE:
+ break;
+ case CONNMAN_MESH_STATE_READY:
+ return true;
+ }
+
+ return false;
+}
+
+struct connman_mesh *connman_get_connected_mesh_from_name(char *name)
+{
+ GList *list, *start;
+
+ list = g_hash_table_get_values(mesh_table);
+ start = list;
+ for (; list; list = list->next) {
+ struct connman_mesh *mesh = list->data;
+
+ if (!g_strcmp0(mesh->name, name) &&
+ mesh->state == CONNMAN_MESH_STATE_READY) {
+ g_list_free(start);
+ return mesh;
+ }
+ }
+
+ g_list_free(start);
+
+ return NULL;
+}
+
+struct connman_mesh *connman_get_connecting_mesh_from_name(char *name)
+{
+ GList *list, *start;
+
+ list = g_hash_table_get_values(mesh_table);
+ start = list;
+ for (; list; list = list->next) {
+ struct connman_mesh *mesh = list->data;
+
+ if (!g_strcmp0(mesh->name, name) && is_connecting(mesh)) {
+ g_list_free(start);
+ return mesh;
+ }
+ }
+
+ g_list_free(start);
+
+ return NULL;
+}
+
+static void mesh_append_ethernet(DBusMessageIter *iter, void *user_data)
+{
+ struct connman_mesh *mesh = user_data;
+
+ if (mesh->ipconfig)
+ __connman_ipconfig_append_ethernet(mesh->ipconfig, iter);
+}
+
+static void mesh_append_ipv4(DBusMessageIter *iter, void *user_data)
+{
+ struct connman_mesh *mesh = user_data;
+
+ if (!is_connected(mesh))
+ return;
+
+ if (mesh->ipconfig)
+ __connman_ipconfig_append_ipv4(mesh->ipconfig, iter);
+}
+
+static void mesh_append_ipv4config(DBusMessageIter *iter, void *user_data)
+{
+ struct connman_mesh *mesh = user_data;
+
+ if (mesh->ipconfig)
+ __connman_ipconfig_append_ipv4config(mesh->ipconfig, iter);
+}
+
+static void append_properties(DBusMessageIter *iter, struct connman_mesh *mesh)
+{
+ const char *state = state2string(mesh->state);
+ const char *security = security2string(mesh->security);
+ const char *peer_type = peertype2string(mesh->peer_type);
+ const char *type = "mesh";
+ DBusMessageIter dict;
+
+ connman_dbus_dict_open(iter, &dict);
+
+ connman_dbus_dict_append_basic(&dict, "Type", DBUS_TYPE_STRING, &type);
+ connman_dbus_dict_append_basic(&dict, "Name",
+ DBUS_TYPE_STRING, &mesh->name);
+ connman_dbus_dict_append_basic(&dict, "BSSID",
+ DBUS_TYPE_STRING, &mesh->address);
+ connman_dbus_dict_append_basic(&dict, "State", DBUS_TYPE_STRING, &state);
+ if (security)
+ connman_dbus_dict_append_basic(&dict, "Security",
+ DBUS_TYPE_STRING, &security);
+ connman_dbus_dict_append_basic(&dict, "Frequency",
+ DBUS_TYPE_UINT16, &mesh->frequency);
+ connman_dbus_dict_append_basic(&dict, "Favorite",
+ DBUS_TYPE_BOOLEAN, &mesh->favorite);
+ connman_dbus_dict_append_basic(&dict, "Strength",
+ DBUS_TYPE_BYTE, &mesh->strength);
+ connman_dbus_dict_append_basic(&dict, "PeerType",
+ DBUS_TYPE_STRING, &peer_type);
+ connman_dbus_dict_append_basic(&dict, "DisconnectReason",
+ DBUS_TYPE_INT32, &mesh->disconnect_reason);
+
+ connman_dbus_dict_append_dict(&dict, "Ethernet", mesh_append_ethernet,
+ mesh);
+
+ connman_dbus_dict_append_dict(&dict, "IPv4", mesh_append_ipv4, mesh);
+
+ connman_dbus_dict_append_dict(&dict, "IPv4.Configuration",
+ mesh_append_ipv4config, mesh);
+
+ connman_dbus_dict_close(iter, &dict);
+}
+
+static void append_mesh_peer_struct(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ DBusMessageIter *array = user_data;
+ struct connman_mesh *mesh = value;
+ DBusMessageIter entry;
+
+ DBG("Mesh Peer path %s", mesh->path);
+ dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
+ NULL, &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+ &mesh->path);
+ append_properties(&entry, mesh);
+ dbus_message_iter_close_container(array, &entry);
+}
+
+void __connman_mesh_peer_list_struct(DBusMessageIter *array)
+{
+ g_hash_table_foreach(mesh_table, append_mesh_peer_struct, array);
+}
+
+static DBusMessage *get_mesh_peer_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_mesh *mesh = data;
+ DBusMessageIter dict;
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &dict);
+ append_properties(&dict, mesh);
+
+ return reply;
+}
+
+static void append_mesh_disconnected_peer_struct(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ DBusMessageIter *array = user_data;
+ struct connman_mesh_disconnected_peer *peer = value;
+ DBusMessageIter entry;
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
+ NULL, &entry);
+
+ connman_dbus_dict_open(&entry, &dict);
+
+ connman_dbus_dict_append_basic(&dict, "PeerAddress",
+ DBUS_TYPE_STRING, &peer->peer_address);
+
+ connman_dbus_dict_append_basic(&dict, "DisconnectReason",
+ DBUS_TYPE_INT32, &peer->disconnect_reason);
+
+ connman_dbus_dict_close(&entry, &dict);
+ dbus_message_iter_close_container(array, &entry);
+}
+
+void __connman_mesh_disconnected_peer_list_struct(DBusMessageIter *array)
+{
+ g_hash_table_foreach(disconnected_peer_table,
+ append_mesh_disconnected_peer_struct, array);
+}
+
+static void append_mesh_connected_peer_struct(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ DBusMessageIter *array = user_data;
+ struct connman_mesh_connected_peer *peer = value;
+ DBusMessageIter entry;
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
+ NULL, &entry);
+
+ connman_dbus_dict_open(&entry, &dict);
+
+ connman_dbus_dict_append_basic(&dict, "PeerAddress",
+ DBUS_TYPE_STRING, &peer->peer_address);
+
+ connman_dbus_dict_close(&entry, &dict);
+ dbus_message_iter_close_container(array, &entry);
+}
+
+void __connman_mesh_connected_peer_list_struct(DBusMessageIter *array)
+{
+ g_hash_table_foreach(connected_peer_table,
+ append_mesh_connected_peer_struct, array);
+}
+
+int connman_mesh_add_connected_peer(const char *peer_address)
+{
+ struct connman_mesh_connected_peer *peer;
+ struct connman_mesh_connected_peer *temp_peer;
+ struct connman_mesh_disconnected_peer *disconn_peer;
+
+ temp_peer = g_hash_table_lookup(connected_peer_table, peer_address);
+
+ if (temp_peer) {
+ DBG("Mesh Peer %s is already connected", peer_address);
+ return 0;
+ }
+
+ peer = g_malloc0(sizeof(struct connman_mesh_connected_peer));
+ peer->peer_address = g_strdup(peer_address);
+ DBG("Peer %s", peer->peer_address);
+
+ g_hash_table_insert(connected_peer_table, peer->peer_address, peer);
+
+ /* Remove from disconnected Peer Table */
+ disconn_peer = g_hash_table_lookup(disconnected_peer_table, peer_address);
+ if (!disconn_peer) {
+ DBG("Peer %s was never disconnected", peer_address);
+ goto done;
+ }
+
+ g_hash_table_remove(disconnected_peer_table, peer_address);
+done:
+ return 0;
+}
+
+int connman_mesh_remove_connected_peer(const char *peer_address, int reason)
+{
+ struct connman_mesh_connected_peer *peer;
+ struct connman_mesh_disconnected_peer *disconn_peer;
+
+ peer = g_hash_table_lookup(connected_peer_table, peer_address);
+
+ if (!peer) {
+ DBG("Peer %s not connected", peer_address);
+ return 0;
+ }
+
+ g_hash_table_remove(connected_peer_table, peer_address);
+
+ /* Add to Disconnected Peer Table */
+ disconn_peer = g_malloc0(sizeof(struct connman_mesh_disconnected_peer));
+ disconn_peer->peer_address = g_strdup(peer_address);
+ disconn_peer->disconnect_reason = convert_to_disconnect_reason(reason);
+
+ g_hash_table_insert(disconnected_peer_table, disconn_peer->peer_address,
+ disconn_peer);
+
+ DBG("Mesh Peer %s removed due to reason %d", peer_address, reason);
+ return 0;
+}
+
+static void __mesh_change_peer_status_cb(int result, void *user_data)
+{
+ struct connman_mesh_change_peer_data *data = user_data;
+
+ DBG("Status %d Peer Address %s result %d", data->status, data->peer_address,
+ result);
+
+ connman_dbus_reply_pending(data->pending, -result, NULL);
+
+ data->pending = NULL;
+ g_free(data->peer_address);
+ g_free(data);
+}
+
+int __connman_mesh_change_peer_status(DBusMessage *msg,
+ const char *peer_address,
+ enum connman_mesh_peer_status status)
+{
+ struct connman_mesh_connected_peer *conn_peer;
+ struct connman_mesh_disconnected_peer *disconn_peer;
+ int err = -ENOTSUP;
+ struct connman_mesh_change_peer_data *data;
+
+ switch (status) {
+ case CONNMAN_MESH_PEER_ADD:
+ conn_peer = g_hash_table_lookup(connected_peer_table, peer_address);
+
+ if (conn_peer) {
+ DBG("Peer %s already connected", peer_address);
+ return -EEXIST;
+ }
+
+ break;
+
+ case CONNMAN_MESH_PEER_REMOVE:
+ disconn_peer = g_hash_table_lookup(disconnected_peer_table,
+ peer_address);
+
+ if (disconn_peer) {
+ DBG("Peer %s already disconnected", peer_address);
+ return -EEXIST;
+ }
+
+ break;
+
+ default:
+ DBG("Invalid Status type");
+ return err;
+ }
+
+ if (mesh_driver->change_peer_status) {
+ data = g_try_malloc0(sizeof(struct connman_mesh_disconnected_peer));
+ if (data == NULL) {
+ DBG("Memory allocation failed");
+ return -ENOMEM;
+ }
+
+ data->pending = dbus_message_ref(msg);
+ data->peer_address = g_strdup(peer_address);
+ data->status = status;
+
+ err = mesh_driver->change_peer_status(peer_address, status,
+ __mesh_change_peer_status_cb, data);
+
+ if (err < 0) {
+ dbus_message_unref(data->pending);
+ g_free(data->peer_address);
+ g_free(data);
+ }
+ }
+
+ return err;
+}
+
+static int mesh_peer_connect(struct connman_mesh *mesh)
+{
+ int err = -ENOTSUP;
+ if (mesh_driver->connect)
+ err = mesh_driver->connect(mesh);
+
+ /* Reset Disconnect Reason */
+ mesh->disconnect_reason = CONNMAN_MESH_REASON_UNKNOWN;
+ return err;
+}
+
+static DBusMessage *connect_mesh_peer(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_mesh *mesh = user_data;
+ int err;
+
+ DBG("mesh %p", mesh);
+
+ if (mesh->state == CONNMAN_MESH_STATE_READY) {
+ DBG("mesh %s already connected", mesh->name);
+ return __connman_error_already_exists(msg);
+ }
+
+ if (mesh->pending)
+ return __connman_error_in_progress(msg);
+
+ mesh->pending = dbus_message_ref(msg);
+
+ err = mesh_peer_connect(mesh);
+ if (err == -EINPROGRESS)
+ return NULL;
+
+ if (err < 0) {
+ dbus_message_unref(mesh->pending);
+ mesh->pending = NULL;
+ return __connman_error_failed(msg, -err);
+ }
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static void auto_connect_mesh_peer(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ bool *conn_started = user_data;
+ struct connman_mesh *mesh = value;
+ int err;
+
+ if (*conn_started)
+ return;
+
+ if (!mesh->favorite || mesh->state != CONNMAN_MESH_STATE_IDLE)
+ return;
+
+ err = mesh_peer_connect(mesh);
+ if (err == -EINPROGRESS)
+ *conn_started = 1;
+}
+
+static gboolean run_mesh_auto_connect(gpointer data)
+{
+ bool conn_started;
+
+ mesh_autoconnect_timeout = 0;
+ DBG("");
+
+ conn_started = false;
+ g_hash_table_foreach(mesh_table, auto_connect_mesh_peer, &conn_started);
+ return FALSE;
+}
+
+void __connman_mesh_auto_connect(void)
+{
+ DBG("");
+
+ if (mesh_autoconnect_timeout != 0)
+ return;
+
+ mesh_autoconnect_timeout = g_idle_add(run_mesh_auto_connect, NULL);
+}
+
+static void mesh_peer_up(struct connman_ipconfig *ipconfig, const char *ifname)
+{
+ DBG("%s up", ifname);
+}
+
+static void mesh_peer_down(struct connman_ipconfig *ipconfig,
+ const char *ifname)
+{
+ DBG("%s down", ifname);
+}
+
+static void mesh_peer_lower_up(struct connman_ipconfig *ipconfig,
+ const char *ifname)
+{
+ DBG("%s lower up", ifname);
+}
+
+static void mesh_peer_lower_down(struct connman_ipconfig *ipconfig,
+ const char *ifname)
+{
+ DBG("%s lower down", ifname);
+}
+
+static void mesh_peer_ip_bound(struct connman_ipconfig *ipconfig,
+ const char *ifname)
+{
+ struct connman_mesh *mesh = __connman_ipconfig_get_data(ipconfig);
+
+ DBG("%s ip bound", ifname);
+
+ connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_READY);
+}
+
+static void mesh_peer_ip_release(struct connman_ipconfig *ipconfig,
+ const char *ifname)
+{
+ DBG("%s ip release", ifname);
+}
+
+static const struct connman_ipconfig_ops mesh_peer_ip_ops = {
+ .up = mesh_peer_up,
+ .down = mesh_peer_down,
+ .lower_up = mesh_peer_lower_up,
+ .lower_down = mesh_peer_lower_down,
+ .ip_bound = mesh_peer_ip_bound,
+ .ip_release = mesh_peer_ip_release,
+ .route_set = NULL,
+ .route_unset = NULL,
+};
+
+static struct connman_ipconfig *create_ipconfig(int index, void *user_data)
+{
+ struct connman_ipconfig *ipconfig;
+
+ ipconfig = __connman_ipconfig_create(index,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
+ if (!ipconfig)
+ return NULL;
+
+ __connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP);
+ __connman_ipconfig_set_data(ipconfig, user_data);
+ __connman_ipconfig_set_ops(ipconfig, &mesh_peer_ip_ops);
+
+ return ipconfig;
+}
+
+static int __connman_mesh_peer_disconnect(struct connman_mesh *mesh)
+{
+ int err;
+
+ reply_pending(mesh, ECONNABORTED);
+
+ if (!is_connected(mesh) && !is_connecting(mesh))
+ return -ENOTCONN;
+
+ err = mesh_driver->disconnect(mesh);
+ if (err < 0 && err != -EINPROGRESS)
+ return err;
+
+ return err;
+}
+
+static DBusMessage *disconnect_mesh_peer(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_mesh *mesh = user_data;
+ int err;
+
+ DBG("mesh %p", mesh);
+ err = __connman_mesh_peer_disconnect(mesh);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg, -err);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static bool __connman_mesh_peer_remove(struct connman_mesh *mesh)
+{
+ if (!mesh->favorite)
+ return false;
+
+ __connman_mesh_peer_disconnect(mesh);
+
+ mesh->favorite = false;
+
+ __connman_storage_remove_service(mesh->identifier);
+
+ return true;
+}
+
+static DBusMessage *remove_mesh_peer(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_mesh *mesh = user_data;
+
+ DBG("mesh %p", mesh);
+
+ if (!__connman_mesh_peer_remove(mesh))
+ return __connman_error_not_supported(msg);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *set_mesh_peer_property(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_mesh *mesh = user_data;
+ DBusMessageIter iter, value;
+ const char *name;
+ int type;
+
+ DBG("mesh %p", mesh);
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return __connman_error_invalid_arguments(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&iter, &name);
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_recurse(&iter, &value);
+
+ type = dbus_message_iter_get_arg_type(&value);
+
+ if (g_str_equal(name, "Passphrase")) {
+ char *passphrase;
+
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value, &passphrase);
+
+ connman_mesh_set_passphrase(mesh, passphrase);
+ } else {
+ DBG("Invalid Property %s", name);
+ return __connman_error_invalid_property(msg);
+ }
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static const GDBusMethodTable mesh_methods[] = {
+ { GDBUS_METHOD("GetProperties",
+ NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+ get_mesh_peer_properties) },
+ { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, connect_mesh_peer) },
+ { GDBUS_METHOD("Disconnect", NULL, NULL, disconnect_mesh_peer) },
+ { GDBUS_METHOD("Remove", NULL, NULL, remove_mesh_peer) },
+ { GDBUS_METHOD("SetProperty",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
+ NULL, set_mesh_peer_property) },
+ { },
+};
+
+static const GDBusSignalTable mesh_signals[] = {
+ { GDBUS_SIGNAL("PropertyChanged",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+ { },
+};
+
+int connman_mesh_register(struct connman_mesh *mesh)
+{
+ struct connman_mesh *temp;
+ DBG("mesh %p", mesh);
+
+ if (mesh->path)
+ return -EALREADY;
+
+ mesh->path = g_strdup_printf("%s/mesh/%s", CONNMAN_PATH,
+ mesh->identifier);
+ DBG("path %s", mesh->path);
+
+ temp = g_hash_table_lookup(mesh_table, mesh->path);
+ if (temp) {
+ DBG("mesh path %s already exists", mesh->path);
+
+ if (mesh->frequency != temp->frequency) {
+ DBG("Update frequency for mesh network %s", mesh->name);
+ connman_mesh_set_frequency(temp, mesh->frequency);
+ }
+
+ mesh_free(mesh);
+ return -EALREADY;
+ }
+
+ if (mesh->br_index > 0)
+ mesh->ipconfig = create_ipconfig(mesh->br_index, mesh);
+ else
+ mesh->ipconfig = create_ipconfig(mesh->index, mesh);
+
+ if (!mesh->ipconfig)
+ return -ENOMEM;
+
+ g_hash_table_insert(mesh_table, mesh->path, mesh);
+
+ mesh_load(mesh);
+
+ g_dbus_register_interface(connection, mesh->path,
+ CONNMAN_MESH_INTERFACE,
+ mesh_methods, mesh_signals,
+ NULL, mesh, NULL);
+ mesh->registered = true;
+ return 0;
+}
+
+void connman_mesh_unregister(struct connman_mesh *mesh)
+{
+ DBG("mesh %p", mesh);
+
+ if (!mesh->path || !mesh->registered)
+ return;
+
+ g_dbus_unregister_interface(connection, mesh->path,
+ CONNMAN_MESH_INTERFACE);
+ mesh->registered = false;
+
+ g_hash_table_remove(mesh_table, mesh->path);
+}
+
+struct connman_mesh *connman_mesh_get(const char *interface_addr,
+ const char *identifier)
+{
+ char *ident = g_strdup_printf("%s/mesh/mesh_%s_%s", CONNMAN_PATH,
+ interface_addr, identifier);
+ struct connman_mesh *mesh;
+
+ mesh = g_hash_table_lookup(mesh_table, ident);
+ g_free(ident);
+
+ return mesh;
+}
+
+int connman_mesh_driver_register(struct connman_mesh_driver *driver)
+{
+ if (mesh_driver && mesh_driver != driver)
+ return -EINVAL;
+
+ mesh_driver = driver;
+
+ return 0;
+}
+
+void connman_mesh_driver_unregister(struct connman_mesh_driver *driver)
+{
+ if (mesh_driver != driver)
+ return;
+
+ mesh_driver = NULL;
+}
+
+int connman_mesh_eth_driver_register(struct connman_mesh_eth_driver *driver)
+{
+ if (mesh_eth_driver && mesh_eth_driver != driver)
+ return -EINVAL;
+
+ mesh_eth_driver = driver;
+
+ return 0;
+}
+
+void connman_mesh_eth_driver_unregister(struct connman_mesh_eth_driver *driver)
+{
+ if (mesh_eth_driver != driver)
+ return;
+
+ mesh_eth_driver = NULL;
+}
+
+int __connman_mesh_init(void)
+{
+ DBG("");
+
+ connection = connman_dbus_get_connection();
+
+ mesh_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, mesh_free);
+
+ connected_peer_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ mesh_connected_peer_free);
+
+ disconnected_peer_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, mesh_disconnected_peer_free);
+
+ nl80211_global = __connman_mesh_nl80211_global_init();
+ return 0;
+}
+
+void __connman_mesh_cleanup(void)
+{
+ DBG("");
+
+ __connman_mesh_nl80211_global_deinit(nl80211_global);
+ g_hash_table_destroy(mesh_table);
+ g_hash_table_destroy(connected_peer_table);
+ g_hash_table_destroy(disconnected_peer_table);
+ dbus_connection_unref(connection);
+}
diff --git a/src/notifier.c b/src/notifier.c
index 5ba5324..7c3d031 100755..100644
--- a/src/notifier.c
+++ b/src/notifier.c
@@ -153,6 +153,9 @@ void __connman_notifier_connect(enum connman_service_type type)
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
case CONNMAN_SERVICE_TYPE_CELLULAR:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
}
@@ -200,6 +203,9 @@ void __connman_notifier_disconnect(enum connman_service_type type)
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
case CONNMAN_SERVICE_TYPE_CELLULAR:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
}
diff --git a/src/rtnl.c b/src/rtnl.c
index ac29f31..d733288 100755..100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -462,6 +462,20 @@ static void process_newlink(unsigned short type, int index, unsigned flags,
if (!extract_link(msg, bytes, &address, &ifname, &mtu, &operstate, &stats))
return;
+#if defined TIZEN_EXT_WIFI_MESH
+ /* Do not accept Wi-Fi Mesh interface */
+ if (g_strrstr(ifname, "mesh") != NULL) {
+ DBG("Newlink event for Wi-Fi Mesh interface ignored");
+ return;
+ }
+
+ /* Do not accept Wi-Fi WLAN1 interface "dedicated for softAP */
+ if (!g_strcmp0(ifname, "wlan1")) {
+ DBG("Newlink event for Wi-Fi WLAN1 interface ignored");
+ return;
+ }
+#endif
+
#if defined TIZEN_EXT
/* Do not accept Wi-Fi P2P interface */
if (g_strrstr(ifname, "p2p") != NULL) {
diff --git a/src/service.c b/src/service.c
index d7a7039..d13aafb 100755..100644
--- a/src/service.c
+++ b/src/service.c
@@ -298,6 +298,10 @@ const char *__connman_service_type2string(enum connman_service_type type)
return "gadget";
case CONNMAN_SERVICE_TYPE_P2P:
return "p2p";
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+ return "mesh";
+#endif
}
return NULL;
@@ -596,6 +600,9 @@ int __connman_service_load_modifiable(struct connman_service *service)
case CONNMAN_SERVICE_TYPE_SYSTEM:
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
case CONNMAN_SERVICE_TYPE_VPN:
set_split_routing(service, g_key_file_get_boolean(keyfile,
@@ -671,6 +678,9 @@ static int service_load(struct connman_service *service)
case CONNMAN_SERVICE_TYPE_SYSTEM:
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
case CONNMAN_SERVICE_TYPE_VPN:
set_split_routing(service, g_key_file_get_boolean(keyfile,
@@ -933,6 +943,9 @@ static int service_save(struct connman_service *service)
case CONNMAN_SERVICE_TYPE_SYSTEM:
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
case CONNMAN_SERVICE_TYPE_VPN:
g_key_file_set_boolean(keyfile, service->identifier,
@@ -3427,6 +3440,9 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_VPN:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
case CONNMAN_SERVICE_TYPE_CELLULAR:
val = service->roaming;
@@ -5046,6 +5062,9 @@ void __connman_service_set_active_session(bool enable, GSList *list)
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_VPN:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
}
@@ -5181,6 +5200,12 @@ static bool auto_connect_service(GList *services,
ignore[CONNMAN_SERVICE_TYPE_VPN] = true;
+#if defined TIZEN_EXT_WIFI_MESH
+ /* Don't auto connect wifi if mesh interface is created */
+ if (connman_mesh_is_interface_created())
+ ignore[CONNMAN_SERVICE_TYPE_WIFI] = true;
+#endif
+
for (list = services; list; list = list->next) {
service = list->data;
@@ -8060,6 +8085,9 @@ static int service_connect(struct connman_service *service)
case CONNMAN_SERVICE_TYPE_SYSTEM:
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
return -EINVAL;
case CONNMAN_SERVICE_TYPE_ETHERNET:
case CONNMAN_SERVICE_TYPE_GADGET:
@@ -8203,6 +8231,9 @@ int __connman_service_connect(struct connman_service *service,
case CONNMAN_SERVICE_TYPE_SYSTEM:
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
return -EINVAL;
case CONNMAN_SERVICE_TYPE_ETHERNET:
@@ -9025,6 +9056,9 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
case CONNMAN_SERVICE_TYPE_WIFI:
case CONNMAN_SERVICE_TYPE_CELLULAR:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
case CONNMAN_SERVICE_TYPE_ETHERNET:
service->favorite = true;
@@ -9056,6 +9090,9 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
case CONNMAN_SERVICE_TYPE_UNKNOWN:
case CONNMAN_SERVICE_TYPE_SYSTEM:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
case CONNMAN_SERVICE_TYPE_GADGET:
diff --git a/src/session.c b/src/session.c
index 9e3c559..26cbf87 100755..100644
--- a/src/session.c
+++ b/src/session.c
@@ -194,6 +194,9 @@ static char *service2bearer(enum connman_service_type type)
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_P2P:
case CONNMAN_SERVICE_TYPE_UNKNOWN:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
return "";
}
diff --git a/src/technology.c b/src/technology.c
index 57ab8e1..6604599 100755..100644
--- a/src/technology.c
+++ b/src/technology.c
@@ -95,6 +95,9 @@ struct connman_technology {
bool softblocked;
bool hardblocked;
bool dbus_registered;
+#if defined TIZEN_EXT_WIFI_MESH
+ DBusMessage *mesh_dbus_msg;
+#endif
};
static GSList *driver_list = NULL;
@@ -165,6 +168,10 @@ static const char *get_name(enum connman_service_type type)
return "Cellular";
case CONNMAN_SERVICE_TYPE_P2P:
return "P2P";
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+ return "Mesh";
+#endif
}
return NULL;
@@ -670,6 +677,11 @@ static int technology_affect_devices(struct connman_technology *technology,
return 0;
}
+#if defined TIZEN_EXT_WIFI_MESH
+ if (technology->type == CONNMAN_SERVICE_TYPE_MESH)
+ return 0;
+#endif
+
for (list = technology->device_list; list; list = list->next) {
struct connman_device *device = list->data;
@@ -1433,6 +1445,471 @@ static DBusMessage *get_scan_state(DBusConnection *conn, DBusMessage *msg, void
}
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+bool __connman_technology_get_connected(enum connman_service_type type)
+{
+ struct connman_technology *technology;
+
+ technology = technology_find(type);
+
+ if (!technology)
+ return false;
+
+ return technology->connected;
+}
+
+void __connman_technology_mesh_interface_create_finished(
+ enum connman_service_type type, bool success,
+ const char *error)
+{
+ DBusMessage *reply;
+ struct connman_technology *technology;
+ DBusMessage *msg;
+ technology = technology_find(type);
+
+ DBG("technology %p success %d", technology, success);
+
+ if (!technology)
+ return;
+
+ msg = technology->mesh_dbus_msg;
+ if (!msg) {
+ DBG("No pending dbus message");
+ return;
+ }
+
+ if (success) {
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ __connman_device_request_scan(technology->type);
+ } else
+ reply = g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".MeshInterfaceAddFailed", "%s", error);
+ g_dbus_send_message(connection, reply);
+ dbus_message_unref(msg);
+ technology->mesh_dbus_msg = NULL;
+}
+
+void __connman_technology_mesh_interface_remove_finished(
+ enum connman_service_type type, bool success)
+{
+ DBusMessage *reply;
+ struct connman_technology *technology;
+ DBusMessage *msg;
+ technology = technology_find(type);
+
+ DBG("technology %p success %d", technology, success);
+
+ if (!technology || !technology->mesh_dbus_msg)
+ return;
+
+ msg = technology->mesh_dbus_msg;
+ if (!msg) {
+ DBG("No pending dbus message");
+ return;
+ }
+
+ if (success)
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ else
+ reply = __connman_error_failed(msg, EINVAL);
+ g_dbus_send_message(connection, reply);
+ dbus_message_unref(msg);
+ technology->mesh_dbus_msg = NULL;
+}
+
+void __connman_technology_notify_abort_scan(enum connman_service_type type,
+ int result)
+{
+ DBusMessage *reply;
+ struct connman_technology *technology;
+ DBusMessage *msg;
+ technology = technology_find(type);
+
+ DBG("technology %p result %d", technology, result);
+
+ if (!technology || !technology->mesh_dbus_msg)
+ return;
+
+ msg = technology->mesh_dbus_msg;
+ if (!msg) {
+ DBG("No pending dbus message");
+ return;
+ }
+
+ if (result < 0)
+ reply = __connman_error_scan_abort_failed(msg);
+ else
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+ g_dbus_send_message(connection, reply);
+ dbus_message_unref(msg);
+ technology->mesh_dbus_msg = NULL;
+}
+
+static DBusMessage *mesh_commands(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_technology *technology = data;
+ DBusMessageIter iter, value, dict;
+ const char *cmd = NULL, *ifname = NULL, *parent_ifname = NULL;
+ int err;
+
+ DBG("conn %p", conn);
+
+ if (technology->type != CONNMAN_SERVICE_TYPE_MESH)
+ return __connman_error_invalid_arguments(msg);
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return __connman_error_invalid_arguments(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&iter, &cmd);
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_recurse(&iter, &value);
+
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY)
+ return __connman_error_invalid_arguments(msg);
+
+ DBG("Mesh Command %s", cmd);
+ if (g_str_equal(cmd, "MeshInterfaceAdd")) {
+ dbus_message_iter_recurse(&value, &dict);
+ const char *bridge_ifname = NULL;
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value2;
+ const char *key;
+ int type;
+
+ dbus_message_iter_recurse(&dict, &entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_recurse(&entry, &value2);
+
+ type = dbus_message_iter_get_arg_type(&value2);
+
+ if (g_str_equal(key, "Ifname")) {
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &ifname);
+ } else if (g_str_equal(key, "ParentIfname")) {
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &parent_ifname);
+ } else if (g_str_equal(key, "BridgeIfname")) {
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &bridge_ifname);
+ }
+ dbus_message_iter_next(&dict);
+ }
+ DBG("Mesh Ifname %s parent %s bridge %s", ifname, parent_ifname,
+ bridge_ifname ? bridge_ifname : "NULL");
+ err = __connman_mesh_add_virtual_interface(ifname, parent_ifname,
+ bridge_ifname);
+
+ if (err != 0) {
+ DBG("Failed to add virtual mesh interface");
+ return __connman_error_failed(msg, -err);
+ }
+
+ DBG("Successfully added virtual mesh interface");
+
+ dbus_message_ref(msg);
+ technology->mesh_dbus_msg = msg;
+
+ } else if (g_str_equal(cmd, "MeshInterfaceRemove")) {
+ dbus_message_iter_recurse(&value, &dict);
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value2;
+ const char *key;
+ int type;
+
+ dbus_message_iter_recurse(&dict, &entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_recurse(&entry, &value2);
+
+ type = dbus_message_iter_get_arg_type(&value2);
+
+ if (g_str_equal(key, "Ifname")) {
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &ifname);
+ }
+ dbus_message_iter_next(&dict);
+ }
+ DBG("Mesh Ifname %s", ifname);
+ err = __connman_mesh_remove_virtual_interface(ifname);
+
+ if (err != 0) {
+ DBG("Failed to remove virtual mesh interface");
+ return __connman_error_failed(msg, -err);
+ }
+
+ DBG("Successfully removed virtual mesh interface");
+
+ dbus_message_ref(msg);
+ technology->mesh_dbus_msg = msg;
+
+ } else if (g_str_equal(cmd, "MeshCreateNetwork")) {
+ struct connman_mesh *connman_mesh;
+ const char *name = NULL;
+ const char *sec_type = NULL;
+ const char *mesh_ifname = NULL;
+ char *identifier, *group, *address;
+ unsigned int freq = 0;
+ unsigned int ieee80211w = 0;
+ GString *str;
+ int i;
+ dbus_message_iter_recurse(&value, &dict);
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value2;
+ const char *key;
+ int type;
+
+ dbus_message_iter_recurse(&dict, &entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_recurse(&entry, &value2);
+
+ type = dbus_message_iter_get_arg_type(&value2);
+
+ if (g_str_equal(key, "Name")) {
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &name);
+ } else if (g_str_equal(key, "Frequency")) {
+ if (type != DBUS_TYPE_UINT16)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &freq);
+ } else if (g_str_equal(key, "Security")) {
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &sec_type);
+ } else if (g_str_equal(key, "Pmf")) {
+ if (type != DBUS_TYPE_UINT16)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &ieee80211w);
+ }
+ dbus_message_iter_next(&dict);
+ }
+
+ if (name == NULL || sec_type == NULL || freq == 0)
+ return __connman_error_invalid_arguments(msg);
+
+ DBG("Name %s Frequency %d Security type %s Pmf %u",
+ name, freq, sec_type, ieee80211w);
+
+ if (g_strcmp0(sec_type, "none") != 0 &&
+ g_strcmp0(sec_type, "sae") != 0) {
+ DBG("Unsupported security");
+ return __connman_error_invalid_arguments(msg);
+ }
+
+ mesh_ifname = connman_mesh_get_interface_name();
+
+ if (!connman_mesh_is_interface_created()) {
+ DBG("Mesh interface doesn't exists");
+ return __connman_error_invalid_command(msg);
+ }
+
+ str = g_string_sized_new((strlen(name) * 2) + 24);
+
+ for (i = 0; name[i]; i++)
+ g_string_append_printf(str, "%02x", name[i]);
+
+ g_string_append_printf(str, "_mesh");
+
+ if (g_strcmp0(sec_type, "none") == 0)
+ g_string_append_printf(str, "_none");
+ else if (g_strcmp0(sec_type, "sae") == 0)
+ g_string_append_printf(str, "_sae");
+
+ group = g_string_free(str, FALSE);
+
+ identifier = connman_inet_ifaddr(mesh_ifname);
+ address = connman_inet_ifname2addr(mesh_ifname);
+
+ connman_mesh = connman_mesh_create(identifier, group);
+ connman_mesh_set_name(connman_mesh, name);
+ connman_mesh_set_address(connman_mesh, address);
+ connman_mesh_set_security(connman_mesh, sec_type);
+ connman_mesh_set_frequency(connman_mesh, freq);
+ connman_mesh_set_index(connman_mesh, connman_inet_ifindex(mesh_ifname));
+ connman_mesh_set_peer_type(connman_mesh,
+ CONNMAN_MESH_PEER_TYPE_CREATED);
+ connman_mesh_set_ieee80211w(connman_mesh, ieee80211w);
+
+ connman_mesh_register(connman_mesh);
+ g_free(group);
+ g_free(identifier);
+ g_free(address);
+ DBG("Successfully Created Mesh Network");
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+ } else if (g_str_equal(cmd, "AbortScan")) {
+ DBG("Abort Scan method");
+ err = __connman_device_abort_scan(technology->type);
+ if (err != 0) {
+ DBG("Failed to abort scan");
+ return __connman_error_failed(msg, -err);
+ }
+
+ DBG("Successfully requested to abort scan");
+ dbus_message_ref(msg);
+ technology->mesh_dbus_msg = msg;
+
+ } else if (g_str_equal(cmd, "MeshSpecificScan")) {
+ const char *name = NULL;
+ unsigned int freq = 0;
+ dbus_message_iter_recurse(&value, &dict);
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value2;
+ const char *key;
+ int type;
+
+ dbus_message_iter_recurse(&dict, &entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_recurse(&entry, &value2);
+
+ type = dbus_message_iter_get_arg_type(&value2);
+
+ if (g_str_equal(key, "Name")) {
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &name);
+ } else if (g_str_equal(key, "Frequency")) {
+ if (type != DBUS_TYPE_UINT16)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &freq);
+ }
+ dbus_message_iter_next(&dict);
+ }
+
+ DBG("MeshID %s Frequency %d sender %s", name, freq,
+ dbus_message_get_sender(msg));
+
+ dbus_message_ref(msg);
+ technology->scan_pending =
+ g_slist_prepend(technology->scan_pending, msg);
+
+ err = __connman_device_request_mesh_specific_scan(technology->type,
+ name, freq);
+ if (err < 0)
+ reply_scan_pending(technology, err);
+ else
+ DBG("Successfully requested to scan specific Mesh Network");
+
+ } else if (g_str_equal(cmd, "SetMeshGate")) {
+ unsigned int hwmp_rootmode = 0;
+ bool gate_announce = false;
+ unsigned int stp = 0;
+ int err;
+ dbus_message_iter_recurse(&value, &dict);
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value2;
+ const char *key;
+ int type;
+
+ dbus_message_iter_recurse(&dict, &entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_recurse(&entry, &value2);
+
+ type = dbus_message_iter_get_arg_type(&value2);
+
+ if (g_str_equal(key, "GateAnnounce")) {
+ if (type != DBUS_TYPE_BOOLEAN)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &gate_announce);
+ } else if (g_str_equal(key, "HWMPRootMode")) {
+ if (type != DBUS_TYPE_UINT16)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &hwmp_rootmode);
+ } else if (g_str_equal(key, "STP")) {
+ if (type != DBUS_TYPE_UINT16)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value2, &stp);
+ }
+ dbus_message_iter_next(&dict);
+ }
+
+ DBG("GateAnnounce %d HWMPRootMode %d STP %d sender %s",
+ gate_announce, hwmp_rootmode, stp, dbus_message_get_sender(msg));
+
+ err = __connman_mesh_set_stp_gate_announce(gate_announce,
+ hwmp_rootmode,
+ stp);
+
+ if (err < 0)
+ return __connman_error_failed(msg, -err);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ } else
+ return __connman_error_invalid_command(msg);
+ return NULL;
+}
+#endif
+
static const GDBusMethodTable technology_methods[] = {
{ GDBUS_DEPRECATED_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
@@ -1447,6 +1924,11 @@ static const GDBusMethodTable technology_methods[] = {
{ GDBUS_METHOD("GetScanState", NULL, GDBUS_ARGS({ "scan_state", "a{sv}" }),
get_scan_state) },
#endif
+#if defined TIZEN_EXT_WIFI_MESH
+ { GDBUS_ASYNC_METHOD("MeshCommands",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
+ NULL, mesh_commands) },
+#endif
{ },
};
@@ -1557,7 +2039,12 @@ static struct connman_technology *technology_get(enum connman_service_type type)
technology = technology_find(type);
if (technology) {
+#if defined TIZEN_EXT_WIFI_MESH
+ if (type != CONNMAN_SERVICE_TYPE_P2P &&
+ type != CONNMAN_SERVICE_TYPE_MESH)
+#else
if (type != CONNMAN_SERVICE_TYPE_P2P)
+#endif
__sync_fetch_and_add(&technology->refcount, 1);
return technology;
}
@@ -1588,6 +2075,16 @@ static struct connman_technology *technology_get(enum connman_service_type type)
technology->path = g_strdup_printf("%s/technology/%s",
CONNMAN_PATH, str);
+#if defined TIZEN_EXT_WIFI_MESH
+ if (type == CONNMAN_SERVICE_TYPE_MESH) {
+ struct connman_technology *wifi;
+
+ wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
+ if (wifi)
+ technology->enabled = wifi->enabled;
+ }
+#endif
+
technology_load(technology);
technology_list = g_slist_prepend(technology_list, technology);
technology->driver_list = tech_drivers;
@@ -1666,6 +2163,13 @@ exist:
return -ENOMEM;
}
+#if defined TIZEN_EXT_WIFI_MESH
+ if (driver->type == CONNMAN_SERVICE_TYPE_MESH) {
+ if (!technology_get(CONNMAN_SERVICE_TYPE_MESH))
+ return -ENOMEM;
+ }
+#endif
+
return 0;
}
@@ -1703,6 +2207,13 @@ void connman_technology_driver_unregister(struct connman_technology_driver *driv
if (technology)
technology_put(technology);
}
+#if defined TIZEN_EXT_WIFI_MESH
+ if (driver->type == CONNMAN_SERVICE_TYPE_MESH) {
+ technology = technology_find(CONNMAN_SERVICE_TYPE_MESH);
+ if (technology)
+ technology_put(technology);
+ }
+#endif
}
void __connman_technology_add_interface(enum connman_service_type type,
@@ -1725,6 +2236,9 @@ void __connman_technology_add_interface(enum connman_service_type type,
case CONNMAN_SERVICE_TYPE_VPN:
case CONNMAN_SERVICE_TYPE_GADGET:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
}
@@ -1776,6 +2290,9 @@ void __connman_technology_remove_interface(enum connman_service_type type,
case CONNMAN_SERVICE_TYPE_VPN:
case CONNMAN_SERVICE_TYPE_GADGET:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
}
@@ -1971,6 +2488,15 @@ int __connman_technology_set_offlinemode(bool offlinemode)
return err;
}
+#if defined TIZEN_EXT_WIFI_MESH
+static gboolean __add_ethernet_to_bridge(gpointer data)
+{
+ DBG("");
+ __connman_mesh_add_ethernet_to_bridge();
+ return FALSE;
+}
+#endif
+
void __connman_technology_set_connected(enum connman_service_type type,
bool connected)
{
@@ -1985,6 +2511,11 @@ void __connman_technology_set_connected(enum connman_service_type type,
technology->connected = connected;
+#if defined TIZEN_EXT_WIFI_MESH
+ if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET && connected)
+ g_idle_add(__add_ethernet_to_bridge, NULL);
+#endif
+
val = connected;
connman_dbus_property_changed_basic(technology->path,
CONNMAN_TECHNOLOGY_INTERFACE, "Connected",
diff --git a/src/wispr.c b/src/wispr.c
index adf6230..a2df55a 100755..100644
--- a/src/wispr.c
+++ b/src/wispr.c
@@ -849,6 +849,9 @@ static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context)
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_VPN:
case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
return -EOPNOTSUPP;
}