5 * Copyright (C) 2016 BMW Car IT GmbH.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <linux/if_ether.h>
31 #define CONNMAN_API_SUBJECT_TO_CHANGE
32 #include <connman/plugin.h>
33 #include <connman/dbus.h>
34 #include <connman/network.h>
35 #include <connman/technology.h>
36 #include <connman/inet.h>
39 static DBusConnection *connection;
40 static GDBusClient *client;
41 static GDBusProxy *agent_proxy;
42 static GHashTable *adapters;
43 static GHashTable *devices;
44 static GHashTable *networks;
45 static GHashTable *known_networks;
46 static GHashTable *stations;
47 static GHashTable *access_points;
48 static bool agent_registered;
50 #define IWD_SERVICE "net.connman.iwd"
52 #define IWD_AGENT_MANAGER_INTERFACE "net.connman.iwd.AgentManager"
53 #define IWD_ADAPTER_INTERFACE "net.connman.iwd.Adapter"
54 #define IWD_DEVICE_INTERFACE "net.connman.iwd.Device"
55 #define IWD_NETWORK_INTERFACE "net.connman.iwd.Network"
56 #define IWD_KNOWN_NETWORK_INTERFACE "net.connman.iwd.KnownNetwork"
57 #define IWD_STATION_INTERFACE "net.connman.iwd.Station"
58 #define IWD_AP_INTERFACE "net.connman.iwd.AccessPoint"
60 #define IWD_AGENT_INTERFACE "net.connman.iwd.Agent"
61 #define IWD_AGENT_ERROR_INTERFACE "net.connman.iwd.Agent.Error"
62 #define AGENT_PATH "/net/connman/iwd_agent"
84 struct connman_device *device;
96 struct iwd_device *iwdd;
97 struct connman_network *network;
98 /* service's autoconnect */
102 struct iwd_known_network {
108 char *last_connected_time;
112 /* service's autoconnect */
120 char *connected_network;
131 struct connman_technology *tech;
134 static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
136 DBusMessageIter iter;
139 if (!g_dbus_proxy_get_property(proxy, property, &iter))
142 dbus_message_iter_get_basic(&iter, &str);
147 static GSList *proxy_get_strings(GDBusProxy *proxy, const char *property)
149 DBusMessageIter array, entry;
152 if (!g_dbus_proxy_get_property(proxy, property, &array))
155 dbus_message_iter_recurse(&array, &entry);
157 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING){
160 dbus_message_iter_get_basic(&entry, &val);
161 list = g_slist_prepend(list, g_strdup(val));
162 dbus_message_iter_next(&entry);
168 static bool proxy_get_bool(GDBusProxy *proxy, const char *property)
170 DBusMessageIter iter;
173 if (!g_dbus_proxy_get_property(proxy, property, &iter))
176 dbus_message_iter_get_basic(&iter, &value);
181 static void address2ident(const char *address, char *ident)
185 for (i = 0; i < ETH_ALEN; i++) {
186 ident[i * 2] = address[i * 3];
187 ident[i * 2 + 1] = address[i * 3 + 1];
189 ident[ETH_ALEN * 2] = '\0';
192 static int cm_network_probe(struct connman_network *network)
197 g_hash_table_iter_init(&iter, networks);
199 while (g_hash_table_iter_next(&iter, &key, &value)) {
200 struct iwd_network *iwdn = value;
202 if (network == iwdn->network)
209 static void update_network_connected(struct iwd_network *iwdn)
211 struct iwd_device *iwdd;
213 iwdd = g_hash_table_lookup(devices, iwdn->device);
217 DBG("interface name %s index %d", iwdd->name,
218 connman_network_get_index(iwdn->network));
219 connman_network_set_connected(iwdn->network, true);
222 static void update_network_disconnected(struct iwd_network *iwdn)
224 DBG("interface name %s", iwdn->name);
225 connman_network_set_connected(iwdn->network, false);
228 static void cm_network_connect_cb(DBusMessage *message, void *user_data)
230 const char *path = user_data;
231 struct iwd_network *iwdn;
233 iwdn = g_hash_table_lookup(networks, path);
237 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
238 const char *dbus_error = dbus_message_get_error_name(message);
240 if (!strcmp(dbus_error, "net.connman.iwd.InProgress"))
243 DBG("%s connect failed: %s", path, dbus_error);
244 if (!strcmp(dbus_error, "net.connman.iwd.Failed"))
245 connman_network_set_error(iwdn->network,
246 CONNMAN_NETWORK_ERROR_INVALID_KEY);
247 else if (!iwdn->autoconnect)
248 connman_network_set_error(iwdn->network,
249 CONNMAN_NETWORK_ERROR_CONNECT_FAIL);
253 update_network_connected(iwdn);
256 static int cm_network_connect(struct connman_network *network)
258 struct iwd_network *iwdn = connman_network_get_data(network);
263 if (!g_dbus_proxy_method_call(iwdn->proxy, "Connect",
264 NULL, cm_network_connect_cb,
265 g_strdup(iwdn->path), g_free))
268 connman_network_set_associating(iwdn->network, true);
273 static void cm_network_disconnect_cb(DBusMessage *message, void *user_data)
275 const char *path = user_data;
276 struct iwd_network *iwdn;
278 iwdn = g_hash_table_lookup(networks, path);
282 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
283 const char *dbus_error = dbus_message_get_error_name(message);
285 if (!strcmp(dbus_error, "net.connman.iwd.NotConnected")) {
288 DBG("%s disconnect failed: %s", path, dbus_error);
294 * We end up in a tight loop in the error case. That is
295 * when we can't connect, bail out in cm_network_connect_cb() with
298 if (connman_network_get_connected(iwdn->network))
299 update_network_disconnected(iwdn);
302 static int cm_network_disconnect(struct connman_network *network)
304 struct iwd_network *iwdn = connman_network_get_data(network);
305 struct iwd_station *iwds;
307 if (!iwdn && !iwdn->iwdd)
310 iwds = g_hash_table_lookup(stations, iwdn->iwdd->path);
314 connman_network_set_associating(network, false);
316 if (!g_dbus_proxy_method_call(iwds->proxy, "Disconnect",
317 NULL, cm_network_disconnect_cb, g_strdup(iwdn->path), g_free))
323 struct auto_connect_cb_data {
328 static void auto_connect_cb_free(struct auto_connect_cb_data *cbd)
334 static void auto_connect_cb(const DBusError *error, void *user_data)
336 struct auto_connect_cb_data *cbd = user_data;
337 struct iwd_known_network *iwdkn;
339 iwdkn = g_hash_table_lookup(known_networks, cbd->path);
343 if (dbus_error_is_set(error))
344 connman_warn("WiFi known network %s property auto connect %s",
345 cbd->path, error->message);
347 /* property is updated via watch known_network_property_change() */
349 auto_connect_cb_free(cbd);
352 static int set_auto_connect(struct iwd_known_network *iwdkn, bool auto_connect)
354 dbus_bool_t dbus_auto_connect = auto_connect;
355 struct auto_connect_cb_data *cbd;
357 if (proxy_get_bool(iwdkn->proxy, "AutoConnect") == auto_connect)
360 cbd = g_new(struct auto_connect_cb_data, 1);
361 cbd->path = g_strdup(iwdkn->path);
362 cbd->auto_connect = auto_connect;
364 if (!g_dbus_proxy_set_property_basic(iwdkn->proxy, "AutoConnect",
367 auto_connect_cb, cbd, NULL)) {
368 auto_connect_cb_free(cbd);
375 static gboolean disable_auto_connect_cb(gpointer data)
378 struct iwd_known_network *iwdkn;
380 iwdkn = g_hash_table_lookup(known_networks, path);
384 if (set_auto_connect(iwdkn, false) != -EINPROGRESS)
385 connman_warn("Failed to disable auto connect");
387 iwdkn->auto_connect_id = 0;
391 static int disable_auto_connect(struct iwd_known_network *iwdkn)
393 if (iwdkn->auto_connect_id)
396 iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
398 disable_auto_connect_cb,
399 g_strdup(iwdkn->path),
404 static gboolean enable_auto_connect_cb(gpointer data)
407 struct iwd_known_network *iwdkn;
409 iwdkn = g_hash_table_lookup(known_networks, path);
413 if (set_auto_connect(iwdkn, true) != -EINPROGRESS)
414 connman_warn("Failed to enable auto connect");
416 iwdkn->auto_connect_id = 0;
420 static int enable_auto_connect(struct iwd_known_network *iwdkn)
422 if (iwdkn->auto_connect_id)
425 iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
427 enable_auto_connect_cb,
428 g_strdup(iwdkn->path),
433 static int update_auto_connect(struct iwd_known_network *iwdkn)
435 DBG("auto_connect %d autoconnect %d", iwdkn->auto_connect, iwdkn->autoconnect);
437 if (iwdkn->auto_connect == iwdkn->autoconnect)
440 if (iwdkn->autoconnect)
441 return enable_auto_connect(iwdkn);
442 return disable_auto_connect(iwdkn);
445 static int cm_network_set_autoconnect(struct connman_network *network,
448 struct iwd_network *iwdn = connman_network_get_data(network);
449 struct iwd_known_network *iwdkn;
451 DBG("autoconnect %d", autoconnect);
453 iwdn->autoconnect = autoconnect;
455 if (!iwdn->known_network)
458 iwdkn = g_hash_table_lookup(known_networks, iwdn->known_network);
462 iwdkn->autoconnect = autoconnect;
464 return update_auto_connect(iwdkn);
467 static struct connman_network_driver network_driver = {
469 .type = CONNMAN_NETWORK_TYPE_WIFI,
470 .probe = cm_network_probe,
471 .connect = cm_network_connect,
472 .disconnect = cm_network_disconnect,
473 .set_autoconnect = cm_network_set_autoconnect,
476 static int cm_device_probe(struct connman_device *device)
481 g_hash_table_iter_init(&iter, devices);
483 while (g_hash_table_iter_next(&iter, &key, &value)) {
484 struct iwd_device *iwdd = value;
486 if (device == iwdd->device)
493 static void cm_device_remove(struct connman_device *device)
502 static void device_powered_cb(const DBusError *error, void *user_data)
504 struct dev_cb_data *cbd = user_data;
505 struct iwd_device *iwdd;
507 iwdd = g_hash_table_lookup(devices, cbd->path);
511 if (dbus_error_is_set(error)) {
512 connman_warn("WiFi device %s not enabled %s",
513 cbd->path, error->message);
517 connman_device_set_powered(iwdd->device, cbd->powered);
523 static int set_device_powered(struct connman_device *device, bool powered)
525 struct iwd_device *iwdd = connman_device_get_data(device);
526 dbus_bool_t device_powered = powered;
527 struct dev_cb_data *cbd;
529 if (proxy_get_bool(iwdd->proxy, "Powered"))
532 cbd = g_new(struct dev_cb_data, 1);
533 cbd->path = g_strdup(iwdd->path);
534 cbd->powered = powered;
536 g_dbus_proxy_set_property_basic(iwdd->proxy, "Powered",
537 DBUS_TYPE_BOOLEAN, &device_powered,
538 device_powered_cb, cbd, NULL);
543 static int cm_device_enable(struct connman_device *device)
545 return set_device_powered(device, true);
548 static int cm_device_disable(struct connman_device *device)
550 return set_device_powered(device, false);
553 static void cm_device_scan_cb(DBusMessage *message, void *user_data)
555 const char *path = user_data;
556 struct iwd_station *iwds;
558 iwds = g_hash_table_lookup(stations, path);
562 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
563 const char *dbus_error = dbus_message_get_error_name(message);
565 DBG("%s scan failed: %s", path, dbus_error);
569 static int cm_device_scan(struct connman_device *device,
570 struct connman_device_scan_params *params)
572 struct iwd_device *iwdd = connman_device_get_data(device);
573 struct iwd_station *iwds;
575 if (strcmp(iwdd->mode, "station"))
578 iwds = g_hash_table_lookup(stations, iwdd->path);
582 if (!g_dbus_proxy_method_call(iwds->proxy, "Scan",
583 NULL, cm_device_scan_cb, g_strdup(iwds->path), g_free))
589 static struct connman_device_driver device_driver = {
591 .type = CONNMAN_DEVICE_TYPE_WIFI,
592 .probe = cm_device_probe,
593 .remove = cm_device_remove,
594 .enable = cm_device_enable,
595 .disable = cm_device_disable,
596 .scan = cm_device_scan,
599 static int cm_tech_probe(struct connman_technology *technology)
604 static void cm_tech_remove(struct connman_technology *technology)
608 struct tech_cb_data {
609 struct iwd_device *iwdd;
615 struct connman_technology *tech;
618 static void tech_cb_free(struct tech_cb_data *cbd)
622 g_free(cbd->passphrase);
627 static int cm_change_tethering(struct iwd_device *iwdd,
628 struct connman_technology *technology,
629 const char *identifier, const char *passphrase,
630 const char *bridge, bool enabled);
632 static void tech_ap_start_cb(DBusMessage *message, void *user_data)
635 struct tech_cb_data *cbd = user_data;
637 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
638 const char *dbus_error = dbus_message_get_error_name(message);
640 connman_warn("iwd device %s could not enable AccessPoint mode: %s",
641 cbd->path, dbus_error);
645 /* wait for 'Started' signal */
648 cm_change_tethering(cbd->iwdd, cbd->tech,
649 cbd->ssid, cbd->passphrase, cbd->bridge, false);
653 static void tech_ap_stop_cb(DBusMessage *message, void *user_data)
655 struct tech_cb_data *cbd = user_data;
657 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
658 const char *dbus_error = dbus_message_get_error_name(message);
660 connman_warn("iwd device %s could not disable AccessPoint mode: %s",
661 cbd->path, dbus_error);
670 static void ap_start_append(DBusMessageIter *iter, void *user_data)
672 struct tech_cb_data *cbd = user_data;
674 DBG("ssid %s", cbd->ssid);
675 DBG("passphrase %s", cbd->passphrase);
677 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cbd->ssid);
678 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cbd->passphrase);
681 static void tech_enable_tethering_cb(const DBusError *error, void *user_data)
683 struct tech_cb_data *cbd = user_data;
684 struct iwd_device *iwdd;
685 struct iwd_ap *iwdap = NULL;
689 iwdd = g_hash_table_lookup(devices, cbd->path);
691 DBG("device already removed");
695 if (dbus_error_is_set(error)) {
696 connman_warn("iwd device %s could not enable AcessPoint mode: %s",
697 cbd->path, error->message);
701 iwdap = g_hash_table_lookup(access_points, iwdd->path);
703 DBG("%s no ap object found", iwdd->path);
707 iwdap->index = cbd->index;
708 iwdap->bridge = g_strdup(cbd->bridge);
709 iwdap->tech = cbd->tech;
711 if (!g_dbus_proxy_method_call(iwdap->proxy, "Start",
712 ap_start_append, tech_ap_start_cb, cbd, NULL)) {
713 connman_warn("iwd ap %s could not start AccessPoint mode: %s",
714 cbd->path, error->message);
722 g_free(iwdap->bridge);
723 iwdap->bridge = NULL;
728 static void tech_disable_tethering_cb(const DBusError *error, void *user_data)
730 struct tech_cb_data *cbd = user_data;
731 struct iwd_device *iwdd;
732 struct iwd_ap *iwdap;
736 iwdd = g_hash_table_lookup(devices, cbd->path);
738 DBG("device already removed");
742 if (dbus_error_is_set(error)) {
743 connman_warn("iwd device %s could not enable Station mode: %s",
744 cbd->path, error->message);
748 iwdap = g_hash_table_lookup(access_points, iwdd->path);
750 DBG("%s no ap object found", iwdd->path);
754 g_free(iwdap->bridge);
756 iwdap->bridge = NULL;
759 if (!connman_inet_remove_from_bridge(cbd->index, cbd->bridge))
762 connman_technology_tethering_notify(cbd->tech, false);
764 if (!g_dbus_proxy_method_call(iwdap->proxy, "Stop",
765 NULL, tech_ap_stop_cb, cbd, NULL)) {
766 connman_warn("iwd ap %s could not stop AccessPoint mode: %s",
767 cbd->path, error->message);
776 static int cm_change_tethering(struct iwd_device *iwdd,
777 struct connman_technology *technology,
778 const char *identifier, const char *passphrase,
779 const char *bridge, bool enabled)
781 struct tech_cb_data *cbd;
784 GDBusResultFunction cb;
786 index = connman_inet_ifindex(iwdd->name);
790 cbd = g_new(struct tech_cb_data, 1);
792 cbd->path = g_strdup(iwdd->path);
793 cbd->ssid = g_strdup(identifier);
794 cbd->passphrase = g_strdup(passphrase);
795 cbd->bridge = g_strdup(bridge);
796 cbd->tech = technology;
801 cb = tech_enable_tethering_cb;
804 cb = tech_disable_tethering_cb;
807 if (!g_dbus_proxy_set_property_basic(iwdd->proxy,
808 "Mode", DBUS_TYPE_STRING, &mode,
817 static int cm_tech_tethering(struct connman_technology *technology,
818 const char *bridge, bool enabled)
827 connman_technology_get_wifi_tethering(technology, &ssid, &psk, &freq);
829 g_hash_table_iter_init(&iter, devices);
831 while (g_hash_table_iter_next(&iter, &key, &value)) {
832 struct iwd_device *iwdd = value;
833 struct iwd_adapter *iwda;
835 iwda = g_hash_table_lookup(adapters, iwdd->adapter);
839 if (!iwda->station || !iwda->ap )
840 /* No support for Station and AccessPoint mode */
843 if (!enabled && !g_strcmp0("ap", iwdd->mode)) {
844 res = cm_change_tethering(iwdd, technology, ssid,
845 psk, bridge, enabled);
847 connman_warn("%s switching to Station mode failed",
854 if (enabled && !g_strcmp0("station", iwdd->mode)) {
855 err = cm_change_tethering(iwdd, technology, ssid,
856 psk, bridge, enabled);
858 connman_warn("%s switching to AccessPoint mode failed",
867 static struct connman_technology_driver tech_driver = {
869 .type = CONNMAN_SERVICE_TYPE_WIFI,
870 .probe = cm_tech_probe,
871 .remove = cm_tech_remove,
872 .set_tethering = cm_tech_tethering,
875 static const char *security_remap(const char *security)
877 if (!g_strcmp0(security, "open"))
879 else if (!g_strcmp0(security, "psk"))
881 else if (!g_strcmp0(security, "8021x"))
887 static char *create_identifier(const char *path, const char *security)
889 char *start, *end, *identifier;
890 char *_path = g_strdup(path);
893 * _path is something like
894 * /0/4/5363686970686f6c5f427573696e6573735f454150_8021x
896 start = strrchr(_path, '/');
898 end = strchr(start, '_');
902 * Create an ident which is identical to the corresponding
903 * wpa_supplicant identifier.
905 identifier = g_strdup_printf("%s_managed_%s", start,
906 security_remap(security));
912 static void add_network(const char *path, struct iwd_network *iwdn)
914 struct iwd_device *iwdd;
918 iwdd = g_hash_table_lookup(devices, iwdn->device);
922 identifier = create_identifier(path, iwdn->type);
923 iwdn->network = connman_network_create(identifier,
924 CONNMAN_NETWORK_TYPE_WIFI);
926 index = connman_inet_ifindex(iwdd->name);
928 connman_network_set_index(iwdn->network, index);
930 connman_network_set_data(iwdn->network, iwdn);
932 connman_network_set_name(iwdn->network, iwdn->name);
933 connman_network_set_blob(iwdn->network, "WiFi.SSID", iwdn->name,
935 connman_network_set_string(iwdn->network, "WiFi.Security",
936 security_remap(iwdn->type));
937 connman_network_set_string(iwdn->network, "WiFi.Mode", "managed");
939 if (connman_device_add_network(iwdd->device, iwdn->network) < 0) {
940 connman_network_unref(iwdn->network);
941 iwdn->network = NULL;
946 if (connman_network_get_strength(iwdn->network))
947 connman_network_set_available(iwdn->network, true);
949 connman_network_set_group(iwdn->network, identifier);
954 static void remove_network(struct iwd_network *iwdn)
960 connman_device_remove_network(iwdn->iwdd->device,
963 connman_network_unref(iwdn->network);
964 iwdn->network = NULL;
967 static void add_device(const char *path, struct iwd_device *iwdd)
969 char ident[ETH_ALEN * 2 + 1];
971 iwdd->device = connman_device_create("wifi", CONNMAN_DEVICE_TYPE_WIFI);
975 connman_device_set_data(iwdd->device, iwdd);
977 address2ident(iwdd->address, ident);
978 connman_device_set_ident(iwdd->device, ident);
980 if (connman_device_register(iwdd->device) < 0) {
981 g_hash_table_remove(devices, path);
985 connman_device_set_powered(iwdd->device, iwdd->powered);
988 static void remove_device_networks(struct iwd_device *iwdd)
992 struct iwd_network *iwdn;
993 GSList *list, *nets = NULL;
995 g_hash_table_iter_init(&iter, networks);
997 while (g_hash_table_iter_next(&iter, &key, &value)) {
1000 if (!strcmp(iwdd->path, iwdn->device))
1001 nets = g_slist_prepend(nets, iwdn);
1004 for (list = nets; list; list = list->next) {
1006 g_hash_table_remove(networks, iwdn->path);
1012 static void remove_device(struct iwd_device *iwdd)
1017 remove_device_networks(iwdd);
1018 connman_device_unregister(iwdd->device);
1019 connman_device_unref(iwdd->device);
1020 iwdd->device = NULL;
1023 static void adapter_property_change(GDBusProxy *proxy, const char *name,
1024 DBusMessageIter *iter, void *user_data)
1026 struct iwd_adapter *adapter;
1029 path = g_dbus_proxy_get_path(proxy);
1030 adapter = g_hash_table_lookup(adapters, path);
1034 if (!strcmp(name, "Powered")) {
1035 dbus_bool_t powered;
1037 dbus_message_iter_get_basic(iter, &powered);
1038 adapter->powered = powered;
1040 DBG("%p powered %d", path, adapter->powered);
1044 static void device_property_change(GDBusProxy *proxy, const char *name,
1045 DBusMessageIter *iter, void *user_data)
1047 struct iwd_device *iwdd;
1050 path = g_dbus_proxy_get_path(proxy);
1051 iwdd = g_hash_table_lookup(devices, path);
1055 if (!strcmp(name, "Name")) {
1058 dbus_message_iter_get_basic(iter, &name);
1060 iwdd->name = g_strdup(name);
1062 DBG("%p name %s", path, iwdd->name);
1063 } else if (!strcmp(name, "Powered")) {
1064 dbus_bool_t powered;
1066 dbus_message_iter_get_basic(iter, &powered);
1067 iwdd->powered = powered;
1069 DBG("%s powered %d", path, iwdd->powered);
1070 } else if (!strcmp(name, "Mode")) {
1073 dbus_message_iter_get_basic(iter, &mode);
1075 iwdd->mode = g_strdup(mode);
1077 DBG("%s mode %s", path, iwdd->mode);
1081 static void network_property_change(GDBusProxy *proxy, const char *name,
1082 DBusMessageIter *iter, void *user_data)
1084 struct iwd_network *iwdn;
1085 struct iwd_known_network *iwdkn;
1088 path = g_dbus_proxy_get_path(proxy);
1089 iwdn = g_hash_table_lookup(networks, path);
1093 if (!strcmp(name, "Connected")) {
1094 dbus_bool_t connected;
1096 dbus_message_iter_get_basic(iter, &connected);
1097 iwdn->connected = connected;
1099 DBG("%s connected %d", path, iwdn->connected);
1101 if (iwdn->connected)
1102 update_network_connected(iwdn);
1104 update_network_disconnected(iwdn);
1105 } else if (!strcmp(name, "KnownNetwork")) {
1106 g_free(iwdn->known_network);
1107 iwdn->known_network =
1108 g_strdup(proxy_get_string(proxy, "KnownNetwork"));
1109 if (!iwdn->known_network)
1112 iwdkn = g_hash_table_lookup(known_networks,
1113 iwdn->known_network);
1115 update_auto_connect(iwdkn);
1119 static unsigned char calculate_strength(int strength)
1124 * Network's maximum signal strength expressed in 100 * dBm.
1125 * The value is the range of 0 (strongest signal) to -10000
1128 * ConnMan expects it in the range from 100 (strongest) to 0
1131 res = (unsigned char)((strength + 10000) / 100);
1136 static void _update_signal_strength(const char *path, int16_t signal_strength)
1138 struct iwd_network *iwdn;
1140 iwdn = g_hash_table_lookup(networks, path);
1144 connman_network_set_strength(iwdn->network,
1145 calculate_strength(signal_strength));
1146 connman_network_set_available(iwdn->network, true);
1147 connman_network_update(iwdn->network);
1150 static void ordered_networks_cb(DBusMessage *message, void *user_data)
1152 DBusMessageIter array, entry;
1153 struct iwd_device *iwdd;
1154 char *path = user_data;
1158 if (!dbus_message_iter_init(message, &array))
1161 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1164 dbus_message_iter_recurse(&array, &entry);
1165 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) {
1166 DBusMessageIter value;
1168 int16_t signal_strength;
1171 dbus_message_iter_recurse(&entry, &value);
1173 dbus_message_iter_get_basic(&value, &path);
1175 dbus_message_iter_next(&value);
1176 dbus_message_iter_get_basic(&value, &signal_strength);
1178 _update_signal_strength(path, signal_strength);
1180 dbus_message_iter_next(&entry);
1183 iwdd = g_hash_table_lookup(devices, path);
1185 connman_device_set_scanning(iwdd->device,
1186 CONNMAN_SERVICE_TYPE_WIFI, false);
1189 static void update_signal_strength(struct iwd_station *iwds)
1191 if (!g_dbus_proxy_method_call(iwds->proxy,
1192 "GetOrderedNetworks",
1193 NULL, ordered_networks_cb,
1194 g_strdup(iwds->path), g_free))
1195 DBG("GetOrderedNetworks() failed");
1198 static void station_property_change(GDBusProxy *proxy, const char *name,
1199 DBusMessageIter *iter, void *user_data)
1201 struct iwd_station *iwds;
1202 struct iwd_device *iwdd;
1205 path = g_dbus_proxy_get_path(proxy);
1206 iwds = g_hash_table_lookup(stations, path);
1210 if (!strcmp(name, "State")) {
1213 dbus_message_iter_get_basic(iter, &state);
1214 g_free(iwds->state);
1215 iwds->state = g_strdup(state);
1217 DBG("%s state %s", path, iwds->state);
1218 } else if (!strcmp(name, "ConnectedNetwork")) {
1219 const char *connected_network;
1221 g_free(iwds->connected_network);
1223 dbus_message_iter_get_basic(iter, &connected_network);
1224 iwds->connected_network = g_strdup(connected_network);
1226 iwds->connected_network = NULL;
1229 DBG("%s connected_network %s", path, iwds->connected_network);
1230 } else if (!strcmp(name, "Scanning")) {
1231 dbus_bool_t scanning;
1233 dbus_message_iter_get_basic(iter, &scanning);
1234 iwds->scanning = scanning;
1236 if (iwds->scanning) {
1237 iwdd = g_hash_table_lookup(devices, path);
1239 connman_device_set_scanning(iwdd->device,
1240 CONNMAN_SERVICE_TYPE_WIFI, true);
1242 update_signal_strength(iwds);
1246 DBG("%s scanning %d", path, iwds->scanning);
1250 static void ap_property_change(GDBusProxy *proxy, const char *name,
1251 DBusMessageIter *iter, void *user_data)
1253 struct iwd_ap *iwdap;
1257 path = g_dbus_proxy_get_path(proxy);
1258 iwdap = g_hash_table_lookup(access_points, path);
1262 if (!strcmp(name, "Started")) {
1263 dbus_bool_t started;
1265 dbus_message_iter_get_basic(iter, &started);
1266 iwdap->started = started;
1268 DBG("%s started %d", path, iwdap->started);
1270 if (iwdap->started && iwdap->index != -1) {
1271 DBG("index %d bridge %s", iwdap->index, iwdap->bridge);
1272 err = connman_technology_tethering_notify(
1276 err = connman_inet_add_to_bridge(
1277 iwdap->index, iwdap->bridge);
1282 static void adapter_free(gpointer data)
1284 struct iwd_adapter *iwda = data;
1287 g_dbus_proxy_unref(iwda->proxy);
1292 g_free(iwda->vendor);
1293 g_free(iwda->model);
1297 static void device_free(gpointer data)
1299 struct iwd_device *iwdd = data;
1302 g_dbus_proxy_unref(iwdd->proxy);
1306 remove_device(iwdd);
1309 g_free(iwdd->adapter);
1311 g_free(iwdd->address);
1315 static void network_free(gpointer data)
1317 struct iwd_network *iwdn = data;
1320 g_dbus_proxy_unref(iwdn->proxy);
1324 remove_network(iwdn);
1327 g_free(iwdn->device);
1330 g_free(iwdn->known_network);
1334 static void known_network_free(gpointer data)
1336 struct iwd_known_network *iwdkn = data;
1339 g_dbus_proxy_unref(iwdkn->proxy);
1340 iwdkn->proxy = NULL;
1343 if (iwdkn->auto_connect_id)
1344 g_source_remove(iwdkn->auto_connect_id);
1346 g_free(iwdkn->path);
1347 g_free(iwdkn->name);
1348 g_free(iwdkn->type);
1349 g_free(iwdkn->last_connected_time);
1353 static void station_free(gpointer data)
1355 struct iwd_station *iwds = data;
1358 g_dbus_proxy_unref(iwds->proxy);
1362 g_free(iwds->connected_network);
1366 static void ap_free(gpointer data)
1368 struct iwd_ap *iwdap = data;
1371 g_dbus_proxy_unref(iwdap->proxy);
1372 iwdap->proxy = NULL;
1374 g_free(iwdap->bridge);
1378 static void create_adapter(GDBusProxy *proxy)
1380 const char *path = g_dbus_proxy_get_path(proxy);
1381 struct iwd_adapter *iwda;
1382 GSList *modes, *list;
1384 iwda = g_new0(struct iwd_adapter, 1);
1385 iwda->path = g_strdup(path);
1386 g_hash_table_replace(adapters, iwda->path, iwda);
1388 iwda->proxy = g_dbus_proxy_ref(proxy);
1391 connman_error("Cannot create IWD adapter watcher %s", path);
1392 g_hash_table_remove(adapters, path);
1396 iwda->vendor = g_strdup(proxy_get_string(proxy, "Vendor"));
1397 iwda->model = g_strdup(proxy_get_string(proxy, "Model"));
1398 iwda->powered = proxy_get_bool(proxy, "Powered");
1400 modes = proxy_get_strings(proxy, "SupportedModes");
1401 for (list = modes; list; list = list->next) {
1402 char *m = list->data;
1407 if (!strcmp(m, "ad-hoc"))
1408 iwda->ad_hoc = true;
1409 else if (!strcmp(m, "station"))
1410 iwda->station = true;
1411 else if (!strcmp(m, "ap"))
1414 g_slist_free_full(modes, g_free);
1416 DBG("%s vendor '%s' model '%s' powered %d ad-hoc %d station %d ap %d",
1417 path, iwda->vendor, iwda->model, iwda->powered,
1418 iwda->ad_hoc, iwda->station, iwda->ap);
1420 g_dbus_proxy_set_property_watch(iwda->proxy,
1421 adapter_property_change, NULL);
1424 static void create_device(GDBusProxy *proxy)
1426 const char *path = g_dbus_proxy_get_path(proxy);
1427 struct iwd_device *iwdd;
1429 iwdd = g_new0(struct iwd_device, 1);
1430 iwdd->path = g_strdup(path);
1431 g_hash_table_replace(devices, iwdd->path, iwdd);
1433 iwdd->proxy = g_dbus_proxy_ref(proxy);
1436 connman_error("Cannot create IWD device watcher %s", path);
1437 g_hash_table_remove(devices, path);
1441 iwdd->adapter = g_strdup(proxy_get_string(proxy, "Adapter"));
1442 iwdd->name = g_strdup(proxy_get_string(proxy, "Name"));
1443 iwdd->address = g_strdup(proxy_get_string(proxy, "Address"));
1444 iwdd->powered = proxy_get_bool(proxy, "Powered");
1445 iwdd->mode = g_strdup(proxy_get_string(proxy, "Mode"));
1447 DBG("adapter %s name %s address %s powered %d mode %s",
1448 iwdd->adapter, iwdd->name, iwdd->address,
1449 iwdd->powered, iwdd->mode);
1451 g_dbus_proxy_set_property_watch(iwdd->proxy,
1452 device_property_change, NULL);
1454 add_device(path, iwdd);
1457 static void unregister_agent();
1459 static DBusMessage *agent_release_method(DBusConnection *dbus_conn,
1460 DBusMessage *message, void *user_data)
1463 return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
1466 static DBusMessage *get_reply_on_error(DBusMessage *message, int error)
1468 return g_dbus_create_error(message,
1469 IWD_AGENT_ERROR_INTERFACE ".Failed", "Invalid parameters");
1472 static DBusMessage *agent_request_passphrase(DBusConnection *dbus_conn,
1473 DBusMessage *message,
1476 struct iwd_network *iwdn;
1477 DBusMessageIter iter;
1478 const char *path, *passwd;
1482 dbus_message_iter_init(message, &iter);
1484 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
1485 return get_reply_on_error(message, EINVAL);
1487 dbus_message_iter_get_basic(&iter, &path);
1489 iwdn = g_hash_table_lookup(networks, path);
1491 return get_reply_on_error(message, EINVAL);
1493 passwd = connman_network_get_string(iwdn->network, "WiFi.Passphrase");
1495 return get_reply_on_error(message, ENOKEY);
1497 return g_dbus_create_reply(message, DBUS_TYPE_STRING, &passwd,
1501 static DBusMessage *agent_cancel(DBusConnection *dbus_conn,
1502 DBusMessage *message, void *user_data)
1504 DBusMessageIter iter;
1507 dbus_message_iter_init(message, &iter);
1509 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1510 return get_reply_on_error(message, EINVAL);
1512 dbus_message_iter_get_basic(&iter, &reason);
1514 DBG("cancel: %s", reason);
1517 * We don't have to do anything here, because we asked the
1518 * user upfront for the passphrase. So
1519 * agent_request_passphrase() will always send a passphrase
1523 return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
1526 static const GDBusMethodTable agent_methods[] = {
1527 { GDBUS_METHOD("Release", NULL, NULL, agent_release_method) },
1528 { GDBUS_METHOD("RequestPassphrase",
1529 GDBUS_ARGS({ "path", "o" }),
1530 GDBUS_ARGS({ "passphrase", "s" }),
1531 agent_request_passphrase)},
1532 { GDBUS_METHOD("Cancel",
1533 GDBUS_ARGS({ "reason", "s" }),
1534 NULL, agent_cancel) },
1538 static void agent_register_builder(DBusMessageIter *iter, void *user_data)
1540 const char *path = AGENT_PATH;
1542 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
1546 static void register_agent(GDBusProxy *proxy)
1548 if (!g_dbus_proxy_method_call(proxy,
1550 agent_register_builder,
1554 agent_proxy = g_dbus_proxy_ref(proxy);
1557 static void unregister_agent()
1562 g_dbus_proxy_method_call(agent_proxy,
1564 agent_register_builder,
1567 g_dbus_proxy_unref(agent_proxy);
1571 static void iwd_is_present(DBusConnection *conn, void *user_data)
1573 if (agent_registered)
1576 if (!g_dbus_register_interface(connection, AGENT_PATH,
1577 IWD_AGENT_INTERFACE, agent_methods,
1578 NULL, NULL, NULL, NULL))
1581 agent_registered = true;
1584 static void iwd_is_out(DBusConnection *conn, void *user_data)
1586 if (agent_registered) {
1587 g_dbus_unregister_interface(connection,
1588 AGENT_PATH, IWD_AGENT_INTERFACE);
1589 agent_registered = false;
1593 static void create_network(GDBusProxy *proxy)
1595 const char *path = g_dbus_proxy_get_path(proxy);
1596 struct iwd_network *iwdn;
1598 iwdn = g_new0(struct iwd_network, 1);
1599 iwdn->path = g_strdup(path);
1600 g_hash_table_replace(networks, iwdn->path, iwdn);
1602 iwdn->proxy = g_dbus_proxy_ref(proxy);
1605 connman_error("Cannot create IWD network watcher %s", path);
1606 g_hash_table_remove(networks, path);
1610 iwdn->device = g_strdup(proxy_get_string(proxy, "Device"));
1611 iwdn->name = g_strdup(proxy_get_string(proxy, "Name"));
1612 iwdn->type = g_strdup(proxy_get_string(proxy, "Type"));
1613 iwdn->connected = proxy_get_bool(proxy, "Connected");
1614 iwdn->known_network = g_strdup(proxy_get_string(proxy, "KnownNetwork"));
1616 DBG("device %s name '%s' type %s connected %d known_network %s",
1617 iwdn->device, iwdn->name, iwdn->type, iwdn->connected,
1618 iwdn->known_network);
1620 g_dbus_proxy_set_property_watch(iwdn->proxy,
1621 network_property_change, NULL);
1623 add_network(path, iwdn);
1626 static void known_network_property_change(GDBusProxy *proxy, const char *name,
1627 DBusMessageIter *iter, void *user_data)
1629 struct iwd_known_network *iwdkn;
1632 path = g_dbus_proxy_get_path(proxy);
1633 iwdkn = g_hash_table_lookup(known_networks, path);
1637 if (!strcmp(name, "AutoConnect")) {
1638 dbus_bool_t auto_connect;
1640 dbus_message_iter_get_basic(iter, &auto_connect);
1641 iwdkn->auto_connect = auto_connect;
1643 DBG("%p auto_connect %d", path, iwdkn->auto_connect);
1645 update_auto_connect(iwdkn);
1649 static void init_auto_connect(struct iwd_known_network *iwdkn)
1651 GHashTableIter iter;
1652 gpointer key, value;
1654 g_hash_table_iter_init(&iter, networks);
1656 while (g_hash_table_iter_next(&iter, &key, &value)) {
1657 struct iwd_network *iwdn = value;
1658 struct iwd_known_network *kn;
1660 if (!iwdn->known_network)
1663 kn = g_hash_table_lookup(known_networks, iwdn->known_network);
1667 iwdkn->autoconnect = iwdn->autoconnect;
1668 update_auto_connect(iwdkn);
1673 static void create_know_network(GDBusProxy *proxy)
1675 const char *path = g_dbus_proxy_get_path(proxy);
1676 struct iwd_known_network *iwdkn;
1678 iwdkn = g_new0(struct iwd_known_network, 1);
1679 iwdkn->path = g_strdup(path);
1680 g_hash_table_replace(known_networks, iwdkn->path, iwdkn);
1682 iwdkn->proxy = g_dbus_proxy_ref(proxy);
1684 if (!iwdkn->proxy) {
1685 connman_error("Cannot create IWD known network watcher %s", path);
1686 g_hash_table_remove(known_networks, path);
1690 iwdkn->name = g_strdup(proxy_get_string(proxy, "Name"));
1691 iwdkn->type = g_strdup(proxy_get_string(proxy, "Type"));
1692 iwdkn->hidden = proxy_get_bool(proxy, "Hidden");
1693 iwdkn->last_connected_time =
1694 g_strdup(proxy_get_string(proxy, "LastConnectedTime"));
1695 iwdkn->auto_connect = proxy_get_bool(proxy, "AutoConnect");
1697 DBG("name '%s' type %s hidden %d, last_connection_time %s auto_connect %d",
1698 iwdkn->name, iwdkn->type, iwdkn->hidden,
1699 iwdkn->last_connected_time, iwdkn->auto_connect);
1701 init_auto_connect(iwdkn);
1703 g_dbus_proxy_set_property_watch(iwdkn->proxy,
1704 known_network_property_change, NULL);
1707 static void create_station(GDBusProxy *proxy)
1709 const char *path = g_dbus_proxy_get_path(proxy);
1710 struct iwd_station *iwds;
1712 iwds = g_new0(struct iwd_station, 1);
1713 iwds->path = g_strdup(path);
1714 g_hash_table_replace(stations, iwds->path, iwds);
1716 iwds->proxy = g_dbus_proxy_ref(proxy);
1719 connman_error("Cannot create IWD station watcher %s", path);
1720 g_hash_table_remove(stations, path);
1724 iwds->state = g_strdup(proxy_get_string(proxy, "State"));
1725 iwds->connected_network = g_strdup(proxy_get_string(proxy, "ConnectedNetwork"));
1726 iwds->scanning = proxy_get_bool(proxy, "Scanning");
1728 DBG("state '%s' connected_network %s scanning %d",
1729 iwds->state, iwds->connected_network, iwds->scanning);
1731 g_dbus_proxy_set_property_watch(iwds->proxy,
1732 station_property_change, NULL);
1735 static void create_ap(GDBusProxy *proxy)
1737 const char *path = g_dbus_proxy_get_path(proxy);
1738 struct iwd_ap *iwdap;
1740 iwdap = g_new0(struct iwd_ap, 1);
1743 iwdap->path = g_strdup(path);
1744 g_hash_table_replace(access_points, iwdap->path, iwdap);
1746 iwdap->proxy = g_dbus_proxy_ref(proxy);
1748 if (!iwdap->proxy) {
1749 connman_error("Cannot create IWD access point watcher %s", path);
1750 g_hash_table_remove(access_points, path);
1754 iwdap->started = proxy_get_bool(proxy, "Started");
1756 DBG("started %d", iwdap->started);
1758 g_dbus_proxy_set_property_watch(iwdap->proxy,
1759 ap_property_change, NULL);
1762 static void object_added(GDBusProxy *proxy, void *user_data)
1764 const char *interface;
1766 interface = g_dbus_proxy_get_interface(proxy);
1768 connman_warn("Interface or proxy missing when adding "
1773 DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
1775 if (!strcmp(interface, IWD_AGENT_MANAGER_INTERFACE))
1776 register_agent(proxy);
1777 else if (!strcmp(interface, IWD_ADAPTER_INTERFACE))
1778 create_adapter(proxy);
1779 else if (!strcmp(interface, IWD_DEVICE_INTERFACE))
1780 create_device(proxy);
1781 else if (!strcmp(interface, IWD_NETWORK_INTERFACE))
1782 create_network(proxy);
1783 else if (!strcmp(interface, IWD_KNOWN_NETWORK_INTERFACE))
1784 create_know_network(proxy);
1785 else if (!strcmp(interface, IWD_STATION_INTERFACE))
1786 create_station(proxy);
1787 else if (!strcmp(interface, IWD_AP_INTERFACE))
1791 static void object_removed(GDBusProxy *proxy, void *user_data)
1793 const char *interface, *path;
1795 interface = g_dbus_proxy_get_interface(proxy);
1797 connman_warn("Interface or proxy missing when removing "
1802 path = g_dbus_proxy_get_path(proxy);
1803 DBG("%s %s", interface, path);
1805 if (!strcmp(interface, IWD_AGENT_MANAGER_INTERFACE))
1807 if (!strcmp(interface, IWD_ADAPTER_INTERFACE))
1808 g_hash_table_remove(adapters, path);
1809 else if (!strcmp(interface, IWD_DEVICE_INTERFACE))
1810 g_hash_table_remove(devices, path);
1811 else if (!strcmp(interface, IWD_NETWORK_INTERFACE))
1812 g_hash_table_remove(networks, path);
1813 else if (!strcmp(interface, IWD_KNOWN_NETWORK_INTERFACE))
1814 g_hash_table_remove(known_networks, path);
1815 else if (!strcmp(interface, IWD_STATION_INTERFACE))
1816 g_hash_table_remove(stations, path);
1817 else if (!strcmp(interface, IWD_AP_INTERFACE))
1818 g_hash_table_remove(access_points, path);
1821 static int iwd_init(void)
1823 connection = connman_dbus_get_connection();
1827 adapters = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1830 devices = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1833 networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1836 known_networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1837 known_network_free);
1839 stations = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1842 access_points = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1845 if (connman_technology_driver_register(&tech_driver) < 0) {
1846 connman_warn("Failed to initialize technology for IWD");
1850 if (connman_device_driver_register(&device_driver) < 0) {
1851 connman_warn("Failed to initialize device driver for "
1853 connman_technology_driver_unregister(&tech_driver);
1857 if (connman_network_driver_register(&network_driver) < 0) {
1858 connman_technology_driver_unregister(&tech_driver);
1859 connman_device_driver_unregister(&device_driver);
1863 client = g_dbus_client_new(connection, IWD_SERVICE, IWD_PATH);
1865 connman_warn("Failed to initialize D-Bus client for "
1870 g_dbus_client_set_connect_watch(client, iwd_is_present, NULL);
1871 g_dbus_client_set_disconnect_watch(client, iwd_is_out, NULL);
1872 g_dbus_client_set_proxy_handlers(client, object_added, object_removed,
1879 g_hash_table_destroy(devices);
1882 g_hash_table_destroy(networks);
1885 g_hash_table_destroy(known_networks);
1888 g_hash_table_destroy(stations);
1891 g_hash_table_destroy(access_points);
1894 g_hash_table_destroy(adapters);
1897 dbus_connection_unref(connection);
1902 static void iwd_exit(void)
1904 connman_network_driver_unregister(&network_driver);
1905 connman_device_driver_unregister(&device_driver);
1906 connman_technology_driver_unregister(&tech_driver);
1908 g_dbus_client_unref(client);
1910 g_hash_table_destroy(access_points);
1911 g_hash_table_destroy(stations);
1912 g_hash_table_destroy(known_networks);
1913 g_hash_table_destroy(networks);
1914 g_hash_table_destroy(devices);
1915 g_hash_table_destroy(adapters);
1917 dbus_connection_unref(connection);
1920 CONNMAN_PLUGIN_DEFINE(iwd, "IWD plugin", VERSION,
1921 CONNMAN_PLUGIN_PRIORITY_DEFAULT, iwd_init, iwd_exit)