/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include "nm-device.h" #include "nm-access-point.h" #define NM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE, NmDevicePrivate)) /** * NmDevicePrivate: * * Private #NmDevice data **/ struct _NmDevicePrivate { GCancellable *cancellable; gchar *active_access_point; gchar *dhcp4_config; gchar *ip4_config; gchar *ip4_address; gchar *ip4_nameserver; gchar *ip4_route; gchar *ip4_subnet_mask; gchar *ip6_config; gchar *ip6_address; gchar *ip6_nameserver; gchar *ip6_route; gchar *mac_address; gchar *modem_imei; gchar *object_path; gchar *operator_name; gchar *speed; gchar *udi; GPtrArray *access_points; NmDeviceKind kind; NmDeviceState state; GDBusProxy *proxy; GDBusProxy *proxy_additional; GDBusProxy *proxy_dhcp4; GDBusProxy *proxy_ip4; GDBusProxy *proxy_ip6; guint device_add_refcount; }; enum { SIGNAL_READY, SIGNAL_CHANGED, SIGNAL_LAST }; enum { PROP_0, PROP_LAST }; static guint signals[SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE (NmDevice, nm_device, G_TYPE_OBJECT) /** * nm_device_kind_to_icon_name: **/ const gchar * nm_device_kind_to_icon_name (NmDeviceKind type) { const gchar *value = NULL; switch (type) { case NM_DEVICE_KIND_ETHERNET: value = "network-wired"; break; case NM_DEVICE_KIND_WIFI: case NM_DEVICE_KIND_GSM: case NM_DEVICE_KIND_CDMA: case NM_DEVICE_KIND_BLUETOOTH: case NM_DEVICE_KIND_MESH: value = "network-wireless"; break; default: break; } return value; } /** * nm_device_kind_to_localized_string: **/ const gchar * nm_device_kind_to_localized_string (NmDeviceKind type) { const gchar *value = NULL; switch (type) { case NM_DEVICE_KIND_UNKNOWN: /* TRANSLATORS: device type */ value = _("Unknown"); break; case NM_DEVICE_KIND_ETHERNET: /* TRANSLATORS: device type */ value = _("Wired"); break; case NM_DEVICE_KIND_WIFI: /* TRANSLATORS: device type */ value = _("Wireless"); break; case NM_DEVICE_KIND_GSM: case NM_DEVICE_KIND_CDMA: /* TRANSLATORS: device type */ value = _("Mobile broadband"); break; case NM_DEVICE_KIND_BLUETOOTH: /* TRANSLATORS: device type */ value = _("Bluetooth"); break; case NM_DEVICE_KIND_MESH: /* TRANSLATORS: device type */ value = _("Mesh"); break; default: break; } return value; } /** * nm_device_kind_to_sortable_string: * * Try to return order of approximate connection speed. **/ const gchar * nm_device_kind_to_sortable_string (NmDeviceKind type) { const gchar *value = NULL; switch (type) { case NM_DEVICE_KIND_ETHERNET: value = "1"; break; case NM_DEVICE_KIND_WIFI: value = "2"; break; case NM_DEVICE_KIND_GSM: case NM_DEVICE_KIND_CDMA: value = "3"; break; case NM_DEVICE_KIND_BLUETOOTH: value = "4"; break; case NM_DEVICE_KIND_MESH: value = "5"; break; default: value = "6"; break; } return value; } /** * nm_device_state_to_localized_string: **/ const gchar * nm_device_state_to_localized_string (NmDeviceState type) { const gchar *value = NULL; switch (type) { case NM_DEVICE_STATE_UNKNOWN: /* TRANSLATORS: device status */ value = _("Status unknown"); break; case NM_DEVICE_STATE_UNMANAGED: /* TRANSLATORS: device status */ value = _("Unmanaged"); break; case NM_DEVICE_STATE_UNAVAILABLE: /* TRANSLATORS: device status */ value = _("Unavailable"); break; case NM_DEVICE_STATE_DISCONNECTED: /* TRANSLATORS: device status */ value = _("Disconnected"); break; case NM_DEVICE_STATE_PREPARE: /* TRANSLATORS: device status */ value = _("Preparing connection"); break; case NM_DEVICE_STATE_CONFIG: /* TRANSLATORS: device status */ value = _("Configuring connection"); break; case NM_DEVICE_STATE_NEED_AUTH: /* TRANSLATORS: device status */ value = _("Authenticating"); break; case NM_DEVICE_STATE_IP_CONFIG: /* TRANSLATORS: device status */ value = _("Getting network address"); break; case NM_DEVICE_STATE_ACTIVATED: /* TRANSLATORS: device status */ value = _("Connected"); break; case NM_DEVICE_STATE_FAILED: /* TRANSLATORS: device status */ value = _("Failed to connect"); break; default: break; } return value; } /** * nm_device_get_object_path: **/ const gchar * nm_device_get_object_path (NmDevice *device) { g_return_val_if_fail (NM_IS_DEVICE (device), NULL); return device->priv->object_path; } /** * nm_device_get_object_path: **/ GPtrArray * nm_device_get_access_points (NmDevice *device) { g_return_val_if_fail (NM_IS_DEVICE (device), NULL); return g_ptr_array_ref (device->priv->access_points); } /** * nm_device_get_active_access_point: **/ const gchar * nm_device_get_active_access_point (NmDevice *device) { g_return_val_if_fail (NM_IS_DEVICE (device), NULL); return device->priv->active_access_point; } /** * nm_device_get_from_options: **/ static const gchar * nm_device_get_from_options (GVariant *variant, const gchar *key) { const gchar *prop_key; const gchar *value = NULL; GVariantIter *iter = NULL; GVariant *prop_value; /* insert the new metadata */ g_variant_get (variant, "a{sv}", &iter); if (iter == NULL) goto out; while (g_variant_iter_loop (iter, "{sv}", &prop_key, &prop_value)) { if (g_strcmp0 (prop_key, key) == 0) { value = g_variant_get_string (prop_value, NULL); break; } } out: return value; } /** * nm_device_ipv6_to_string: * * Formats an 'ay' variant into a IPv6 address you recognise, e.g. * "fe80::21c:bfff:fe81:e8de" **/ static gchar * nm_device_ipv6_to_string (GVariant *variant) { gchar tmp1; gchar tmp2; guint i = 0; gboolean ret = FALSE; GString *string; if (g_variant_n_children (variant) != 16) return NULL; string = g_string_new (""); for (i=0; i<16; i+=2) { g_variant_get_child (variant, i+0, "y", &tmp1); g_variant_get_child (variant, i+1, "y", &tmp2); if (tmp1 == 0 && tmp2 == 0) { if (!ret) { g_string_append (string, ":"); ret = TRUE; } } else { g_string_append_printf (string, "%x%x%x%x:", (tmp1 & 0xf0) / 16, tmp1 & 0x0f, (tmp2 & 0xf0) / 16, tmp2 & 0x0f); ret = FALSE; } } g_string_set_size (string, string->len - 1); return g_string_free (string, FALSE); } /** * nm_device_ipv6_prefixed_array_to_string: * * This is some crazy shit. NM sends us the following data type: * "array of [struct of (array of [byte], uint32, array of [byte])]" **/ static gchar * nm_device_ipv6_prefixed_array_to_string (GVariant *variant) { GString *string; gchar *tmp; GVariant *outer; GVariantIter iter; gsize len; GVariant *address; guint32 prefix; string = g_string_new (""); /* get an iter of the outer array */ len = g_variant_iter_init (&iter, variant); if (len == 0) { g_debug ("no ipv6 address"); goto out; } /* unwrap the outer array */ outer = g_variant_iter_next_value (&iter); while (outer != NULL) { /* format the address and add to the string */ address = g_variant_get_child_value (outer, 0); tmp = nm_device_ipv6_to_string (address); g_variant_get_child (outer, 1, "u", &prefix); g_string_append_printf (string, "%s/%i, ", tmp, prefix); outer = g_variant_iter_next_value (&iter); } /* remove trailing space comma */ if (string->len > 2) g_string_set_size (string, string->len - 2); out: return g_string_free (string, FALSE); } /** * nm_device_ipv6_array_to_string: * * NM sends us the following data type: * "array of [array of (byte)]" **/ static gchar * nm_device_ipv6_array_to_string (GVariant *variant) { GString *string; gchar *tmp; GVariantIter iter; gsize len; GVariant *address; string = g_string_new (""); /* get an iter of the outer array */ len = g_variant_iter_init (&iter, variant); if (len == 0) { g_debug ("no ipv6 address"); goto out; } /* unwrap the outer array */ address = g_variant_iter_next_value (&iter); while (address != NULL) { /* format the address and add to the string */ tmp = nm_device_ipv6_to_string (address); g_string_append_printf (string, "%s, ", tmp); address = g_variant_iter_next_value (&iter); } /* remove trailing space comma */ if (string->len > 2) g_string_set_size (string, string->len - 2); out: return g_string_free (string, FALSE); } /** * nm_device_get_ip6_address: **/ const gchar * nm_device_get_ip6_address (NmDevice *device) { GVariant *value = NULL; g_return_val_if_fail (NM_IS_DEVICE (device), NULL); /* invalidate */ g_free (device->priv->ip6_address); device->priv->ip6_address = NULL; /* array of (ipdata, prefix, route) */ if (device->priv->proxy_ip6 == NULL) goto out; value = g_dbus_proxy_get_cached_property (device->priv->proxy_ip6, "Addresses"); device->priv->ip6_address = nm_device_ipv6_prefixed_array_to_string (value); out: if (value != NULL) g_variant_unref (value); return device->priv->ip6_address; } /** * nm_device_get_ip6_nameserver: **/ const gchar * nm_device_get_ip6_nameserver (NmDevice *device) { GVariant *value = NULL; g_return_val_if_fail (NM_IS_DEVICE (device), NULL); /* invalidate */ g_free (device->priv->ip6_nameserver); device->priv->ip6_nameserver = NULL; /* array of ipdata */ if (device->priv->proxy_ip6 == NULL) goto out; value = g_dbus_proxy_get_cached_property (device->priv->proxy_ip6, "Nameservers"); device->priv->ip6_nameserver = nm_device_ipv6_array_to_string (value); out: if (value != NULL) g_variant_unref (value); return device->priv->ip6_nameserver; } /** * nm_device_get_ip6_route: **/ const gchar * nm_device_get_ip6_route (NmDevice *device) { GVariant *value = NULL; g_return_val_if_fail (NM_IS_DEVICE (device), NULL); /* invalidate */ g_free (device->priv->ip6_route); device->priv->ip6_route = NULL; /* array of (ipdata, prefix, route) */ if (device->priv->proxy_ip6 == NULL) goto out; value = g_dbus_proxy_get_cached_property (device->priv->proxy_ip6, "Routes"); device->priv->ip6_route = nm_device_ipv6_prefixed_array_to_string (value); out: if (value != NULL) g_variant_unref (value); return device->priv->ip6_route; } /** * nm_device_ipv4_to_string: **/ static gchar * nm_device_ipv4_to_string (GVariant *variant) { gchar *ip_str; guint32 ip; g_variant_get (variant, "u", &ip); ip_str = g_strdup_printf ("%i.%i.%i.%i", ip & 0x000000ff, (ip & 0x0000ff00) / 0x100, (ip & 0x00ff0000) / 0x10000, (ip & 0xff000000) / 0x1000000); return ip_str; } /** * nm_device_ipv4_array_to_string_array: * * This is some crazy shit. NM sends us the following data type: * "array of [array of [uint32]]" **/ static gchar * nm_device_ipv4_array_to_string_array (GVariant *variant) { gchar *tmp; gsize len; GString *string; guint i; GVariantIter iter; GVariant *outer; GVariant *value; string = g_string_new (""); /* get an iter of the outer array */ len = g_variant_iter_init (&iter, variant); /* unwrap the outer array */ outer = g_variant_iter_next_value (&iter); while (outer != NULL) { /* unwrap the inner array */ len = g_variant_n_children (outer); if (len == 0) { g_warning ("invalid ipv4 address on inner?!"); goto out; } for (i=0; ilen > 2) g_string_set_size (string, string->len - 2); out: return g_string_free (string, FALSE); } /** * nm_device_ipv4_array_to_string: * * TNM sends us the following data type "array of [uint32]" **/ static gchar * nm_device_ipv4_array_to_string (GVariant *variant) { gchar *tmp; gsize len; GString *string; guint i; GVariant *value; string = g_string_new (""); /* unwrap the array */ len = g_variant_n_children (variant); if (len == 0) { g_warning ("invalid ipv4 address on inner?!"); goto out; } for (i=0; ilen > 2) g_string_set_size (string, string->len - 2); out: return g_string_free (string, FALSE); } /** * nm_device_get_ip4_address: **/ const gchar * nm_device_get_ip4_address (NmDevice *device) { const gchar *tmp; GVariant *options = NULL; GVariant *value = NULL; g_return_val_if_fail (NM_IS_DEVICE (device), NULL); /* invalidate */ g_free (device->priv->ip4_address); device->priv->ip4_address = NULL; /* set from DHCPv4 */ if (device->priv->proxy_dhcp4 != NULL) { options = g_dbus_proxy_get_cached_property (device->priv->proxy_dhcp4, "Options"); if (options != NULL) { tmp = nm_device_get_from_options (options, "ip_address"); device->priv->ip4_address = g_strdup (tmp); goto out; } } /* set IPv4 */ if (device->priv->proxy_ip4 != NULL) { /* array of (array of uint32) */ value = g_dbus_proxy_get_cached_property (device->priv->proxy_ip4, "Addresses"); device->priv->ip4_address = nm_device_ipv4_array_to_string_array (value); goto out; } out: if (value != NULL) g_variant_unref (value); if (options != NULL) g_variant_unref (options); return device->priv->ip4_address; } /** * nm_device_get_ip4_nameserver: **/ const gchar * nm_device_get_ip4_nameserver (NmDevice *device) { const gchar *tmp; GVariant *options = NULL; GVariant *value = NULL; g_return_val_if_fail (NM_IS_DEVICE (device), NULL); /* invalidate */ g_free (device->priv->ip4_nameserver); device->priv->ip4_nameserver = NULL; /* set from DHCPv4 */ if (device->priv->proxy_dhcp4 != NULL) { options = g_dbus_proxy_get_cached_property (device->priv->proxy_dhcp4, "Options"); if (options != NULL) { tmp = nm_device_get_from_options (options, "domain_name_servers"); device->priv->ip4_nameserver = g_strdup (tmp); goto out; } } /* set IPv4 */ if (device->priv->proxy_ip4 != NULL) { /* array of uint32 */ value = g_dbus_proxy_get_cached_property (device->priv->proxy_ip4, "Nameservers"); device->priv->ip4_nameserver = nm_device_ipv4_array_to_string (value); } out: if (value != NULL) g_variant_unref (value); if (options != NULL) g_variant_unref (options); return device->priv->ip4_nameserver; } /** * nm_device_get_ip4_route: **/ const gchar * nm_device_get_ip4_route (NmDevice *device) { const gchar *tmp; GVariant *options = NULL; GVariant *value = NULL; g_return_val_if_fail (NM_IS_DEVICE (device), NULL); /* invalidate */ g_free (device->priv->ip4_route); device->priv->ip4_route = NULL; /* set from DHCPv4 */ if (device->priv->proxy_dhcp4 != NULL) { options = g_dbus_proxy_get_cached_property (device->priv->proxy_dhcp4, "Options"); if (options != NULL) { tmp = nm_device_get_from_options (options, "routers"); device->priv->ip4_route = g_strdup (tmp); goto out; } } /* set IPv4 */ if (device->priv->proxy_ip4 != NULL) { /* array of (array of uint32) */ value = g_dbus_proxy_get_cached_property (device->priv->proxy_ip4, "Routes"); device->priv->ip4_route = nm_device_ipv4_array_to_string_array (value); } out: if (options != NULL) g_variant_unref (options); if (value != NULL) g_variant_unref (value); return device->priv->ip4_route; } /** * nm_device_get_ip4_subnet_mask: **/ const gchar * nm_device_get_ip4_subnet_mask (NmDevice *device) { const gchar *tmp; GVariant *options = NULL; g_return_val_if_fail (NM_IS_DEVICE (device), NULL); /* invalidate */ g_free (device->priv->ip4_subnet_mask); device->priv->ip4_subnet_mask = NULL; /* set from DHCPv4 */ if (device->priv->proxy_dhcp4 != NULL) { options = g_dbus_proxy_get_cached_property (device->priv->proxy_dhcp4, "Options"); if (options != NULL) { tmp = nm_device_get_from_options (options, "subnet_mask"); device->priv->ip4_subnet_mask = g_strdup (tmp); goto out; } } out: if (options != NULL) g_variant_unref (options); return device->priv->ip4_subnet_mask; } /** * nm_device_get_mac_address: **/ const gchar * nm_device_get_mac_address (NmDevice *device) { GVariant *value; g_return_val_if_fail (NM_IS_DEVICE (device), NULL); /* invalidate */ g_free (device->priv->mac_address); device->priv->mac_address = NULL; /* get HwAddress */ value = g_dbus_proxy_get_cached_property (device->priv->proxy_additional, "HwAddress"); device->priv->mac_address = g_variant_dup_string (value, NULL); g_variant_unref (value); return device->priv->mac_address; } /** * nm_device_get_modem_imei: **/ const gchar * nm_device_get_modem_imei (NmDevice *device) { g_return_val_if_fail (NM_IS_DEVICE (device), NULL); return device->priv->modem_imei; } /** * nm_device_get_operator_name: **/ const gchar * nm_device_get_operator_name (NmDevice *device) { g_return_val_if_fail (NM_IS_DEVICE (device), NULL); return device->priv->operator_name; } /** * nm_device_value_to_string_bitrate: **/ static gchar * nm_device_value_to_string_bitrate (GVariant *variant) { guint bitrate; gchar *tmp; /* format with correct scale */ g_variant_get (variant, "u", &bitrate); if (bitrate < 1000) { tmp = g_strdup_printf (_("%i kb/s"), bitrate); } else { tmp = g_strdup_printf (_("%i Mb/s"), bitrate / 1000); } return tmp; } /** * nm_device_value_to_string_speed: **/ static gchar * nm_device_value_to_string_speed (GVariant *variant) { guint speed; gchar *tmp; /* format with correct scale */ g_variant_get (variant, "u", &speed); if (speed < 1000) { tmp = g_strdup_printf (_("%i Mb/s"), speed); } else { tmp = g_strdup_printf (_("%i Gb/s"), speed / 1000); } return tmp; } /** * nm_device_get_speed: **/ const gchar * nm_device_get_speed (NmDevice *device) { GVariant *value; g_return_val_if_fail (NM_IS_DEVICE (device), NULL); /* invalidate */ g_free (device->priv->speed); device->priv->speed = NULL; value = g_dbus_proxy_get_cached_property (device->priv->proxy_additional, "Speed"); if (value != NULL) { device->priv->speed = nm_device_value_to_string_speed (value); goto out; } value = g_dbus_proxy_get_cached_property (device->priv->proxy_additional, "Bitrate"); if (value != NULL) { device->priv->speed = nm_device_value_to_string_bitrate (value); goto out; } out: return device->priv->speed; } /** * nm_device_get_kind: **/ NmDeviceKind nm_device_get_kind (NmDevice *device) { g_return_val_if_fail (NM_IS_DEVICE (device), 0); return device->priv->kind; } /** * nm_device_get_state: **/ NmDeviceState nm_device_get_state (NmDevice *device) { GVariant *variant_state; g_return_val_if_fail (NM_IS_DEVICE (device), 0); variant_state = g_dbus_proxy_get_cached_property (device->priv->proxy, "State"); g_variant_get (variant_state, "u", &device->priv->state); g_variant_unref (variant_state); return device->priv->state; } /** * nm_device_emit_ready: **/ static void nm_device_emit_ready (NmDevice *device) { g_debug ("NmDevice: emit 'ready' for %s", device->priv->object_path); g_signal_emit (device, signals[SIGNAL_READY], 0); } /** * nm_device_emit_changed: **/ static void nm_device_emit_changed (NmDevice *device) { g_debug ("NmDevice: emit 'changed' for %s", device->priv->object_path); g_signal_emit (device, signals[SIGNAL_CHANGED], 0); } /** * nm_device_get_active_access_point_data: **/ static void nm_device_get_active_access_point_data (NmDevice *device, const gchar *access_point_id) { NmAccessPoint *access_point; access_point = nm_access_point_new (); g_ptr_array_add (device->priv->access_points, access_point); nm_access_point_refresh (access_point, access_point_id, device->priv->cancellable); } /** * nm_device_get_access_points_cb: **/ static void nm_device_get_access_points_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { const gchar *object_path; GError *error = NULL; gsize len; GVariantIter iter; GVariant *result = NULL; GVariant *test; NmDevice *device = (NmDevice *) user_data; result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (result == NULL) { g_printerr ("Error getting access points: %s\n", error->message); g_error_free (error); return; } /* clear list of access points */ g_ptr_array_set_size (device->priv->access_points, 0); test = g_variant_get_child_value (result, 0); len = g_variant_iter_init (&iter, test); if (len == 0) { g_warning ("no access points?!"); goto out; } /* for each entry in the array */ while (g_variant_iter_loop (&iter, "o", &object_path)) { g_debug ("adding access point %s", object_path); nm_device_get_active_access_point_data (device, object_path); } /* emit */ nm_device_emit_changed (device); out: g_variant_unref (result); g_variant_unref (test); } /** * nm_device_get_registration_info_cb: **/ static void nm_device_get_registration_info_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { gchar *operator_code = NULL; GError *error = NULL; guint registration_status; GVariant *result = NULL; NmDevice *device = (NmDevice *) user_data; result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (result == NULL) { g_printerr ("Error getting registration info: %s\n", error->message); g_error_free (error); return; } /* get values */ g_variant_get (result, "((uss))", ®istration_status, &operator_code, &device->priv->operator_name); g_free (operator_code); g_variant_unref (result); } /** * nm_device_got_device_proxy_modem_manager_gsm_network_cb: **/ static void nm_device_got_device_proxy_modem_manager_gsm_network_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; GVariant *result = NULL; NmDevice *device = (NmDevice *) user_data; device->priv->proxy_additional = g_dbus_proxy_new_for_bus_finish (res, &error); if (device->priv->proxy_additional == NULL) { g_printerr ("Error creating additional proxy: %s\n", error->message); g_error_free (error); goto out; } /* get the currently active access point */ result = g_dbus_proxy_get_cached_property (device->priv->proxy_additional, "AccessTechnology"); // device->priv->active_access_point = g_variant_dup_string (result, NULL); g_dbus_proxy_call (device->priv->proxy_additional, "GetRegistrationInfo", NULL, G_DBUS_CALL_FLAGS_NONE, -1, device->priv->cancellable, nm_device_get_registration_info_cb, device); /* add device if there are no more pending actions */ if (--device->priv->device_add_refcount == 0) nm_device_emit_ready (device); out: if (result != NULL) g_variant_unref (result); return; } /** * nm_device_got_device_proxy_modem_manager_cb: **/ static void nm_device_got_device_proxy_modem_manager_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; GVariant *result = NULL; NmDevice *device = (NmDevice *) user_data; device->priv->proxy_additional = g_dbus_proxy_new_for_bus_finish (res, &error); if (device->priv->proxy_additional == NULL) { g_printerr ("Error creating additional proxy: %s\n", error->message); g_error_free (error); goto out; } /* get the IMEI */ result = g_dbus_proxy_get_cached_property (device->priv->proxy_additional, "EquipmentIdentifier"); device->priv->modem_imei = g_variant_dup_string (result, NULL); /* add device if there are no more pending actions */ if (--device->priv->device_add_refcount == 0) nm_device_emit_ready (device); out: if (result != NULL) g_variant_unref (result); return; } /** * nm_device_got_device_proxy_additional_cb: **/ static void nm_device_got_device_proxy_additional_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; GVariant *result = NULL; NmDevice *device = (NmDevice *) user_data; device->priv->proxy_additional = g_dbus_proxy_new_for_bus_finish (res, &error); if (device->priv->proxy_additional == NULL) { g_printerr ("Error creating additional proxy: %s\n", error->message); g_error_free (error); goto out; } /* async populate the list of access points */ if (device->priv->kind == NM_DEVICE_KIND_WIFI) { /* get the currently active access point */ result = g_dbus_proxy_get_cached_property (device->priv->proxy_additional, "ActiveAccessPoint"); device->priv->active_access_point = g_variant_dup_string (result, NULL); g_dbus_proxy_call (device->priv->proxy_additional, "GetAccessPoints", NULL, G_DBUS_CALL_FLAGS_NONE, -1, device->priv->cancellable, nm_device_get_access_points_cb, device); } /* add device if there are no more pending actions */ if (--device->priv->device_add_refcount == 0) nm_device_emit_ready (device); out: if (result != NULL) g_variant_unref (result); return; } /** * nm_device_got_device_proxy_ip4_cb: **/ static void nm_device_got_device_proxy_ip4_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; NmDevice *device = (NmDevice *) user_data; device->priv->proxy_ip4 = g_dbus_proxy_new_for_bus_finish (res, &error); if (device->priv->proxy_ip4 == NULL) { g_printerr ("Error creating ip4 proxy: %s\n", error->message); g_error_free (error); goto out; } /* add device if there are no more pending actions */ if (--device->priv->device_add_refcount == 0) nm_device_emit_ready (device); out: return; } /** * nm_device_got_device_proxy_dhcp4_cb: **/ static void nm_device_got_device_proxy_dhcp4_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; NmDevice *device = (NmDevice *) user_data; device->priv->proxy_dhcp4 = g_dbus_proxy_new_for_bus_finish (res, &error); if (device->priv->proxy_dhcp4 == NULL) { g_printerr ("Error creating dhcp4 proxy: %s\n", error->message); g_error_free (error); goto out; } /* add device if there are no more pending actions */ if (--device->priv->device_add_refcount == 0) nm_device_emit_ready (device); out: return; } /** * nm_device_got_device_proxy_ip6_cb: **/ static void nm_device_got_device_proxy_ip6_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; NmDevice *device = (NmDevice *) user_data; device->priv->proxy_ip6 = g_dbus_proxy_new_for_bus_finish (res, &error); if (device->priv->proxy_ip6 == NULL) { g_printerr ("Error creating ip6 proxy: %s\n", error->message); g_error_free (error); goto out; } /* add device if there are no more pending actions */ if (--device->priv->device_add_refcount == 0) nm_device_emit_ready (device); out: return; } /** * nm_device_properties_changed_cb: **/ static void nm_device_properties_changed_cb (GDBusProxy *proxy, GVariant *changed_properties, const gchar* const *invalidated_properties, gpointer user_data) { NmDevice *device = (NmDevice *) user_data; nm_device_emit_changed (device); } /** * nm_device_got_device_proxy_cb: **/ static void nm_device_got_device_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; GVariant *variant_ip4 = NULL; GVariant *variant_dhcp4 = NULL; GVariant *variant_ip6 = NULL; GVariant *variant_type = NULL; GVariant *variant_udi = NULL; NmDevice *device = (NmDevice *) user_data; device->priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (device->priv->proxy == NULL) { g_printerr ("Error creating proxy: %s\n", error->message); g_error_free (error); goto out; } /* get the UDI, so we can query ModemManager devices */ variant_udi = g_dbus_proxy_get_cached_property (device->priv->proxy, "Udi"); g_variant_get (variant_udi, "s", &device->priv->udi); /* get the IP object paths */ variant_ip4 = g_dbus_proxy_get_cached_property (device->priv->proxy, "Ip4Config"); g_variant_get (variant_ip4, "o", &device->priv->ip4_config); variant_ip6 = g_dbus_proxy_get_cached_property (device->priv->proxy, "Ip6Config"); g_variant_get (variant_ip6, "o", &device->priv->ip6_config); /* get the IP DHCP object paths */ variant_dhcp4 = g_dbus_proxy_get_cached_property (device->priv->proxy, "Dhcp4Config"); g_variant_get (variant_dhcp4, "o", &device->priv->dhcp4_config); /* get the IP information */ if (g_strcmp0 (device->priv->dhcp4_config, "/") != 0) { device->priv->device_add_refcount++; g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.NetworkManager", device->priv->dhcp4_config, "org.freedesktop.NetworkManager.DHCP4Config", device->priv->cancellable, nm_device_got_device_proxy_dhcp4_cb, device); } else if (g_strcmp0 (device->priv->ip4_config, "/") != 0) { device->priv->device_add_refcount++; g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.NetworkManager", device->priv->ip4_config, "org.freedesktop.NetworkManager.IP4Config", device->priv->cancellable, nm_device_got_device_proxy_ip4_cb, device); } if (g_strcmp0 (device->priv->ip6_config, "/") != 0) { device->priv->device_add_refcount++; g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.NetworkManager", device->priv->ip6_config, "org.freedesktop.NetworkManager.IP6Config", device->priv->cancellable, nm_device_got_device_proxy_ip6_cb, device); } /* get the additional interface for this device type */ variant_type = g_dbus_proxy_get_cached_property (device->priv->proxy, "DeviceType"); g_variant_get (variant_type, "u", &device->priv->kind); if (device->priv->kind == NM_DEVICE_KIND_ETHERNET) { device->priv->device_add_refcount++; g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.NetworkManager", device->priv->object_path, "org.freedesktop.NetworkManager.Device.Wired", device->priv->cancellable, nm_device_got_device_proxy_additional_cb, device); } else if (device->priv->kind == NM_DEVICE_KIND_WIFI) { device->priv->device_add_refcount++; g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.NetworkManager", device->priv->object_path, "org.freedesktop.NetworkManager.Device.Wireless", device->priv->cancellable, nm_device_got_device_proxy_additional_cb, device); } else if (device->priv->kind == NM_DEVICE_KIND_GSM || device->priv->kind == NM_DEVICE_KIND_CDMA) { device->priv->device_add_refcount++; g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.ModemManager", device->priv->udi, "org.freedesktop.ModemManager.Modem", device->priv->cancellable, nm_device_got_device_proxy_modem_manager_cb, device); device->priv->device_add_refcount++; g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.ModemManager", device->priv->udi, "org.freedesktop.ModemManager.Modem.Gsm.Network", device->priv->cancellable, nm_device_got_device_proxy_modem_manager_gsm_network_cb, device); } /* add device if there are no more pending actions */ if (--device->priv->device_add_refcount == 0) nm_device_emit_ready (device); /* we want to update the UI */ g_signal_connect (device->priv->proxy, "g-properties-changed", G_CALLBACK (nm_device_properties_changed_cb), device); out: if (variant_ip4 != NULL) g_variant_unref (variant_ip4); if (variant_dhcp4 != NULL) g_variant_unref (variant_dhcp4); if (variant_ip6 != NULL) g_variant_unref (variant_ip6); if (variant_udi != NULL) g_variant_unref (variant_udi); if (variant_type != NULL) g_variant_unref (variant_type); return; } /** * nm_device_refresh: * * 100% async. Object emits ::ready when device has been refreshed **/ void nm_device_refresh (NmDevice *device, const gchar *object_path, GCancellable *cancellable) { device->priv->object_path = g_strdup (object_path); if (cancellable != NULL) device->priv->cancellable = g_object_ref (cancellable); device->priv->device_add_refcount++; g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.NetworkManager", object_path, "org.freedesktop.NetworkManager.Device", device->priv->cancellable, nm_device_got_device_proxy_cb, device); } /** * nm_device_finalize: **/ static void nm_device_finalize (GObject *object) { NmDevice *device = NM_DEVICE (object); NmDevicePrivate *priv = device->priv; if (priv->proxy != NULL) g_object_unref (priv->proxy); if (priv->proxy_additional != NULL) g_object_unref (priv->proxy_additional); if (priv->proxy_ip4 != NULL) g_object_unref (priv->proxy_ip4); if (priv->proxy_ip6 != NULL) g_object_unref (priv->proxy_ip6); if (priv->cancellable != NULL) g_object_unref (priv->cancellable); g_free (priv->active_access_point); g_free (priv->ip4_config); g_free (priv->ip4_address); g_free (priv->ip6_address); g_free (priv->ip6_nameserver); g_free (priv->ip6_route); g_free (priv->ip4_nameserver); g_free (priv->ip4_route); g_free (priv->ip4_subnet_mask); g_free (priv->ip6_config); g_free (priv->mac_address); g_free (priv->modem_imei); g_free (priv->modem_imei); g_free (priv->object_path); g_free (priv->operator_name); g_free (priv->speed); g_free (priv->udi); g_ptr_array_unref (priv->access_points); G_OBJECT_CLASS (nm_device_parent_class)->finalize (object); } /** * nm_device_class_init: **/ static void nm_device_class_init (NmDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = nm_device_finalize; /** * NmDevice::ready: **/ signals[SIGNAL_READY] = g_signal_new ("ready", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NmDeviceClass, ready), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * NmDevice::changed: **/ signals[SIGNAL_CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NmDeviceClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_type_class_add_private (klass, sizeof (NmDevicePrivate)); } /** * nm_device_init: **/ static void nm_device_init (NmDevice *device) { device->priv = NM_DEVICE_GET_PRIVATE (device); device->priv->access_points = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); } /** * nm_device_new: **/ NmDevice * nm_device_new (void) { NmDevice *device; device = g_object_new (NM_TYPE_DEVICE, NULL); return NM_DEVICE (device); }