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;
214 iwdd = g_hash_table_lookup(devices, iwdn->device);
218 index = connman_inet_ifindex(iwdd->name);
222 DBG("interface name %s index %d", iwdd->name, index);
223 connman_network_set_index(iwdn->network, index);
224 connman_network_set_connected(iwdn->network, true);
227 static void update_network_disconnected(struct iwd_network *iwdn)
229 DBG("interface name %s", iwdn->name);
230 connman_network_set_connected(iwdn->network, false);
233 static void cm_network_connect_cb(DBusMessage *message, void *user_data)
235 const char *path = user_data;
236 struct iwd_network *iwdn;
238 iwdn = g_hash_table_lookup(networks, path);
242 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
243 const char *dbus_error = dbus_message_get_error_name(message);
245 if (!strcmp(dbus_error, "net.connman.iwd.InProgress"))
248 DBG("%s connect failed: %s", path, dbus_error);
249 if (!strcmp(dbus_error, "net.connman.iwd.Failed"))
250 connman_network_set_error(iwdn->network,
251 CONNMAN_NETWORK_ERROR_INVALID_KEY);
252 else if (!iwdn->autoconnect)
253 connman_network_set_error(iwdn->network,
254 CONNMAN_NETWORK_ERROR_CONNECT_FAIL);
258 update_network_connected(iwdn);
261 static int cm_network_connect(struct connman_network *network)
263 struct iwd_network *iwdn = connman_network_get_data(network);
268 if (!g_dbus_proxy_method_call(iwdn->proxy, "Connect",
269 NULL, cm_network_connect_cb,
270 g_strdup(iwdn->path), g_free))
273 connman_network_set_associating(iwdn->network, true);
278 static void cm_network_disconnect_cb(DBusMessage *message, void *user_data)
280 const char *path = user_data;
281 struct iwd_network *iwdn;
283 iwdn = g_hash_table_lookup(networks, path);
287 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
288 const char *dbus_error = dbus_message_get_error_name(message);
290 if (!strcmp(dbus_error, "net.connman.iwd.NotConnected")) {
293 DBG("%s disconnect failed: %s", path, dbus_error);
299 * We end up in a tight loop in the error case. That is
300 * when we can't connect, bail out in cm_network_connect_cb() with
303 if (connman_network_get_connected(iwdn->network))
304 update_network_disconnected(iwdn);
307 static int cm_network_disconnect(struct connman_network *network)
309 struct iwd_network *iwdn = connman_network_get_data(network);
310 struct iwd_station *iwds;
312 if (!iwdn && !iwdn->iwdd)
315 iwds = g_hash_table_lookup(stations, iwdn->iwdd->path);
319 if (!g_dbus_proxy_method_call(iwds->proxy, "Disconnect",
320 NULL, cm_network_disconnect_cb, g_strdup(iwdn->path), g_free))
326 struct auto_connect_cb_data {
331 static void auto_connect_cb_free(struct auto_connect_cb_data *cbd)
337 static void auto_connect_cb(const DBusError *error, void *user_data)
339 struct auto_connect_cb_data *cbd = user_data;
340 struct iwd_known_network *iwdkn;
342 iwdkn = g_hash_table_lookup(known_networks, cbd->path);
346 if (dbus_error_is_set(error))
347 connman_warn("WiFi known network %s property auto connect %s",
348 cbd->path, error->message);
350 /* property is updated via watch known_network_property_change() */
352 auto_connect_cb_free(cbd);
355 static int set_auto_connect(struct iwd_known_network *iwdkn, bool auto_connect)
357 dbus_bool_t dbus_auto_connect = auto_connect;
358 struct auto_connect_cb_data *cbd;
360 if (proxy_get_bool(iwdkn->proxy, "AutoConnect") == auto_connect)
363 cbd = g_new(struct auto_connect_cb_data, 1);
364 cbd->path = g_strdup(iwdkn->path);
365 cbd->auto_connect = auto_connect;
367 if (!g_dbus_proxy_set_property_basic(iwdkn->proxy, "AutoConnect",
370 auto_connect_cb, cbd, NULL)) {
371 auto_connect_cb_free(cbd);
378 static gboolean disable_auto_connect_cb(gpointer data)
381 struct iwd_known_network *iwdkn;
383 iwdkn = g_hash_table_lookup(known_networks, path);
387 if (set_auto_connect(iwdkn, false) != -EINPROGRESS)
388 connman_warn("Failed to disable auto connect");
390 iwdkn->auto_connect_id = 0;
394 static int disable_auto_connect(struct iwd_known_network *iwdkn)
396 if (iwdkn->auto_connect_id)
399 iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
401 disable_auto_connect_cb,
402 g_strdup(iwdkn->path),
407 static gboolean enable_auto_connect_cb(gpointer data)
410 struct iwd_known_network *iwdkn;
412 iwdkn = g_hash_table_lookup(known_networks, path);
416 if (set_auto_connect(iwdkn, true) != -EINPROGRESS)
417 connman_warn("Failed to enable auto connect");
419 iwdkn->auto_connect_id = 0;
423 static int enable_auto_connect(struct iwd_known_network *iwdkn)
425 if (iwdkn->auto_connect_id)
428 iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
430 enable_auto_connect_cb,
431 g_strdup(iwdkn->path),
436 static int update_auto_connect(struct iwd_known_network *iwdkn)
438 DBG("auto_connect %d autoconnect %d", iwdkn->auto_connect, iwdkn->autoconnect);
440 if (iwdkn->auto_connect == iwdkn->autoconnect)
443 if (iwdkn->autoconnect)
444 return enable_auto_connect(iwdkn);
445 return disable_auto_connect(iwdkn);
448 static int cm_network_set_autoconnect(struct connman_network *network,
451 struct iwd_network *iwdn = connman_network_get_data(network);
452 struct iwd_known_network *iwdkn;
454 DBG("autoconnect %d", autoconnect);
456 iwdn->autoconnect = autoconnect;
458 if (!iwdn->known_network)
461 iwdkn = g_hash_table_lookup(known_networks, iwdn->known_network);
465 iwdkn->autoconnect = autoconnect;
467 return update_auto_connect(iwdkn);
470 static struct connman_network_driver network_driver = {
472 .type = CONNMAN_NETWORK_TYPE_WIFI,
473 .probe = cm_network_probe,
474 .connect = cm_network_connect,
475 .disconnect = cm_network_disconnect,
476 .set_autoconnect = cm_network_set_autoconnect,
479 static int cm_device_probe(struct connman_device *device)
484 g_hash_table_iter_init(&iter, devices);
486 while (g_hash_table_iter_next(&iter, &key, &value)) {
487 struct iwd_device *iwdd = value;
489 if (device == iwdd->device)
496 static void cm_device_remove(struct connman_device *device)
505 static void device_powered_cb(const DBusError *error, void *user_data)
507 struct dev_cb_data *cbd = user_data;
508 struct iwd_device *iwdd;
510 iwdd = g_hash_table_lookup(devices, cbd->path);
514 if (dbus_error_is_set(error)) {
515 connman_warn("WiFi device %s not enabled %s",
516 cbd->path, error->message);
520 connman_device_set_powered(iwdd->device, cbd->powered);
526 static int set_device_powered(struct connman_device *device, bool powered)
528 struct iwd_device *iwdd = connman_device_get_data(device);
529 dbus_bool_t device_powered = powered;
530 struct dev_cb_data *cbd;
532 if (proxy_get_bool(iwdd->proxy, "Powered"))
535 cbd = g_new(struct dev_cb_data, 1);
536 cbd->path = g_strdup(iwdd->path);
537 cbd->powered = powered;
539 g_dbus_proxy_set_property_basic(iwdd->proxy, "Powered",
540 DBUS_TYPE_BOOLEAN, &device_powered,
541 device_powered_cb, cbd, NULL);
546 static int cm_device_enable(struct connman_device *device)
548 return set_device_powered(device, true);
551 static int cm_device_disable(struct connman_device *device)
553 return set_device_powered(device, false);
556 static void cm_device_scan_cb(DBusMessage *message, void *user_data)
558 const char *path = user_data;
559 struct iwd_station *iwds;
561 iwds = g_hash_table_lookup(networks, path);
565 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
566 const char *dbus_error = dbus_message_get_error_name(message);
568 DBG("%s scan failed: %s", path, dbus_error);
572 static int cm_device_scan(struct connman_device *device,
573 struct connman_device_scan_params *params)
575 struct iwd_device *iwdd = connman_device_get_data(device);
576 struct iwd_station *iwds;
578 if (strcmp(iwdd->mode, "station"))
581 iwds = g_hash_table_lookup(stations, iwdd->path);
585 if (!g_dbus_proxy_method_call(iwds->proxy, "Scan",
586 NULL, cm_device_scan_cb, g_strdup(iwds->path), g_free))
592 static struct connman_device_driver device_driver = {
594 .type = CONNMAN_DEVICE_TYPE_WIFI,
595 .probe = cm_device_probe,
596 .remove = cm_device_remove,
597 .enable = cm_device_enable,
598 .disable = cm_device_disable,
599 .scan = cm_device_scan,
602 static int cm_tech_probe(struct connman_technology *technology)
607 static void cm_tech_remove(struct connman_technology *technology)
611 struct tech_cb_data {
612 struct iwd_device *iwdd;
618 struct connman_technology *tech;
621 static void tech_cb_free(struct tech_cb_data *cbd)
625 g_free(cbd->passphrase);
630 static int cm_change_tethering(struct iwd_device *iwdd,
631 struct connman_technology *technology,
632 const char *identifier, const char *passphrase,
633 const char *bridge, bool enabled);
635 static void tech_ap_start_cb(DBusMessage *message, void *user_data)
638 struct tech_cb_data *cbd = user_data;
640 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
641 const char *dbus_error = dbus_message_get_error_name(message);
643 connman_warn("iwd device %s could not enable AccessPoint mode: %s",
644 cbd->path, dbus_error);
648 /* wait for 'Started' signal */
651 cm_change_tethering(cbd->iwdd, cbd->tech,
652 cbd->ssid, cbd->passphrase, cbd->bridge, false);
656 static void tech_ap_stop_cb(DBusMessage *message, void *user_data)
658 struct tech_cb_data *cbd = user_data;
660 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
661 const char *dbus_error = dbus_message_get_error_name(message);
663 connman_warn("iwd device %s could not disable AccessPoint mode: %s",
664 cbd->path, dbus_error);
673 static void ap_start_append(DBusMessageIter *iter, void *user_data)
675 struct tech_cb_data *cbd = user_data;
677 DBG("ssid %s", cbd->ssid);
678 DBG("passphrase %s", cbd->passphrase);
680 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cbd->ssid);
681 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cbd->passphrase);
684 static void tech_enable_tethering_cb(const DBusError *error, void *user_data)
686 struct tech_cb_data *cbd = user_data;
687 struct iwd_device *iwdd;
688 struct iwd_ap *iwdap = NULL;
692 iwdd = g_hash_table_lookup(devices, cbd->path);
694 DBG("device already removed");
698 if (dbus_error_is_set(error)) {
699 connman_warn("iwd device %s could not enable AcessPoint mode: %s",
700 cbd->path, error->message);
704 iwdap = g_hash_table_lookup(access_points, iwdd->path);
706 DBG("%s no ap object found", iwdd->path);
710 iwdap->index = cbd->index;
711 iwdap->bridge = g_strdup(cbd->bridge);
712 iwdap->tech = cbd->tech;
714 if (!g_dbus_proxy_method_call(iwdap->proxy, "Start",
715 ap_start_append, tech_ap_start_cb, cbd, NULL)) {
716 connman_warn("iwd ap %s could not start AccessPoint mode: %s",
717 cbd->path, error->message);
725 g_free(iwdap->bridge);
726 iwdap->bridge = NULL;
731 static void tech_disable_tethering_cb(const DBusError *error, void *user_data)
733 struct tech_cb_data *cbd = user_data;
734 struct iwd_device *iwdd;
735 struct iwd_ap *iwdap;
739 iwdd = g_hash_table_lookup(devices, cbd->path);
741 DBG("device already removed");
745 if (dbus_error_is_set(error)) {
746 connman_warn("iwd device %s could not enable Station mode: %s",
747 cbd->path, error->message);
751 iwdap = g_hash_table_lookup(access_points, iwdd->path);
753 DBG("%s no ap object found", iwdd->path);
757 g_free(iwdap->bridge);
759 iwdap->bridge = NULL;
762 if (!connman_inet_remove_from_bridge(cbd->index, cbd->bridge))
765 connman_technology_tethering_notify(cbd->tech, false);
767 if (!g_dbus_proxy_method_call(iwdap->proxy, "Stop",
768 NULL, tech_ap_stop_cb, cbd, NULL)) {
769 connman_warn("iwd ap %s could not stop AccessPoint mode: %s",
770 cbd->path, error->message);
779 static int cm_change_tethering(struct iwd_device *iwdd,
780 struct connman_technology *technology,
781 const char *identifier, const char *passphrase,
782 const char *bridge, bool enabled)
784 struct tech_cb_data *cbd;
787 GDBusResultFunction cb;
789 index = connman_inet_ifindex(iwdd->name);
793 cbd = g_new(struct tech_cb_data, 1);
795 cbd->path = g_strdup(iwdd->path);
796 cbd->ssid = g_strdup(identifier);
797 cbd->passphrase = g_strdup(passphrase);
798 cbd->bridge = g_strdup(bridge);
799 cbd->tech = technology;
804 cb = tech_enable_tethering_cb;
807 cb = tech_disable_tethering_cb;
810 if (!g_dbus_proxy_set_property_basic(iwdd->proxy,
811 "Mode", DBUS_TYPE_STRING, &mode,
820 static int cm_tech_tethering(struct connman_technology *technology,
821 const char *identifier, const char *passphrase,
822 const char *bridge, bool enabled)
828 g_hash_table_iter_init(&iter, devices);
830 while (g_hash_table_iter_next(&iter, &key, &value)) {
831 struct iwd_device *iwdd = value;
832 struct iwd_adapter *iwda;
834 iwda = g_hash_table_lookup(adapters, iwdd->adapter);
838 if (!iwda->station || !iwda->ap )
839 /* No support for Station and AccessPoint mode */
842 if (!enabled && !g_strcmp0("ap", iwdd->mode)) {
843 res = cm_change_tethering(iwdd, technology, identifier,
844 passphrase, bridge, enabled);
846 connman_warn("%s switching to Station mode failed",
853 if (enabled && !g_strcmp0("station", iwdd->mode)) {
854 err = cm_change_tethering(iwdd, technology, identifier,
855 passphrase, bridge, enabled);
857 connman_warn("%s switching to AccessPoint mode failed",
866 static struct connman_technology_driver tech_driver = {
868 .type = CONNMAN_SERVICE_TYPE_WIFI,
869 .probe = cm_tech_probe,
870 .remove = cm_tech_remove,
871 .set_tethering = cm_tech_tethering,
874 static const char *security_remap(const char *security)
876 if (!g_strcmp0(security, "open"))
878 else if (!g_strcmp0(security, "psk"))
880 else if (!g_strcmp0(security, "8021x"))
886 static char *create_identifier(const char *path, const char *security)
888 char *start, *end, *identifier;
889 char *_path = g_strdup(path);
892 * _path is something like
893 * /0/4/5363686970686f6c5f427573696e6573735f454150_8021x
895 start = strrchr(_path, '/');
897 end = strchr(start, '_');
901 * Create an ident which is identical to the corresponding
902 * wpa_supplicant identifier.
904 identifier = g_strdup_printf("%s_managed_%s", start,
905 security_remap(security));
911 static void add_network(const char *path, struct iwd_network *iwdn)
913 struct iwd_device *iwdd;
916 iwdd = g_hash_table_lookup(devices, iwdn->device);
920 identifier = create_identifier(path, iwdn->type);
921 iwdn->network = connman_network_create(identifier,
922 CONNMAN_NETWORK_TYPE_WIFI);
923 connman_network_set_data(iwdn->network, iwdn);
925 connman_network_set_name(iwdn->network, iwdn->name);
926 connman_network_set_blob(iwdn->network, "WiFi.SSID", iwdn->name,
928 connman_network_set_string(iwdn->network, "WiFi.Security",
929 security_remap(iwdn->type));
930 connman_network_set_string(iwdn->network, "WiFi.Mode", "managed");
932 if (connman_device_add_network(iwdd->device, iwdn->network) < 0) {
933 connman_network_unref(iwdn->network);
934 iwdn->network = NULL;
939 connman_network_set_available(iwdn->network, true);
940 connman_network_set_group(iwdn->network, identifier);
945 static void remove_network(struct iwd_network *iwdn)
951 connman_device_remove_network(iwdn->iwdd->device,
954 connman_network_unref(iwdn->network);
955 iwdn->network = NULL;
958 static void add_device(const char *path, struct iwd_device *iwdd)
960 char ident[ETH_ALEN * 2 + 1];
962 iwdd->device = connman_device_create("wifi", CONNMAN_DEVICE_TYPE_WIFI);
966 connman_device_set_data(iwdd->device, iwdd);
968 address2ident(iwdd->address, ident);
969 connman_device_set_ident(iwdd->device, ident);
971 if (connman_device_register(iwdd->device) < 0) {
972 g_hash_table_remove(devices, path);
976 connman_device_set_powered(iwdd->device, iwdd->powered);
979 static void remove_device_networks(struct iwd_device *iwdd)
983 struct iwd_network *iwdn;
984 GSList *list, *nets = NULL;
986 g_hash_table_iter_init(&iter, networks);
988 while (g_hash_table_iter_next(&iter, &key, &value)) {
991 if (!strcmp(iwdd->path, iwdn->device))
992 nets = g_slist_prepend(nets, iwdn);
995 for (list = nets; list; list = list->next) {
997 g_hash_table_remove(networks, iwdn->path);
1003 static void remove_device(struct iwd_device *iwdd)
1008 remove_device_networks(iwdd);
1009 connman_device_unregister(iwdd->device);
1010 connman_device_unref(iwdd->device);
1011 iwdd->device = NULL;
1014 static void adapter_property_change(GDBusProxy *proxy, const char *name,
1015 DBusMessageIter *iter, void *user_data)
1017 struct iwd_adapter *adapter;
1020 path = g_dbus_proxy_get_path(proxy);
1021 adapter = g_hash_table_lookup(adapters, path);
1025 if (!strcmp(name, "Powered")) {
1026 dbus_bool_t powered;
1028 dbus_message_iter_get_basic(iter, &powered);
1029 adapter->powered = powered;
1031 DBG("%p powered %d", path, adapter->powered);
1035 static void device_property_change(GDBusProxy *proxy, const char *name,
1036 DBusMessageIter *iter, void *user_data)
1038 struct iwd_device *iwdd;
1041 path = g_dbus_proxy_get_path(proxy);
1042 iwdd = g_hash_table_lookup(devices, path);
1046 if (!strcmp(name, "Name")) {
1049 dbus_message_iter_get_basic(iter, &name);
1051 iwdd->name = g_strdup(name);
1053 DBG("%p name %s", path, iwdd->name);
1054 } else if (!strcmp(name, "Powered")) {
1055 dbus_bool_t powered;
1057 dbus_message_iter_get_basic(iter, &powered);
1058 iwdd->powered = powered;
1060 DBG("%s powered %d", path, iwdd->powered);
1061 } else if (!strcmp(name, "Mode")) {
1064 dbus_message_iter_get_basic(iter, &mode);
1066 iwdd->mode = g_strdup(mode);
1068 DBG("%s mode %s", path, iwdd->mode);
1072 static void network_property_change(GDBusProxy *proxy, const char *name,
1073 DBusMessageIter *iter, void *user_data)
1075 struct iwd_network *iwdn;
1076 struct iwd_known_network *iwdkn;
1079 path = g_dbus_proxy_get_path(proxy);
1080 iwdn = g_hash_table_lookup(networks, path);
1084 if (!strcmp(name, "Connected")) {
1085 dbus_bool_t connected;
1087 dbus_message_iter_get_basic(iter, &connected);
1088 iwdn->connected = connected;
1090 DBG("%s connected %d", path, iwdn->connected);
1092 if (iwdn->connected)
1093 update_network_connected(iwdn);
1095 update_network_disconnected(iwdn);
1096 } else if (!strcmp(name, "KnownNetwork")) {
1097 g_free(iwdn->known_network);
1098 iwdn->known_network =
1099 g_strdup(proxy_get_string(proxy, "KnownNetwork"));
1100 if (!iwdn->known_network)
1103 iwdkn = g_hash_table_lookup(known_networks,
1104 iwdn->known_network);
1106 update_auto_connect(iwdkn);
1110 static unsigned char calculate_strength(int strength)
1115 * Network's maximum signal strength expressed in 100 * dBm.
1116 * The value is the range of 0 (strongest signal) to -10000
1119 * ConnMan expects it in the range from 100 (strongest) to 0
1122 res = (unsigned char)((strength + 10000) / 100);
1127 static void _update_signal_strength(const char *path, int16_t signal_strength)
1129 struct iwd_network *iwdn;
1131 iwdn = g_hash_table_lookup(networks, path);
1135 connman_network_set_strength(iwdn->network,
1136 calculate_strength(signal_strength));
1137 connman_network_set_available(iwdn->network, true);
1138 connman_network_update(iwdn->network);
1141 static void ordered_networks_cb(DBusMessage *message, void *user_data)
1143 DBusMessageIter array, entry;
1144 struct iwd_device *iwdd;
1145 char *path = user_data;
1149 if (!dbus_message_iter_init(message, &array))
1152 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1155 dbus_message_iter_recurse(&array, &entry);
1156 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) {
1157 DBusMessageIter value;
1159 int16_t signal_strength;
1162 dbus_message_iter_recurse(&entry, &value);
1164 dbus_message_iter_get_basic(&value, &path);
1166 dbus_message_iter_next(&value);
1167 dbus_message_iter_get_basic(&value, &signal_strength);
1169 _update_signal_strength(path, signal_strength);
1171 dbus_message_iter_next(&entry);
1174 iwdd = g_hash_table_lookup(devices, path);
1176 connman_device_set_scanning(iwdd->device,
1177 CONNMAN_SERVICE_TYPE_WIFI, false);
1180 static void update_signal_strength(struct iwd_station *iwds)
1182 if (!g_dbus_proxy_method_call(iwds->proxy,
1183 "GetOrderedNetworks",
1184 NULL, ordered_networks_cb,
1185 g_strdup(iwds->path), g_free))
1186 DBG("GetOrderedNetworks() failed");
1189 static void station_property_change(GDBusProxy *proxy, const char *name,
1190 DBusMessageIter *iter, void *user_data)
1192 struct iwd_station *iwds;
1193 struct iwd_device *iwdd;
1196 path = g_dbus_proxy_get_path(proxy);
1197 iwds = g_hash_table_lookup(stations, path);
1201 if (!strcmp(name, "State")) {
1204 dbus_message_iter_get_basic(iter, &state);
1205 g_free(iwds->state);
1206 iwds->state = g_strdup(state);
1208 DBG("%s state %s", path, iwds->state);
1209 } else if (!strcmp(name, "ConnectedNetwork")) {
1210 const char *connected_network;
1212 g_free(iwds->connected_network);
1214 dbus_message_iter_get_basic(iter, &connected_network);
1215 iwds->connected_network = g_strdup(connected_network);
1217 iwds->connected_network = NULL;
1220 DBG("%s connected_network %s", path, iwds->connected_network);
1221 } else if (!strcmp(name, "Scanning")) {
1222 dbus_bool_t scanning;
1224 dbus_message_iter_get_basic(iter, &scanning);
1225 iwds->scanning = scanning;
1227 if (iwds->scanning) {
1228 iwdd = g_hash_table_lookup(devices, path);
1230 connman_device_set_scanning(iwdd->device,
1231 CONNMAN_SERVICE_TYPE_WIFI, true);
1233 update_signal_strength(iwds);
1237 DBG("%s scanning %d", path, iwds->scanning);
1241 static void ap_property_change(GDBusProxy *proxy, const char *name,
1242 DBusMessageIter *iter, void *user_data)
1244 struct iwd_ap *iwdap;
1248 path = g_dbus_proxy_get_path(proxy);
1249 iwdap = g_hash_table_lookup(access_points, path);
1253 if (!strcmp(name, "Started")) {
1254 dbus_bool_t started;
1256 dbus_message_iter_get_basic(iter, &started);
1257 iwdap->started = started;
1259 DBG("%s started %d", path, iwdap->started);
1261 if (iwdap->started && iwdap->index != -1) {
1262 DBG("index %d bridge %s", iwdap->index, iwdap->bridge);
1263 err = connman_technology_tethering_notify(
1267 err = connman_inet_add_to_bridge(
1268 iwdap->index, iwdap->bridge);
1273 static void adapter_free(gpointer data)
1275 struct iwd_adapter *iwda = data;
1278 g_dbus_proxy_unref(iwda->proxy);
1283 g_free(iwda->vendor);
1284 g_free(iwda->model);
1288 static void device_free(gpointer data)
1290 struct iwd_device *iwdd = data;
1293 g_dbus_proxy_unref(iwdd->proxy);
1297 remove_device(iwdd);
1300 g_free(iwdd->adapter);
1302 g_free(iwdd->address);
1306 static void network_free(gpointer data)
1308 struct iwd_network *iwdn = data;
1311 g_dbus_proxy_unref(iwdn->proxy);
1315 remove_network(iwdn);
1318 g_free(iwdn->device);
1321 g_free(iwdn->known_network);
1325 static void known_network_free(gpointer data)
1327 struct iwd_known_network *iwdkn = data;
1330 g_dbus_proxy_unref(iwdkn->proxy);
1331 iwdkn->proxy = NULL;
1334 if (iwdkn->auto_connect_id)
1335 g_source_remove(iwdkn->auto_connect_id);
1337 g_free(iwdkn->path);
1338 g_free(iwdkn->name);
1339 g_free(iwdkn->type);
1340 g_free(iwdkn->last_connected_time);
1344 static void station_free(gpointer data)
1346 struct iwd_station *iwds = data;
1349 g_dbus_proxy_unref(iwds->proxy);
1353 g_free(iwds->connected_network);
1357 static void ap_free(gpointer data)
1359 struct iwd_ap *iwdap = data;
1362 g_dbus_proxy_unref(iwdap->proxy);
1363 iwdap->proxy = NULL;
1365 g_free(iwdap->bridge);
1369 static void create_adapter(GDBusProxy *proxy)
1371 const char *path = g_dbus_proxy_get_path(proxy);
1372 struct iwd_adapter *iwda;
1373 GSList *modes, *list;
1375 iwda = g_try_new0(struct iwd_adapter, 1);
1378 connman_error("Out of memory creating IWD adapter");
1382 iwda->path = g_strdup(path);
1383 g_hash_table_replace(adapters, iwda->path, iwda);
1385 iwda->proxy = g_dbus_proxy_ref(proxy);
1388 connman_error("Cannot create IWD adapter watcher %s", path);
1389 g_hash_table_remove(adapters, path);
1393 iwda->vendor = g_strdup(proxy_get_string(proxy, "Vendor"));
1394 iwda->model = g_strdup(proxy_get_string(proxy, "Model"));
1395 iwda->powered = proxy_get_bool(proxy, "Powered");
1397 modes = proxy_get_strings(proxy, "SupportedModes");
1398 for (list = modes; list; list = list->next) {
1399 char *m = list->data;
1404 if (!strcmp(m, "ad-hoc"))
1405 iwda->ad_hoc = true;
1406 else if (!strcmp(m, "station"))
1407 iwda->station = true;
1408 else if (!strcmp(m, "ap"))
1411 g_slist_free_full(modes, g_free);
1413 DBG("%s vendor '%s' model '%s' powered %d ad-hoc %d station %d ap %d",
1414 path, iwda->vendor, iwda->model, iwda->powered,
1415 iwda->ad_hoc, iwda->station, iwda->ap);
1417 g_dbus_proxy_set_property_watch(iwda->proxy,
1418 adapter_property_change, NULL);
1421 static void create_device(GDBusProxy *proxy)
1423 const char *path = g_dbus_proxy_get_path(proxy);
1424 struct iwd_device *iwdd;
1426 iwdd = g_try_new0(struct iwd_device, 1);
1429 connman_error("Out of memory creating IWD device");
1433 iwdd->path = g_strdup(path);
1434 g_hash_table_replace(devices, iwdd->path, iwdd);
1436 iwdd->proxy = g_dbus_proxy_ref(proxy);
1439 connman_error("Cannot create IWD device watcher %s", path);
1440 g_hash_table_remove(devices, path);
1444 iwdd->adapter = g_strdup(proxy_get_string(proxy, "Adapter"));
1445 iwdd->name = g_strdup(proxy_get_string(proxy, "Name"));
1446 iwdd->address = g_strdup(proxy_get_string(proxy, "Address"));
1447 iwdd->powered = proxy_get_bool(proxy, "Powered");
1448 iwdd->mode = g_strdup(proxy_get_string(proxy, "Mode"));
1450 DBG("adapter %s name %s address %s powered %d mode %s",
1451 iwdd->adapter, iwdd->name, iwdd->address,
1452 iwdd->powered, iwdd->mode);
1454 g_dbus_proxy_set_property_watch(iwdd->proxy,
1455 device_property_change, NULL);
1457 add_device(path, iwdd);
1460 static void unregister_agent();
1462 static DBusMessage *agent_release_method(DBusConnection *dbus_conn,
1463 DBusMessage *message, void *user_data)
1466 return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
1469 static DBusMessage *get_reply_on_error(DBusMessage *message, int error)
1471 return g_dbus_create_error(message,
1472 IWD_AGENT_ERROR_INTERFACE ".Failed", "Invalid parameters");
1475 static DBusMessage *agent_request_passphrase(DBusConnection *dbus_conn,
1476 DBusMessage *message,
1479 struct iwd_network *iwdn;
1480 DBusMessageIter iter;
1481 const char *path, *passwd;
1485 dbus_message_iter_init(message, &iter);
1487 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
1488 return get_reply_on_error(message, EINVAL);
1490 dbus_message_iter_get_basic(&iter, &path);
1492 iwdn = g_hash_table_lookup(networks, path);
1494 return get_reply_on_error(message, EINVAL);
1496 passwd = connman_network_get_string(iwdn->network, "WiFi.Passphrase");
1498 return g_dbus_create_reply(message, DBUS_TYPE_STRING, &passwd,
1502 static DBusMessage *agent_cancel(DBusConnection *dbus_conn,
1503 DBusMessage *message, void *user_data)
1505 DBusMessageIter iter;
1508 dbus_message_iter_init(message, &iter);
1510 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1511 return get_reply_on_error(message, EINVAL);
1513 dbus_message_iter_get_basic(&iter, &reason);
1515 DBG("cancel: %s", reason);
1518 * We don't have to do anything here, because we asked the
1519 * user upfront for the passphrase. So
1520 * agent_request_passphrase() will always send a passphrase
1524 return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
1527 static const GDBusMethodTable agent_methods[] = {
1528 { GDBUS_METHOD("Release", NULL, NULL, agent_release_method) },
1529 { GDBUS_METHOD("RequestPassphrase",
1530 GDBUS_ARGS({ "path", "o" }),
1531 GDBUS_ARGS({ "passphrase", "s" }),
1532 agent_request_passphrase)},
1533 { GDBUS_METHOD("Cancel",
1534 GDBUS_ARGS({ "reason", "s" }),
1535 NULL, agent_cancel) },
1539 static void agent_register_builder(DBusMessageIter *iter, void *user_data)
1541 const char *path = AGENT_PATH;
1543 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
1547 static void register_agent(GDBusProxy *proxy)
1549 if (!g_dbus_proxy_method_call(proxy,
1551 agent_register_builder,
1555 agent_proxy = g_dbus_proxy_ref(proxy);
1558 static void unregister_agent()
1563 g_dbus_proxy_method_call(agent_proxy,
1565 agent_register_builder,
1568 g_dbus_proxy_unref(agent_proxy);
1572 static void iwd_is_present(DBusConnection *conn, void *user_data)
1574 if (agent_registered)
1577 if (!g_dbus_register_interface(connection, AGENT_PATH,
1578 IWD_AGENT_INTERFACE, agent_methods,
1579 NULL, NULL, NULL, NULL))
1582 agent_registered = true;
1585 static void iwd_is_out(DBusConnection *conn, void *user_data)
1587 if (agent_registered) {
1588 g_dbus_unregister_interface(connection,
1589 AGENT_PATH, IWD_AGENT_INTERFACE);
1590 agent_registered = false;
1594 static void create_network(GDBusProxy *proxy)
1596 const char *path = g_dbus_proxy_get_path(proxy);
1597 struct iwd_network *iwdn;
1599 iwdn = g_try_new0(struct iwd_network, 1);
1602 connman_error("Out of memory creating IWD network");
1606 iwdn->path = g_strdup(path);
1607 g_hash_table_replace(networks, iwdn->path, iwdn);
1609 iwdn->proxy = g_dbus_proxy_ref(proxy);
1612 connman_error("Cannot create IWD network watcher %s", path);
1613 g_hash_table_remove(networks, path);
1617 iwdn->device = g_strdup(proxy_get_string(proxy, "Device"));
1618 iwdn->name = g_strdup(proxy_get_string(proxy, "Name"));
1619 iwdn->type = g_strdup(proxy_get_string(proxy, "Type"));
1620 iwdn->connected = proxy_get_bool(proxy, "Connected");
1621 iwdn->known_network = g_strdup(proxy_get_string(proxy, "KnownNetwork"));
1623 DBG("device %s name '%s' type %s connected %d known_network %s",
1624 iwdn->device, iwdn->name, iwdn->type, iwdn->connected,
1625 iwdn->known_network);
1627 g_dbus_proxy_set_property_watch(iwdn->proxy,
1628 network_property_change, NULL);
1630 add_network(path, iwdn);
1633 static void known_network_property_change(GDBusProxy *proxy, const char *name,
1634 DBusMessageIter *iter, void *user_data)
1636 struct iwd_known_network *iwdkn;
1639 path = g_dbus_proxy_get_path(proxy);
1640 iwdkn = g_hash_table_lookup(known_networks, path);
1644 if (!strcmp(name, "AutoConnect")) {
1645 dbus_bool_t auto_connect;
1647 dbus_message_iter_get_basic(iter, &auto_connect);
1648 iwdkn->auto_connect = auto_connect;
1650 DBG("%p auto_connect %d", path, iwdkn->auto_connect);
1652 update_auto_connect(iwdkn);
1656 static void init_auto_connect(struct iwd_known_network *iwdkn)
1658 GHashTableIter iter;
1659 gpointer key, value;
1661 g_hash_table_iter_init(&iter, networks);
1663 while (g_hash_table_iter_next(&iter, &key, &value)) {
1664 struct iwd_network *iwdn = value;
1665 struct iwd_known_network *kn;
1667 if (!iwdn->known_network)
1670 kn = g_hash_table_lookup(known_networks, iwdn->known_network);
1674 iwdkn->autoconnect = iwdn->autoconnect;
1675 update_auto_connect(iwdkn);
1680 static void create_know_network(GDBusProxy *proxy)
1682 const char *path = g_dbus_proxy_get_path(proxy);
1683 struct iwd_known_network *iwdkn;
1685 iwdkn = g_try_new0(struct iwd_known_network, 1);
1687 connman_error("Out of memory creating IWD known network");
1691 iwdkn->path = g_strdup(path);
1692 g_hash_table_replace(known_networks, iwdkn->path, iwdkn);
1694 iwdkn->proxy = g_dbus_proxy_ref(proxy);
1696 if (!iwdkn->proxy) {
1697 connman_error("Cannot create IWD known network watcher %s", path);
1698 g_hash_table_remove(known_networks, path);
1702 iwdkn->name = g_strdup(proxy_get_string(proxy, "Name"));
1703 iwdkn->type = g_strdup(proxy_get_string(proxy, "Type"));
1704 iwdkn->hidden = proxy_get_bool(proxy, "Hidden");
1705 iwdkn->last_connected_time =
1706 g_strdup(proxy_get_string(proxy, "LastConnectedTime"));
1707 iwdkn->auto_connect = proxy_get_bool(proxy, "AutoConnect");
1709 DBG("name '%s' type %s hidden %d, last_connection_time %s auto_connect %d",
1710 iwdkn->name, iwdkn->type, iwdkn->hidden,
1711 iwdkn->last_connected_time, iwdkn->auto_connect);
1713 init_auto_connect(iwdkn);
1715 g_dbus_proxy_set_property_watch(iwdkn->proxy,
1716 known_network_property_change, NULL);
1719 static void create_station(GDBusProxy *proxy)
1721 const char *path = g_dbus_proxy_get_path(proxy);
1722 struct iwd_station *iwds;
1724 iwds = g_try_new0(struct iwd_station, 1);
1726 connman_error("Out of memory creating IWD station");
1730 iwds->path = g_strdup(path);
1731 g_hash_table_replace(stations, iwds->path, iwds);
1733 iwds->proxy = g_dbus_proxy_ref(proxy);
1736 connman_error("Cannot create IWD station watcher %s", path);
1737 g_hash_table_remove(stations, path);
1741 iwds->state = g_strdup(proxy_get_string(proxy, "State"));
1742 iwds->connected_network = g_strdup(proxy_get_string(proxy, "ConnectedNetwork"));
1743 iwds->scanning = proxy_get_bool(proxy, "Scanning");
1745 DBG("state '%s' connected_network %s scanning %d",
1746 iwds->state, iwds->connected_network, iwds->scanning);
1748 g_dbus_proxy_set_property_watch(iwds->proxy,
1749 station_property_change, NULL);
1752 static void create_ap(GDBusProxy *proxy)
1754 const char *path = g_dbus_proxy_get_path(proxy);
1755 struct iwd_ap *iwdap;
1757 iwdap = g_try_new0(struct iwd_ap, 1);
1759 connman_error("Out of memory creating IWD access point");
1764 iwdap->path = g_strdup(path);
1765 g_hash_table_replace(access_points, iwdap->path, iwdap);
1767 iwdap->proxy = g_dbus_proxy_ref(proxy);
1769 if (!iwdap->proxy) {
1770 connman_error("Cannot create IWD access point watcher %s", path);
1771 g_hash_table_remove(access_points, path);
1775 iwdap->started = proxy_get_bool(proxy, "Started");
1777 DBG("started %d", iwdap->started);
1779 g_dbus_proxy_set_property_watch(iwdap->proxy,
1780 ap_property_change, NULL);
1783 static void object_added(GDBusProxy *proxy, void *user_data)
1785 const char *interface;
1787 interface = g_dbus_proxy_get_interface(proxy);
1789 connman_warn("Interface or proxy missing when adding "
1794 DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
1796 if (!strcmp(interface, IWD_AGENT_MANAGER_INTERFACE))
1797 register_agent(proxy);
1798 else if (!strcmp(interface, IWD_ADAPTER_INTERFACE))
1799 create_adapter(proxy);
1800 else if (!strcmp(interface, IWD_DEVICE_INTERFACE))
1801 create_device(proxy);
1802 else if (!strcmp(interface, IWD_NETWORK_INTERFACE))
1803 create_network(proxy);
1804 else if (!strcmp(interface, IWD_KNOWN_NETWORK_INTERFACE))
1805 create_know_network(proxy);
1806 else if (!strcmp(interface, IWD_STATION_INTERFACE))
1807 create_station(proxy);
1808 else if (!strcmp(interface, IWD_AP_INTERFACE))
1812 static void object_removed(GDBusProxy *proxy, void *user_data)
1814 const char *interface, *path;
1816 interface = g_dbus_proxy_get_interface(proxy);
1818 connman_warn("Interface or proxy missing when removing "
1823 path = g_dbus_proxy_get_path(proxy);
1824 DBG("%s %s", interface, path);
1826 if (!strcmp(interface, IWD_AGENT_MANAGER_INTERFACE))
1828 if (!strcmp(interface, IWD_ADAPTER_INTERFACE))
1829 g_hash_table_remove(adapters, path);
1830 else if (!strcmp(interface, IWD_DEVICE_INTERFACE))
1831 g_hash_table_remove(devices, path);
1832 else if (!strcmp(interface, IWD_NETWORK_INTERFACE))
1833 g_hash_table_remove(networks, path);
1834 else if (!strcmp(interface, IWD_KNOWN_NETWORK_INTERFACE))
1835 g_hash_table_remove(known_networks, path);
1836 else if (!strcmp(interface, IWD_STATION_INTERFACE))
1837 g_hash_table_remove(stations, path);
1838 else if (!strcmp(interface, IWD_AP_INTERFACE))
1839 g_hash_table_remove(access_points, path);
1842 static int iwd_init(void)
1844 connection = connman_dbus_get_connection();
1848 adapters = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1851 devices = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1854 networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1857 known_networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1858 known_network_free);
1860 stations = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1863 access_points = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1866 if (connman_technology_driver_register(&tech_driver) < 0) {
1867 connman_warn("Failed to initialize technology for IWD");
1871 if (connman_device_driver_register(&device_driver) < 0) {
1872 connman_warn("Failed to initialize device driver for "
1874 connman_technology_driver_unregister(&tech_driver);
1878 if (connman_network_driver_register(&network_driver) < 0) {
1879 connman_technology_driver_unregister(&tech_driver);
1880 connman_device_driver_unregister(&device_driver);
1884 client = g_dbus_client_new(connection, IWD_SERVICE, IWD_PATH);
1886 connman_warn("Failed to initialize D-Bus client for "
1891 g_dbus_client_set_connect_watch(client, iwd_is_present, NULL);
1892 g_dbus_client_set_disconnect_watch(client, iwd_is_out, NULL);
1893 g_dbus_client_set_proxy_handlers(client, object_added, object_removed,
1900 g_hash_table_destroy(devices);
1903 g_hash_table_destroy(networks);
1906 g_hash_table_destroy(known_networks);
1909 g_hash_table_destroy(stations);
1912 g_hash_table_destroy(access_points);
1915 g_hash_table_destroy(adapters);
1918 dbus_connection_unref(connection);
1923 static void iwd_exit(void)
1925 connman_network_driver_unregister(&network_driver);
1926 connman_device_driver_unregister(&device_driver);
1927 connman_technology_driver_unregister(&tech_driver);
1929 g_dbus_client_unref(client);
1931 g_hash_table_destroy(access_points);
1932 g_hash_table_destroy(stations);
1933 g_hash_table_destroy(known_networks);
1934 g_hash_table_destroy(networks);
1935 g_hash_table_destroy(devices);
1936 g_hash_table_destroy(adapters);
1938 dbus_connection_unref(connection);
1941 CONNMAN_PLUGIN_DEFINE(iwd, "IWD plugin", VERSION,
1942 CONNMAN_PLUGIN_PRIORITY_DEFAULT, iwd_init, iwd_exit)