6 * Copyright (C) 2017 Samsung Electronics Co., Ltd.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
30 #include <connman/storage.h>
32 #include <sys/types.h>
34 #include <linux/if_bridge.h>
35 #include <sys/ioctl.h>
38 #include "mesh-netlink.h"
40 static DBusConnection *connection;
42 static GHashTable *mesh_table;
43 static GHashTable *connected_peer_table;
44 static GHashTable *disconnected_peer_table;
46 static struct connman_mesh_driver *mesh_driver;
47 static struct connman_mesh_eth_driver *mesh_eth_driver;
50 char *bridge_interface;
51 static unsigned int mesh_autoconnect_timeout;
52 static bool is_mesh_if_created;
54 mesh_nl80211_global *nl80211_global;
63 enum connman_mesh_security security;
65 enum connman_mesh_state state;
66 enum connman_mesh_peer_type peer_type;
67 enum connman_mesh_peer_disconnect_reason disconnect_reason;
76 struct connman_ipconfig *ipconfig;
79 struct connman_mesh_connected_peer {
83 struct connman_mesh_disconnected_peer {
85 enum connman_mesh_peer_disconnect_reason disconnect_reason;
88 struct connman_mesh_change_peer_data {
91 enum connman_mesh_peer_status status;
94 static void mesh_dhcp_callback(struct connman_ipconfig *ipconfig,
95 struct connman_network *network, bool success, gpointer data);
97 static void mesh_free(gpointer data)
99 struct connman_mesh *mesh = data;
101 connman_mesh_unregister(mesh);
105 if (mesh->state == CONNMAN_MESH_STATE_CONFIGURATION ||
106 mesh->state == CONNMAN_MESH_STATE_READY)
107 __connman_dhcp_stop(mesh->ipconfig);
109 if (mesh->ipconfig) {
110 __connman_ipconfig_set_ops(mesh->ipconfig, NULL);
111 __connman_ipconfig_set_data(mesh->ipconfig, NULL);
112 __connman_ipconfig_unref(mesh->ipconfig);
113 mesh->ipconfig = NULL;
115 g_free(mesh->identifier);
117 g_free(mesh->passphrase);
118 g_free(mesh->interface_addr);
119 g_free(mesh->address);
123 static void mesh_connected_peer_free(gpointer data)
125 struct connman_mesh_connected_peer *peer = data;
127 g_free(peer->peer_address);
131 static void mesh_disconnected_peer_free(gpointer data)
133 struct connman_mesh_disconnected_peer *peer = data;
135 g_free(peer->peer_address);
139 static void __mesh_load_and_create_network(char *mesh_id)
143 struct connman_mesh *connman_mesh;
144 gchar *name, *passphrase, *peer_type;
145 char *identifier, *group, *address;
146 const char *sec_type, *mesh_ifname;
149 keyfile = connman_storage_load_service(mesh_id);
151 DBG("Mesh profile doesn't exist");
155 peer_type = g_key_file_get_string(keyfile, mesh_id, "PeerType", NULL);
156 if (g_strcmp0(peer_type, "created")) {
157 DBG("Mesh Profile was not created");
161 name = g_key_file_get_string(keyfile, mesh_id, "Name", NULL);
163 DBG("Failed to get Mesh Profile Name");
167 passphrase = g_key_file_get_string(keyfile, mesh_id, "Passphrase", NULL);
173 freq = g_key_file_get_integer(keyfile, mesh_id, "Frequency", NULL);
175 mesh_ifname = connman_mesh_get_interface_name();
177 str = g_string_sized_new((strlen(name) * 2) + 24);
179 for (i = 0; name[i]; i++)
180 g_string_append_printf(str, "%02x", name[i]);
182 g_string_append_printf(str, "_mesh");
184 if (g_strcmp0(sec_type, "none") == 0)
185 g_string_append_printf(str, "_none");
186 else if (g_strcmp0(sec_type, "sae") == 0)
187 g_string_append_printf(str, "_sae");
189 group = g_string_free(str, FALSE);
191 identifier = connman_inet_ifaddr(mesh_ifname);
192 address = connman_inet_ifname2addr(mesh_ifname);
194 connman_mesh = connman_mesh_create(identifier, group);
195 connman_mesh_set_name(connman_mesh, name);
196 connman_mesh_set_address(connman_mesh, address);
197 connman_mesh_set_security(connman_mesh, sec_type);
198 connman_mesh_set_frequency(connman_mesh, freq);
199 connman_mesh_set_index(connman_mesh, connman_inet_ifindex(mesh_ifname));
200 connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_CREATED);
202 connman_mesh_register(connman_mesh);
207 g_key_file_free(keyfile);
210 static bool is_connected(struct connman_mesh *mesh)
212 if (mesh->state == CONNMAN_MESH_STATE_READY)
218 static void mesh_peer_dhcp_refresh(gpointer key, gpointer value,
221 struct connman_mesh *mesh = value;
223 DBG("mesh %p state %d", mesh, mesh->state);
225 if (is_connected(mesh))
226 __connman_mesh_dhcp_start(mesh->ipconfig, mesh_dhcp_callback, mesh);
229 int connman_inet_set_stp(int stp)
233 unsigned long args[4];
235 if (!bridge_interface)
238 sk = socket(AF_LOCAL, SOCK_STREAM, 0);
244 args[0] = BRCTL_SET_BRIDGE_STP_STATE;
246 args[2] = args[3] = 0;
247 memset(&ifr, 0, sizeof(struct ifreq));
248 strncpy(ifr.ifr_name, bridge_interface, sizeof(ifr.ifr_name) - 1);
249 ifr.ifr_data = (char *)args;
251 if (ioctl(sk, SIOCDEVPRIVATE, &ifr) < 0)
258 DBG("Set STP Failed error %s", strerror(-err));
263 int __connman_mesh_set_stp_gate_announce(bool gate_announce, int hwmp_rootmode,
271 err = connman_inet_set_stp(stp);
275 err = __connman_mesh_netlink_set_gate_announce(nl80211_global,
276 connman_inet_ifindex(mesh_ifname), gate_announce,
282 void __connman_mesh_add_ethernet_to_bridge(void)
284 if (is_mesh_if_created) {
286 mesh_eth_driver->add_to_bridge(bridge_interface);
287 eth_if_bridged = true;
288 g_hash_table_foreach(mesh_table, mesh_peer_dhcp_refresh, NULL);
289 connman_inet_set_stp(1);
290 __connman_mesh_netlink_set_gate_announce(nl80211_global,
291 connman_inet_ifindex(mesh_ifname), true,
292 MESH_HWMP_ROOTMODE_RANN);
296 void __connman_mesh_remove_ethernet_from_bridge(void)
298 if (eth_if_bridged) {
300 mesh_eth_driver->remove_from_bridge(bridge_interface);
301 eth_if_bridged = false;
302 g_hash_table_foreach(mesh_table, mesh_peer_dhcp_refresh, NULL);
303 connman_inet_set_stp(0);
304 __connman_mesh_netlink_set_gate_announce(nl80211_global,
305 connman_inet_ifindex(mesh_ifname), false,
306 MESH_HWMP_ROOTMODE_NO_ROOT);
310 int connman_mesh_notify_interface_create(bool success)
314 const char *error = NULL;
319 error = "Operation Failed";
323 if (!bridge_interface) {
324 DBG("Don't create bridge interface");
328 DBG("Creating bridge [%s]", bridge_interface);
330 /* Create bridge interface */
331 ret = __connman_bridge_create(bridge_interface);
333 DBG("Failed to create bridge [%s] : [%s]", bridge_interface,
335 error = "Bridge Creation";
340 /* Get Mesh Interface Index */
341 index = connman_inet_ifindex(mesh_ifname);
343 DBG("Failed to get interface index for %s", mesh_ifname);
344 error = "Operation Failed";
349 /* Add mesh interface into bridge */
350 ret = connman_inet_add_to_bridge(index, bridge_interface);
352 DBG("Failed to add interface[%s] into bridge[%s]", mesh_ifname,
354 error = "Add Mesh into bridge";
359 if (__connman_technology_get_connected(CONNMAN_SERVICE_TYPE_ETHERNET)) {
360 mesh_eth_driver->add_to_bridge(bridge_interface);
361 eth_if_bridged = true;
364 index = connman_inet_ifindex(bridge_interface);
366 DBG("Failed to get interface index for %s", bridge_interface);
367 error = "Operation Failed";
372 /* Make bridge interface UP */
373 ret = connman_inet_ifup(index);
375 DBG("Failed to change bridge interface state");
376 error = "Make bridge interface UP";
382 is_mesh_if_created = true;
384 /* Load previously created mesh profiles */
385 dir = opendir(STORAGEDIR);
387 DBG("Failed to open %s directory", STORAGEDIR);
388 __connman_technology_mesh_interface_create_finished(
389 CONNMAN_SERVICE_TYPE_MESH, success, error);
393 while ((d = readdir(dir))) {
394 if (g_str_has_prefix(d->d_name, "mesh_")) {
395 DBG("%s is a mesh profile", d->d_name);
396 __mesh_load_and_create_network(d->d_name);
397 __connman_mesh_auto_connect();
405 mesh_eth_driver->remove_from_bridge(bridge_interface);
407 __connman_bridge_disable(bridge_interface);
409 __connman_bridge_remove(bridge_interface);
411 mesh_driver->remove_interface(mesh_ifname);
413 __connman_technology_mesh_interface_create_finished(
414 CONNMAN_SERVICE_TYPE_MESH, success, error);
418 int __connman_mesh_add_virtual_interface(const char *ifname,
419 const char *parent_ifname, const char *bridge_ifname)
423 if (!ifname || !parent_ifname)
426 ret = mesh_driver->add_interface(ifname, parent_ifname);
427 if (ret != -EINPROGRESS) {
428 DBG("Failed to add virtual mesh interface");
432 mesh_ifname = g_strdup(ifname);
433 bridge_interface = g_strdup(bridge_ifname);
434 DBG("Success adding virtual mesh interface");
438 int connman_mesh_notify_interface_remove(bool success)
440 struct connman_device *device;
445 g_hash_table_remove_all(mesh_table);
446 is_mesh_if_created = false;
448 if (eth_if_bridged) {
449 if (bridge_interface)
450 mesh_eth_driver->remove_from_bridge(bridge_interface);
452 device = __connman_device_find_device(
453 CONNMAN_SERVICE_TYPE_ETHERNET);
455 index = connman_device_get_index(device);
456 connman_inet_ifup(index);
458 eth_if_bridged = false;
461 if (bridge_interface) {
462 __connman_bridge_disable(bridge_interface);
463 if (__connman_bridge_remove(bridge_interface))
464 DBG("Failed to remove bridge [%s]", bridge_interface);
466 g_free(bridge_interface);
467 bridge_interface = NULL;
471 __connman_technology_mesh_interface_remove_finished(
472 CONNMAN_SERVICE_TYPE_MESH, success);
476 int __connman_mesh_remove_virtual_interface(const char *ifname)
484 if (bridge_interface) {
485 index = connman_inet_ifindex(mesh_ifname);
487 DBG("Failed to get interface index for %s", mesh_ifname);
491 ret = connman_inet_remove_from_bridge(index, bridge_interface);
493 DBG("Failed to remove interface[%s] freom bridge[%s]", mesh_ifname,
499 mesh_eth_driver->remove_from_bridge(bridge_interface);
501 __connman_bridge_disable(bridge_interface);
503 ret = __connman_bridge_remove(bridge_interface);
505 DBG("Failed to remove bridge [%s]", bridge_interface);
509 g_free(bridge_interface);
510 bridge_interface = NULL;
513 ret = mesh_driver->remove_interface(ifname);
514 if (ret != -EINPROGRESS) {
515 DBG("Failed to remove virtual mesh interface");
519 DBG("Success removing virtual mesh interface");
523 const char *connman_mesh_get_interface_name(void)
528 bool connman_mesh_is_interface_created(void)
530 DBG("Mesh interface is %screated", is_mesh_if_created ? "" : "not ");
531 return is_mesh_if_created;
534 struct connman_mesh *connman_mesh_create(const char *interface_addr,
535 const char *identifier)
537 struct connman_mesh *mesh;
539 mesh = g_malloc0(sizeof(struct connman_mesh));
540 mesh->identifier = g_strdup_printf("mesh_%s_%s", interface_addr,
542 mesh->interface_addr = g_strdup(interface_addr);
543 mesh->state = CONNMAN_MESH_STATE_IDLE;
550 void connman_mesh_set_name(struct connman_mesh *mesh, const char *name)
553 mesh->name = g_strdup(name);
556 const char *connman_mesh_get_name(struct connman_mesh *mesh)
561 void connman_mesh_set_passphrase(struct connman_mesh *mesh,
562 const char *passphrase)
564 g_free(mesh->passphrase);
565 mesh->passphrase = g_strdup(passphrase);
568 const char *connman_mesh_get_passphrase(struct connman_mesh *mesh)
570 return mesh->passphrase;
573 void connman_mesh_set_address(struct connman_mesh *mesh, const char *address)
575 g_free(mesh->address);
576 mesh->address = g_strdup(address);
579 void connman_mesh_set_security(struct connman_mesh *mesh, const char *security)
581 if (!g_strcmp0(security, "none"))
582 mesh->security = CONNMAN_MESH_SECURITY_NONE;
583 else if (!g_strcmp0(security, "sae"))
584 mesh->security = CONNMAN_MESH_SECURITY_SAE;
586 mesh->security = CONNMAN_MESH_SECURITY_UNKNOWN;
589 static const char *security2string(enum connman_mesh_security security)
592 case CONNMAN_MESH_SECURITY_UNKNOWN:
594 case CONNMAN_MESH_SECURITY_NONE:
596 case CONNMAN_MESH_SECURITY_SAE:
603 const char *connman_mesh_get_security(struct connman_mesh *mesh)
605 return security2string(mesh->security);
608 void connman_mesh_set_frequency(struct connman_mesh *mesh, uint16_t frequency)
610 mesh->frequency = frequency;
613 uint16_t connman_mesh_get_frequency(struct connman_mesh *mesh)
615 return mesh->frequency;
618 void connman_mesh_set_ieee80211w(struct connman_mesh *mesh, uint16_t ieee80211w)
620 mesh->ieee80211w = ieee80211w;
623 uint16_t connman_mesh_get_ieee80211w(struct connman_mesh *mesh)
625 return mesh->ieee80211w;
628 void connman_mesh_set_index(struct connman_mesh *mesh, int index)
632 if (bridge_interface)
633 mesh->br_index = connman_inet_ifindex(bridge_interface);
636 void connman_mesh_set_strength(struct connman_mesh *mesh, uint8_t strength)
638 mesh->strength = strength;
641 static const char *peertype2string(enum connman_mesh_peer_type type)
644 case CONNMAN_MESH_PEER_TYPE_CREATED:
646 case CONNMAN_MESH_PEER_TYPE_DISCOVERED:
653 void connman_mesh_set_peer_type(struct connman_mesh *mesh,
654 enum connman_mesh_peer_type type)
656 mesh->peer_type = type;
659 static const char *state2string(enum connman_mesh_state state)
662 case CONNMAN_MESH_STATE_UNKNOWN:
664 case CONNMAN_MESH_STATE_IDLE:
666 case CONNMAN_MESH_STATE_ASSOCIATION:
667 return "association";
668 case CONNMAN_MESH_STATE_CONFIGURATION:
669 return "configuration";
670 case CONNMAN_MESH_STATE_READY:
672 case CONNMAN_MESH_STATE_DISCONNECT:
674 case CONNMAN_MESH_STATE_FAILURE:
681 static enum connman_mesh_peer_disconnect_reason convert_to_disconnect_reason(
686 return CONNMAN_MESH_DEAUTH_LEAVING;
688 return CONNMAN_MESH_PEERING_CANCELLED;
690 return CONNMAN_MESH_MAX_PEERS;
692 return CONNMAN_MESH_CONFIG_POLICY_VIOLATION;
694 return CONNMAN_MESH_CLOSE_RCVD;
696 return CONNMAN_MESH_MAX_RETRIES;
698 return CONNMAN_MESH_CONFIRM_TIMEOUT;
700 return CONNMAN_MESH_INVALID_GTK;
702 return CONNMAN_MESH_INCONSISTENT_PARAMS;
704 return CONNMAN_MESH_INVALID_SECURITY_CAP;
707 return CONNMAN_MESH_REASON_UNKNOWN;
710 void connman_mesh_peer_set_disconnect_reason(struct connman_mesh *mesh,
711 int disconnect_reason)
713 mesh->disconnect_reason = convert_to_disconnect_reason(disconnect_reason);
716 static bool is_connecting(struct connman_mesh *mesh)
718 if (mesh->state == CONNMAN_MESH_STATE_ASSOCIATION ||
719 mesh->state == CONNMAN_MESH_STATE_CONFIGURATION)
725 static int mesh_load(struct connman_mesh *mesh)
729 GError *error = NULL;
732 keyfile = connman_storage_load_service(mesh->identifier);
734 DBG("Mesh profile is new");
738 favorite = g_key_file_get_boolean(keyfile,
739 mesh->identifier, "Favorite", &error);
742 mesh->favorite = favorite;
744 g_clear_error(&error);
746 str = g_key_file_get_string(keyfile, mesh->identifier, "Passphrase", NULL);
749 g_free(mesh->passphrase);
750 mesh->passphrase = str;
756 static int mesh_save(struct connman_mesh *mesh)
760 keyfile = g_key_file_new();
764 g_key_file_set_string(keyfile, mesh->identifier, "Name", mesh->name);
765 g_key_file_set_integer(keyfile, mesh->identifier, "Frequency",
767 g_key_file_set_boolean(keyfile, mesh->identifier, "Favorite",
770 if (mesh->passphrase)
771 g_key_file_set_string(keyfile, mesh->identifier, "Passphrase",
774 g_key_file_set_string(keyfile, mesh->identifier, "PeerType",
775 peertype2string(mesh->peer_type));
777 __connman_storage_save_service(keyfile, mesh->identifier);
779 g_key_file_free(keyfile);
784 static void reply_pending(struct connman_mesh *mesh, int error)
789 connman_dbus_reply_pending(mesh->pending, error, NULL);
790 mesh->pending = NULL;
793 static void state_changed(struct connman_mesh *mesh)
797 state = state2string(mesh->state);
801 connman_dbus_property_changed_basic(mesh->path,
802 CONNMAN_MESH_INTERFACE, "State",
803 DBUS_TYPE_STRING, &state);
806 static void mesh_dhcp_callback(struct connman_ipconfig *ipconfig,
807 struct connman_network *network, bool success, gpointer data)
809 struct connman_mesh *mesh = data;
815 err = __connman_ipconfig_address_add(ipconfig);
822 connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_FAILURE);
825 static int mesh_start_dhcp_client(struct connman_mesh *mesh)
829 __connman_ipconfig_enable(mesh->ipconfig);
831 return __connman_mesh_dhcp_start(mesh->ipconfig, mesh_dhcp_callback, mesh);
834 static void mesh_remove_connected_peer(gpointer key, gpointer value,
837 struct connman_mesh_connected_peer *peer = value;
839 DBG("Remove Peer %s", peer->peer_address);
840 g_hash_table_remove(connected_peer_table, key);
843 static void mesh_remove_disconnected_peer(gpointer key, gpointer value,
846 struct connman_mesh_disconnected_peer *peer = value;
848 DBG("Remove Peer %s", peer->peer_address);
849 g_hash_table_remove(disconnected_peer_table, key);
852 int connman_mesh_peer_set_state(struct connman_mesh *mesh,
853 enum connman_mesh_state new_state)
855 enum connman_mesh_state old_state = mesh->state;
857 DBG("mesh peer %s old state %s new state %s", mesh->name,
858 state2string(old_state), state2string(new_state));
860 if (old_state == new_state)
864 case CONNMAN_MESH_STATE_UNKNOWN:
866 case CONNMAN_MESH_STATE_IDLE:
867 case CONNMAN_MESH_STATE_ASSOCIATION:
869 case CONNMAN_MESH_STATE_CONFIGURATION:
870 /* Start Link Local IP Address */
871 mesh_start_dhcp_client(mesh);
873 case CONNMAN_MESH_STATE_READY:
874 reply_pending(mesh, 0);
875 mesh->favorite = true;
876 __connman_notifier_connect(CONNMAN_SERVICE_TYPE_MESH);
878 /* Set Gate Announce option */
879 if (eth_if_bridged) {
880 connman_inet_set_stp(1);
881 __connman_mesh_netlink_set_gate_announce(nl80211_global,
882 connman_inet_ifindex(mesh_ifname), true,
883 MESH_HWMP_ROOTMODE_RANN);
888 case CONNMAN_MESH_STATE_DISCONNECT:
889 __connman_dhcp_stop(mesh->ipconfig);
890 g_hash_table_foreach(connected_peer_table, mesh_remove_connected_peer,
892 g_hash_table_foreach(disconnected_peer_table,
893 mesh_remove_disconnected_peer, NULL);
894 __connman_notifier_disconnect(CONNMAN_SERVICE_TYPE_MESH);
896 case CONNMAN_MESH_STATE_FAILURE:
897 reply_pending(mesh, ECONNABORTED);
901 mesh->state = new_state;
907 bool connman_mesh_peer_is_connected_state(struct connman_mesh *mesh)
909 switch (mesh->state) {
910 case CONNMAN_MESH_STATE_UNKNOWN:
911 case CONNMAN_MESH_STATE_IDLE:
912 case CONNMAN_MESH_STATE_ASSOCIATION:
913 case CONNMAN_MESH_STATE_CONFIGURATION:
914 case CONNMAN_MESH_STATE_DISCONNECT:
915 case CONNMAN_MESH_STATE_FAILURE:
917 case CONNMAN_MESH_STATE_READY:
924 struct connman_mesh *connman_get_connected_mesh_from_name(char *name)
928 list = g_hash_table_get_values(mesh_table);
930 for (; list; list = list->next) {
931 struct connman_mesh *mesh = list->data;
933 if (!g_strcmp0(mesh->name, name) &&
934 mesh->state == CONNMAN_MESH_STATE_READY) {
945 struct connman_mesh *connman_get_connecting_mesh_from_name(char *name)
949 list = g_hash_table_get_values(mesh_table);
951 for (; list; list = list->next) {
952 struct connman_mesh *mesh = list->data;
954 if (!g_strcmp0(mesh->name, name) && is_connecting(mesh)) {
965 static void mesh_append_ethernet(DBusMessageIter *iter, void *user_data)
967 struct connman_mesh *mesh = user_data;
970 __connman_ipconfig_append_ethernet(mesh->ipconfig, iter);
973 static void mesh_append_ipv4(DBusMessageIter *iter, void *user_data)
975 struct connman_mesh *mesh = user_data;
977 if (!is_connected(mesh))
981 __connman_ipconfig_append_ipv4(mesh->ipconfig, iter);
984 static void mesh_append_ipv4config(DBusMessageIter *iter, void *user_data)
986 struct connman_mesh *mesh = user_data;
989 __connman_ipconfig_append_ipv4config(mesh->ipconfig, iter);
992 static void append_properties(DBusMessageIter *iter, struct connman_mesh *mesh)
994 const char *state = state2string(mesh->state);
995 const char *security = security2string(mesh->security);
996 const char *peer_type = peertype2string(mesh->peer_type);
997 const char *type = "mesh";
998 DBusMessageIter dict;
1000 connman_dbus_dict_open(iter, &dict);
1002 connman_dbus_dict_append_basic(&dict, "Type", DBUS_TYPE_STRING, &type);
1003 connman_dbus_dict_append_basic(&dict, "Name",
1004 DBUS_TYPE_STRING, &mesh->name);
1005 connman_dbus_dict_append_basic(&dict, "BSSID",
1006 DBUS_TYPE_STRING, &mesh->address);
1007 connman_dbus_dict_append_basic(&dict, "State", DBUS_TYPE_STRING, &state);
1009 connman_dbus_dict_append_basic(&dict, "Security",
1010 DBUS_TYPE_STRING, &security);
1011 connman_dbus_dict_append_basic(&dict, "Frequency",
1012 DBUS_TYPE_UINT16, &mesh->frequency);
1013 connman_dbus_dict_append_basic(&dict, "Favorite",
1014 DBUS_TYPE_BOOLEAN, &mesh->favorite);
1015 connman_dbus_dict_append_basic(&dict, "Strength",
1016 DBUS_TYPE_BYTE, &mesh->strength);
1017 connman_dbus_dict_append_basic(&dict, "PeerType",
1018 DBUS_TYPE_STRING, &peer_type);
1019 connman_dbus_dict_append_basic(&dict, "DisconnectReason",
1020 DBUS_TYPE_INT32, &mesh->disconnect_reason);
1022 connman_dbus_dict_append_dict(&dict, "Ethernet", mesh_append_ethernet,
1025 connman_dbus_dict_append_dict(&dict, "IPv4", mesh_append_ipv4, mesh);
1027 connman_dbus_dict_append_dict(&dict, "IPv4.Configuration",
1028 mesh_append_ipv4config, mesh);
1030 connman_dbus_dict_close(iter, &dict);
1033 static void append_mesh_peer_struct(gpointer key, gpointer value,
1036 DBusMessageIter *array = user_data;
1037 struct connman_mesh *mesh = value;
1038 DBusMessageIter entry;
1040 DBG("Mesh Peer path %s", mesh->path);
1041 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
1043 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
1045 append_properties(&entry, mesh);
1046 dbus_message_iter_close_container(array, &entry);
1049 void __connman_mesh_peer_list_struct(DBusMessageIter *array)
1051 g_hash_table_foreach(mesh_table, append_mesh_peer_struct, array);
1054 static DBusMessage *get_mesh_peer_properties(DBusConnection *conn,
1055 DBusMessage *msg, void *data)
1057 struct connman_mesh *mesh = data;
1058 DBusMessageIter dict;
1061 reply = dbus_message_new_method_return(msg);
1065 dbus_message_iter_init_append(reply, &dict);
1066 append_properties(&dict, mesh);
1071 static void append_mesh_disconnected_peer_struct(gpointer key, gpointer value,
1074 DBusMessageIter *array = user_data;
1075 struct connman_mesh_disconnected_peer *peer = value;
1076 DBusMessageIter entry;
1077 DBusMessageIter dict;
1079 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
1082 connman_dbus_dict_open(&entry, &dict);
1084 connman_dbus_dict_append_basic(&dict, "PeerAddress",
1085 DBUS_TYPE_STRING, &peer->peer_address);
1087 connman_dbus_dict_append_basic(&dict, "DisconnectReason",
1088 DBUS_TYPE_INT32, &peer->disconnect_reason);
1090 connman_dbus_dict_close(&entry, &dict);
1091 dbus_message_iter_close_container(array, &entry);
1094 void __connman_mesh_disconnected_peer_list_struct(DBusMessageIter *array)
1096 g_hash_table_foreach(disconnected_peer_table,
1097 append_mesh_disconnected_peer_struct, array);
1100 static void append_mesh_connected_peer_struct(gpointer key, gpointer value,
1103 DBusMessageIter *array = user_data;
1104 struct connman_mesh_connected_peer *peer = value;
1105 DBusMessageIter entry;
1106 DBusMessageIter dict;
1108 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
1111 connman_dbus_dict_open(&entry, &dict);
1113 connman_dbus_dict_append_basic(&dict, "PeerAddress",
1114 DBUS_TYPE_STRING, &peer->peer_address);
1116 connman_dbus_dict_close(&entry, &dict);
1117 dbus_message_iter_close_container(array, &entry);
1120 void __connman_mesh_connected_peer_list_struct(DBusMessageIter *array)
1122 g_hash_table_foreach(connected_peer_table,
1123 append_mesh_connected_peer_struct, array);
1126 int connman_mesh_add_connected_peer(const char *peer_address)
1128 struct connman_mesh_connected_peer *peer;
1129 struct connman_mesh_connected_peer *temp_peer;
1130 struct connman_mesh_disconnected_peer *disconn_peer;
1132 temp_peer = g_hash_table_lookup(connected_peer_table, peer_address);
1135 DBG("Mesh Peer %s is already connected", peer_address);
1139 peer = g_malloc0(sizeof(struct connman_mesh_connected_peer));
1140 peer->peer_address = g_strdup(peer_address);
1141 DBG("Peer %s", peer->peer_address);
1143 g_hash_table_insert(connected_peer_table, peer->peer_address, peer);
1145 /* Remove from disconnected Peer Table */
1146 disconn_peer = g_hash_table_lookup(disconnected_peer_table, peer_address);
1147 if (!disconn_peer) {
1148 DBG("Peer %s was never disconnected", peer_address);
1152 g_hash_table_remove(disconnected_peer_table, peer_address);
1157 int connman_mesh_remove_connected_peer(const char *peer_address, int reason)
1159 struct connman_mesh_connected_peer *peer;
1160 struct connman_mesh_disconnected_peer *disconn_peer;
1162 peer = g_hash_table_lookup(connected_peer_table, peer_address);
1165 DBG("Peer %s not connected", peer_address);
1169 g_hash_table_remove(connected_peer_table, peer_address);
1171 /* Add to Disconnected Peer Table */
1172 disconn_peer = g_malloc0(sizeof(struct connman_mesh_disconnected_peer));
1173 disconn_peer->peer_address = g_strdup(peer_address);
1174 disconn_peer->disconnect_reason = convert_to_disconnect_reason(reason);
1176 g_hash_table_insert(disconnected_peer_table, disconn_peer->peer_address,
1179 DBG("Mesh Peer %s removed due to reason %d", peer_address, reason);
1183 static void __mesh_change_peer_status_cb(int result, void *user_data)
1185 struct connman_mesh_change_peer_data *data = user_data;
1187 DBG("Status %d Peer Address %s result %d", data->status, data->peer_address,
1190 connman_dbus_reply_pending(data->pending, -result, NULL);
1192 data->pending = NULL;
1193 g_free(data->peer_address);
1197 int __connman_mesh_change_peer_status(DBusMessage *msg,
1198 const char *peer_address,
1199 enum connman_mesh_peer_status status)
1201 struct connman_mesh_connected_peer *conn_peer;
1202 struct connman_mesh_disconnected_peer *disconn_peer;
1204 struct connman_mesh_change_peer_data *data;
1207 case CONNMAN_MESH_PEER_ADD:
1208 conn_peer = g_hash_table_lookup(connected_peer_table, peer_address);
1211 DBG("Peer %s already connected", peer_address);
1217 case CONNMAN_MESH_PEER_REMOVE:
1218 disconn_peer = g_hash_table_lookup(disconnected_peer_table,
1222 DBG("Peer %s already disconnected", peer_address);
1229 DBG("Invalid Status type");
1233 if (mesh_driver->change_peer_status) {
1234 data = g_try_malloc0(sizeof(struct connman_mesh_disconnected_peer));
1236 DBG("Memory allocation failed");
1240 data->pending = dbus_message_ref(msg);
1241 data->peer_address = g_strdup(peer_address);
1242 data->status = status;
1244 err = mesh_driver->change_peer_status(peer_address, status,
1245 __mesh_change_peer_status_cb, data);
1248 dbus_message_unref(data->pending);
1249 g_free(data->peer_address);
1257 static int mesh_peer_connect(struct connman_mesh *mesh)
1260 if (mesh_driver->connect)
1261 err = mesh_driver->connect(mesh);
1263 /* Reset Disconnect Reason */
1264 mesh->disconnect_reason = CONNMAN_MESH_REASON_UNKNOWN;
1268 static DBusMessage *connect_mesh_peer(DBusConnection *conn,
1269 DBusMessage *msg, void *user_data)
1271 struct connman_mesh *mesh = user_data;
1274 DBG("mesh %p", mesh);
1276 if (mesh->state == CONNMAN_MESH_STATE_READY) {
1277 DBG("mesh %s already connected", mesh->name);
1278 return __connman_error_already_exists(msg);
1282 return __connman_error_in_progress(msg);
1284 mesh->pending = dbus_message_ref(msg);
1286 err = mesh_peer_connect(mesh);
1287 if (err == -EINPROGRESS)
1291 dbus_message_unref(mesh->pending);
1292 mesh->pending = NULL;
1293 return __connman_error_failed(msg, -err);
1296 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1299 static void auto_connect_mesh_peer(gpointer key, gpointer value,
1302 bool *conn_started = user_data;
1303 struct connman_mesh *mesh = value;
1309 if (!mesh->favorite || mesh->state != CONNMAN_MESH_STATE_IDLE)
1312 err = mesh_peer_connect(mesh);
1313 if (err == -EINPROGRESS)
1317 static gboolean run_mesh_auto_connect(gpointer data)
1321 mesh_autoconnect_timeout = 0;
1324 conn_started = false;
1325 g_hash_table_foreach(mesh_table, auto_connect_mesh_peer, &conn_started);
1329 void __connman_mesh_auto_connect(void)
1333 if (mesh_autoconnect_timeout != 0)
1336 mesh_autoconnect_timeout = g_idle_add(run_mesh_auto_connect, NULL);
1339 static void mesh_peer_up(struct connman_ipconfig *ipconfig, const char *ifname)
1341 DBG("%s up", ifname);
1344 static void mesh_peer_down(struct connman_ipconfig *ipconfig,
1347 DBG("%s down", ifname);
1350 static void mesh_peer_lower_up(struct connman_ipconfig *ipconfig,
1353 DBG("%s lower up", ifname);
1356 static void mesh_peer_lower_down(struct connman_ipconfig *ipconfig,
1359 DBG("%s lower down", ifname);
1362 static void mesh_peer_ip_bound(struct connman_ipconfig *ipconfig,
1365 struct connman_mesh *mesh = __connman_ipconfig_get_data(ipconfig);
1367 DBG("%s ip bound", ifname);
1369 connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_READY);
1372 static void mesh_peer_ip_release(struct connman_ipconfig *ipconfig,
1375 DBG("%s ip release", ifname);
1378 static const struct connman_ipconfig_ops mesh_peer_ip_ops = {
1380 .down = mesh_peer_down,
1381 .lower_up = mesh_peer_lower_up,
1382 .lower_down = mesh_peer_lower_down,
1383 .ip_bound = mesh_peer_ip_bound,
1384 .ip_release = mesh_peer_ip_release,
1386 .route_unset = NULL,
1389 static struct connman_ipconfig *create_ipconfig(int index, void *user_data)
1391 struct connman_ipconfig *ipconfig;
1393 ipconfig = __connman_ipconfig_create(index,
1394 CONNMAN_IPCONFIG_TYPE_IPV4);
1398 __connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP);
1399 __connman_ipconfig_set_data(ipconfig, user_data);
1400 __connman_ipconfig_set_ops(ipconfig, &mesh_peer_ip_ops);
1405 static int __connman_mesh_peer_disconnect(struct connman_mesh *mesh)
1409 reply_pending(mesh, ECONNABORTED);
1411 if (!is_connected(mesh) && !is_connecting(mesh))
1414 err = mesh_driver->disconnect(mesh);
1415 if (err < 0 && err != -EINPROGRESS)
1421 static DBusMessage *disconnect_mesh_peer(DBusConnection *conn,
1422 DBusMessage *msg, void *user_data)
1424 struct connman_mesh *mesh = user_data;
1427 DBG("mesh %p", mesh);
1428 err = __connman_mesh_peer_disconnect(mesh);
1429 if (err < 0 && err != -EINPROGRESS)
1430 return __connman_error_failed(msg, -err);
1432 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1435 static bool __connman_mesh_peer_remove(struct connman_mesh *mesh)
1437 if (!mesh->favorite)
1440 __connman_mesh_peer_disconnect(mesh);
1442 mesh->favorite = false;
1444 __connman_storage_remove_service(mesh->identifier);
1449 static DBusMessage *remove_mesh_peer(DBusConnection *conn,
1450 DBusMessage *msg, void *user_data)
1452 struct connman_mesh *mesh = user_data;
1454 DBG("mesh %p", mesh);
1456 if (!__connman_mesh_peer_remove(mesh))
1457 return __connman_error_not_supported(msg);
1459 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1462 static DBusMessage *set_mesh_peer_property(DBusConnection *conn,
1463 DBusMessage *msg, void *user_data)
1465 struct connman_mesh *mesh = user_data;
1466 DBusMessageIter iter, value;
1470 DBG("mesh %p", mesh);
1472 if (!dbus_message_iter_init(msg, &iter))
1473 return __connman_error_invalid_arguments(msg);
1475 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1476 return __connman_error_invalid_arguments(msg);
1478 dbus_message_iter_get_basic(&iter, &name);
1479 dbus_message_iter_next(&iter);
1481 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1482 return __connman_error_invalid_arguments(msg);
1484 dbus_message_iter_recurse(&iter, &value);
1486 type = dbus_message_iter_get_arg_type(&value);
1488 if (g_str_equal(name, "Passphrase")) {
1491 if (type != DBUS_TYPE_STRING)
1492 return __connman_error_invalid_arguments(msg);
1494 dbus_message_iter_get_basic(&value, &passphrase);
1496 connman_mesh_set_passphrase(mesh, passphrase);
1498 DBG("Invalid Property %s", name);
1499 return __connman_error_invalid_property(msg);
1502 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1505 static const GDBusMethodTable mesh_methods[] = {
1506 { GDBUS_METHOD("GetProperties",
1507 NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
1508 get_mesh_peer_properties) },
1509 { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, connect_mesh_peer) },
1510 { GDBUS_METHOD("Disconnect", NULL, NULL, disconnect_mesh_peer) },
1511 { GDBUS_METHOD("Remove", NULL, NULL, remove_mesh_peer) },
1512 { GDBUS_METHOD("SetProperty",
1513 GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
1514 NULL, set_mesh_peer_property) },
1518 static const GDBusSignalTable mesh_signals[] = {
1519 { GDBUS_SIGNAL("PropertyChanged",
1520 GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
1524 int connman_mesh_register(struct connman_mesh *mesh)
1526 struct connman_mesh *temp;
1527 DBG("mesh %p", mesh);
1532 mesh->path = g_strdup_printf("%s/mesh/%s", CONNMAN_PATH,
1534 DBG("path %s", mesh->path);
1536 temp = g_hash_table_lookup(mesh_table, mesh->path);
1538 DBG("mesh path %s already exists", mesh->path);
1540 if (mesh->frequency != temp->frequency) {
1541 DBG("Update frequency for mesh network %s", mesh->name);
1542 connman_mesh_set_frequency(temp, mesh->frequency);
1549 if (mesh->br_index > 0)
1550 mesh->ipconfig = create_ipconfig(mesh->br_index, mesh);
1552 mesh->ipconfig = create_ipconfig(mesh->index, mesh);
1554 if (!mesh->ipconfig)
1557 g_hash_table_insert(mesh_table, mesh->path, mesh);
1561 g_dbus_register_interface(connection, mesh->path,
1562 CONNMAN_MESH_INTERFACE,
1563 mesh_methods, mesh_signals,
1565 mesh->registered = true;
1569 void connman_mesh_unregister(struct connman_mesh *mesh)
1571 DBG("mesh %p", mesh);
1573 if (!mesh->path || !mesh->registered)
1576 g_dbus_unregister_interface(connection, mesh->path,
1577 CONNMAN_MESH_INTERFACE);
1578 mesh->registered = false;
1580 g_hash_table_remove(mesh_table, mesh->path);
1583 struct connman_mesh *connman_mesh_get(const char *interface_addr,
1584 const char *identifier)
1586 char *ident = g_strdup_printf("%s/mesh/mesh_%s_%s", CONNMAN_PATH,
1587 interface_addr, identifier);
1588 struct connman_mesh *mesh;
1590 mesh = g_hash_table_lookup(mesh_table, ident);
1596 int connman_mesh_driver_register(struct connman_mesh_driver *driver)
1598 if (mesh_driver && mesh_driver != driver)
1601 mesh_driver = driver;
1606 void connman_mesh_driver_unregister(struct connman_mesh_driver *driver)
1608 if (mesh_driver != driver)
1614 int connman_mesh_eth_driver_register(struct connman_mesh_eth_driver *driver)
1616 if (mesh_eth_driver && mesh_eth_driver != driver)
1619 mesh_eth_driver = driver;
1624 void connman_mesh_eth_driver_unregister(struct connman_mesh_eth_driver *driver)
1626 if (mesh_eth_driver != driver)
1629 mesh_eth_driver = NULL;
1632 int __connman_mesh_init(void)
1636 connection = connman_dbus_get_connection();
1638 mesh_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1641 connected_peer_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1642 mesh_connected_peer_free);
1644 disconnected_peer_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1645 NULL, mesh_disconnected_peer_free);
1647 nl80211_global = __connman_mesh_nl80211_global_init();
1651 void __connman_mesh_cleanup(void)
1655 __connman_mesh_nl80211_global_deinit(nl80211_global);
1656 g_hash_table_destroy(mesh_table);
1657 g_hash_table_destroy(connected_peer_table);
1658 g_hash_table_destroy(disconnected_peer_table);
1659 dbus_connection_unref(connection);