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;
100 struct iwd_known_network {
106 char *last_connected_time;
115 char *connected_network;
126 struct connman_technology *tech;
129 static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
131 DBusMessageIter iter;
134 if (!g_dbus_proxy_get_property(proxy, property, &iter))
137 dbus_message_iter_get_basic(&iter, &str);
142 static GSList *proxy_get_strings(GDBusProxy *proxy, const char *property)
144 DBusMessageIter array, entry;
147 if (!g_dbus_proxy_get_property(proxy, property, &array))
150 dbus_message_iter_recurse(&array, &entry);
152 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING){
155 dbus_message_iter_get_basic(&entry, &val);
156 list = g_slist_prepend(list, g_strdup(val));
157 dbus_message_iter_next(&entry);
163 static bool proxy_get_bool(GDBusProxy *proxy, const char *property)
165 DBusMessageIter iter;
168 if (!g_dbus_proxy_get_property(proxy, property, &iter))
171 dbus_message_iter_get_basic(&iter, &value);
176 static void address2ident(const char *address, char *ident)
180 for (i = 0; i < ETH_ALEN; i++) {
181 ident[i * 2] = address[i * 3];
182 ident[i * 2 + 1] = address[i * 3 + 1];
184 ident[ETH_ALEN * 2] = '\0';
187 static int cm_network_probe(struct connman_network *network)
192 g_hash_table_iter_init(&iter, networks);
194 while (g_hash_table_iter_next(&iter, &key, &value)) {
195 struct iwd_network *iwdn = value;
197 if (network == iwdn->network)
204 static void update_network_connected(struct iwd_network *iwdn)
206 struct iwd_device *iwdd;
209 iwdd = g_hash_table_lookup(devices, iwdn->device);
213 index = connman_inet_ifindex(iwdd->name);
217 DBG("interface name %s index %d", iwdd->name, index);
218 connman_network_set_index(iwdn->network, index);
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);
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 if (!g_dbus_proxy_method_call(iwds->proxy, "Disconnect",
315 NULL, cm_network_disconnect_cb, g_strdup(iwdn->path), g_free))
321 static struct connman_network_driver network_driver = {
323 .type = CONNMAN_NETWORK_TYPE_WIFI,
324 .probe = cm_network_probe,
325 .connect = cm_network_connect,
326 .disconnect = cm_network_disconnect,
329 static int cm_device_probe(struct connman_device *device)
334 g_hash_table_iter_init(&iter, devices);
336 while (g_hash_table_iter_next(&iter, &key, &value)) {
337 struct iwd_device *iwdd = value;
339 if (device == iwdd->device)
346 static void cm_device_remove(struct connman_device *device)
355 static void device_powered_cb(const DBusError *error, void *user_data)
357 struct dev_cb_data *cbd = user_data;
358 struct iwd_device *iwdd;
360 iwdd = g_hash_table_lookup(devices, cbd->path);
364 if (dbus_error_is_set(error)) {
365 connman_warn("WiFi device %s not enabled %s",
366 cbd->path, error->message);
370 connman_device_set_powered(iwdd->device, cbd->powered);
376 static int set_device_powered(struct connman_device *device, bool powered)
378 struct iwd_device *iwdd = connman_device_get_data(device);
379 dbus_bool_t device_powered = powered;
380 struct dev_cb_data *cbd;
382 if (proxy_get_bool(iwdd->proxy, "Powered"))
385 cbd = g_new(struct dev_cb_data, 1);
386 cbd->path = g_strdup(iwdd->path);
387 cbd->powered = powered;
389 g_dbus_proxy_set_property_basic(iwdd->proxy, "Powered",
390 DBUS_TYPE_BOOLEAN, &device_powered,
391 device_powered_cb, cbd, NULL);
396 static int cm_device_enable(struct connman_device *device)
398 return set_device_powered(device, true);
401 static int cm_device_disable(struct connman_device *device)
403 return set_device_powered(device, false);
406 static void cm_device_scan_cb(DBusMessage *message, void *user_data)
408 const char *path = user_data;
409 struct iwd_station *iwds;
411 iwds = g_hash_table_lookup(networks, path);
415 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
416 const char *dbus_error = dbus_message_get_error_name(message);
418 DBG("%s scan failed: %s", path, dbus_error);
422 static int cm_device_scan(struct connman_device *device,
423 struct connman_device_scan_params *params)
425 struct iwd_device *iwdd = connman_device_get_data(device);
426 struct iwd_station *iwds;
428 if (strcmp(iwdd->mode, "station"))
431 iwds = g_hash_table_lookup(stations, iwdd->path);
435 if (!g_dbus_proxy_method_call(iwds->proxy, "Scan",
436 NULL, cm_device_scan_cb, g_strdup(iwds->path), g_free))
442 static struct connman_device_driver device_driver = {
444 .type = CONNMAN_DEVICE_TYPE_WIFI,
445 .probe = cm_device_probe,
446 .remove = cm_device_remove,
447 .enable = cm_device_enable,
448 .disable = cm_device_disable,
449 .scan = cm_device_scan,
452 static int cm_tech_probe(struct connman_technology *technology)
457 static void cm_tech_remove(struct connman_technology *technology)
461 struct tech_cb_data {
462 struct iwd_device *iwdd;
468 struct connman_technology *tech;
471 static void tech_cb_free(struct tech_cb_data *cbd)
475 g_free(cbd->passphrase);
480 static int cm_change_tethering(struct iwd_device *iwdd,
481 struct connman_technology *technology,
482 const char *identifier, const char *passphrase,
483 const char *bridge, bool enabled);
485 static void tech_ap_start_cb(DBusMessage *message, void *user_data)
488 struct tech_cb_data *cbd = user_data;
490 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
491 const char *dbus_error = dbus_message_get_error_name(message);
493 connman_warn("iwd device %s could not enable AccessPoint mode: %s",
494 cbd->path, dbus_error);
498 /* wait for 'Started' signal */
501 cm_change_tethering(cbd->iwdd, cbd->tech,
502 cbd->ssid, cbd->passphrase, cbd->bridge, false);
506 static void tech_ap_stop_cb(DBusMessage *message, void *user_data)
508 struct tech_cb_data *cbd = user_data;
510 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
511 const char *dbus_error = dbus_message_get_error_name(message);
513 connman_warn("iwd device %s could not disable AccessPoint mode: %s",
514 cbd->path, dbus_error);
523 static void ap_start_append(DBusMessageIter *iter, void *user_data)
525 struct tech_cb_data *cbd = user_data;
527 DBG("ssid %s", cbd->ssid);
528 DBG("passphrase %s", cbd->passphrase);
530 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cbd->ssid);
531 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cbd->passphrase);
534 static void tech_enable_tethering_cb(const DBusError *error, void *user_data)
536 struct tech_cb_data *cbd = user_data;
537 struct iwd_device *iwdd;
538 struct iwd_ap *iwdap;
542 iwdd = g_hash_table_lookup(devices, cbd->path);
544 DBG("device already removed");
548 if (dbus_error_is_set(error)) {
549 connman_warn("iwd device %s could not enable AcessPoint mode: %s",
550 cbd->path, error->message);
554 iwdap = g_hash_table_lookup(access_points, iwdd->path);
556 DBG("%s no ap object found", iwdd->path);
560 iwdap->index = cbd->index;
561 iwdap->bridge = g_strdup(cbd->bridge);
562 iwdap->tech = cbd->tech;
564 if (!g_dbus_proxy_method_call(iwdap->proxy, "Start",
565 ap_start_append, tech_ap_start_cb, cbd, NULL)) {
566 connman_warn("iwd ap %s could not start AccessPoint mode: %s",
567 cbd->path, error->message);
575 g_free(iwdap->bridge);
576 iwdap->bridge = NULL;
581 static void tech_disable_tethering_cb(const DBusError *error, void *user_data)
583 struct tech_cb_data *cbd = user_data;
584 struct iwd_device *iwdd;
585 struct iwd_ap *iwdap;
589 iwdd = g_hash_table_lookup(devices, cbd->path);
591 DBG("device already removed");
595 if (dbus_error_is_set(error)) {
596 connman_warn("iwd device %s could not enable Station mode: %s",
597 cbd->path, error->message);
601 iwdap = g_hash_table_lookup(access_points, iwdd->path);
603 DBG("%s no ap object found", iwdd->path);
607 g_free(iwdap->bridge);
609 iwdap->bridge = NULL;
612 if (!connman_inet_remove_from_bridge(cbd->index, cbd->bridge))
615 connman_technology_tethering_notify(cbd->tech, false);
617 if (!g_dbus_proxy_method_call(iwdap->proxy, "Stop",
618 NULL, tech_ap_stop_cb, cbd, NULL)) {
619 connman_warn("iwd ap %s could not start AccessPoint mode: %s",
620 cbd->path, error->message);
629 static int cm_change_tethering(struct iwd_device *iwdd,
630 struct connman_technology *technology,
631 const char *identifier, const char *passphrase,
632 const char *bridge, bool enabled)
634 struct tech_cb_data *cbd;
637 GDBusResultFunction cb;
639 index = connman_inet_ifindex(iwdd->name);
643 cbd = g_new(struct tech_cb_data, 1);
645 cbd->path = g_strdup(iwdd->path);
646 cbd->ssid = g_strdup(identifier);
647 cbd->passphrase = g_strdup(passphrase);
648 cbd->bridge = g_strdup(bridge);
649 cbd->tech = technology;
654 cb = tech_enable_tethering_cb;
657 cb = tech_disable_tethering_cb;
660 if (!g_dbus_proxy_set_property_basic(iwdd->proxy,
661 "Mode", DBUS_TYPE_STRING, &mode,
670 static int cm_tech_tethering(struct connman_technology *technology,
671 const char *identifier, const char *passphrase,
672 const char *bridge, bool enabled)
678 g_hash_table_iter_init(&iter, devices);
680 while (g_hash_table_iter_next(&iter, &key, &value)) {
681 struct iwd_device *iwdd = value;
682 struct iwd_adapter *iwda;
684 iwda = g_hash_table_lookup(adapters, iwdd->adapter);
688 if (!iwda->station || !iwda->ap )
689 /* No support for Station and AccessPoint mode */
692 if (!enabled && !g_strcmp0("ap", iwdd->mode)) {
693 res = cm_change_tethering(iwdd, technology, identifier,
694 passphrase, bridge, enabled);
696 connman_warn("%s switching to Station mode failed",
703 if (enabled && !g_strcmp0("station", iwdd->mode)) {
704 err = cm_change_tethering(iwdd, technology, identifier,
705 passphrase, bridge, enabled);
707 connman_warn("%s switching to AccessPoint mode failed",
716 static struct connman_technology_driver tech_driver = {
718 .type = CONNMAN_SERVICE_TYPE_WIFI,
719 .probe = cm_tech_probe,
720 .remove = cm_tech_remove,
721 .set_tethering = cm_tech_tethering,
724 static const char *security_remap(const char *security)
726 if (!g_strcmp0(security, "open"))
728 else if (!g_strcmp0(security, "psk"))
730 else if (!g_strcmp0(security, "8021x"))
736 static char *create_identifier(const char *path, const char *security)
738 char *start, *end, *identifier;
739 char *_path = g_strdup(path);
742 * _path is something like
743 * /0/4/5363686970686f6c5f427573696e6573735f454150_8021x
745 start = strrchr(_path, '/');
747 end = strchr(start, '_');
751 * Create an ident which is identical to the corresponding
752 * wpa_supplicant identifier.
754 identifier = g_strdup_printf("%s_managed_%s", start,
755 security_remap(security));
761 static void add_network(const char *path, struct iwd_network *iwdn)
763 struct iwd_device *iwdd;
766 iwdd = g_hash_table_lookup(devices, iwdn->device);
770 identifier = create_identifier(path, iwdn->type);
771 iwdn->network = connman_network_create(identifier,
772 CONNMAN_NETWORK_TYPE_WIFI);
773 connman_network_set_data(iwdn->network, iwdn);
775 connman_network_set_name(iwdn->network, iwdn->name);
776 connman_network_set_blob(iwdn->network, "WiFi.SSID", iwdn->name,
778 connman_network_set_string(iwdn->network, "WiFi.Security",
779 security_remap(iwdn->type));
780 connman_network_set_string(iwdn->network, "WiFi.Mode", "managed");
782 if (connman_device_add_network(iwdd->device, iwdn->network) < 0) {
783 connman_network_unref(iwdn->network);
784 iwdn->network = NULL;
789 connman_network_set_available(iwdn->network, true);
790 connman_network_set_group(iwdn->network, identifier);
795 static void remove_network(struct iwd_network *iwdn)
801 connman_device_remove_network(iwdn->iwdd->device,
804 connman_network_unref(iwdn->network);
805 iwdn->network = NULL;
808 static void add_device(const char *path, struct iwd_device *iwdd)
810 char ident[ETH_ALEN * 2 + 1];
812 iwdd->device = connman_device_create("wifi", CONNMAN_DEVICE_TYPE_WIFI);
816 connman_device_set_data(iwdd->device, iwdd);
818 address2ident(iwdd->address, ident);
819 connman_device_set_ident(iwdd->device, ident);
821 if (connman_device_register(iwdd->device) < 0) {
822 g_hash_table_remove(devices, path);
826 connman_device_set_powered(iwdd->device, iwdd->powered);
829 static void remove_device_networks(struct iwd_device *iwdd)
833 struct iwd_network *iwdn;
834 GSList *list, *nets = NULL;
836 g_hash_table_iter_init(&iter, networks);
838 while (g_hash_table_iter_next(&iter, &key, &value)) {
841 if (!strcmp(iwdd->path, iwdn->device))
842 nets = g_slist_prepend(nets, iwdn);
845 for (list = nets; list; list = list->next) {
847 g_hash_table_remove(networks, iwdn->path);
853 static void remove_device(struct iwd_device *iwdd)
858 remove_device_networks(iwdd);
859 connman_device_unregister(iwdd->device);
860 connman_device_unref(iwdd->device);
864 static void adapter_property_change(GDBusProxy *proxy, const char *name,
865 DBusMessageIter *iter, void *user_data)
867 struct iwd_adapter *adapter;
870 path = g_dbus_proxy_get_path(proxy);
871 adapter = g_hash_table_lookup(adapters, path);
875 if (!strcmp(name, "Powered")) {
878 dbus_message_iter_get_basic(iter, &powered);
879 adapter->powered = powered;
881 DBG("%p powered %d", path, adapter->powered);
885 static void device_property_change(GDBusProxy *proxy, const char *name,
886 DBusMessageIter *iter, void *user_data)
888 struct iwd_device *iwdd;
891 path = g_dbus_proxy_get_path(proxy);
892 iwdd = g_hash_table_lookup(devices, path);
896 if (!strcmp(name, "Name")) {
899 dbus_message_iter_get_basic(iter, &name);
901 iwdd->name = g_strdup(name);
903 DBG("%p name %s", path, iwdd->name);
904 } else if (!strcmp(name, "Powered")) {
907 dbus_message_iter_get_basic(iter, &powered);
908 iwdd->powered = powered;
910 DBG("%s powered %d", path, iwdd->powered);
911 } else if (!strcmp(name, "Mode")) {
914 dbus_message_iter_get_basic(iter, &mode);
916 iwdd->mode = g_strdup(mode);
918 DBG("%s mode %s", path, iwdd->mode);
922 static void network_property_change(GDBusProxy *proxy, const char *name,
923 DBusMessageIter *iter, void *user_data)
925 struct iwd_network *iwdn;
928 path = g_dbus_proxy_get_path(proxy);
929 iwdn = g_hash_table_lookup(networks, path);
933 if (!strcmp(name, "Connected")) {
934 dbus_bool_t connected;
936 dbus_message_iter_get_basic(iter, &connected);
937 iwdn->connected = connected;
939 DBG("%s connected %d", path, iwdn->connected);
942 update_network_connected(iwdn);
944 update_network_disconnected(iwdn);
948 static unsigned char calculate_strength(int strength)
953 * Network's maximum signal strength expressed in 100 * dBm.
954 * The value is the range of 0 (strongest signal) to -10000
957 * ConnMan expects it in the range from 100 (strongest) to 0
960 res = (unsigned char)((strength + 10000) / 100);
965 static void _update_signal_strength(const char *path, int16_t signal_strength)
967 struct iwd_network *iwdn;
969 iwdn = g_hash_table_lookup(networks, path);
973 connman_network_set_strength(iwdn->network,
974 calculate_strength(signal_strength));
975 connman_network_update(iwdn->network);
978 static void ordered_networks_cb(DBusMessage *message, void *user_data)
980 DBusMessageIter array, entry;
984 if (!dbus_message_iter_init(message, &array))
987 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
990 dbus_message_iter_recurse(&array, &entry);
991 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) {
992 DBusMessageIter value;
994 int16_t signal_strength;
997 dbus_message_iter_recurse(&entry, &value);
999 dbus_message_iter_get_basic(&value, &path);
1001 dbus_message_iter_next(&value);
1002 dbus_message_iter_get_basic(&value, &signal_strength);
1004 _update_signal_strength(path, signal_strength);
1006 dbus_message_iter_next(&entry);
1010 static void update_signal_strength(struct iwd_station *iwds)
1012 if (!g_dbus_proxy_method_call(iwds->proxy,
1013 "GetOrderedNetworks",
1014 NULL, ordered_networks_cb,
1016 DBG("GetOrderedNetworks() failed");
1019 static void station_property_change(GDBusProxy *proxy, const char *name,
1020 DBusMessageIter *iter, void *user_data)
1022 struct iwd_station *iwds;
1025 path = g_dbus_proxy_get_path(proxy);
1026 iwds = g_hash_table_lookup(stations, path);
1030 if (!strcmp(name, "State")) {
1033 dbus_message_iter_get_basic(iter, &state);
1034 g_free(iwds->state);
1035 iwds->state = g_strdup(state);
1037 DBG("%s state %s", path, iwds->state);
1038 } else if (!strcmp(name, "ConnectedNetwork")) {
1039 const char *connected_network;
1041 g_free(iwds->connected_network);
1043 dbus_message_iter_get_basic(iter, &connected_network);
1044 iwds->connected_network = g_strdup(connected_network);
1046 iwds->connected_network = NULL;
1049 DBG("%s connected_network %s", path, iwds->connected_network);
1050 } else if (!strcmp(name, "Scanning")) {
1051 dbus_bool_t scanning;
1053 dbus_message_iter_get_basic(iter, &scanning);
1054 iwds->scanning = scanning;
1056 if (!iwds->scanning)
1057 update_signal_strength(iwds);
1059 DBG("%s scanning %d", path, iwds->scanning);
1063 static void ap_property_change(GDBusProxy *proxy, const char *name,
1064 DBusMessageIter *iter, void *user_data)
1066 struct iwd_ap *iwdap;
1070 path = g_dbus_proxy_get_path(proxy);
1071 iwdap = g_hash_table_lookup(access_points, path);
1075 if (!strcmp(name, "Started")) {
1076 dbus_bool_t started;
1078 dbus_message_iter_get_basic(iter, &started);
1079 iwdap->started = started;
1081 DBG("%s started %d", path, iwdap->started);
1083 if (iwdap->started && iwdap->index != -1) {
1084 DBG("index %d bridge %s", iwdap->index, iwdap->bridge);
1085 err = connman_technology_tethering_notify(
1089 err = connman_inet_add_to_bridge(
1090 iwdap->index, iwdap->bridge);
1095 static void adapter_free(gpointer data)
1097 struct iwd_adapter *iwda = data;
1100 g_dbus_proxy_unref(iwda->proxy);
1105 g_free(iwda->vendor);
1106 g_free(iwda->model);
1110 static void device_free(gpointer data)
1112 struct iwd_device *iwdd = data;
1115 g_dbus_proxy_unref(iwdd->proxy);
1119 remove_device(iwdd);
1122 g_free(iwdd->adapter);
1124 g_free(iwdd->address);
1128 static void network_free(gpointer data)
1130 struct iwd_network *iwdn = data;
1133 g_dbus_proxy_unref(iwdn->proxy);
1137 remove_network(iwdn);
1140 g_free(iwdn->device);
1143 g_free(iwdn->known_network);
1147 static void known_network_free(gpointer data)
1149 struct iwd_known_network *iwdkn = data;
1152 g_dbus_proxy_unref(iwdkn->proxy);
1153 iwdkn->proxy = NULL;
1156 if (iwdkn->auto_connect_id)
1157 g_source_remove(iwdkn->auto_connect_id);
1159 g_free(iwdkn->path);
1160 g_free(iwdkn->name);
1161 g_free(iwdkn->type);
1162 g_free(iwdkn->last_connected_time);
1166 static void station_free(gpointer data)
1168 struct iwd_station *iwds = data;
1171 g_dbus_proxy_unref(iwds->proxy);
1175 g_free(iwds->connected_network);
1179 static void ap_free(gpointer data)
1181 struct iwd_ap *iwdap = data;
1184 g_dbus_proxy_unref(iwdap->proxy);
1185 iwdap->proxy = NULL;
1187 g_free(iwdap->bridge);
1191 static void create_adapter(GDBusProxy *proxy)
1193 const char *path = g_dbus_proxy_get_path(proxy);
1194 struct iwd_adapter *iwda;
1195 GSList *modes, *list;
1197 iwda = g_try_new0(struct iwd_adapter, 1);
1200 connman_error("Out of memory creating IWD adapter");
1204 iwda->path = g_strdup(path);
1205 g_hash_table_replace(adapters, iwda->path, iwda);
1207 iwda->proxy = g_dbus_proxy_ref(proxy);
1210 connman_error("Cannot create IWD adapter watcher %s", path);
1211 g_hash_table_remove(adapters, path);
1215 iwda->vendor = g_strdup(proxy_get_string(proxy, "Vendor"));
1216 iwda->model = g_strdup(proxy_get_string(proxy, "Model"));
1217 iwda->powered = proxy_get_bool(proxy, "Powered");
1219 modes = proxy_get_strings(proxy, "SupportedModes");
1220 for (list = modes; list; list = list->next) {
1221 char *m = list->data;
1226 if (!strcmp(m, "ad-hoc"))
1227 iwda->ad_hoc = true;
1228 else if (!strcmp(m, "station"))
1229 iwda->station = true;
1230 else if (!strcmp(m, "ap"))
1233 g_slist_free_full(modes, g_free);
1235 DBG("%s vendor '%s' model '%s' powered %d ad-hoc %d station %d ap %d",
1236 path, iwda->vendor, iwda->model, iwda->powered,
1237 iwda->ad_hoc, iwda->station, iwda->ap);
1239 g_dbus_proxy_set_property_watch(iwda->proxy,
1240 adapter_property_change, NULL);
1243 static void create_device(GDBusProxy *proxy)
1245 const char *path = g_dbus_proxy_get_path(proxy);
1246 struct iwd_device *iwdd;
1248 iwdd = g_try_new0(struct iwd_device, 1);
1251 connman_error("Out of memory creating IWD device");
1255 iwdd->path = g_strdup(path);
1256 g_hash_table_replace(devices, iwdd->path, iwdd);
1258 iwdd->proxy = g_dbus_proxy_ref(proxy);
1261 connman_error("Cannot create IWD device watcher %s", path);
1262 g_hash_table_remove(devices, path);
1266 iwdd->adapter = g_strdup(proxy_get_string(proxy, "Adapter"));
1267 iwdd->name = g_strdup(proxy_get_string(proxy, "Name"));
1268 iwdd->address = g_strdup(proxy_get_string(proxy, "Address"));
1269 iwdd->powered = proxy_get_bool(proxy, "Powered");
1270 iwdd->mode = g_strdup(proxy_get_string(proxy, "Mode"));
1272 DBG("adapter %s name %s address %s powered %d mode %s",
1273 iwdd->adapter, iwdd->name, iwdd->address,
1274 iwdd->powered, iwdd->mode);
1276 g_dbus_proxy_set_property_watch(iwdd->proxy,
1277 device_property_change, NULL);
1279 add_device(path, iwdd);
1282 static void unregister_agent();
1284 static DBusMessage *agent_release_method(DBusConnection *dbus_conn,
1285 DBusMessage *message, void *user_data)
1288 return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
1291 static DBusMessage *get_reply_on_error(DBusMessage *message, int error)
1293 return g_dbus_create_error(message,
1294 IWD_AGENT_ERROR_INTERFACE ".Failed", "Invalid parameters");
1297 static DBusMessage *agent_request_passphrase(DBusConnection *dbus_conn,
1298 DBusMessage *message,
1301 struct iwd_network *iwdn;
1302 DBusMessageIter iter;
1303 const char *path, *passwd;
1307 dbus_message_iter_init(message, &iter);
1309 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
1310 return get_reply_on_error(message, EINVAL);
1312 dbus_message_iter_get_basic(&iter, &path);
1314 iwdn = g_hash_table_lookup(networks, path);
1316 return get_reply_on_error(message, EINVAL);
1318 passwd = connman_network_get_string(iwdn->network, "WiFi.Passphrase");
1320 return g_dbus_create_reply(message, DBUS_TYPE_STRING, &passwd,
1324 static DBusMessage *agent_cancel(DBusConnection *dbus_conn,
1325 DBusMessage *message, void *user_data)
1327 DBusMessageIter iter;
1330 dbus_message_iter_init(message, &iter);
1332 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1333 return get_reply_on_error(message, EINVAL);
1335 dbus_message_iter_get_basic(&iter, &reason);
1337 DBG("cancel: %s", reason);
1340 * We don't have to do anything here, because we asked the
1341 * user upfront for the passphrase. So
1342 * agent_request_passphrase() will always send a passphrase
1346 return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
1349 static const GDBusMethodTable agent_methods[] = {
1350 { GDBUS_METHOD("Release", NULL, NULL, agent_release_method) },
1351 { GDBUS_METHOD("RequestPassphrase",
1352 GDBUS_ARGS({ "path", "o" }),
1353 GDBUS_ARGS({ "passphrase", "s" }),
1354 agent_request_passphrase)},
1355 { GDBUS_METHOD("Cancel",
1356 GDBUS_ARGS({ "reason", "s" }),
1357 NULL, agent_cancel) },
1361 static void agent_register_builder(DBusMessageIter *iter, void *user_data)
1363 const char *path = AGENT_PATH;
1365 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
1369 static void register_agent(GDBusProxy *proxy)
1371 if (!g_dbus_proxy_method_call(proxy,
1373 agent_register_builder,
1377 agent_proxy = g_dbus_proxy_ref(proxy);
1380 static void unregister_agent()
1385 g_dbus_proxy_method_call(agent_proxy,
1387 agent_register_builder,
1390 g_dbus_proxy_unref(agent_proxy);
1394 static void iwd_is_present(DBusConnection *conn, void *user_data)
1396 if (agent_registered)
1399 if (!g_dbus_register_interface(connection, AGENT_PATH,
1400 IWD_AGENT_INTERFACE, agent_methods,
1401 NULL, NULL, NULL, NULL))
1404 agent_registered = true;
1407 static void iwd_is_out(DBusConnection *conn, void *user_data)
1409 if (agent_registered) {
1410 g_dbus_unregister_interface(connection,
1411 AGENT_PATH, IWD_AGENT_INTERFACE);
1412 agent_registered = false;
1416 static void create_network(GDBusProxy *proxy)
1418 const char *path = g_dbus_proxy_get_path(proxy);
1419 struct iwd_network *iwdn;
1421 iwdn = g_try_new0(struct iwd_network, 1);
1424 connman_error("Out of memory creating IWD network");
1428 iwdn->path = g_strdup(path);
1429 g_hash_table_replace(networks, iwdn->path, iwdn);
1431 iwdn->proxy = g_dbus_proxy_ref(proxy);
1434 connman_error("Cannot create IWD network watcher %s", path);
1435 g_hash_table_remove(networks, path);
1439 iwdn->device = g_strdup(proxy_get_string(proxy, "Device"));
1440 iwdn->name = g_strdup(proxy_get_string(proxy, "Name"));
1441 iwdn->type = g_strdup(proxy_get_string(proxy, "Type"));
1442 iwdn->connected = proxy_get_bool(proxy, "Connected");
1443 iwdn->known_network = g_strdup(proxy_get_string(proxy, "KnownNetwork"));
1445 DBG("device %s name '%s' type %s connected %d known_network %s",
1446 iwdn->device, iwdn->name, iwdn->type, iwdn->connected,
1447 iwdn->known_network);
1449 g_dbus_proxy_set_property_watch(iwdn->proxy,
1450 network_property_change, NULL);
1452 add_network(path, iwdn);
1455 struct auto_connect_cb_data {
1460 static void auto_connect_cb_free(struct auto_connect_cb_data *cbd)
1466 static void auto_connect_cb(const DBusError *error, void *user_data)
1468 struct auto_connect_cb_data *cbd = user_data;
1469 struct iwd_known_network *iwdkn;
1471 iwdkn = g_hash_table_lookup(known_networks, cbd->path);
1475 if (dbus_error_is_set(error))
1476 connman_warn("WiFi known network %s property auto connect %s",
1477 cbd->path, error->message);
1479 /* property is updated via watch known_network_property_change() */
1481 auto_connect_cb_free(cbd);
1484 static int set_auto_connect(struct iwd_known_network *iwdkn, bool auto_connect)
1486 dbus_bool_t dbus_auto_connect = auto_connect;
1487 struct auto_connect_cb_data *cbd;
1489 if (proxy_get_bool(iwdkn->proxy, "AutoConnect") == auto_connect)
1492 cbd = g_new(struct auto_connect_cb_data, 1);
1493 cbd->path = g_strdup(iwdkn->path);
1494 cbd->auto_connect = auto_connect;
1496 if (!g_dbus_proxy_set_property_basic(iwdkn->proxy, "AutoConnect",
1499 auto_connect_cb, cbd, NULL)) {
1500 auto_connect_cb_free(cbd);
1504 return -EINPROGRESS;
1507 static gboolean disable_auto_connect_cb(gpointer data)
1510 struct iwd_known_network *iwdkn;
1512 iwdkn = g_hash_table_lookup(known_networks, path);
1516 if (set_auto_connect(iwdkn, false) != -EINPROGRESS)
1517 connman_warn("Failed to disable auto connect");
1519 iwdkn->auto_connect_id = 0;
1523 static void disable_auto_connect(struct iwd_known_network *iwdkn)
1525 if (iwdkn->auto_connect_id)
1528 iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
1530 disable_auto_connect_cb,
1531 g_strdup(iwdkn->path),
1535 static void known_network_property_change(GDBusProxy *proxy, const char *name,
1536 DBusMessageIter *iter, void *user_data)
1538 struct iwd_known_network *iwdkn;
1541 path = g_dbus_proxy_get_path(proxy);
1542 iwdkn = g_hash_table_lookup(known_networks, path);
1546 if (!strcmp(name, "AutoConnect")) {
1547 dbus_bool_t auto_connect;
1549 dbus_message_iter_get_basic(iter, &auto_connect);
1550 iwdkn->auto_connect = auto_connect;
1552 DBG("%p auto_connect %d", path, iwdkn->auto_connect);
1554 if (iwdkn->auto_connect)
1555 disable_auto_connect(iwdkn);
1559 static void create_know_network(GDBusProxy *proxy)
1561 const char *path = g_dbus_proxy_get_path(proxy);
1562 struct iwd_known_network *iwdkn;
1564 iwdkn = g_try_new0(struct iwd_known_network, 1);
1566 connman_error("Out of memory creating IWD known network");
1570 iwdkn->path = g_strdup(path);
1571 g_hash_table_replace(known_networks, iwdkn->path, iwdkn);
1573 iwdkn->proxy = g_dbus_proxy_ref(proxy);
1575 if (!iwdkn->proxy) {
1576 connman_error("Cannot create IWD known network watcher %s", path);
1577 g_hash_table_remove(known_networks, path);
1581 iwdkn->name = g_strdup(proxy_get_string(proxy, "Name"));
1582 iwdkn->type = g_strdup(proxy_get_string(proxy, "Type"));
1583 iwdkn->hidden = proxy_get_bool(proxy, "Hidden");
1584 iwdkn->last_connected_time =
1585 g_strdup(proxy_get_string(proxy, "LastConnectedTime"));
1586 iwdkn->auto_connect = proxy_get_bool(proxy, "AutoConnect");
1588 DBG("name '%s' type %s hidden %d, last_connection_time %s auto_connect %d",
1589 iwdkn->name, iwdkn->type, iwdkn->hidden,
1590 iwdkn->last_connected_time, iwdkn->auto_connect);
1592 g_dbus_proxy_set_property_watch(iwdkn->proxy,
1593 known_network_property_change, NULL);
1595 if (iwdkn->auto_connect)
1596 disable_auto_connect(iwdkn);
1599 static void create_station(GDBusProxy *proxy)
1601 const char *path = g_dbus_proxy_get_path(proxy);
1602 struct iwd_station *iwds;
1604 iwds = g_try_new0(struct iwd_station, 1);
1606 connman_error("Out of memory creating IWD station");
1610 iwds->path = g_strdup(path);
1611 g_hash_table_replace(stations, iwds->path, iwds);
1613 iwds->proxy = g_dbus_proxy_ref(proxy);
1616 connman_error("Cannot create IWD station watcher %s", path);
1617 g_hash_table_remove(stations, path);
1621 iwds->state = g_strdup(proxy_get_string(proxy, "State"));
1622 iwds->connected_network = g_strdup(proxy_get_string(proxy, "ConnectedNetwork"));
1623 iwds->scanning = proxy_get_bool(proxy, "Scanning");
1625 DBG("state '%s' connected_network %s scanning %d",
1626 iwds->state, iwds->connected_network, iwds->scanning);
1628 g_dbus_proxy_set_property_watch(iwds->proxy,
1629 station_property_change, NULL);
1632 static void create_ap(GDBusProxy *proxy)
1634 const char *path = g_dbus_proxy_get_path(proxy);
1635 struct iwd_ap *iwdap;
1637 iwdap = g_try_new0(struct iwd_ap, 1);
1639 connman_error("Out of memory creating IWD access point");
1644 iwdap->path = g_strdup(path);
1645 g_hash_table_replace(access_points, iwdap->path, iwdap);
1647 iwdap->proxy = g_dbus_proxy_ref(proxy);
1649 if (!iwdap->proxy) {
1650 connman_error("Cannot create IWD access point watcher %s", path);
1651 g_hash_table_remove(access_points, path);
1655 iwdap->started = proxy_get_bool(proxy, "Started");
1657 DBG("started %d", iwdap->started);
1659 g_dbus_proxy_set_property_watch(iwdap->proxy,
1660 ap_property_change, NULL);
1663 static void object_added(GDBusProxy *proxy, void *user_data)
1665 const char *interface;
1667 interface = g_dbus_proxy_get_interface(proxy);
1669 connman_warn("Interface or proxy missing when adding "
1674 DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
1676 if (!strcmp(interface, IWD_AGENT_MANAGER_INTERFACE))
1677 register_agent(proxy);
1678 else if (!strcmp(interface, IWD_ADAPTER_INTERFACE))
1679 create_adapter(proxy);
1680 else if (!strcmp(interface, IWD_DEVICE_INTERFACE))
1681 create_device(proxy);
1682 else if (!strcmp(interface, IWD_NETWORK_INTERFACE))
1683 create_network(proxy);
1684 else if (!strcmp(interface, IWD_KNOWN_NETWORK_INTERFACE))
1685 create_know_network(proxy);
1686 else if (!strcmp(interface, IWD_STATION_INTERFACE))
1687 create_station(proxy);
1688 else if (!strcmp(interface, IWD_AP_INTERFACE))
1692 static void object_removed(GDBusProxy *proxy, void *user_data)
1694 const char *interface, *path;
1696 interface = g_dbus_proxy_get_interface(proxy);
1698 connman_warn("Interface or proxy missing when removing "
1703 path = g_dbus_proxy_get_path(proxy);
1704 DBG("%s %s", interface, path);
1706 if (!strcmp(interface, IWD_AGENT_MANAGER_INTERFACE))
1708 if (!strcmp(interface, IWD_ADAPTER_INTERFACE))
1709 g_hash_table_remove(adapters, path);
1710 else if (!strcmp(interface, IWD_DEVICE_INTERFACE))
1711 g_hash_table_remove(devices, path);
1712 else if (!strcmp(interface, IWD_NETWORK_INTERFACE))
1713 g_hash_table_remove(networks, path);
1714 else if (!strcmp(interface, IWD_KNOWN_NETWORK_INTERFACE))
1715 g_hash_table_remove(known_networks, path);
1716 else if (!strcmp(interface, IWD_STATION_INTERFACE))
1717 g_hash_table_remove(stations, path);
1718 else if (!strcmp(interface, IWD_AP_INTERFACE))
1719 g_hash_table_remove(access_points, path);
1722 static int iwd_init(void)
1724 connection = connman_dbus_get_connection();
1728 adapters = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1731 devices = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1734 networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1737 known_networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1738 known_network_free);
1740 stations = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1743 access_points = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1746 if (connman_technology_driver_register(&tech_driver) < 0) {
1747 connman_warn("Failed to initialize technology for IWD");
1751 if (connman_device_driver_register(&device_driver) < 0) {
1752 connman_warn("Failed to initialize device driver for "
1754 connman_technology_driver_unregister(&tech_driver);
1758 if (connman_network_driver_register(&network_driver) < 0) {
1759 connman_technology_driver_unregister(&tech_driver);
1760 connman_device_driver_unregister(&device_driver);
1764 client = g_dbus_client_new(connection, IWD_SERVICE, IWD_PATH);
1766 connman_warn("Failed to initialize D-Bus client for "
1771 g_dbus_client_set_connect_watch(client, iwd_is_present, NULL);
1772 g_dbus_client_set_disconnect_watch(client, iwd_is_out, NULL);
1773 g_dbus_client_set_proxy_handlers(client, object_added, object_removed,
1780 g_hash_table_destroy(devices);
1783 g_hash_table_destroy(networks);
1786 g_hash_table_destroy(known_networks);
1789 g_hash_table_destroy(stations);
1792 g_hash_table_destroy(access_points);
1795 g_hash_table_destroy(adapters);
1798 dbus_connection_unref(connection);
1803 static void iwd_exit(void)
1805 connman_network_driver_unregister(&network_driver);
1806 connman_device_driver_unregister(&device_driver);
1807 connman_technology_driver_unregister(&tech_driver);
1809 g_dbus_client_unref(client);
1811 g_hash_table_destroy(access_points);
1812 g_hash_table_destroy(stations);
1813 g_hash_table_destroy(known_networks);
1814 g_hash_table_destroy(networks);
1815 g_hash_table_destroy(devices);
1816 g_hash_table_destroy(adapters);
1818 dbus_connection_unref(connection);
1821 CONNMAN_PLUGIN_DEFINE(iwd, "IWD plugin", VERSION,
1822 CONNMAN_PLUGIN_PRIORITY_DEFAULT, iwd_init, iwd_exit)