diff --git a/ChangeLog b/ChangeLog index 73a0f1f923..a4268bf6cf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2005-12-31 Dan Williams + + * refactor NMDevice into a GObject-based framework with separate + objects for wired and wireless. The following files are no + longer used but should stick around for a bit so we don't + loose code through the cracks: + NetworkManagerDevice.c + NetworkManagerDevice.h + NetworkManagerWireless.c + NetworkManagerWireless.h + + The intent here is to allow each device type to manage its own + connection & activation life-cycle, ie to allow wireless devices + to interface with wpa_supplicant, etc. There's a fair bit of + encapsulation breakage right now that should gradually get pulled + back into each device, along with things like periodic property + updates and link probing. + 2005-12-29 Dan Williams * include/NetworkManager.h diff --git a/src/Makefile.am b/src/Makefile.am index 3f33c7a777..0c8a5a1989 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,6 +11,13 @@ INCLUDES = -I${top_srcdir} \ bin_PROGRAMS = NetworkManager NetworkManager_SOURCES = \ + nm-device.c \ + nm-device.h \ + nm-device-private.h \ + nm-device-802-3-ethernet.c \ + nm-device-802-3-ethernet.h \ + nm-device-802-11-wireless.c \ + nm-device-802-11-wireless.h \ NetworkManagerAP.c \ NetworkManagerAP.h \ NetworkManagerAPList.c \ @@ -28,9 +35,6 @@ NetworkManager_SOURCES = \ nm-dbus-net.h \ nm-dbus-nmi.c \ nm-dbus-nmi.h \ - NetworkManagerDevice.c \ - NetworkManagerDevice.h \ - NetworkManagerDevicePrivate.h \ nm-ip4-config.c \ nm-ip4-config.h \ NetworkManager.c \ @@ -39,8 +43,6 @@ NetworkManager_SOURCES = \ NetworkManagerPolicy.h \ NetworkManagerUtils.c \ NetworkManagerUtils.h \ - NetworkManagerWireless.c \ - NetworkManagerWireless.h \ NetworkManagerSystem.c \ NetworkManagerSystem.h \ nm-netlink-monitor.c \ diff --git a/src/NetworkManager.c b/src/NetworkManager.c index 27d8f2533e..77156c20f8 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -36,9 +36,10 @@ #include "NetworkManager.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "nm-device-802-3-ethernet.h" +#include "nm-device-802-11-wireless.h" #include "NetworkManagerPolicy.h" -#include "NetworkManagerWireless.h" #include "NetworkManagerDbus.h" #include "NetworkManagerAP.h" #include "NetworkManagerAPList.h" @@ -143,7 +144,7 @@ NMDevice * nm_create_device_and_add_to_list (NMData *data, const char *udi, cons { /* If we couldn't add the device to our list, free its data. */ nm_warning ("could not acquire device list mutex." ); - nm_device_unref (dev); + g_object_unref (G_OBJECT (dev)); dev = NULL; } } else nm_warning ("could not allocate device data." ); @@ -168,7 +169,7 @@ void nm_remove_device (NMData *data, NMDevice *dev) nm_device_worker_thread_stop (dev); nm_dbus_schedule_device_status_change_signal (data, dev, NULL, DEVICE_REMOVED); - nm_device_unref (dev); + g_object_unref (G_OBJECT (dev)); /* Remove the device entry from the device list and free its data */ data->dev_list = g_slist_remove (data->dev_list, dev); @@ -442,7 +443,7 @@ static void device_stop_and_free (NMDevice *dev, gpointer user_data) nm_device_set_removed (dev, TRUE); nm_device_deactivate (dev); - nm_device_unref (dev); + g_object_unref (G_OBJECT (dev)); } @@ -555,7 +556,7 @@ static gboolean nm_poll_and_update_wireless_link_state (NMData *data) { if ((dev = (NMDevice *)(elt->data))) { - nm_device_ref (dev); + g_object_ref (G_OBJECT (dev)); copy = g_slist_append (copy, dev); } } @@ -568,10 +569,11 @@ static gboolean nm_poll_and_update_wireless_link_state (NMData *data) { if (nm_device_is_802_11_wireless (dev) && !nm_device_is_activating (dev)) { - nm_device_set_link_active (dev, nm_device_probe_link_state (dev)); - nm_device_update_signal_strength (dev); + NMDevice80211Wireless *wdev = NM_DEVICE_802_11_WIRELESS (dev); + nm_device_set_active_link (dev, nm_device_probe_link_state (dev)); + nm_device_802_11_wireless_update_signal_strength (wdev); } - nm_device_unref (dev); + g_object_unref (G_OBJECT (dev)); } } @@ -598,7 +600,7 @@ static void nm_device_link_activated (NmNetlinkMonitor *monitor, const gchar *in if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__)) { if ((dev = nm_get_device_by_iface (data, interface_name))) - nm_device_ref (dev); + g_object_ref (G_OBJECT (dev)); nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); } @@ -607,10 +609,10 @@ static void nm_device_link_activated (NmNetlinkMonitor *monitor, const gchar *in { if (nm_device_is_802_3_ethernet (dev) && !nm_device_has_active_link (dev)) { - nm_device_set_link_active (dev, TRUE); + nm_device_set_active_link (dev, TRUE); nm_policy_schedule_device_change_check (data); } - nm_device_unref (dev); + g_object_unref (G_OBJECT (dev)); } } @@ -621,15 +623,15 @@ static void nm_device_link_deactivated (NmNetlinkMonitor *monitor, const gchar * if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__)) { if ((dev = nm_get_device_by_iface (data, interface_name))) - nm_device_ref (dev); + g_object_ref (G_OBJECT (dev)); nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); } if (dev) { if (nm_device_is_802_3_ethernet (dev)) - nm_device_set_link_active (dev, FALSE); - nm_device_unref (dev); + nm_device_set_active_link (dev, FALSE); + g_object_unref (G_OBJECT (dev)); } } diff --git a/src/NetworkManagerAP.c b/src/NetworkManagerAP.c index d64734ca72..d542267296 100644 --- a/src/NetworkManagerAP.c +++ b/src/NetworkManagerAP.c @@ -22,7 +22,6 @@ #include "NetworkManagerAP.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" -#include "NetworkManagerWireless.h" #include "nm-ap-security.h" #include @@ -85,6 +84,7 @@ NMAccessPoint * nm_ap_new (void) ap->mode = IW_MODE_INFRA; ap->refcount = 1; + ap->capabilities = NM_802_11_CAP_PROTO_NONE; return ap; } @@ -203,12 +203,20 @@ void nm_ap_set_essid (NMAccessPoint *ap, const char * essid) guint32 nm_ap_get_capabilities (NMAccessPoint *ap) { - g_return_val_if_fail (ap != NULL, -1); + g_return_val_if_fail (ap != NULL, NM_802_11_CAP_NONE); return ap->capabilities; } +void nm_ap_set_capabilities (NMAccessPoint *ap, guint32 capabilities) +{ + g_return_if_fail (ap != NULL); + + ap->capabilities = capabilities; +} + + /* * Get/set functions for encrypted flag * @@ -222,16 +230,6 @@ gboolean nm_ap_get_encrypted (const NMAccessPoint *ap) || (ap->capabilities & NM_802_11_CAP_PROTO_WPA2)); } -void nm_ap_set_encrypted (NMAccessPoint *ap, gboolean privacy) -{ -#define ALL_WEP (NM_802_11_CAP_PROTO_WEP | NM_802_11_CAP_CIPHER_WEP104 | NM_802_11_CAP_CIPHER_WEP40) - g_return_if_fail (ap != NULL); - - if (privacy) - ap->capabilities |= ALL_WEP; - else - ap->capabilities &= ~ALL_WEP; -} /* * Accessorts for AP security info @@ -544,41 +542,72 @@ gboolean nm_ap_has_manufacturer_default_essid (NMAccessPoint *ap) } -static void set_capabilities_from_cipher (NMAccessPoint *ap, int cipher) +static guint32 add_capabilities_from_cipher (guint32 caps, int cipher) { if (cipher & IW_AUTH_CIPHER_WEP40) - ap->capabilities |= NM_802_11_CAP_CIPHER_WEP40; + { + caps |= (NM_802_11_CAP_PROTO_WEP & NM_802_11_CAP_CIPHER_WEP40); + caps &= ~NM_802_11_CAP_PROTO_NONE; + } if (cipher & IW_AUTH_CIPHER_WEP104) - ap->capabilities |= NM_802_11_CAP_CIPHER_WEP104; + { + caps |= (NM_802_11_CAP_PROTO_WEP & NM_802_11_CAP_CIPHER_WEP104); + caps &= ~NM_802_11_CAP_PROTO_NONE; + } if (cipher & IW_AUTH_CIPHER_TKIP) - ap->capabilities |= NM_802_11_CAP_CIPHER_TKIP; + { + caps |= NM_802_11_CAP_CIPHER_TKIP; + caps &= ~NM_802_11_CAP_PROTO_NONE; + } if (cipher & IW_AUTH_CIPHER_CCMP) - ap->capabilities |= NM_802_11_CAP_CIPHER_CCMP; + { + caps |= NM_802_11_CAP_CIPHER_CCMP; + caps &= ~NM_802_11_CAP_PROTO_NONE; + } + + return caps; } -void nm_ap_set_capabilities_from_wpa_ie (NMAccessPoint *ap, const guint8 *wpa_ie, guint32 length) +void nm_ap_add_capabilities_from_ie (NMAccessPoint *ap, const guint8 *wpa_ie, guint32 length) { wpa_ie_data * cap_data; + guint32 caps; g_return_if_fail (ap != NULL); if (!(cap_data = wpa_parse_wpa_ie (wpa_ie, length))) return; - ap->capabilities = NM_802_11_CAP_NONE; - + caps = nm_ap_get_capabilities (ap); if (cap_data->proto & IW_AUTH_WPA_VERSION_WPA) - ap->capabilities |= NM_802_11_CAP_PROTO_WPA; + { + caps |= NM_802_11_CAP_PROTO_WPA; + caps &= ~NM_802_11_CAP_PROTO_NONE; + } if (cap_data->proto & IW_AUTH_WPA_VERSION_WPA2) - ap->capabilities |= NM_802_11_CAP_PROTO_WPA2; + { + caps |= NM_802_11_CAP_PROTO_WPA2; + caps &= ~NM_802_11_CAP_PROTO_NONE; + } - set_capabilities_from_cipher (ap, cap_data->pairwise_cipher); - set_capabilities_from_cipher (ap, cap_data->group_cipher); + caps = add_capabilities_from_cipher (caps, cap_data->pairwise_cipher); + caps = add_capabilities_from_cipher (caps, cap_data->group_cipher); if (cap_data->key_mgmt & IW_AUTH_KEY_MGMT_802_1X) - ap->capabilities |= NM_802_11_CAP_KEY_MGMT_802_1X; + caps |= NM_802_11_CAP_KEY_MGMT_802_1X; if (cap_data->key_mgmt & IW_AUTH_KEY_MGMT_PSK) - ap->capabilities |= NM_802_11_CAP_KEY_MGMT_PSK; + caps |= NM_802_11_CAP_KEY_MGMT_PSK; + + nm_ap_set_capabilities (ap, caps); } +void nm_ap_add_capabilities_for_wep (NMAccessPoint *ap) +{ + guint32 caps; + + g_return_if_fail (ap != NULL); + + ap->capabilities |= (NM_802_11_CAP_PROTO_WEP | NM_802_11_CAP_CIPHER_WEP40 | NM_802_11_CAP_CIPHER_WEP104); + ap->capabilities &= ~NM_802_11_CAP_PROTO_NONE; +} diff --git a/src/NetworkManagerAP.h b/src/NetworkManagerAP.h index 7f7cf6a1cb..d27a7bce63 100644 --- a/src/NetworkManagerAP.h +++ b/src/NetworkManagerAP.h @@ -44,9 +44,9 @@ char * nm_ap_get_essid (const NMAccessPoint *ap); void nm_ap_set_essid (NMAccessPoint *ap, const char *essid); guint32 nm_ap_get_capabilities (NMAccessPoint *ap); +void nm_ap_set_capabilities (NMAccessPoint *ap, guint32 capabilities); gboolean nm_ap_get_encrypted (const NMAccessPoint *ap); -void nm_ap_set_encrypted (NMAccessPoint *ap, gboolean privacy); NMAPSecurity * nm_ap_get_security (const NMAccessPoint *ap); void nm_ap_set_security (NMAccessPoint *ap, NMAPSecurity *security); @@ -87,7 +87,8 @@ void nm_ap_set_user_created (NMAccessPoint *ap, gboolean user_created); GSList * nm_ap_get_user_addresses (const NMAccessPoint *ap); void nm_ap_set_user_addresses (NMAccessPoint *ap, GSList *list); -void nm_ap_set_capabilities_from_wpa_ie (NMAccessPoint *ap, const guint8 *wpa_ie, guint32 length); +void nm_ap_add_capabilities_from_ie (NMAccessPoint *ap, const guint8 *wpa_ie, guint32 length); +void nm_ap_add_capabilities_for_wep (NMAccessPoint *ap); /* * NOTE: diff --git a/src/NetworkManagerAPList.c b/src/NetworkManagerAPList.c index d47d189301..83cbb39151 100644 --- a/src/NetworkManagerAPList.c +++ b/src/NetworkManagerAPList.c @@ -457,8 +457,8 @@ gboolean nm_ap_list_merge_scanned_ap (NMAccessPointList *list, NMAccessPoint *me const GTimeVal *merge_ap_seen = nm_ap_get_last_seen (merge_ap); - nm_ap_set_encrypted (list_ap_addr, nm_ap_get_encrypted (merge_ap)); - if (nm_ap_get_strength (merge_ap) != nm_ap_get_strength (list_ap_addr)) + nm_ap_set_capabilities (list_ap_addr, nm_ap_get_capabilities (merge_ap)); + if (nm_ap_get_strength (merge_ap) != nm_ap_get_strength (list_ap_addr)) { nm_ap_set_strength (list_ap_addr, nm_ap_get_strength (merge_ap)); *strength_changed = TRUE; @@ -480,7 +480,7 @@ gboolean nm_ap_list_merge_scanned_ap (NMAccessPointList *list, NMAccessPoint *me const GTimeVal *merge_ap_seen = nm_ap_get_last_seen (merge_ap); const GTimeVal *list_ap_essid_seen = nm_ap_get_last_seen (list_ap_essid); - nm_ap_set_encrypted (list_ap_essid, nm_ap_get_encrypted (merge_ap)); + nm_ap_set_capabilities (list_ap_essid, nm_ap_get_capabilities (merge_ap)); if (!((list_ap_essid_seen->tv_sec == merge_ap_seen->tv_sec) && (nm_ap_get_strength (list_ap_essid) >= nm_ap_get_strength (merge_ap)))) @@ -600,7 +600,7 @@ void nm_ap_list_copy_essids_by_address (NMAccessPointList *dest, NMAccessPointLi * may result in undesired behavior. * */ -void nm_ap_list_diff (NMData *data, NMDevice *dev, NMAccessPointList *old, NMAccessPointList *new) +void nm_ap_list_diff (NMData *data, NMDevice80211Wireless *dev, NMAccessPointList *old, NMAccessPointList *new) { NMAPListIter *iter; NMAccessPoint *old_ap; diff --git a/src/NetworkManagerAPList.h b/src/NetworkManagerAPList.h index 301160674c..7c94979abd 100644 --- a/src/NetworkManagerAPList.h +++ b/src/NetworkManagerAPList.h @@ -24,8 +24,10 @@ #include #include "NetworkManager.h" -#include "NetworkManagerDevice.h" - +#include "NetworkManagerMain.h" +#include "NetworkManagerAP.h" +#include "nm-device.h" +#include "nm-device-802-11-wireless.h" typedef struct NMAccessPointList NMAccessPointList; typedef struct NMAPListIter NMAPListIter; @@ -49,7 +51,7 @@ void nm_ap_list_copy_properties (NMAccessPointList *dest, NMAccessPointList void nm_ap_list_copy_essids_by_address (NMAccessPointList *dest, NMAccessPointList *source); void nm_ap_list_copy_one_essid_by_address (NMAccessPoint *ap, NMAccessPointList *search_list); -void nm_ap_list_diff (NMData *data, NMDevice *dev, NMAccessPointList *old, NMAccessPointList *new); +void nm_ap_list_diff (NMData *data, NMDevice80211Wireless *dev, NMAccessPointList *old, NMAccessPointList *new); gboolean nm_ap_list_merge_scanned_ap (NMAccessPointList *list, NMAccessPoint *merge_ap, gboolean *new, gboolean *strength_changed); NMNetworkType nm_ap_list_get_type (NMAccessPointList *list); diff --git a/src/NetworkManagerDbus.c b/src/NetworkManagerDbus.c index c0e84f9be9..1e0d57cbd6 100644 --- a/src/NetworkManagerDbus.c +++ b/src/NetworkManagerDbus.c @@ -30,13 +30,12 @@ #include "NetworkManager.h" #include "NetworkManagerUtils.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" #include "NetworkManagerDbus.h" #include "NetworkManagerDbusUtils.h" #include "NetworkManagerAP.h" #include "NetworkManagerAPList.h" #include "NetworkManagerPolicy.h" -#include "NetworkManagerWireless.h" #include "nm-dbus-nm.h" #include "nm-dbus-device.h" #include "nm-dbus-net.h" @@ -251,7 +250,7 @@ static gboolean nm_dbus_signal_device_status_change (gpointer user_data) dbus_message_unref (message); - nm_device_unref (cb_data->dev); + g_object_unref (G_OBJECT (cb_data->dev)); g_free (cb_data); return FALSE; @@ -267,7 +266,7 @@ void nm_dbus_schedule_device_status_change_signal (NMData *data, NMDevice *dev, g_return_if_fail (dev != NULL); cb_data = g_malloc0 (sizeof (NMStatusChangeData)); - nm_device_ref (dev); + g_object_ref (G_OBJECT (dev)); cb_data->data = data; cb_data->dev = dev; if (ap) @@ -351,7 +350,7 @@ void nm_dbus_signal_state_change (DBusConnection *connection, NMData *data) * Notifies the bus that a new wireless network has come into range * */ -void nm_dbus_signal_wireless_network_change (DBusConnection *connection, NMDevice *dev, NMAccessPoint *ap, NMNetworkStatus status, gint strength) +void nm_dbus_signal_wireless_network_change (DBusConnection *connection, NMDevice80211Wireless *dev, NMAccessPoint *ap, NMNetworkStatus status, gint strength) { DBusMessage * message; char * dev_path = NULL; @@ -362,10 +361,10 @@ void nm_dbus_signal_wireless_network_change (DBusConnection *connection, NMDevic g_return_if_fail (dev != NULL); g_return_if_fail (ap != NULL); - if (!(dev_path = nm_dbus_get_object_path_for_device (dev))) + if (!(dev_path = nm_dbus_get_object_path_for_device (NM_DEVICE (dev)))) goto out; - if (!(net_path = nm_dbus_get_object_path_for_network (dev, ap))) + if (!(net_path = nm_dbus_get_object_path_for_network (NM_DEVICE (dev), ap))) goto out; switch (status) @@ -410,7 +409,7 @@ out: } -void nm_dbus_signal_device_strength_change (DBusConnection *connection, NMDevice *dev, gint strength) +void nm_dbus_signal_device_strength_change (DBusConnection *connection, NMDevice80211Wireless *dev, gint strength) { DBusMessage * message; char * dev_path = NULL; @@ -418,7 +417,7 @@ void nm_dbus_signal_device_strength_change (DBusConnection *connection, NMDevice g_return_if_fail (connection != NULL); g_return_if_fail (dev != NULL); - if (!(dev_path = nm_dbus_get_object_path_for_device (dev))) + if (!(dev_path = nm_dbus_get_object_path_for_device (NM_DEVICE (dev)))) goto out; if (!(message = dbus_message_new_signal (NM_DBUS_PATH, NM_DBUS_INTERFACE, "DeviceStrengthChanged"))) @@ -494,7 +493,7 @@ static DBusHandlerResult nm_dbus_signal_filter (DBusConnection *connection, DBus } else if (dbus_message_is_signal (message, NMI_DBUS_INTERFACE, "UserInterfaceActivated")) { - nm_wireless_set_scan_interval (data, NULL, NM_WIRELESS_SCAN_INTERVAL_ACTIVE); + nm_device_802_11_wireless_set_scan_interval (data, NULL, NM_WIRELESS_SCAN_INTERVAL_ACTIVE); handled = TRUE; } } diff --git a/src/NetworkManagerDbus.h b/src/NetworkManagerDbus.h index ac544b63ba..6fab558ec2 100644 --- a/src/NetworkManagerDbus.h +++ b/src/NetworkManagerDbus.h @@ -26,6 +26,9 @@ #include #include #include "NetworkManager.h" +#include "NetworkManagerMain.h" +#include "nm-device.h" +#include "nm-device-802-11-wireless.h" #include "NetworkManagerAPList.h" @@ -51,7 +54,6 @@ static inline gboolean message_is_error (DBusMessage *msg) return (dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_ERROR); } - DBusConnection *nm_dbus_init (NMData *data); gboolean nm_dbus_is_info_daemon_running (DBusConnection *connection); @@ -64,8 +66,8 @@ void nm_dbus_schedule_device_status_change_signal (NMData *data, NMDevice *dev void nm_dbus_signal_state_change (DBusConnection *connection, NMData *data); -void nm_dbus_signal_wireless_network_change (DBusConnection *connection, NMDevice *dev, NMAccessPoint *ap, NMNetworkStatus status, gint strength); -void nm_dbus_signal_device_strength_change (DBusConnection *connection, NMDevice *dev, gint strength); +void nm_dbus_signal_wireless_network_change (DBusConnection *connection, NMDevice80211Wireless *dev, NMAccessPoint *ap, NMNetworkStatus status, gint strength); +void nm_dbus_signal_device_strength_change (DBusConnection *connection, NMDevice80211Wireless *dev, gint strength); NMDevice * nm_dbus_get_device_from_object_path (NMData *data, const char *path); diff --git a/src/NetworkManagerDbusUtils.h b/src/NetworkManagerDbusUtils.h index f87927c0ac..68d43b4b4b 100644 --- a/src/NetworkManagerDbusUtils.h +++ b/src/NetworkManagerDbusUtils.h @@ -27,7 +27,8 @@ #include #include -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "NetworkManagerMain.h" typedef struct NMDbusCBData { diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index 03988c483e..f5d0ed1b54 100644 --- a/src/NetworkManagerDevice.c +++ b/src/NetworkManagerDevice.c @@ -857,6 +857,20 @@ guint32 nm_device_get_capabilities (NMDevice *dev) } +/* + * Accessor for type-specific device capabilities + */ +guint32 nm_device_get_type_capabilities (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, NM_DEVICE_CAP_NONE); + + if (dev->type == DEVICE_TYPE_802_11_WIRELESS) + return dev->options.wireless.capabilities; + + return NM_DEVICE_CAP_NONE; +} + + /* * Get/set functions for link_active */ @@ -3700,7 +3714,7 @@ static void nm_device_fake_ap_list (NMDevice *dev) {{0x12, 0x34, 0x56, 0x78, 0x90, 0xab}}, {{0xcd, 0xef, 0x12, 0x34, 0x56, 0x78}}, {{0x90, 0xab, 0xcd, 0xef, 0x12, 0x34}} }; - guint8 fake_qualities[NUM_FAKE_APS] = { 150, 26, 200, 100 }; + guint8 fake_qualities[NUM_FAKE_APS] = { 45, 26, 12, 93 }; double fake_freqs[NUM_FAKE_APS] = { 3.1416, 4.1416, 5.1415, 6.1415 }; gboolean fake_enc[NUM_FAKE_APS] = { FALSE, TRUE, FALSE, TRUE }; @@ -3718,9 +3732,7 @@ static void nm_device_fake_ap_list (NMDevice *dev) nm_ap_set_essid (nm_ap, fake_essids[i]); if (fake_enc[i]) - nm_ap_set_encrypted (nm_ap, FALSE); - else - nm_ap_set_encrypted (nm_ap, TRUE); + nm_ap_add_capabilities_for_wep (nm_ap); nm_ap_set_address (nm_ap, (const struct ether_addr *)(&fake_addrs[i])); nm_ap_set_strength (nm_ap, fake_qualities[i]); @@ -4497,7 +4509,7 @@ static gboolean process_scan_results (NMDevice *dev, const guint8 *res_buf, guin break; case SIOCGIWENCODE: if (!(iwe->u.data.flags & IW_ENCODE_DISABLED)) - nm_ap_set_encrypted (ap, TRUE); + nm_ap_add_capabilities_for_wep (ap); break; #if 0 case SIOCGIWRATE: @@ -4539,10 +4551,10 @@ static gboolean process_scan_results (NMDevice *dev, const guint8 *res_buf, guin case WPA_GENERIC_INFO_ELEM: if ((ielen < 2 + 4) || (memcmp (&gpos[2], "\x00\x50\xf2\x01", 4) != 0)) break; - nm_ap_set_capabilities_from_wpa_ie (ap, (const guint8 *)gpos, ielen); + nm_ap_add_capabilities_from_ie (ap, (const guint8 *)gpos, ielen); break; case WPA_RSN_INFO_ELEM: - nm_ap_set_capabilities_from_wpa_ie (ap, (const guint8 *)gpos, ielen); + nm_ap_add_capabilities_from_ie (ap, (const guint8 *)gpos, ielen); break; } gpos += ielen; @@ -4571,9 +4583,9 @@ static gboolean process_scan_results (NMDevice *dev, const guint8 *res_buf, guin ie_buf = g_malloc0 (bytes); hexstr2bin (spos, ie_buf, bytes); if (strncmp (custom, "wpa_ie=", 7) == 0) - nm_ap_set_capabilities_from_wpa_ie (ap, (const guint8 *)ie_buf, bytes); + nm_ap_add_capabilities_from_ie (ap, (const guint8 *)ie_buf, bytes); else if (strncmp (custom, "rsn_ie=", 7) == 0) - nm_ap_set_capabilities_from_wpa_ie (ap, (const guint8 *)ie_buf, bytes); + nm_ap_add_capabilities_from_ie (ap, (const guint8 *)ie_buf, bytes); g_free (ie_buf); } break; diff --git a/src/NetworkManagerDevice.h b/src/NetworkManagerDevice.h index 0675077f45..3da7b472d8 100644 --- a/src/NetworkManagerDevice.h +++ b/src/NetworkManagerDevice.h @@ -60,6 +60,7 @@ const char * nm_device_get_driver (NMDevice *dev); NMDeviceType nm_device_get_type (NMDevice *dev); guint32 nm_device_get_capabilities (NMDevice *dev); +guint32 nm_device_get_type_capabilities (NMDevice *dev); gboolean nm_device_is_802_11_wireless (NMDevice *dev); gboolean nm_device_is_802_3_ethernet (NMDevice *dev); diff --git a/src/NetworkManagerMain.h b/src/NetworkManagerMain.h index 02caab1f35..ddc8534842 100644 --- a/src/NetworkManagerMain.h +++ b/src/NetworkManagerMain.h @@ -30,6 +30,7 @@ #include "NetworkManagerAP.h" #include "nm-netlink-monitor.h" #include "nm-named-manager.h" +#include "nm-device.h" typedef enum NMIntState @@ -92,14 +93,14 @@ typedef struct NMData } NMData; -struct NMDevice * nm_get_active_device (NMData *data); +NMDevice * nm_get_active_device (NMData *data); -struct NMDevice * nm_create_device_and_add_to_list (NMData *data, const char *udi, const char *iface, +NMDevice * nm_create_device_and_add_to_list (NMData *data, const char *udi, const char *iface, gboolean test_device, NMDeviceType test_device_type); void nm_add_initial_devices (NMData *data); -void nm_remove_device (NMData *data, struct NMDevice *dev); +void nm_remove_device (NMData *data, NMDevice *dev); void nm_schedule_state_change_signal_broadcast (NMData *data); diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 374380b84d..480ca27ceb 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -36,6 +36,8 @@ #include "nm-activation-request.h" #include "nm-utils.h" #include "nm-dbus-nmi.h" +#include "nm-device-802-11-wireless.h" +#include "nm-device-802-3-ethernet.h" /* @@ -61,6 +63,7 @@ static gboolean nm_policy_activation_finish (NMActRequest *req) /* Tell NetworkManagerInfo to store the MAC address of the active device's AP */ if (nm_device_is_802_11_wireless (dev)) { + NMDevice80211Wireless * wdev = NM_DEVICE_802_11_WIRELESS (dev); struct ether_addr addr; NMAccessPoint * ap = nm_act_request_get_ap (req); NMAccessPoint * tmp_ap; @@ -69,7 +72,7 @@ static gboolean nm_policy_activation_finish (NMActRequest *req) /* Cache details in the info-daemon since the connect was successful */ automatic = !nm_act_request_get_user_requested (req); - nm_device_get_ap_address (dev, &addr); + nm_device_802_11_wireless_get_bssid (wdev, &addr); if (!nm_ap_get_address (ap) || !nm_ethernet_address_is_valid (nm_ap_get_address (ap))) nm_ap_set_address (ap, &addr); @@ -203,12 +206,12 @@ void nm_policy_schedule_activation_failed (NMActRequest *req) */ static NMDevice * nm_policy_auto_get_best_device (NMData *data, NMAccessPoint **ap) { - GSList *elt; - NMDevice *best_wired_dev = NULL; - guint best_wired_prio = 0; - NMDevice *best_wireless_dev = NULL; - guint best_wireless_prio = 0; - NMDevice *highest_priority_dev = NULL; + GSList * elt; + NMDevice8023Ethernet * best_wired_dev = NULL; + guint best_wired_prio = 0; + NMDevice80211Wireless * best_wireless_dev = NULL; + guint best_wireless_prio = 0; + NMDevice * highest_priority_dev = NULL; g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (ap != NULL, NULL); @@ -224,7 +227,7 @@ static NMDevice * nm_policy_auto_get_best_device (NMData *data, NMAccessPoint ** NMDevice * dev = (NMDevice *)(elt->data); guint32 caps; - dev_type = nm_device_get_type (dev); + dev_type = nm_device_get_device_type (dev); link_active = nm_device_has_active_link (dev); caps = nm_device_get_capabilities (dev); @@ -246,7 +249,7 @@ static NMDevice * nm_policy_auto_get_best_device (NMData *data, NMAccessPoint ** if (prio > best_wired_prio) { - best_wired_dev = dev; + best_wired_dev = NM_DEVICE_802_3_ETHERNET (dev); best_wired_prio = prio; } } @@ -267,21 +270,22 @@ static NMDevice * nm_policy_auto_get_best_device (NMData *data, NMAccessPoint ** if (prio > best_wireless_prio) { - best_wireless_dev = dev; + best_wireless_dev = NM_DEVICE_802_11_WIRELESS (dev); best_wireless_prio = prio; } } } if (best_wired_dev) - highest_priority_dev = best_wired_dev; + highest_priority_dev = NM_DEVICE (best_wired_dev); else if (best_wireless_dev) { - highest_priority_dev = best_wireless_dev; - *ap = nm_device_get_best_ap (highest_priority_dev); + *ap = nm_device_802_11_wireless_get_best_ap (best_wireless_dev); /* If the device doesn't have a "best" ap, then we can't use it */ if (!*ap) highest_priority_dev = NULL; + else + highest_priority_dev = NM_DEVICE (best_wireless_dev); } #if 0 @@ -619,19 +623,21 @@ static gboolean nm_policy_device_list_update_from_allowed_list (NMData *data) NMDevice *dev = (NMDevice *)(elt->data); if (nm_device_is_802_11_wireless (dev)) { - if (nm_device_get_supports_wireless_scan (dev)) + NMDevice80211Wireless * wdev = NM_DEVICE_802_11_WIRELESS (dev); + + if (nm_device_get_capabilities (dev) & NM_DEVICE_CAP_WIRELESS_SCAN) { /* Once we have the list, copy in any relevant information from our Allowed list and fill * in the ESSID of base stations that aren't broadcasting their ESSID, if we have their * MAC address in our allowed list. */ - nm_ap_list_copy_essids_by_address (nm_device_ap_list_get (dev), data->allowed_ap_list); - nm_ap_list_copy_properties (nm_device_ap_list_get (dev), data->allowed_ap_list); + nm_ap_list_copy_essids_by_address (nm_device_802_11_wireless_ap_list_get (wdev), data->allowed_ap_list); + nm_ap_list_copy_properties (nm_device_802_11_wireless_ap_list_get (wdev), data->allowed_ap_list); } else - nm_device_copy_allowed_to_dev_list (dev, data->allowed_ap_list); + nm_device_802_11_wireless_copy_allowed_to_dev_list (wdev, data->allowed_ap_list); - nm_ap_list_remove_duplicate_essids (nm_device_ap_list_get (dev)); + nm_ap_list_remove_duplicate_essids (nm_device_802_11_wireless_ap_list_get (wdev)); } } diff --git a/src/NetworkManagerPolicy.h b/src/NetworkManagerPolicy.h index a9692b24db..eb11228ac6 100644 --- a/src/NetworkManagerPolicy.h +++ b/src/NetworkManagerPolicy.h @@ -23,7 +23,7 @@ #define NETWORK_MANAGER_POLICY_H #include "NetworkManager.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" #include "NetworkManagerDbus.h" #include "nm-activation-request.h" diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index c26cf51fcd..f32f5868e4 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -42,7 +42,7 @@ #include #include #include "NetworkManagerSystem.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index 594ac4418f..a18dc44e5f 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -23,7 +23,9 @@ #define NETWORK_MANAGER_SYSTEM_H #include -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "nm-ip4-config.h" +#include "nm-named-manager.h" /* Prototypes for system/distribution dependent functions, diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 4ecf6afe47..79ecf8dff0 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -36,6 +36,9 @@ #include "NetworkManager.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" +#include "nm-device.h" +#include "nm-device-802-11-wireless.h" +#include "nm-device-802-3-ethernet.h" #include #include @@ -217,7 +220,7 @@ NMSock *nm_dev_sock_open (NMDevice *dev, SockType type, const char *func_name, c sock->desc = desc ? g_strdup (desc) : NULL; sock->dev = dev; if (sock->dev) - nm_device_ref (sock->dev); + g_object_ref (G_OBJECT (sock->dev)); /* Add the sock to our global sock list for tracking */ g_static_mutex_lock (&sock_list_mutex); @@ -244,7 +247,7 @@ void nm_dev_sock_close (NMSock *sock) g_free (sock->func); g_free (sock->desc); if (sock->dev) - nm_device_unref (sock->dev); + g_object_unref (G_OBJECT (sock->dev)); memset (sock, 0, sizeof (NMSock)); diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 4c5258c89f..0ab55baeb9 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -32,7 +32,7 @@ #include "NetworkManager.h" #include "NetworkManagerMain.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" typedef enum SockType { diff --git a/src/autoip.c b/src/autoip.c index d9dc3e2454..587f4554dd 100644 --- a/src/autoip.c +++ b/src/autoip.c @@ -30,7 +30,9 @@ #include #include #include "NetworkManager.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "nm-device-802-3-ethernet.h" +#include "nm-device-802-11-wireless.h" #include "NetworkManagerMain.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" @@ -210,7 +212,7 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) ARPMessage p; struct ether_addr addr; struct in_addr ip = {0}; - NMSock *sk; + NMSock * sk = NULL; int nprobes = 0; int nannounce = 0; gboolean success = FALSE; @@ -224,6 +226,13 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) memset (&saddr, 0, sizeof (saddr)); strncpy (saddr.sa_data, nm_device_get_iface (dev), sizeof (saddr.sa_data)); + if (nm_device_is_802_3_ethernet (dev)) + nm_device_802_3_ethernet_get_address (NM_DEVICE_802_3_ETHERNET (dev), &addr); + else if (nm_device_is_802_11_wireless (dev)) + nm_device_802_11_wireless_get_address (NM_DEVICE_802_11_WIRELESS (dev), &addr); + else + goto out; + /* open an ARP socket */ if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) { @@ -238,8 +247,6 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) goto out; } - nm_device_get_hw_address (dev, &addr); - /* initialize pseudo random selection of IP addresses */ srandom ( (addr.ether_addr_octet[ETHER_ADDR_LEN-4] << 24) | (addr.ether_addr_octet[ETHER_ADDR_LEN-3] << 16) | @@ -344,6 +351,7 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) } out: - nm_dev_sock_close (sk); + if (sk) + nm_dev_sock_close (sk); return success; } diff --git a/src/autoip.h b/src/autoip.h index b2be3e2a8a..1ebd7eb0af 100644 --- a/src/autoip.h +++ b/src/autoip.h @@ -1,3 +1,3 @@ -#include "NetworkManagerDevice.h" +#include "nm-device.h" extern gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip); diff --git a/src/backends/NetworkManagerDebian.c b/src/backends/NetworkManagerDebian.c index 195b2b0ff5..7d0a1bb71d 100644 --- a/src/backends/NetworkManagerDebian.c +++ b/src/backends/NetworkManagerDebian.c @@ -29,7 +29,9 @@ #include #include "NetworkManagerSystem.h" #include "NetworkManagerUtils.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "nm-device-802-3-ethernet.h" +#include "nm-device-802-11-wireless.h" #include "NetworkManagerDialup.h" #include "interface_parser.h" #include "nm-utils.h" @@ -386,7 +388,10 @@ void nm_system_device_add_ip6_link_address (NMDevice *dev) struct ether_addr hw_addr; unsigned char eui[8]; - nm_device_get_hw_address(dev, &hw_addr); + if (nm_device_is_802_3_ethernet (dev)) + nm_device_802_3_ethernet_get_address (NM_DEVICE_802_3_ETHERNET (dev), &hw_addr); + else if (nm_device_is_802_11_wireless (dev)) + nm_device_802_11_wireless_get_address (NM_DEVICE_802_11_WIRELESS (dev), &hw_addr); memcpy (eui, &(hw_addr.ether_addr_octet), sizeof (hw_addr.ether_addr_octet)); memmove(eui+5, eui+3, 3); diff --git a/src/backends/NetworkManagerGentoo.c b/src/backends/NetworkManagerGentoo.c index 830f03b20a..754ed0910c 100644 --- a/src/backends/NetworkManagerGentoo.c +++ b/src/backends/NetworkManagerGentoo.c @@ -30,7 +30,9 @@ #include #include "NetworkManagerSystem.h" #include "NetworkManagerUtils.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "nm-device-802-3-ethernet.h" +#include "nm-device-802-11-wireless.h" #include "nm-utils.h" #include "shvar.h" @@ -264,7 +266,10 @@ void nm_system_device_add_ip6_link_address (NMDevice *dev) struct ether_addr hw_addr; unsigned char eui[8]; - nm_device_get_hw_address(dev, &hw_addr); + if (nm_device_is_802_3_ethernet (dev)) + nm_device_802_3_ethernet_get_address (NM_DEVICE_802_3_ETHERNET (dev), &hw_addr); + else if (nm_device_is_802_11_wireless (dev)) + nm_device_802_11_wireless_get_address (NM_DEVICE_802_11_WIRELESS (dev), &hw_addr); memcpy (eui, &(hw_addr.ether_addr_octet), sizeof (hw_addr.ether_addr_octet)); memmove (eui+5, eui+3, 3); diff --git a/src/backends/NetworkManagerRedHat.c b/src/backends/NetworkManagerRedHat.c index eb6fc67645..2409efcf83 100644 --- a/src/backends/NetworkManagerRedHat.c +++ b/src/backends/NetworkManagerRedHat.c @@ -25,7 +25,9 @@ #include #include "NetworkManagerSystem.h" #include "NetworkManagerUtils.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "nm-device-802-3-ethernet.h" +#include "nm-device-802-11-wireless.h" #include "NetworkManagerDialup.h" #include "nm-utils.h" #include "shvar.h" @@ -319,7 +321,10 @@ void nm_system_device_add_ip6_link_address (NMDevice *dev) struct ether_addr hw_addr; unsigned char eui[8]; - nm_device_get_hw_address(dev, &hw_addr); + if (nm_device_is_802_3_ethernet (dev)) + nm_device_802_3_ethernet_get_address (NM_DEVICE_802_3_ETHERNET (dev), &hw_addr); + else if (nm_device_is_802_11_wireless (dev)) + nm_device_802_11_wireless_get_address (NM_DEVICE_802_11_WIRELESS (dev), &hw_addr); memcpy (eui, &(hw_addr.ether_addr_octet), sizeof (hw_addr.ether_addr_octet)); memmove (eui+5, eui+3, 3); diff --git a/src/backends/NetworkManagerSlackware.c b/src/backends/NetworkManagerSlackware.c index 5b0b8d5602..7f5b8610f8 100644 --- a/src/backends/NetworkManagerSlackware.c +++ b/src/backends/NetworkManagerSlackware.c @@ -25,7 +25,9 @@ #include #include "NetworkManagerSystem.h" #include "NetworkManagerUtils.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "nm-device-802-3-ethernet.h" +#include "nm-device-802-11-wireless.h" #include "nm-utils.h" /* @@ -230,7 +232,10 @@ void nm_system_device_add_ip6_link_address (NMDevice *dev) struct ether_addr hw_addr; unsigned char eui[8]; - nm_device_get_hw_address (dev, &hw_addr); + if (nm_device_is_802_3_ethernet (dev)) + nm_device_802_3_ethernet_get_address (NM_DEVICE_802_3_ETHERNET (dev), &hw_addr); + else if (nm_device_is_802_11_wireless (dev)) + nm_device_802_11_wireless_get_address (NM_DEVICE_802_11_WIRELESS (dev), &hw_addr); memcpy (eui, &(hw_addr.ether_addr_octet), sizeof (hw_addr.ether_addr_octet)); memmove (eui+5, eui+3, 3); diff --git a/src/backends/NetworkManagerSuSE.c b/src/backends/NetworkManagerSuSE.c index 59178cd80c..1e0e23f77f 100644 --- a/src/backends/NetworkManagerSuSE.c +++ b/src/backends/NetworkManagerSuSE.c @@ -31,7 +31,9 @@ #include "NetworkManagerSystem.h" #include "NetworkManagerUtils.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "nm-device-802-3-ethernet.h" +#include "nm-device-802-11-wireless.h" #include "NetworkManagerDialup.h" #include "nm-utils.h" #include "shvar.h" @@ -315,7 +317,10 @@ void nm_system_device_add_ip6_link_address (NMDevice *dev) struct ether_addr hw_addr; unsigned char eui[8]; - nm_device_get_hw_address (dev, &hw_addr); + if (nm_device_is_802_3_ethernet (dev)) + nm_device_802_3_ethernet_get_address (NM_DEVICE_802_3_ETHERNET (dev), &hw_addr); + else if (nm_device_is_802_11_wireless (dev)) + nm_device_802_11_wireless_get_address (NM_DEVICE_802_11_WIRELESS (dev), &hw_addr); memcpy (eui, &(hw_addr.ether_addr_octet), sizeof (hw_addr.ether_addr_octet)); memmove (eui+5, eui+3, 3); diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index 5997e11de1..a09a9c8950 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -21,15 +21,16 @@ #include #include +#include +#include +#include + #include "nm-dhcp-manager.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" #include "NetworkManagerPolicy.h" #include "NetworkManagerUtils.h" #include "nm-activation-request.h" #include "nm-utils.h" -#include -#include -#include struct NMDHCPManager @@ -173,9 +174,9 @@ guint8 nm_dhcp_manager_get_state_for_device (NMDHCPManager *manager, NMDevice *d nm_info ("Error from dhcdbd on 'reason' request because: name '%s', message '%s'.", error.name, error.message); dbus_error_free (&error); } - if (reply) + else if (reply) { - if (!dbus_message_get_args (reply, &error, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)) + if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)) state = 0; dbus_message_unref (reply); } diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h index a139ca96c3..71fdca7600 100644 --- a/src/dhcp-manager/nm-dhcp-manager.h +++ b/src/dhcp-manager/nm-dhcp-manager.h @@ -22,7 +22,7 @@ #define NM_DHCP_MANAGER_H #include "NetworkManagerMain.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" char * get_dhcp_match_string (const char *owner); diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 66dbe71350..83223c1c53 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -24,7 +24,7 @@ #include #include #include "nm-activation-request.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" #include "NetworkManagerDbus.h" #include "nm-dhcp-manager.h" #include "nm-utils.h" @@ -62,7 +62,7 @@ NMActRequest * nm_act_request_new (NMData *data, NMDevice *dev, NMAccessPoint *a req->refcount = 1; req->data = data; - nm_device_ref (dev); + g_object_ref (G_OBJECT (dev)); req->dev = dev; if (ap) @@ -90,7 +90,7 @@ void nm_act_request_unref (NMActRequest *req) req->refcount--; if (req->refcount <= 0) { - nm_device_unref (req->dev); + g_object_unref (G_OBJECT (req->dev)); if (req->ap) nm_ap_unref (req->ap); diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h index e3ce6d34be..3a55519b5c 100644 --- a/src/nm-activation-request.h +++ b/src/nm-activation-request.h @@ -26,7 +26,7 @@ #include #include "NetworkManager.h" #include "NetworkManagerMain.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" #include "NetworkManagerAP.h" #include "nm-ip4-config.h" diff --git a/src/nm-ap-security-wep.c b/src/nm-ap-security-wep.c index 367763c8ea..514639dbc3 100644 --- a/src/nm-ap-security-wep.c +++ b/src/nm-ap-security-wep.c @@ -28,7 +28,7 @@ #include "nm-ap-security-wep.h" #include "nm-ap-security-private.h" #include "dbus-helpers.h" -#include "NetworkManagerDevice.h" +#include "nm-device-802-11-wireless.h" #define NM_AP_SECURITY_WEP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP_SECURITY_WEP, NMAPSecurityWEPPrivate)) @@ -112,11 +112,11 @@ real_write_wpa_supplicant_config (NMAPSecurity *instance, int fd) } static int -real_device_setup (NMAPSecurity *instance, NMDevice * dev) +real_device_setup (NMAPSecurity *instance, NMDevice80211Wireless * dev) { NMAPSecurityWEP * self = NM_AP_SECURITY_WEP (instance); - nm_device_set_wep_enc_key (dev, nm_ap_security_get_key (instance), + nm_device_802_11_wireless_set_wep_enc_key (dev, nm_ap_security_get_key (instance), self->priv->auth_algorithm); return 0; } diff --git a/src/nm-ap-security-wpa-psk.c b/src/nm-ap-security-wpa-psk.c index 8606344854..ba01a4161e 100644 --- a/src/nm-ap-security-wpa-psk.c +++ b/src/nm-ap-security-wpa-psk.c @@ -28,7 +28,7 @@ #include "nm-ap-security-wpa-psk.h" #include "nm-ap-security-private.h" #include "dbus-helpers.h" -#include "NetworkManagerDevice.h" +#include "nm-device-802-11-wireless.h" #define NM_AP_SECURITY_WPA_PSK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP_SECURITY_WPA_PSK, NMAPSecurityWPA_PSKPrivate)) @@ -90,7 +90,7 @@ real_write_wpa_supplicant_config (NMAPSecurity *instance, int fd) } static int -real_device_setup (NMAPSecurity *self, NMDevice * dev) +real_device_setup (NMAPSecurity *self, NMDevice80211Wireless * dev) { /* Stub; should be farmed out to wpa_supplicant eventually */ return 0; diff --git a/src/nm-ap-security.c b/src/nm-ap-security.c index b08c0209ed..66e92bac1a 100644 --- a/src/nm-ap-security.c +++ b/src/nm-ap-security.c @@ -28,7 +28,7 @@ #include "nm-ap-security-private.h" #include "nm-ap-security-wep.h" #include "nm-ap-security-wpa-psk.h" -#include "NetworkManagerDevice.h" +#include "nm-device-802-11-wireless.h" #define NM_AP_SECURITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP_SECURITY, NMAPSecurityPrivate)) @@ -195,10 +195,10 @@ real_write_wpa_supplicant_config (NMAPSecurity *self, int fd) } static int -real_device_setup (NMAPSecurity *self, NMDevice * dev) +real_device_setup (NMAPSecurity *self, NMDevice80211Wireless * dev) { /* unencrypted */ - nm_device_set_wep_enc_key (dev, NULL, 0); + nm_device_802_11_wireless_set_wep_enc_key (dev, NULL, 0); return 0; } @@ -236,7 +236,7 @@ nm_ap_security_set_description (NMAPSecurity *self, const char *desc) } int -nm_ap_security_device_setup (NMAPSecurity *self, NMDevice *dev) +nm_ap_security_device_setup (NMAPSecurity *self, NMDevice80211Wireless *dev) { g_return_val_if_fail (self != NULL, -1); g_return_val_if_fail (dev != NULL, -1); diff --git a/src/nm-ap-security.h b/src/nm-ap-security.h index 4b530721a5..dbfb8224d8 100644 --- a/src/nm-ap-security.h +++ b/src/nm-ap-security.h @@ -25,6 +25,12 @@ #include #include +/* Grr */ +#ifndef NM_DEVICE_802_11_WIRELESS_DEFINED +#define NM_DEVICE_802_11_WIRELESS_DEFINED +typedef struct _NMDevice80211Wireless NMDevice80211Wireless; +#endif + G_BEGIN_DECLS #define NM_TYPE_AP_SECURITY (nm_ap_security_get_type ()) @@ -46,7 +52,6 @@ struct _NMAPSecurity NMAPSecurityPrivate *priv; }; -struct NMDevice; struct NMAccessPoint; struct _NMAPSecurityClass @@ -60,7 +65,7 @@ struct _NMAPSecurityClass void (*write_wpa_supplicant_config_func)(NMAPSecurity *self, int fd); - int (*device_setup_func) (NMAPSecurity *self, struct NMDevice * dev); + int (*device_setup_func) (NMAPSecurity *self, NMDevice80211Wireless * dev); }; @@ -80,7 +85,7 @@ int nm_ap_security_serialize (NMAPSecurity *self, DBusMessageIter *iter); void nm_ap_security_write_wpa_supplicant_config (NMAPSecurity *self, int fd); -int nm_ap_security_device_setup (NMAPSecurity *self, struct NMDevice *dev); +int nm_ap_security_device_setup (NMAPSecurity *self, NMDevice80211Wireless *dev); const char *nm_ap_security_get_description (NMAPSecurity *self); diff --git a/src/nm-dbus-device.c b/src/nm-dbus-device.c index 432f05c1bb..29351cb6aa 100644 --- a/src/nm-dbus-device.c +++ b/src/nm-dbus-device.c @@ -28,12 +28,14 @@ #include #include "nm-utils.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" #include "NetworkManagerDbus.h" #include "NetworkManagerDbusUtils.h" #include "NetworkManagerPolicy.h" #include "NetworkManagerUtils.h" #include "nm-dbus-device.h" +#include "nm-device-802-3-ethernet.h" +#include "nm-device-802-11-wireless.h" static DBusMessage *nm_dbus_device_get_name (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) @@ -61,11 +63,12 @@ static DBusMessage *nm_dbus_device_get_type (DBusConnection *connection, DBusMes g_return_val_if_fail (data && data->data && data->dev && connection && message, NULL); dev = data->dev; - if ((reply = dbus_message_new_method_return (message))) { - dbus_int32_t type; - type = nm_device_get_type (dev); + if ((reply = dbus_message_new_method_return (message))) + { + dbus_int32_t type; + type = nm_device_get_device_type (dev); dbus_message_append_args (reply, DBUS_TYPE_INT32, &type, DBUS_TYPE_INVALID); - } + } return reply; } @@ -117,9 +120,13 @@ static DBusMessage *nm_dbus_device_get_hw_address (DBusConnection *connection, D { struct ether_addr addr; char char_addr[20]; - char *ptr = &char_addr[0]; + char * ptr = &char_addr[0]; - nm_device_get_hw_address (dev, &addr); + memset (&addr, 0, sizeof (struct ether_addr)); + if (nm_device_is_802_3_ethernet (dev)) + nm_device_802_3_ethernet_get_address (NM_DEVICE_802_3_ETHERNET (dev), &addr); + else if (nm_device_is_802_11_wireless (dev)) + nm_device_802_11_wireless_get_address (NM_DEVICE_802_11_WIRELESS (dev), &addr); memset (char_addr, 0, 20); iw_ether_ntop (&addr, char_addr); dbus_message_append_args (reply, DBUS_TYPE_STRING, &ptr, DBUS_TYPE_INVALID); @@ -136,9 +143,14 @@ static DBusMessage *nm_dbus_device_get_mode (DBusConnection *connection, DBusMes g_return_val_if_fail (data && data->data && data->dev && connection && message, NULL); dev = data->dev; - if ((reply = dbus_message_new_method_return (message))) + if (!nm_device_is_802_11_wireless (dev)) { - dbus_int32_t mode = (dbus_int32_t) nm_device_get_mode (dev); + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "DeviceNotWireless", + "Wired devices cannot see wireless networks."); + } + else if ((reply = dbus_message_new_method_return (message))) + { + dbus_int32_t mode = (dbus_int32_t) nm_device_802_11_wireless_get_mode (NM_DEVICE_802_11_WIRELESS (dev)); dbus_message_append_args (reply, DBUS_TYPE_INT32, &mode, DBUS_TYPE_INVALID); } @@ -153,12 +165,13 @@ static DBusMessage *nm_dbus_device_get_link_active (DBusConnection *connection, g_return_val_if_fail (data && data->data && data->dev && connection && message, NULL); dev = data->dev; - if ((reply = dbus_message_new_method_return (message))) { - dbus_bool_t is_active; + if ((reply = dbus_message_new_method_return (message))) + { + dbus_bool_t is_active; - is_active = nm_device_has_active_link (dev); + is_active = nm_device_has_active_link (dev); dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &is_active, DBUS_TYPE_INVALID); - } + } return reply; } @@ -188,8 +201,8 @@ static DBusMessage *nm_dbus_device_get_active_network (DBusConnection *connectio NMAccessPoint *tmp_ap; char * object_path = NULL; - if ( (tmp_ap = nm_device_ap_list_get_ap_by_essid (dev, nm_ap_get_essid (ap))) - && (object_path = nm_dbus_get_object_path_for_network (dev, tmp_ap))) + tmp_ap = nm_device_802_11_wireless_ap_list_get_ap_by_essid (NM_DEVICE_802_11_WIRELESS (dev), nm_ap_get_essid (ap)); + if (tmp_ap && (object_path = nm_dbus_get_object_path_for_network (dev, tmp_ap))) { dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID); g_free (object_path); @@ -234,7 +247,7 @@ static DBusMessage *nm_dbus_device_get_networks (DBusConnection *connection, DBu dbus_message_iter_init_append (reply, &iter); dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter_array); - if ((ap_list = nm_device_ap_list_get (dev))) + if ((ap_list = nm_device_802_11_wireless_ap_list_get (NM_DEVICE_802_11_WIRELESS (dev)))) { if ((list_iter = nm_ap_list_iter_new (ap_list))) { @@ -304,7 +317,7 @@ static DBusMessage *nm_dbus_device_set_link_active (DBusConnection *connection, dbus_error_init (&error); if (dbus_message_get_args (message, &error, DBUS_TYPE_BOOLEAN, &link, DBUS_TYPE_INVALID)) { - nm_device_set_link_active (dev, link); + nm_device_set_active_link (dev, link); nm_policy_schedule_device_change_check (data->data); } } @@ -324,7 +337,7 @@ static DBusMessage *nm_dbus_device_get_properties (DBusConnection *connection, D { char * op = nm_dbus_get_object_path_for_device (dev); const char * iface = nm_device_get_iface (dev); - dbus_uint32_t type = (dbus_uint32_t) nm_device_get_type (dev); + dbus_uint32_t type = (dbus_uint32_t) nm_device_get_device_type (dev); const char * udi = nm_device_get_udi (dev); gchar * ip4_address; gchar * broadcast; @@ -340,6 +353,7 @@ static DBusMessage *nm_dbus_device_get_properties (DBusConnection *connection, D char * active_network_path = NULL; dbus_bool_t link_active = (dbus_bool_t) nm_device_has_active_link (dev); dbus_uint32_t capabilities = (dbus_uint32_t) nm_device_get_capabilities (dev); + dbus_uint32_t type_capabilities = (dbus_uint32_t) nm_device_get_type_capabilities (dev); char ** networks = NULL; int num_networks = 0; dbus_bool_t active = nm_device_get_act_request (dev) ? TRUE : FALSE; @@ -351,8 +365,11 @@ static DBusMessage *nm_dbus_device_get_properties (DBusConnection *connection, D guint32 primary_dns_addr = 0; guint32 secondary_dns_addr = 0; - nm_device_get_hw_address (dev, &hw_addr); memset (hw_addr_buf, 0, 20); + if (nm_device_is_802_3_ethernet (dev)) + nm_device_802_3_ethernet_get_address (NM_DEVICE_802_3_ETHERNET (dev), &hw_addr); + else if (nm_device_is_802_11_wireless (dev)) + nm_device_802_11_wireless_get_address (NM_DEVICE_802_11_WIRELESS (dev), &hw_addr); iw_ether_ntop (&hw_addr, hw_addr_buf); ip4config = nm_device_get_ip4_config (dev); @@ -379,23 +396,24 @@ static DBusMessage *nm_dbus_device_get_properties (DBusConnection *connection, D if (nm_device_is_802_11_wireless (dev)) { + NMDevice80211Wireless * wdev = NM_DEVICE_802_11_WIRELESS (dev); NMActRequest * req = nm_device_get_act_request (dev); NMAccessPoint * ap; NMAccessPointList * ap_list; NMAPListIter * iter; - strength = (dbus_int32_t) nm_device_get_signal_strength (dev); - mode = (dbus_int32_t) nm_device_get_mode (dev); + strength = (dbus_int32_t) nm_device_802_11_wireless_get_signal_strength (wdev); + mode = (dbus_int32_t) nm_device_802_11_wireless_get_mode (wdev); if (req && (ap = nm_act_request_get_ap (req))) { NMAccessPoint *tmp_ap; - if ((tmp_ap = nm_device_ap_list_get_ap_by_essid (dev, nm_ap_get_essid (ap)))) + if ((tmp_ap = nm_device_802_11_wireless_ap_list_get_ap_by_essid (wdev, nm_ap_get_essid (ap)))) active_network_path = nm_dbus_get_object_path_for_network (dev, tmp_ap); } - ap_list = nm_device_ap_list_get (dev); + ap_list = nm_device_802_11_wireless_ap_list_get (wdev); if (ap_list && (num_networks = nm_ap_list_size (ap_list))) { if ((iter = nm_ap_list_iter_new (ap_list))) @@ -436,6 +454,7 @@ static DBusMessage *nm_dbus_device_get_properties (DBusConnection *connection, D DBUS_TYPE_INT32, &strength, DBUS_TYPE_BOOLEAN,&link_active, DBUS_TYPE_UINT32, &capabilities, + DBUS_TYPE_UINT32, &type_capabilities, DBUS_TYPE_STRING, &active_network_path, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &networks, num_networks, DBUS_TYPE_INVALID); diff --git a/src/nm-dbus-net.c b/src/nm-dbus-net.c index 8e6111a02c..7d634f7403 100644 --- a/src/nm-dbus-net.c +++ b/src/nm-dbus-net.c @@ -19,7 +19,8 @@ * (C) Copyright 2005 Red Hat, Inc. */ -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "nm-device-802-11-wireless.h" #include "NetworkManagerDbus.h" #include "NetworkManagerAP.h" #include "NetworkManagerAPList.h" @@ -43,7 +44,7 @@ static NMAccessPoint *nm_dbus_get_ap_from_object_path (const char *path, NMDevic g_return_val_if_fail (path != NULL, NULL); g_return_val_if_fail (dev != NULL, NULL); - ap_list = nm_device_ap_list_get (dev); + ap_list = nm_device_802_11_wireless_ap_list_get (NM_DEVICE_802_11_WIRELESS (dev)); if (!ap_list) return (NULL); @@ -145,7 +146,7 @@ static DBusMessage *nm_dbus_net_get_strength (DBusConnection *connection, DBusMe NMAPListIter *iter; int best_strength = nm_ap_get_strength (data->ap); - if (!(ap_list = nm_device_ap_list_get (data->dev))) + if (!(ap_list = nm_device_802_11_wireless_ap_list_get (NM_DEVICE_802_11_WIRELESS (data->dev)))) goto append; if (!(iter = nm_ap_list_iter_new (ap_list))) @@ -243,8 +244,8 @@ static DBusMessage *nm_dbus_net_get_properties (DBusConnection *connection, DBus dbus_int32_t strength = nm_ap_get_strength (data->ap); double freq = nm_ap_get_freq (data->ap); dbus_int32_t rate = nm_ap_get_rate (data->ap); - dbus_bool_t enc = nm_ap_get_encrypted (data->ap); dbus_int32_t mode = (dbus_int32_t) nm_ap_get_mode (data->ap); + dbus_int32_t capabilities = (dbus_int32_t) nm_ap_get_capabilities (data->ap); memset (&hw_addr_buf[0], 0, 20); if (nm_ap_get_address (data->ap)) @@ -256,8 +257,8 @@ static DBusMessage *nm_dbus_net_get_properties (DBusConnection *connection, DBus DBUS_TYPE_INT32, &strength, DBUS_TYPE_DOUBLE, &freq, DBUS_TYPE_INT32, &rate, - DBUS_TYPE_BOOLEAN,&enc, DBUS_TYPE_INT32, &mode, + DBUS_TYPE_INT32, &capabilities, DBUS_TYPE_INVALID); g_free (op); } diff --git a/src/nm-dbus-nm.c b/src/nm-dbus-nm.c index 92db7fd33d..0458836e45 100644 --- a/src/nm-dbus-nm.c +++ b/src/nm-dbus-nm.c @@ -35,6 +35,8 @@ #include "NetworkManagerSystem.h" #include "NetworkManager.h" #include "nm-ap-security.h" +#include "nm-device-802-3-ethernet.h" +#include "nm-device-802-11-wireless.h" /* @@ -255,7 +257,7 @@ static DBusMessage *nm_dbus_nm_set_active_device (DBusConnection *connection, DB } /* Set up the wireless-specific activation request properties */ - ap = nm_device_wireless_get_activation_ap (dev, essid, security); + ap = nm_device_802_11_wireless_get_activation_ap (NM_DEVICE_802_11_WIRELESS (dev), essid, security); if (security) g_object_unref (G_OBJECT (security)); diff --git a/src/nm-dbus-nmi.c b/src/nm-dbus-nmi.c index f2771e7c14..ce085e2847 100644 --- a/src/nm-dbus-nmi.c +++ b/src/nm-dbus-nmi.c @@ -20,7 +20,7 @@ */ #include "NetworkManager.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" #include "nm-activation-request.h" #include "NetworkManagerAPList.h" #include "NetworkManagerPolicy.h" diff --git a/src/nm-device-802-11-wireless.c b/src/nm-device-802-11-wireless.c new file mode 100644 index 0000000000..dd41b8bc52 --- /dev/null +++ b/src/nm-device-802-11-wireless.c @@ -0,0 +1,2808 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "nm-device.h" +#include "nm-device-802-11-wireless.h" +#include "nm-device-private.h" +#include "NetworkManagerAPList.h" +#include "NetworkManagerDbus.h" +#include "nm-utils.h" +#include "NetworkManagerUtils.h" +#include "NetworkManagerPolicy.h" +#include "nm-activation-request.h" +#include "nm-dbus-nmi.h" + +/* #define IW_QUAL_DEBUG */ + +#define NM_DEVICE_802_11_WIRELESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_802_11_WIRELESS, NMDevice80211WirelessPrivate)) + +struct _NMDevice80211WirelessPrivate +{ + gboolean dispose_has_run; + + struct ether_addr hw_addr; + + char * cur_essid; + gint8 strength; + gint8 invalid_strength_counter; + iwqual max_qual; + iwqual avg_qual; + + guint failed_link_count; + + gint8 num_freqs; + double freqs[IW_MAX_FREQUENCIES]; + + GMutex * scan_mutex; + NMAccessPointList * ap_list; + guint8 scan_interval; /* seconds */ + guint32 last_scan; + + /* Static options from driver */ + guint8 we_version; + guint32 capabilities; +}; + + +typedef struct +{ + NMDevice80211Wireless * dev; + guint8 * results; + guint32 results_len; +} NMWirelessScanResults; + +typedef struct +{ + NMDevice80211Wireless * dev; + gboolean force; +} NMWirelessScanCB; + + +static void nm_device_802_11_wireless_ap_list_clear (NMDevice80211Wireless *self); +void nm_device_802_11_wireless_set_essid (NMDevice80211Wireless *self, + const char *essid); +char * nm_device_802_11_wireless_get_essid (NMDevice80211Wireless *self); +void nm_device_802_11_wireless_get_bssid (NMDevice80211Wireless *self, + struct ether_addr *bssid); +void nm_device_802_11_wireless_set_wep_enc_key (NMDevice80211Wireless *self, + const char *key, + int auth_method); + +gboolean nm_device_802_11_wireless_set_mode (NMDevice80211Wireless *self, + const int mode); + +static gboolean nm_device_802_11_wireless_scan (gpointer user_data); + +static gboolean process_scan_results (NMDevice80211Wireless *dev, + const guint8 *res_buf, + guint32 res_buf_len); + +static gboolean get_scan_results (NMDevice80211Wireless *dev, + NMSock *sk, + guint8 **out_res_buf, + guint32 *data_len); + +static int wireless_qual_to_percent (const struct iw_quality *qual, + const struct iw_quality *max_qual, + const struct iw_quality *avg_qual); + +static gboolean is_associated (NMDevice80211Wireless *self); + + +static guint32 +real_discover_generic_capabilities (NMDevice *dev) +{ + NMDevice80211Wireless * wdev; + NMSock * sk; + int err; + wireless_scan_head scan_data; + guint32 caps = NM_DEVICE_CAP_NONE; + iwrange range; + struct iwreq wrq; + + /* Check for Wireless Extensions support >= 16 for wireless devices */ + + if (!(sk = nm_dev_sock_open (dev, DEV_WIRELESS, __func__, NULL))) + goto out; + + if (iw_get_range_info (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), &range) < 0) + goto out; + + if (range.we_version_compiled < 16) + { + nm_warning ("%s: driver's Wireless Extensions version (%d) is too old. Can't use device.", + nm_device_get_iface (dev), range.we_version_compiled); + } + else + caps |= NM_DEVICE_CAP_NM_SUPPORTED; + + memset (&wrq, 0, sizeof (struct iwreq)); + err = iw_set_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCSIWSCAN, &wrq); + if (!((err == -1) && (errno == EOPNOTSUPP))) + caps |= NM_DEVICE_CAP_WIRELESS_SCAN; + +out: + if (sk) + nm_dev_sock_close (sk); + return caps; +} + +static guint32 +discover_wireless_capabilities (NMDevice80211Wireless *self, + iwrange * range, + guint32 data_len) +{ + int minlen; + guint32 caps = NM_802_11_CAP_NONE; + + g_return_val_if_fail (self != NULL, NM_802_11_CAP_NONE); + g_return_val_if_fail (range != NULL, NM_802_11_CAP_NONE); + + minlen = ((char *) range->enc_capa) - (char *) range + sizeof (range->enc_capa); + + /* All drivers should support WEP by default */ + caps |= (NM_802_11_CAP_CIPHER_WEP40 | NM_802_11_CAP_CIPHER_WEP104); + /* All drivers should support no encryption by default */ + caps |= (NM_802_11_CAP_PROTO_NONE | NM_802_11_CAP_PROTO_WEP); + + if ((data_len >= minlen) && range->we_version_compiled >= 18) + { + if (range->enc_capa & IW_ENC_CAPA_WPA) + { + caps |= (NM_802_11_CAP_PROTO_WPA + | NM_802_11_CAP_KEY_MGMT_PSK + | NM_802_11_CAP_KEY_MGMT_802_1X); + } + if (range->enc_capa & IW_ENC_CAPA_WPA2) + { + caps |= (NM_802_11_CAP_PROTO_WPA2 + | NM_802_11_CAP_KEY_MGMT_PSK + | NM_802_11_CAP_KEY_MGMT_802_1X); + } + + if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) + caps |= NM_802_11_CAP_CIPHER_TKIP; + if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) + caps |= NM_802_11_CAP_CIPHER_CCMP; + } + + return caps; +} + + +static void +nm_device_802_11_wireless_init (NMDevice80211Wireless * self) +{ + self->priv = NM_DEVICE_802_11_WIRELESS_GET_PRIVATE (self); + self->priv->dispose_has_run = FALSE; + + memset (&(self->priv->hw_addr), 0, sizeof (struct ether_addr)); +} + +static void +real_init (NMDevice *dev) +{ + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); + NMDevice80211WirelessClass * klass; + NMData * app_data; + guint32 caps; + NMSock * sk; + NMDeviceClass * parent_class; + + /* Chain up to parent first */ + klass = NM_DEVICE_802_11_WIRELESS_GET_CLASS (self); + parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); + parent_class->init (NM_DEVICE (self)); + + self->priv->scan_mutex = g_mutex_new (); + nm_register_mutex_desc (self->priv->scan_mutex, "Scan Mutex"); + + self->priv->ap_list = nm_ap_list_new (NETWORK_TYPE_DEVICE); + + app_data = nm_device_get_app_data (NM_DEVICE (self)); + nm_device_802_11_wireless_set_scan_interval (app_data, self, NM_WIRELESS_SCAN_INTERVAL_ACTIVE); + + nm_device_802_11_wireless_set_mode (self, IW_MODE_INFRA); + + /* Non-scanning devices show the entire allowed AP list as their + * available networks. + */ + caps = nm_device_get_capabilities (NM_DEVICE (self)); + if (!(caps & NM_DEVICE_CAP_WIRELESS_SCAN)) + nm_device_802_11_wireless_copy_allowed_to_dev_list (self, app_data->allowed_ap_list); + + self->priv->we_version = 0; + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + struct iw_range range; + struct iwreq wrq; + int minlen = ((char *) &range.enc_capa) - (char *) &range + sizeof (range.enc_capa); + + memset (&wrq, 0, sizeof (wrq)); + strncpy (wrq.ifr_name, nm_device_get_iface (NM_DEVICE (self)), IFNAMSIZ); + wrq.u.data.pointer = (caddr_t) ⦥ + wrq.u.data.length = sizeof (struct iw_range); + + if (ioctl (nm_dev_sock_get_fd (sk), SIOCGIWRANGE, &wrq) >= 0) + { + int i; + + self->priv->max_qual.qual = range.max_qual.qual; + self->priv->max_qual.level = range.max_qual.level; + self->priv->max_qual.noise = range.max_qual.noise; + self->priv->max_qual.updated = range.max_qual.updated; + + self->priv->avg_qual.qual = range.avg_qual.qual; + self->priv->avg_qual.level = range.avg_qual.level; + self->priv->avg_qual.noise = range.avg_qual.noise; + self->priv->avg_qual.updated = range.avg_qual.updated; + + self->priv->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES); + for (i = 0; i < self->priv->num_freqs; i++) + self->priv->freqs[i] = iw_freq2float (&(range.freq[i])); + + self->priv->we_version = range.we_version_compiled; + + /* 802.11 wireless-specific capabilities */ + self->priv->capabilities = discover_wireless_capabilities (self, &range, wrq.u.data.length); + } + nm_dev_sock_close (sk); + } +} + +static void +real_start (NMDevice *dev) +{ + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); + guint32 caps; + + /* Start the scanning timeout for devices that can do scanning */ + caps = nm_device_get_capabilities (dev); + if (caps & NM_DEVICE_CAP_WIRELESS_SCAN) + { + GSource *source = g_idle_source_new (); + guint source_id = 0; + NMWirelessScanCB *scan_cb; + + scan_cb = g_malloc0 (sizeof (NMWirelessScanCB)); + scan_cb->dev = self; + scan_cb->force = TRUE; + + g_source_set_callback (source, nm_device_802_11_wireless_scan, scan_cb, NULL); + source_id = g_source_attach (source, nm_device_get_main_context (dev)); + g_source_unref (source); + } + +} + +static void +real_deactivate (NMDevice *dev) +{ + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); + NMData * app_data; + + app_data = nm_device_get_app_data (dev); + g_assert (app_data); + + /* Clean up stuff, don't leave the card associated */ + nm_device_802_11_wireless_set_essid (self, ""); + nm_device_802_11_wireless_set_wep_enc_key (self, NULL, 0); + nm_device_802_11_wireless_set_mode (self, IW_MODE_INFRA); + nm_device_802_11_wireless_set_scan_interval (app_data, self, NM_WIRELESS_SCAN_INTERVAL_ACTIVE); +} + + +/* + * nm_device_copy_allowed_to_dev_list + * + * For devices that don't support wireless scanning, copy + * the allowed AP list to the device's ap list. + * + */ +void +nm_device_802_11_wireless_copy_allowed_to_dev_list (NMDevice80211Wireless *self, + NMAccessPointList *allowed_list) +{ + NMAPListIter *iter; + NMAccessPoint *src_ap; + NMAccessPointList *dev_list; + + g_return_if_fail (self != NULL); + + if (allowed_list == NULL) + return; + + nm_device_802_11_wireless_ap_list_clear (self); + self->priv->ap_list = nm_ap_list_new (NETWORK_TYPE_ALLOWED); + + if (!(iter = nm_ap_list_iter_new (allowed_list))) + return; + + dev_list = nm_device_802_11_wireless_ap_list_get (self); + while ((src_ap = nm_ap_list_iter_next (iter))) + { + NMAccessPoint * dst_ap = nm_ap_new_from_ap (src_ap); + + nm_ap_list_append_ap (dev_list, dst_ap); + nm_ap_unref (dst_ap); + } + nm_ap_list_iter_free (iter); +} + + + +/* + * nm_device_802_11_wireless_get_address + * + * Get a device's hardware address + * + */ +void +nm_device_802_11_wireless_get_address (NMDevice80211Wireless *self, + struct ether_addr *addr) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (addr != NULL); + + memcpy (addr, &(self->priv->hw_addr), sizeof (struct ether_addr)); +} + + +static gboolean +link_to_specific_ap (NMDevice80211Wireless *self, + NMAccessPoint *ap, + gboolean default_link) +{ + gboolean link = FALSE; + + /* Checking hardware's ESSID during a scan is doesn't work. */ + nm_lock_mutex (self->priv->scan_mutex, __func__); + + if (is_associated (self)) + { + char * dev_essid = nm_device_802_11_wireless_get_essid (self); + char * ap_essid = nm_ap_get_essid (ap); + + if (dev_essid && ap_essid && !strcmp (dev_essid, ap_essid)) + { + self->priv->failed_link_count = 0; + link = TRUE; + } + } + + nm_unlock_mutex (self->priv->scan_mutex, __func__); + + if (!link) + { + self->priv->failed_link_count++; + if (self->priv->failed_link_count <= 6) + link = default_link; + } + + return link; +} + + +/* + * nm_device_update_best_ap + * + * Recalculate the "best" access point we should be associating with. + * + */ +NMAccessPoint * +nm_device_802_11_wireless_get_best_ap (NMDevice80211Wireless *self) +{ + NMAccessPointList * ap_list; + NMAPListIter * iter; + NMAccessPoint * scan_ap = NULL; + NMAccessPoint * best_ap = NULL; + NMAccessPoint * cur_ap = NULL; + NMActRequest * req = NULL; + NMAccessPoint * trusted_best_ap = NULL; + NMAccessPoint * untrusted_best_ap = NULL; + GTimeVal trusted_latest_timestamp = {0, 0}; + GTimeVal untrusted_latest_timestamp = {0, 0}; + NMData * app_data; + + g_return_val_if_fail (self != NULL, NULL); + + app_data = nm_device_get_app_data (NM_DEVICE (self)); + g_assert (app_data); + + /* Devices that can't scan don't do anything automatic. + * The user must choose the access point from the menu. + */ + if ( !(nm_device_get_capabilities (NM_DEVICE (self)) & NM_DEVICE_CAP_WIRELESS_SCAN) + && !nm_device_has_active_link (NM_DEVICE (self))) + return NULL; + + if (!(ap_list = nm_device_802_11_wireless_ap_list_get (self))) + return NULL; + + /* We prefer the currently selected access point if its user-chosen or if there + * is still a hardware link to it. + */ + if ((req = nm_device_get_act_request (NM_DEVICE (self)))) + { + if ((cur_ap = nm_act_request_get_ap (req))) + { + char * essid = nm_ap_get_essid (cur_ap); + gboolean keep = FALSE; + + if (nm_ap_get_user_created (cur_ap)) + keep = TRUE; + else if (nm_act_request_get_user_requested (req)) + keep = TRUE; + else if (link_to_specific_ap (self, cur_ap, TRUE)) + keep = TRUE; + + /* Only keep if its not in the invalid list and its _is_ in our scaned list */ + if ( keep + && !nm_ap_list_get_ap_by_essid (app_data->invalid_ap_list, essid) + && nm_device_802_11_wireless_ap_list_get_ap_by_essid (self, essid)) + { + nm_ap_ref (cur_ap); + return cur_ap; + } + } + } + + if (!(iter = nm_ap_list_iter_new (ap_list))) + return NULL; + while ((scan_ap = nm_ap_list_iter_next (iter))) + { + NMAccessPoint *tmp_ap; + char *ap_essid = nm_ap_get_essid (scan_ap); + + /* Access points in the "invalid" list cannot be used */ + if (nm_ap_list_get_ap_by_essid (app_data->invalid_ap_list, ap_essid)) + continue; + + if ((tmp_ap = nm_ap_list_get_ap_by_essid (app_data->allowed_ap_list, ap_essid))) + { + const GTimeVal *curtime = nm_ap_get_timestamp (tmp_ap); + + /* Only connect to a blacklisted AP if the user has connected + * to this specific AP before. + */ + gboolean blacklisted = nm_ap_has_manufacturer_default_essid (scan_ap); + if (blacklisted) + { + GSList *elt, *user_addrs; + const struct ether_addr *ap_addr; + char char_addr[20]; + + ap_addr = nm_ap_get_address (scan_ap); + user_addrs = nm_ap_get_user_addresses (tmp_ap); + + memset (&char_addr[0], 0, 20); + iw_ether_ntop (ap_addr, &char_addr[0]); + + for (elt = user_addrs; elt; elt = g_slist_next (elt)) + { + if (elt->data && !strcmp (elt->data, &char_addr[0])) + { + blacklisted = FALSE; + break; + } + } + + g_slist_foreach (user_addrs, (GFunc)g_free, NULL); + g_slist_free (user_addrs); + } + + if (!blacklisted && nm_ap_get_trusted (tmp_ap) && (curtime->tv_sec > trusted_latest_timestamp.tv_sec)) + { + trusted_latest_timestamp = *nm_ap_get_timestamp (tmp_ap); + trusted_best_ap = scan_ap; + nm_ap_set_security (trusted_best_ap, nm_ap_get_security (tmp_ap)); + } + else if (!blacklisted && !nm_ap_get_trusted (tmp_ap) && (curtime->tv_sec > untrusted_latest_timestamp.tv_sec)) + { + untrusted_latest_timestamp = *nm_ap_get_timestamp (tmp_ap); + untrusted_best_ap = scan_ap; + nm_ap_set_security (untrusted_best_ap, nm_ap_get_security (tmp_ap)); + } + } + } + best_ap = trusted_best_ap ? trusted_best_ap : untrusted_best_ap; + nm_ap_list_iter_free (iter); + + if (best_ap) + nm_ap_ref (best_ap); + + return best_ap; +} + + +/* + * nm_device_802_11_wireless_get_activation_ap + * + * Return an access point suitable for use in the device activation + * request. + * + */ +NMAccessPoint * +nm_device_802_11_wireless_get_activation_ap (NMDevice80211Wireless *self, + const char *essid, + NMAPSecurity *security) +{ + gboolean encrypted = FALSE; + NMAccessPoint *ap = NULL; + NMAccessPoint *tmp_ap = NULL; + NMData * app_data; + NMAccessPointList * dev_ap_list; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (essid != NULL, NULL); + + app_data = nm_device_get_app_data (NM_DEVICE (self)); + g_assert (app_data); + + nm_debug ("Forcing AP '%s'", essid); + + /* Find the AP in our card's scan list first. + * If its not there, create an entirely new AP. + */ + dev_ap_list = nm_device_802_11_wireless_ap_list_get (self); + if (!(ap = nm_ap_list_get_ap_by_essid (dev_ap_list, essid))) + { + /* We need security information from the user if the network they + * request isn't in our scan list. + */ + if (!security) + { + nm_warning ("%s: tried to manually connect to network '%s' without " + "providing security information!", __func__, essid); + return NULL; + } + + /* User chose a network we haven't seen in a scan, so create a + * "fake" access point and add it to yhe scan list. + */ + ap = nm_ap_new (); + nm_ap_set_essid (ap, essid); + nm_ap_set_artificial (ap, TRUE); + nm_ap_list_append_ap (dev_ap_list, ap); + nm_ap_unref (ap); + } + else + { + /* If the AP is in the ignore list, we have to remove it since + * the User Knows What's Best. + */ + nm_ap_list_remove_ap_by_essid (app_data->invalid_ap_list, nm_ap_get_essid (ap)); + + /* If we didn't get any security info, make some up. */ + if (!security) + security = nm_ap_security_new_from_ap (ap); + } + g_assert (security); + nm_ap_set_security (ap, security); + + return ap; +} + + +/* + * nm_device_802_11_wireless_ap_list_add_ap + * + * Add an access point to the devices internal AP list. + * + */ +static void +nm_device_802_11_wireless_ap_list_add_ap (NMDevice80211Wireless *self, + NMAccessPoint *ap) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (ap != NULL); + + nm_ap_list_append_ap (self->priv->ap_list, ap); + /* Transfer ownership of ap to the list by unrefing it here */ + nm_ap_unref (ap); +} + + +/* + * nm_device_802_11_wireless_ap_list_clear + * + * Clears out the device's internal list of available access points. + * + */ +static void +nm_device_802_11_wireless_ap_list_clear (NMDevice80211Wireless *self) +{ + g_return_if_fail (self != NULL); + + if (!self->priv->ap_list) + return; + + nm_ap_list_unref (self->priv->ap_list); + self->priv->ap_list = NULL; +} + + +/* + * nm_device_ap_list_get_ap_by_essid + * + * Get the access point for a specific essid + * + */ +NMAccessPoint * +nm_device_802_11_wireless_ap_list_get_ap_by_essid (NMDevice80211Wireless *self, + const char *essid) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (essid != NULL, NULL); + + if (!self->priv->ap_list) + return NULL; + + return nm_ap_list_get_ap_by_essid (self->priv->ap_list, essid); +} + + +/* + * nm_device_ap_list_get_ap_by_bssid + * + * Get the access point for a specific BSSID + * + */ +NMAccessPoint * +nm_device_802_11_wireless_ap_list_get_ap_by_bssid (NMDevice80211Wireless *self, + const struct ether_addr *bssid) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (bssid != NULL, NULL); + + if (!self->priv->ap_list) + return NULL; + + return nm_ap_list_get_ap_by_address (self->priv->ap_list, bssid); +} + + +/* + * nm_device_ap_list_get_ap_by_obj_path + * + * Get the access point for a dbus object path. Requires an _unescaped_ + * object path. + * + */ +NMAccessPoint * +nm_device_802_11_wireless_ap_list_get_ap_by_obj_path (NMDevice80211Wireless *self, + const char *obj_path) +{ + NMAccessPoint * ret_ap = NULL; + char * built_path; + char * dev_path; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (obj_path != NULL, NULL); + + if (!self->priv->ap_list) + return NULL; + + dev_path = nm_dbus_get_object_path_for_device (NM_DEVICE (self)); + dev_path = nm_dbus_unescape_object_path (dev_path); + built_path = g_strdup_printf ("%s/Networks/", dev_path); + g_free (dev_path); + + if (strncmp (built_path, obj_path, strlen (built_path)) == 0) + { + char *essid = g_strdup (obj_path + strlen (built_path)); + + ret_ap = nm_ap_list_get_ap_by_essid (self->priv->ap_list, essid); + g_free (essid); + } + g_free (built_path); + + return ret_ap; +} + + +/* + * nm_device_ap_list_get + * + * Return a pointer to the AP list + * + */ +NMAccessPointList * +nm_device_802_11_wireless_ap_list_get (NMDevice80211Wireless *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return self->priv->ap_list; +} + + +static gboolean +set_scan_interval_cb (gpointer user_data) +{ + NMData *data = (NMData*) user_data; + + nm_device_802_11_wireless_set_scan_interval (data, NULL, NM_WIRELESS_SCAN_INTERVAL_INACTIVE); + + return FALSE; +} + +void +nm_device_802_11_wireless_set_scan_interval (NMData *data, + NMDevice80211Wireless *self, + NMWirelessScanInterval interval) +{ + static guint source_id = 0; + GSource * source = NULL; + GSList * elt; + + g_return_if_fail (data != NULL); + + if (source_id != 0) + g_source_remove (source_id); + + for (elt = data->dev_list; elt; elt = g_slist_next (elt)) + { + NMDevice *d = (NMDevice *)(elt->data); + if (self && (NM_DEVICE (self) != d)) + continue; + + if (d && nm_device_is_802_11_wireless (d)) + { + guint seconds; + + switch (interval) + { + case NM_WIRELESS_SCAN_INTERVAL_INIT: + seconds = 15; + break; + + case NM_WIRELESS_SCAN_INTERVAL_INACTIVE: + seconds = 120; + break; + + case NM_WIRELESS_SCAN_INTERVAL_ACTIVE: + default: + seconds = 20; + break; + } + + NM_DEVICE_802_11_WIRELESS (d)->priv->scan_interval = seconds; + } + } + + if (interval != NM_WIRELESS_SCAN_INTERVAL_INACTIVE) + { + source = g_timeout_source_new (120000); + g_source_set_callback (source, set_scan_interval_cb, (gpointer) data, NULL); + source_id = g_source_attach (source, data->main_context); + g_source_unref (source); + } +} + + +/* + * nm_device_get_mode + * + * Get managed/infrastructure/adhoc mode on a device + * + */ +int +nm_device_802_11_wireless_get_mode (NMDevice80211Wireless *self) +{ + NMSock * sk; + int mode = IW_MODE_AUTO; + + g_return_val_if_fail (self != NULL, -1); + + /* Force the card into Managed/Infrastructure mode */ + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + struct iwreq wrq; + + memset (&wrq, 0, sizeof (struct iwreq)); +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET IWMODE.", nm_device_get_iface (NM_DEVICE (self))); +#endif + if (iw_get_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (NM_DEVICE (self)), SIOCGIWMODE, &wrq) == 0) + { + if ((mode == IW_MODE_ADHOC) || (mode == IW_MODE_INFRA)) + mode = wrq.u.mode; + } + else + { + nm_warning ("nm_device_get_mode (%s): error getting card mode. errno = %d", + nm_device_get_iface (NM_DEVICE (self)), errno); + } + nm_dev_sock_close (sk); + } + + return mode; +} + + +/* + * nm_device_set_mode + * + * Set managed/infrastructure/adhoc mode on a device + * + */ +gboolean +nm_device_802_11_wireless_set_mode (NMDevice80211Wireless *self, + const int mode) +{ + NMSock * sk; + gboolean success = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail ((mode == IW_MODE_INFRA) || (mode == IW_MODE_ADHOC) || (mode == IW_MODE_AUTO), FALSE); + + if (nm_device_802_11_wireless_get_mode (self) == mode) + return TRUE; + + /* Force the card into Managed/Infrastructure mode */ + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + const char * iface = nm_device_get_iface (NM_DEVICE (self)); + struct iwreq wreq; + +#ifdef IOCTL_DEBUG + nm_info ("%s: About to SET IWMODE.", iface); +#endif + wreq.u.mode = mode; + if (iw_set_ext (nm_dev_sock_get_fd (sk), iface, SIOCSIWMODE, &wreq) == 0) + success = TRUE; + else + { + if (errno != ENODEV) + nm_warning ("nm_device_set_mode (%s): error setting card to %s mode: %s", + iface, + mode == IW_MODE_INFRA ? "Infrastructure" : \ + (mode == IW_MODE_ADHOC ? "Ad-Hoc" : \ + (mode == IW_MODE_AUTO ? "Auto" : "unknown")), + strerror (errno)); + } + nm_dev_sock_close (sk); + } + + return success; +} + + +/* + * nm_device_802_11_wireless_get_signal_strength + * + * Get the current signal strength of a wireless device. This only works when + * the card is associated with an access point, so will only work for the + * active device. + * + * Returns: -1 on error + * 0 - 100 strength percentage of the connection to the current access point + * + */ +gint8 +nm_device_802_11_wireless_get_signal_strength (NMDevice80211Wireless *self) +{ + g_return_val_if_fail (self != NULL, -1); + + return (self->priv->strength); +} + + +/* + * wireless_stats_to_percent + * + * Convert an iw_stats structure from a scan or the card into + * a magical signal strength percentage. + * + */ +static int +wireless_qual_to_percent (const struct iw_quality *qual, + const struct iw_quality *max_qual, + const struct iw_quality *avg_qual) +{ + int percent = -1; + int level_percent = -1; + + g_return_val_if_fail (qual != NULL, -1); + g_return_val_if_fail (max_qual != NULL, -1); + g_return_val_if_fail (avg_qual != NULL, -1); + +#ifdef IW_QUAL_DEBUG +nm_debug ("QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X", +(__s8)qual->qual, qual->qual, qual->qual, +(__s8)qual->level, qual->level, qual->level, +(__s8)qual->noise, qual->noise, qual->noise, +qual->updated, +(__s8)max_qual->qual, max_qual->qual, max_qual->qual, +(__s8)max_qual->level, max_qual->level, max_qual->level, +(__s8)max_qual->noise, max_qual->noise, max_qual->noise, +max_qual->updated); +#endif + + /* Try using the card's idea of the signal quality first as long as it tells us what the max quality is. + * Drivers that fill in quality values MUST treat them as percentages, ie the "Link Quality" MUST be + * bounded by 0 and max_qual->qual, and MUST change in a linear fashion. Within those bounds, drivers + * are free to use whatever they want to calculate "Link Quality". + */ + if ((max_qual->qual != 0) && !(max_qual->updated & IW_QUAL_QUAL_INVALID) && !(qual->updated & IW_QUAL_QUAL_INVALID)) + percent = (int)(100 * ((double)qual->qual / (double)max_qual->qual)); + + /* If the driver doesn't specify a complete and valid quality, we have two options: + * + * 1) dBm: driver must specify max_qual->level = 0, and have valid values for + * qual->level and (qual->noise OR max_qual->noise) + * 2) raw RSSI: driver must specify max_qual->level > 0, and have valid values for + * qual->level and max_qual->level + * + * This is the WEXT spec. If this interpretation is wrong, I'll fix it. Otherwise, + * If drivers don't conform to it, they are wrong and need to be fixed. + */ + + if ( (max_qual->level == 0) && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level == 0 */ + && !(qual->updated & IW_QUAL_LEVEL_INVALID) /* Must have valid qual->level */ + && ( ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) /* Must have valid max_qual->noise */ + || ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID))) /* OR valid qual->noise */ + ) + { + /* Absolute power values (dBm) */ + + /* Reasonable fallbacks for dumb drivers that don't specify either level. */ + #define FALLBACK_NOISE_FLOOR_DBM -90 + #define FALLBACK_SIGNAL_MAX_DBM -20 + int max_level = FALLBACK_SIGNAL_MAX_DBM; + int noise = FALLBACK_NOISE_FLOOR_DBM; + int level = qual->level - 0x100; + + level = CLAMP (level, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM); + + if ((qual->noise > 0) && (!qual->updated & IW_QUAL_NOISE_INVALID)) + noise = qual->noise - 0x100; + else if ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) + noise = max_qual->noise - 0x100; + noise = CLAMP (noise, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM); + + /* A sort of signal-to-noise ratio calculation */ + level_percent = (int)(100 - 70 *( + ((double)max_level - (double)level) / + ((double)max_level - (double)noise))); +#ifdef IW_QUAL_DEBUG + nm_debug ("QL1: level_percent is %d. max_level %d, level %d, noise_floor %d.", level_percent, max_level, level, noise); +#endif + } + else if ((max_qual->level != 0) && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level as upper bound */ + && !(qual->updated & IW_QUAL_LEVEL_INVALID)) + { + /* Relative power values (RSSI) */ + + int level = qual->level; + + /* Signal level is relavtive (0 -> max_qual->level) */ + level = CLAMP (level, 0, max_qual->level); + level_percent = (int)(100 * ((double)level / (double)max_qual->level)); +#ifdef IW_QUAL_DEBUG + nm_debug ("QL2: level_percent is %d. max_level %d, level %d.", level_percent, max_qual->level, level); +#endif + } + else if (percent == -1) + { +#ifdef IW_QUAL_DEBUG + nm_debug ("QL: Could not get quality %% value from driver. Driver is probably buggy."); +#endif + } + + /* If the quality percent was 0 or doesn't exist, then try to use signal levels instead */ + if ((percent < 1) && (level_percent >= 0)) + percent = level_percent; + +#ifdef IW_QUAL_DEBUG + nm_debug ("QL: Final quality percent is %d (%d).", percent, CLAMP (percent, 0, 100)); +#endif + return (CLAMP (percent, 0, 100)); +} + + +/* + * nm_device_802_11_wireless_update_signal_strength + * + * Update the device's idea of the strength of its connection to the + * current access point. + * + */ +void +nm_device_802_11_wireless_update_signal_strength (NMDevice80211Wireless *self) +{ + NMData * app_data; + gboolean has_range = FALSE; + NMSock * sk; + iwrange range; + iwstats stats; + int percent = -1; + + g_return_if_fail (self != NULL); + + app_data = nm_device_get_app_data (NM_DEVICE (self)); + g_assert (app_data); + + /* Grab the scan lock since our strength is meaningless during a scan. */ + if (!nm_try_acquire_mutex (self->priv->scan_mutex, __FUNCTION__)) + return; + + /* If we aren't the active device, we don't really have a signal strength + * that would mean anything. + */ + if (!nm_device_get_act_request (NM_DEVICE (self))) + { + self->priv->strength = -1; + goto out; + } + + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + const char *iface = nm_device_get_iface (NM_DEVICE (self)); + + memset (&range, 0, sizeof (iwrange)); + memset (&stats, 0, sizeof (iwstats)); +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET 'iwrange'.", iface); +#endif + has_range = (iw_get_range_info (nm_dev_sock_get_fd (sk), iface, &range) >= 0); +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET 'iwstats'.", iface); +#endif + if (iw_get_stats (nm_dev_sock_get_fd (sk), iface, &stats, &range, has_range) == 0) + { + percent = wireless_qual_to_percent (&stats.qual, (const iwqual *)(&self->priv->max_qual), + (const iwqual *)(&self->priv->avg_qual)); + } + nm_dev_sock_close (sk); + } + + /* Try to smooth out the strength. Atmel cards, for example, will give no strength + * one second and normal strength the next. + */ + if ((percent == -1) && (++self->priv->invalid_strength_counter <= 3)) + percent = self->priv->strength; + else + self->priv->invalid_strength_counter = 0; + + if (percent != self->priv->strength) + nm_dbus_signal_device_strength_change (app_data->dbus_connection, self, percent); + + self->priv->strength = percent; + +out: + nm_unlock_mutex (self->priv->scan_mutex, __func__); +} + + +/* + * nm_device_get_essid + * + * If a device is wireless, return the essid that it is attempting + * to use. + * + * Returns: allocated string containing essid. Must be freed by caller. + * + */ +char * +nm_device_802_11_wireless_get_essid (NMDevice80211Wireless *self) +{ + NMSock * sk; + int err; + const char * iface; + + g_return_val_if_fail (self != NULL, NULL); + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + wireless_config info; + +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET 'basic config' for ESSID.", iface); +#endif + err = iw_get_basic_config (nm_dev_sock_get_fd (sk), iface, &info); + if (err >= 0) + { + if (self->priv->cur_essid) + g_free (self->priv->cur_essid); + self->priv->cur_essid = g_strdup (info.essid); + } + else + { + nm_warning ("nm_device_get_essid(): error getting ESSID for device %s. errno = %d", + iface, errno); + } + + nm_dev_sock_close (sk); + } + + return self->priv->cur_essid; +} + + +/* + * nm_device_802_11_wireless_set_essid + * + * If a device is wireless, set the essid that it should use. + */ +void +nm_device_802_11_wireless_set_essid (NMDevice80211Wireless *self, + const char *essid) +{ + NMSock* sk; + int err; + struct iwreq wreq; + unsigned char safe_essid[IW_ESSID_MAX_SIZE + 1] = "\0"; + const char * iface; + + g_return_if_fail (self != NULL); + + /* Make sure the essid we get passed is a valid size */ + if (!essid) + safe_essid[0] = '\0'; + else + { + strncpy ((char *) safe_essid, essid, IW_ESSID_MAX_SIZE); + safe_essid[IW_ESSID_MAX_SIZE] = '\0'; + } + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + wreq.u.essid.pointer = (caddr_t) safe_essid; + wreq.u.essid.length = strlen ((char *) safe_essid) + 1; + wreq.u.essid.flags = 1; /* Enable essid on card */ + +#ifdef IOCTL_DEBUG + nm_info ("%s: About to SET IWESSID.", iface); +#endif + if ((err = iw_set_ext (nm_dev_sock_get_fd (sk), iface, SIOCSIWESSID, &wreq)) == -1) + { + if (errno != ENODEV) + { + nm_warning ("nm_device_set_essid(): error setting ESSID '%s' for device %s. errno = %d", + safe_essid, iface, errno); + } + } + + nm_dev_sock_close (sk); + + /* Orinoco cards seem to need extra time here to not screw + * up the firmware, which reboots when you set the ESSID. + * Unfortunately, there's no way to know when the card is back up + * again. Sigh... + */ + sleep (2); + } +} + + +/* + * nm_device_get_frequency + * + * For wireless devices, get the frequency we broadcast/receive on. + * + */ +static double +nm_device_802_11_wireless_get_frequency (NMDevice80211Wireless *self) +{ + NMSock * sk; + int err; + double freq = 0; + const char * iface; + + g_return_val_if_fail (self != NULL, 0); + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + struct iwreq wrq; + +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET IWFREQ.", iface); +#endif + err = iw_get_ext (nm_dev_sock_get_fd (sk), iface, SIOCGIWFREQ, &wrq); + if (err >= 0) + freq = iw_freq2float (&wrq.u.freq); + if (err == -1) + { + nm_warning ("nm_device_get_frequency(): error getting frequency for device %s. errno = %d", + iface, errno); + } + + nm_dev_sock_close (sk); + } + + return freq; +} + + +/* + * nm_device_set_frequency + * + * For wireless devices, set the frequency to broadcast/receive on. + * A frequency <= 0 means "auto". + * + */ +static void +nm_device_802_11_wireless_set_frequency (NMDevice80211Wireless *self, + const double freq) +{ + NMSock * sk; + int err; + const char * iface; + + /* HACK FOR NOW */ + if (freq <= 0) + return; + + g_return_if_fail (self != NULL); + + if (nm_device_802_11_wireless_get_frequency (self) == freq) + return; + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + struct iwreq wrq; + + if (freq <= 0) + { + /* Auto */ + /* People like to make things hard for us. Even though iwlib/iwconfig say + * that wrq.u.freq.m should be -1 for "auto" mode, nobody actually supports + * that. Madwifi actually uses "0" to mean "auto". So, we'll try 0 first + * and if that doesn't work, fall back to the iwconfig method and use -1. + * + * As a further note, it appears that Atheros/Madwifi cards can't go back to + * any-channel operation once you force set the channel on them. For example, + * if you set a prism54 card to a specific channel, but then set the ESSID to + * something else later, it will scan for the ESSID and switch channels just fine. + * Atheros cards, however, just stay at the channel you previously set and don't + * budge, no matter what you do to them, until you tell them to go back to + * any-channel operation. + */ + wrq.u.freq.m = 0; + wrq.u.freq.e = 0; + wrq.u.freq.flags = 0; + } + else + { + /* Fixed */ + wrq.u.freq.flags = IW_FREQ_FIXED; + iw_float2freq (freq, &wrq.u.freq); + } +#ifdef IOCTL_DEBUG + nm_info ("%s: About to SET IWFREQ.", iface); +#endif + if ((err = iw_set_ext (nm_dev_sock_get_fd (sk), iface, SIOCSIWFREQ, &wrq)) == -1) + { + gboolean success = FALSE; + if ((freq <= 0) && ((errno == EINVAL) || (errno == EOPNOTSUPP))) + { + /* Ok, try "auto" the iwconfig way if the Atheros way didn't work */ + wrq.u.freq.m = -1; + wrq.u.freq.e = 0; + wrq.u.freq.flags = 0; + if (iw_set_ext (nm_dev_sock_get_fd (sk), iface, SIOCSIWFREQ, &wrq) != -1) + success = TRUE; + } + } + + nm_dev_sock_close (sk); + } +} + + +/* + * nm_device_get_bitrate + * + * For wireless devices, get the bitrate to broadcast/receive at. + * Returned value is rate in KHz. + * + */ +static int +nm_device_802_11_wireless_get_bitrate (NMDevice80211Wireless *self) +{ + NMSock * sk; + int err = -1; + struct iwreq wrq; + const char * iface; + + g_return_val_if_fail (self != NULL, 0); + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET IWRATE.", iface); +#endif + err = iw_get_ext (nm_dev_sock_get_fd (sk), iface, SIOCGIWRATE, &wrq); + nm_dev_sock_close (sk); + } + + return ((err >= 0) ? wrq.u.bitrate.value / 1000 : 0); +} + + +/* + * nm_device_set_bitrate + * + * For wireless devices, set the bitrate to broadcast/receive at. + * Rate argument should be in Mbps (mega-bits per second), or 0 for automatic. + * + */ +static void +nm_device_802_11_wireless_set_bitrate (NMDevice80211Wireless *self, + const int Mbps) +{ + NMSock * sk; + const char * iface; + + g_return_if_fail (self != NULL); + + if (nm_device_802_11_wireless_get_bitrate (self) == Mbps) + return; + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + struct iwreq wrq; + + if (Mbps != 0) + { + wrq.u.bitrate.value = Mbps * 1000; + wrq.u.bitrate.fixed = 1; + } + else + { + /* Auto bitrate */ + wrq.u.bitrate.value = -1; + wrq.u.bitrate.fixed = 0; + } + /* Silently fail as not all drivers support setting bitrate yet (ipw2x00 for example) */ +#ifdef IOCTL_DEBUG + nm_info ("%s: About to SET IWRATE.", iface); +#endif + iw_set_ext (nm_dev_sock_get_fd (sk), iface, SIOCSIWRATE, &wrq); + + nm_dev_sock_close (sk); + } +} + + +/* + * nm_device_get_bssid + * + * If a device is wireless, get the access point's ethernet address + * that the card is associated with. + */ +void +nm_device_802_11_wireless_get_bssid (NMDevice80211Wireless *self, + struct ether_addr *bssid) +{ + NMSock * sk; + struct iwreq wrq; + const char * iface; + + g_return_if_fail (self != NULL); + g_return_if_fail (bssid != NULL); + + memset (bssid, 0, sizeof (struct ether_addr)); + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET IWAP.", iface); +#endif + if (iw_get_ext (nm_dev_sock_get_fd (sk), iface, SIOCGIWAP, &wrq) >= 0) + memcpy (bssid, &(wrq.u.ap_addr.sa_data), sizeof (struct ether_addr)); + nm_dev_sock_close (sk); + } +} + + +/* + * nm_device_set_wep_enc_key + * + * If a device is wireless, set the encryption key that it should use. + * + * key: encryption key to use, or NULL or "" to disable encryption. + */ +void +nm_device_802_11_wireless_set_wep_enc_key (NMDevice80211Wireless *self, + const char *key, + int auth_method) +{ + NMSock * sk; + struct iwreq wreq; + int keylen; + unsigned char safe_key[IW_ENCODING_TOKEN_MAX + 1]; + gboolean set_key = FALSE; + const char * iface; + + g_return_if_fail (self != NULL); + + /* Make sure the essid we get passed is a valid size */ + if (!key) + safe_key[0] = '\0'; + else + { + strncpy ((char *) safe_key, key, IW_ENCODING_TOKEN_MAX); + safe_key[IW_ENCODING_TOKEN_MAX] = '\0'; + } + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + wreq.u.data.pointer = (caddr_t) NULL; + wreq.u.data.length = 0; + wreq.u.data.flags = IW_ENCODE_ENABLED; + + /* Unfortunately, some drivers (Cisco) don't make a distinction between + * Open System authentication mode and whether or not to use WEP. You + * DON'T have to use WEP when using Open System, but these cards force + * it. Therefore, we have to set Open System mode when using WEP. + */ + + if (strlen ((char *) safe_key) == 0) + { + wreq.u.data.flags |= IW_ENCODE_DISABLED | IW_ENCODE_NOKEY; + set_key = TRUE; + } + else + { + unsigned char parsed_key[IW_ENCODING_TOKEN_MAX + 1]; + + keylen = iw_in_key_full (nm_dev_sock_get_fd (sk), iface, + (char *) safe_key, &parsed_key[0], &wreq.u.data.flags); + if (keylen > 0) + { + switch (auth_method) + { + case IW_AUTH_ALG_OPEN_SYSTEM: + wreq.u.data.flags |= IW_ENCODE_OPEN; + break; + case IW_AUTH_ALG_SHARED_KEY: + wreq.u.data.flags |= IW_ENCODE_RESTRICTED; + break; + default: + wreq.u.data.flags |= IW_ENCODE_RESTRICTED; + break; + } + wreq.u.data.pointer = (caddr_t) &parsed_key; + wreq.u.data.length = keylen; + set_key = TRUE; + } + } + + if (set_key) + { +#ifdef IOCTL_DEBUG + nm_info ("%s: About to SET IWENCODE.", iface); +#endif + if (iw_set_ext (nm_dev_sock_get_fd (sk), iface, SIOCSIWENCODE, &wreq) == -1) + { + if (errno != ENODEV) + { + nm_warning ("nm_device_set_wep_enc_key(): error setting key for device %s. errno = %d", + iface, errno); + } + } + } + + nm_dev_sock_close (sk); + } else nm_warning ("nm_device_set_wep_enc_key(): could not get wireless control socket."); +} + +/* + * nm_device_wireless_schedule_scan + * + * Schedule a wireless scan in the /device's/ thread. + * + */ +static void +schedule_scan (NMDevice80211Wireless *self) +{ + GSource * wscan_source; + guint wscan_source_id; + NMWirelessScanCB * scan_cb; + GMainContext * context; + + g_return_if_fail (self != NULL); + + scan_cb = g_malloc0 (sizeof (NMWirelessScanCB)); + scan_cb->dev = self; + scan_cb->force = FALSE; + + wscan_source = g_timeout_source_new (self->priv->scan_interval * 1000); + g_source_set_callback (wscan_source, nm_device_802_11_wireless_scan, scan_cb, NULL); + context = nm_device_get_main_context (NM_DEVICE (self)); + wscan_source_id = g_source_attach (wscan_source, context); + g_source_unref (wscan_source); +} + + +static void +free_process_scan_cb_data (NMWirelessScanResults *cb_data) +{ + if (!cb_data) + return; + + if (cb_data->results) + g_free (cb_data->results); + g_object_unref (G_OBJECT (cb_data->dev)); + memset (cb_data, 0, sizeof (NMWirelessScanResults)); + g_free (cb_data); +} + +/* + * nm_device_wireless_process_scan_results + * + * Process results of an iwscan() into our own AP lists. We're an idle function, + * but we never reschedule ourselves. + * + */ +static gboolean +handle_scan_results (gpointer user_data) +{ + NMWirelessScanResults * cb_data = (NMWirelessScanResults *) user_data; + NMDevice80211Wireless * self; + GTimeVal cur_time; + NMAPListIter * iter = NULL; + const char * iface; + NMData * app_data; + NMAccessPointList * ap_list; + + g_return_val_if_fail (cb_data != NULL, FALSE); + + self = NM_DEVICE_802_11_WIRELESS (cb_data->dev); + if (!self || !cb_data->results) + { + free_process_scan_cb_data (cb_data); + return FALSE; + } + + iface = nm_device_get_iface (NM_DEVICE (self)); + app_data = nm_device_get_app_data (NM_DEVICE (self)); + if (cb_data->results_len > 0) + { + if (!process_scan_results (self, cb_data->results, cb_data->results_len)) + nm_warning ("nm_device_wireless_process_scan_results(%s): process_scan_results() returned an error.", iface); + + /* Once we have the list, copy in any relevant information from our Allowed list. */ + nm_ap_list_copy_properties (nm_device_802_11_wireless_ap_list_get (self), app_data->allowed_ap_list); + } + + /* Walk the access point list and remove any access points older than 180s */ + g_get_current_time (&cur_time); + ap_list = nm_device_802_11_wireless_ap_list_get (self); + if (ap_list && (iter = nm_ap_list_iter_new (ap_list))) + { + NMAccessPoint *outdated_ap; + GSList * outdated_list = NULL; + GSList * elt; + NMActRequest * req = nm_device_get_act_request (NM_DEVICE (self)); + NMAccessPoint *cur_ap = NULL; + + if (req) + { + cur_ap = nm_act_request_get_ap (req); + g_assert (cur_ap); + } + + while ((outdated_ap = nm_ap_list_iter_next (iter))) + { + const GTimeVal *ap_time = nm_ap_get_last_seen (outdated_ap); + gboolean keep_around = FALSE; + + /* Don't ever prune the AP we're currently associated with */ + if ( nm_ap_get_essid (outdated_ap) + && (cur_ap && (nm_null_safe_strcmp (nm_ap_get_essid (cur_ap), nm_ap_get_essid (outdated_ap))) == 0)) + keep_around = TRUE; + + if (!keep_around && (ap_time->tv_sec + 180 < cur_time.tv_sec)) + outdated_list = g_slist_append (outdated_list, outdated_ap); + } + nm_ap_list_iter_free (iter); + + /* Ok, now remove outdated ones. We have to do it after the lock + * because nm_ap_list_remove_ap() locks the list too. + */ + for (elt = outdated_list; elt; elt = g_slist_next (elt)) + { + if ((outdated_ap = (NMAccessPoint *)(elt->data))) + { + nm_dbus_signal_wireless_network_change (app_data->dbus_connection, self, outdated_ap, NETWORK_STATUS_DISAPPEARED, -1); + nm_ap_list_remove_ap (nm_device_802_11_wireless_ap_list_get (self), outdated_ap); + } + } + g_slist_free (outdated_list); + } + + nm_policy_schedule_device_change_check (app_data); + + free_process_scan_cb_data (cb_data); + + return FALSE; +} + + +/* + * nm_device_wireless_scan + * + * Get a list of access points this device can see. + * + */ +static gboolean +nm_device_802_11_wireless_scan (gpointer user_data) +{ + NMWirelessScanCB * scan_cb = (NMWirelessScanCB *)(user_data); + NMDevice80211Wireless * self = NULL; + NMWirelessScanResults * scan_results = NULL; + guint32 caps; + NMData * app_data; + + g_return_val_if_fail (scan_cb != NULL, FALSE); + + self = scan_cb->dev; + if (!self || !nm_device_get_app_data (NM_DEVICE (self))) + { + g_free (scan_cb); + return FALSE; + } + app_data = nm_device_get_app_data (NM_DEVICE (self)); + + caps = nm_device_get_capabilities (NM_DEVICE (self)); + if (!(caps & NM_DEVICE_CAP_NM_SUPPORTED) || !(caps & NM_DEVICE_CAP_WIRELESS_SCAN)) + { + g_free (scan_cb); + return FALSE; + } + + /* Reschedule ourselves if all wireless is disabled, we're asleep, + * or we are currently activating. + */ + if ( (app_data->wireless_enabled == FALSE) + || (app_data->asleep == TRUE) + || (nm_device_is_activating (NM_DEVICE (self)) == TRUE)) + { + nm_device_802_11_wireless_set_scan_interval (app_data, self, NM_WIRELESS_SCAN_INTERVAL_INIT); + goto reschedule; + } + + /* + * A/B/G cards should only scan if they are disconnected. Set the timeout to active + * for the case we lose this connection shortly, it will reach this point and then + * nm_device_is_activated will return FALSE, letting the scan proceed. + */ + if ((self->priv->num_freqs > 14) && nm_device_is_activated (NM_DEVICE (self)) == TRUE) + { + nm_device_802_11_wireless_set_scan_interval (app_data, self, NM_WIRELESS_SCAN_INTERVAL_ACTIVE); + goto reschedule; + } + + /* Grab the scan mutex */ + if (nm_try_acquire_mutex (self->priv->scan_mutex, __func__)) + { + NMSock * sk; + gboolean devup_err; + const char * iface; + + /* Device must be up before we can scan */ + devup_err = nm_device_bring_up_wait (NM_DEVICE (self), 1); + if (devup_err) + { + nm_unlock_mutex (self->priv->scan_mutex, __func__); + goto reschedule; + } + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL))) + { + int err; + int orig_mode = IW_MODE_INFRA; + double orig_freq = 0; + int orig_rate = 0; + const int interval = 20; + struct iwreq wrq; + + orig_mode = nm_device_802_11_wireless_get_mode (self); + if (orig_mode == IW_MODE_ADHOC) + { + orig_freq = nm_device_802_11_wireless_get_frequency (self); + orig_rate = nm_device_802_11_wireless_get_bitrate (self); + } + + /* Must be in infrastructure mode during scan, otherwise we don't get a full + * list of scan results. Scanning doesn't work well in Ad-Hoc mode :( + */ + nm_device_802_11_wireless_set_mode (self, IW_MODE_INFRA); + nm_device_802_11_wireless_set_frequency (self, 0); + + wrq.u.data.pointer = NULL; + wrq.u.data.flags = 0; + wrq.u.data.length = 0; + if (iw_set_ext (nm_dev_sock_get_fd (sk), iface, SIOCSIWSCAN, &wrq) < 0) + { + nm_warning ("nm_device_wireless_scan(%s): couldn't trigger wireless scan. errno = %d", + iface, errno); + } + else + { + guint8 * results = NULL; + guint32 results_len = 0; + + /* Initial pause for card to return data */ + g_usleep (G_USEC_PER_SEC / 4); + + if (get_scan_results (self, sk, &results, &results_len)) + { + scan_results = g_malloc0 (sizeof (NMWirelessScanResults)); + g_object_ref (G_OBJECT (self)); + scan_results->dev = self; + scan_results->results = results; + scan_results->results_len = results_len; + } + else + nm_warning ("nm_device_wireless_scan(%s): get_scan_results() returned an error.", iface); + } + + nm_device_802_11_wireless_set_mode (self, orig_mode); + /* Only set frequency if ad-hoc mode */ + if (orig_mode == IW_MODE_ADHOC) + { + nm_device_802_11_wireless_set_frequency (self, orig_freq); + nm_device_802_11_wireless_set_bitrate (self, orig_rate); + } + + nm_dev_sock_close (sk); + } + nm_unlock_mutex (self->priv->scan_mutex, __func__); + } + + /* We run the scan processing function from the main thread, since it must deliver + * messages over DBUS. Plus, that way the main thread is the only thread that has + * to modify the device's access point list. + */ + if (scan_results != NULL) + { + guint scan_process_source_id = 0; + GSource * scan_process_source = g_idle_source_new (); + GTimeVal cur_time; + + g_source_set_callback (scan_process_source, handle_scan_results, scan_results, NULL); + scan_process_source_id = g_source_attach (scan_process_source, app_data->main_context); + g_source_unref (scan_process_source); + + g_get_current_time (&cur_time); + self->priv->last_scan = cur_time.tv_sec; + } + +reschedule: + /* Make sure we reschedule ourselves so we keep scanning */ + schedule_scan (self); + + g_free (scan_cb); + return FALSE; +} + +/* + * Return the amount of time we should wait for the device + * to get a link, based on the # of frequencies it has to + * scan. + */ +static inline gint +get_association_pause_value (NMDevice80211Wireless *self) +{ + /* If the card supports more than 14 channels, we should probably wait + * around 10s so it can scan them all. After we set the ESSID on the card, the card + * has to scan all channels to find our requested AP (which can take a long time + * if it is an A/B/G chipset like the Atheros 5212, for example). + */ + if (self->priv->num_freqs > 14) + return 8; + else + return 5; +} + + +static gboolean +link_test (int tries, + nm_completion_args args) +{ + NMDevice80211Wireless * self = args[0]; + gboolean *err = args[1]; + + g_return_val_if_fail (self != NULL, TRUE); + g_return_val_if_fail (err != NULL, TRUE); + + if (is_associated (self) && nm_device_802_11_wireless_get_essid (self)) + { + *err = FALSE; + return TRUE; + } + *err = TRUE; + return FALSE; +} + +static gboolean +is_up_and_associated_wait (NMDevice80211Wireless *self, + int timeout, + int interval) +{ + gboolean err; + const gint delay = (G_USEC_PER_SEC * get_association_pause_value (self)) / interval; + const gint max_cycles = timeout * interval; + nm_completion_args args; + + args[0] = self; + args[1] = &err; + nm_wait_for_completion (max_cycles, delay, NULL, link_test, args); + return !err; +} + + +/* + * nm_device_set_wireless_config + * + * Bring up a wireless card with the essid and wep key of its "best" ap + * + * Returns: TRUE on successful activation + * FALSE on unsuccessful activation (ie no best AP) + * + */ +static gboolean +set_wireless_config (NMDevice80211Wireless *self, + NMAccessPoint *ap) +{ + const char * essid = NULL; + NMAPSecurity * security; + int we_cipher; + + g_return_val_if_fail (ap != NULL, FALSE); + g_return_val_if_fail (nm_ap_get_essid (ap) != NULL, FALSE); + + security = nm_ap_get_security (ap); + g_return_val_if_fail (security != NULL, FALSE); + + self->priv->failed_link_count = 0; + + /* Force the card into Managed/Infrastructure mode */ + nm_device_bring_down_wait (NM_DEVICE (self), 0); + nm_device_bring_up_wait (NM_DEVICE (self), 0); + + nm_device_802_11_wireless_set_mode (self, IW_MODE_INFRA); + + essid = nm_ap_get_essid (ap); + + nm_device_802_11_wireless_set_mode (self, nm_ap_get_mode (ap)); + nm_device_802_11_wireless_set_bitrate (self, 0); + + if (nm_ap_get_user_created (ap) || (nm_ap_get_freq (ap) && (nm_ap_get_mode (ap) == IW_MODE_ADHOC))) + nm_device_802_11_wireless_set_frequency (self, nm_ap_get_freq (ap)); + else + nm_device_802_11_wireless_set_frequency (self, 0); /* auto */ + + /* FIXME: set card's config using wpa_supplicant, not ourselves */ + nm_ap_security_device_setup (security, self); + + nm_device_802_11_wireless_set_essid (self, essid); + + nm_info ("Activation (%s/wireless): using essid '%s', with '%s' security.", + nm_device_get_iface (NM_DEVICE (self)), essid, nm_ap_security_get_description (security)); + + /* Bring the device up and pause to allow card to associate. After we set the ESSID + * on the card, the card has to scan all channels to find our requested AP (which can + * take a long time if it is an A/B/G chipset like the Atheros 5212, for example). + */ + is_up_and_associated_wait (self, 2, 100); + + /* Some cards don't really work well in ad-hoc mode unless you explicitly set the bitrate + * on them. (Netgear WG511T/Atheros 5212 with madwifi drivers). Until we can get rate information + * from scanned access points out of iwlib, clamp bitrate for these cards at 11Mbps. + */ + if ((nm_ap_get_mode (ap) == IW_MODE_ADHOC) && (nm_device_802_11_wireless_get_bitrate (self) <= 0)) + nm_device_802_11_wireless_set_bitrate (self, 11000); /* In Kbps */ + + return TRUE; +} + + +/* + * nm_device_wireless_configure_adhoc + * + * Create an ad-hoc network (rather than associating with one). + * + */ +static gboolean +wireless_configure_adhoc (NMDevice80211Wireless *self, + NMAccessPoint *ap, + NMActRequest *req) +{ + NMData * data; + int auth = 0; + NMAPListIter * iter; + NMAccessPoint * tmp_ap; + double card_freqs[IW_MAX_FREQUENCIES]; + int num_freqs = 0, i; + double freq_to_use = 0; + iwrange range; + NMSock * sk; + int err; + const char * iface; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + if (nm_ap_get_encrypted (ap)) + auth = IW_AUTH_ALG_SHARED_KEY; + + /* Build our local list of frequencies to whittle down until we find a free one */ + memset (&card_freqs, 0, sizeof (card_freqs)); + num_freqs = MIN (self->priv->num_freqs, IW_MAX_FREQUENCIES); + for (i = 0; i < num_freqs; i++) + card_freqs[i] = self->priv->freqs[i]; + + /* We need to find a clear wireless channel to use. We will + * only use 802.11b channels for now. + */ + iter = nm_ap_list_iter_new (nm_device_802_11_wireless_ap_list_get (self)); + while ((tmp_ap = nm_ap_list_iter_next (iter))) + { + double ap_freq = nm_ap_get_freq (tmp_ap); + for (i = 0; i < num_freqs && ap_freq; i++) + { + if (card_freqs[i] == ap_freq) + card_freqs[i] = 0; + } + } + nm_ap_list_iter_free (iter); + + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __func__, NULL)) == NULL) + return FALSE; + + iface = nm_device_get_iface (NM_DEVICE (self)); + err = iw_get_range_info (nm_dev_sock_get_fd (sk), iface, &range); + nm_dev_sock_close (sk); + if (err < 0) + return FALSE; + + /* Ok, find the first non-zero freq in our table and use it. + * For now we only try to use a channel in the 802.11b channel + * space so that most everyone can see it. + */ + for (i = 0; i < num_freqs; i++) + { + int channel = iw_freq_to_channel (card_freqs[i], &range); + if (card_freqs[i] && (channel > 0) && (channel < 15)) + { + freq_to_use = card_freqs[i]; + break; + } + } + + /* Hmm, no free channels in 802.11b space. Pick one more or less randomly */ + if (!freq_to_use) + { + double pfreq; + int channel = (int)(random () % 14); + int err; + + err = iw_channel_to_freq (channel, &pfreq, &range); + if (err == channel) + freq_to_use = pfreq; + } + + if (!freq_to_use) + return FALSE; + + nm_ap_set_freq (ap, freq_to_use); + + nm_info ("Will create network '%s' with frequency %f.", nm_ap_get_essid (ap), nm_ap_get_freq (ap)); + set_wireless_config (self, ap); + + return TRUE; +} + + +/* + * nm_device_wireless_is_associated + * + * Figure out whether or not we're associated to an access point + */ +static gboolean +is_associated (NMDevice80211Wireless *self) +{ + struct iwreq wrq; + NMSock * sk; + gboolean associated = FALSE; + NMData * app_data; + const char * iface; + + app_data = nm_device_get_app_data (NM_DEVICE (self)); + g_assert (app_data); + + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL)) == NULL) + return FALSE; + + /* Some cards, for example ipw2x00 cards, can short-circuit the MAC + * address check using this check on IWNAME. Its faster. + */ + memset (&wrq, 0, sizeof (struct iwreq)); + iface = nm_device_get_iface (NM_DEVICE (self)); +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET IWNAME.", iface); +#endif + if (iw_get_ext (nm_dev_sock_get_fd (sk), iface, SIOCGIWNAME, &wrq) >= 0) + { + if (!strcmp (wrq.u.name, "unassociated")) + { + associated = FALSE; + goto out; + } + } + + if (!associated) + { + /* + * For all other wireless cards, the best indicator of a "link" at this time + * seems to be whether the card has a valid access point MAC address. + * Is there a better way? Some cards don't work too well with this check, ie + * Lucent WaveLAN. + */ +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET IWAP.", iface); +#endif + if (iw_get_ext (nm_dev_sock_get_fd (sk), iface, SIOCGIWAP, &wrq) >= 0) + if (nm_ethernet_address_is_valid ((struct ether_addr *)(&(wrq.u.ap_addr.sa_data)))) + associated = TRUE; + } + +out: + nm_dev_sock_close (sk); + + return associated; +} + + +static gboolean +nm_dwwfl_test (int tries, + nm_completion_args args) +{ + NMDevice80211Wireless * self = args[0]; + guint * assoc_count = args[1]; + double * last_freq = args[2]; + char * essid = args[3]; + guint required = GPOINTER_TO_UINT (args[4]); + + double cur_freq = nm_device_802_11_wireless_get_frequency (self); + gboolean assoc = is_associated (self); + const char * cur_essid = nm_device_802_11_wireless_get_essid (self); + + /* If we've been cancelled, return that we should stop */ + if (nm_device_activation_should_cancel (NM_DEVICE (self))) + return TRUE; + + /* If we're on the same frequency and essid, and we're associated, + * increment the count for how many iterations we've been associated; + * otherwise start over. To avoid a direct comparison of floating points, we + * ensure that the absolute value of their difference is within an epsilon. */ + if ((fabs(cur_freq - *last_freq) < DBL_EPSILON) && assoc && !strcmp (essid, cur_essid)) + { + (*assoc_count)++; + } + else + { + *assoc_count = 0; + *last_freq = cur_freq; + } + + /* If we're told to cancel, return that we're finished. + * If the card's frequency has been stable for more than the required + * interval, return that we're finished. + * Otherwise, we're not finished. */ + if (nm_device_activation_should_cancel (NM_DEVICE (self)) || (*assoc_count >= required)) + return TRUE; + + return FALSE; +} + + +/* + * nm_device_wireless_wait_for_link + * + * Try to be clever about when the wireless card really has associated with the access point. + * Return TRUE when we think that it has, and FALSE when we thing it has not associated. + * + */ +static gboolean +nm_device_wireless_wait_for_link (NMDevice80211Wireless *self, + const char *essid) +{ + guint assoc = 0; + double last_freq = 0; + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; + nm_completion_args args; + + /* we want to sleep for a very short amount of time, to minimize + * hysteresis on the boundaries of our required time. But we + * also want the maximum to be based on what the card can handle. */ + const guint delay = 30; + const guint required_tries = 10; + const guint min_delay = 2 * (delay / required_tries); + + /* for cards that don't scan many frequencies, this will return + * 5 seconds, which we'll bump up to 6 seconds below. Oh well. */ + timeout.tv_sec = (time_t) get_association_pause_value (self); + + /* Refuse to have a timeout that's _less_ than twice the total time + * required before calling a link valid */ + if (timeout.tv_sec < min_delay) + timeout.tv_sec = min_delay; + + /* We more or less keep asking the driver for the frequency the + * card is listening on until it connects to an AP. Once it's + * associated, the driver stops scanning. To detect that, we look + * for the essid and frequency to remain constant for 3 seconds. + * When it remains constant, we assume it's a real link. */ + args[0] = self; + args[1] = &assoc; + args[2] = &last_freq; + args[3] = (void *)essid; + args[4] = (void *)(required_tries * 2); + nm_wait_for_timeout (&timeout, G_USEC_PER_SEC / delay, nm_dwwfl_test, nm_dwwfl_test, args); + + /* If we've had a reasonable association count, we say we have a link */ + if (assoc > required_tries) + return TRUE; + return FALSE; +} + + +static gboolean +ap_need_key (NMDevice80211Wireless *self, NMAccessPoint *ap) +{ + char * essid; + gboolean need_key = FALSE; + NMAPSecurity * security; + const char * iface; + + g_return_val_if_fail (ap != NULL, FALSE); + + essid = nm_ap_get_essid (ap); + security = nm_ap_get_security (ap); + g_assert (security); + + iface = nm_device_get_iface (NM_DEVICE (self)); + + if (!nm_ap_get_encrypted (ap)) + { + nm_info ("Activation (%s/wireless): access point '%s' is unencrypted, no key needed.", + iface, essid ? essid : "(null)"); + } + else + { + if (nm_ap_security_get_key (security)) + { + nm_info ("Activation (%s/wireless): access point '%s' " + "is encrypted, and a key exists. No new key needed.", + iface, essid ? essid : "(null)"); + } + else + { + nm_info ("Activation (%s/wireless): access point '%s' " + "is encrypted, but NO valid key exists. New key needed.", + iface, essid ? essid : "(null)"); + need_key = TRUE; + } + } + + return need_key; +} + + +/* + * nm_device_activate_wireless_configure + * + * Configure a wireless device for association with a particular access point. + * + */ +static gboolean +wireless_configure_infra (NMDevice80211Wireless *self, + NMAccessPoint *ap, + NMActRequest *req) +{ + NMData * data; + gboolean success = FALSE; + const char * iface; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + nm_device_bring_up_wait (NM_DEVICE (self), 1); + + iface = nm_device_get_iface (NM_DEVICE (self)); + nm_info ("Activation (%s/wireless) Stage 2 (Device Configure) will connect to access point '%s'.", + iface, nm_ap_get_essid (ap)); + + if (ap_need_key (self, ap)) + { + nm_dbus_get_user_key_for_network (data->dbus_connection, req, FALSE); +/* FIXME */ +/* Deal with stuff like this */ + return FALSE; + } + + while (success == FALSE) + { + gboolean link = FALSE; + + if (nm_device_activation_should_cancel (NM_DEVICE (self))) + break; + + set_wireless_config (self, ap); + + success = link = nm_device_wireless_wait_for_link (self, nm_ap_get_essid (ap)); + + if (nm_device_activation_should_cancel (NM_DEVICE (self))) + break; + + if (!link) + { + nm_info ("Activation (%s/wireless): no hardware link to '%s'.", + iface, nm_ap_get_essid (ap) ? nm_ap_get_essid (ap) : "(none)"); + break; + } + } + + if (success) + { + nm_info ("Activation (%s/wireless) Stage 2 (Device Configure) successful. Connected to access point '%s'.", + iface, nm_ap_get_essid (ap) ? nm_ap_get_essid (ap) : "(none)"); + } +/* +What's this for again? + else if (!nm_device_activation_should_cancel (NM_DEVICE (self)) && (nm_act_request_get_stage (req) != NM_ACT_STAGE_NEED_USER_KEY)) +*/ + + return success; +} + + +static gboolean +real_activation_config (NMDevice *dev, NMActRequest *req) +{ + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); + NMAccessPoint * ap = nm_act_request_get_ap (req); + gboolean success = FALSE; + + g_assert (ap); + + if (nm_ap_get_user_created (ap)) + success = wireless_configure_adhoc (self, ap, req); + else + success = wireless_configure_infra (self, ap, req); + + return success; +} + +static guint32 +real_get_type_capabilities (NMDevice *dev) +{ + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); + + return self->priv->capabilities; +} + + +static gboolean +real_probe_link (NMDevice *dev) +{ + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); + gboolean link = FALSE; + NMAccessPoint * ap; + NMActRequest * req; + + if ((req = nm_device_get_act_request (dev))) + { + if ((ap = nm_act_request_get_ap (req))) + link = link_to_specific_ap (self, ap, TRUE); + } + + nm_device_802_11_wireless_update_signal_strength (self); + + return link; +} + + +static void +nm_device_802_11_wireless_dispose (GObject *object) +{ + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (object); + NMDevice80211WirelessClass * klass = NM_DEVICE_802_11_WIRELESS_GET_CLASS (object); + NMDeviceClass * parent_class; + + if (self->priv->dispose_has_run) + /* If dispose did already run, return. */ + return; + + /* Make sure dispose does not run twice. */ + self->priv->dispose_has_run = TRUE; + + /* + * In dispose, you are supposed to free all types referenced from this + * object which might themselves hold a reference to self. Generally, + * the most simple solution is to unref all members on which you own a + * reference. + */ + + nm_device_802_11_wireless_ap_list_clear (self); + if (self->priv->ap_list) + nm_ap_list_unref (self->priv->ap_list); + g_mutex_free (self->priv->scan_mutex); + + /* Chain up to the parent class */ + parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +nm_device_802_11_wireless_finalize (GObject *object) +{ + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (object); + NMDevice80211WirelessClass * klass = NM_DEVICE_802_11_WIRELESS_GET_CLASS (object); + NMDeviceClass * parent_class; + + /* Chain up to the parent class */ + parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +static void +nm_device_802_11_wireless_class_init (NMDevice80211WirelessClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + + object_class->dispose = nm_device_802_11_wireless_dispose; + object_class->finalize = nm_device_802_11_wireless_finalize; + + parent_class->get_type_capabilities = real_get_type_capabilities; + parent_class->discover_generic_capabilities = real_discover_generic_capabilities; + parent_class->init = real_init; + parent_class->start = real_start; + parent_class->deactivate = real_deactivate; + parent_class->activation_config = real_activation_config; + parent_class->probe_link = real_probe_link; + + g_type_class_add_private (object_class, sizeof (NMDevice80211WirelessPrivate)); +} + +GType +nm_device_802_11_wireless_get_type (void) +{ + static GType type = 0; + if (type == 0) + { + static const GTypeInfo info = + { + sizeof (NMDevice80211WirelessClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) nm_device_802_11_wireless_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (NMDevice80211Wireless), + 0, /* n_preallocs */ + (GInstanceInitFunc) nm_device_802_11_wireless_init + }; + type = g_type_register_static (NM_TYPE_DEVICE, + "NMDevice80211Wireless", + &info, 0); + } + return type; +} + + +/*****************************************/ +/* Start code ripped from wpa_supplicant */ +/*****************************************/ +/* + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + +static int hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + + +static int hex2byte(const char *hex) +{ + int a, b; + a = hex2num(*hex++); + if (a < 0) + return -1; + b = hex2num(*hex++); + if (b < 0) + return -1; + return (a << 4) | b; +} + +static int hexstr2bin(const char *hex, char *buf, size_t len) +{ + int i, a; + const char *ipos = hex; + char *opos = buf; + + for (i = 0; i < len; i++) { + a = hex2byte(ipos); + if (a < 0) + return -1; + *opos++ = a; + ipos += 2; + } + return 0; +} + +#define SCAN_SLEEP_CENTISECONDS 10 /* sleep 1/10 of a second, waiting for data */ +static gboolean +get_scan_results (NMDevice80211Wireless *dev, + NMSock *sk, + guint8 **out_res_buf, + guint32 *data_len) +{ + struct iwreq iwr; + guint8 *res_buf; + size_t len, res_buf_len = IW_SCAN_MAX_DATA; + guint8 tries = 0; + gboolean success = FALSE; + + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (sk != NULL, FALSE); + g_return_val_if_fail (out_res_buf != NULL, FALSE); + g_return_val_if_fail (*out_res_buf == NULL, FALSE); + g_return_val_if_fail (data_len != NULL, FALSE); + + *data_len = 0; + + for (;;) + { + res_buf = g_malloc (res_buf_len); + if (!res_buf) + break; + memset (&iwr, 0, sizeof (struct iwreq)); + iwr.u.data.pointer = res_buf; + iwr.u.data.flags = 0; + iwr.u.data.length = res_buf_len; + + if (iw_get_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (NM_DEVICE (dev)), SIOCGIWSCAN, &iwr) == 0) + { + /* success */ + *data_len = iwr.u.data.length; + *out_res_buf = res_buf; + success = TRUE; + break; + } + + g_free (res_buf); + res_buf = NULL; + + if ((errno == E2BIG) && (res_buf_len < 100000)) /* Buffer not big enough */ + { + res_buf_len *= 2; + } + else if (errno == EAGAIN) /* Card doesn't have results yet */ + { + if (tries > 20 * SCAN_SLEEP_CENTISECONDS) + { + nm_warning ("get_scan_results(): card took too much time scanning. Get a better one."); + break; + } + + g_usleep (G_USEC_PER_SEC / SCAN_SLEEP_CENTISECONDS); + tries++; + } + else if (errno == ENODATA) /* No scan results */ + { + success = TRUE; + break; + } + else /* Random errors */ + { + nm_warning ("get_scan_results(): unknown error, or the card returned too much scan info. errno = %d", errno); + break; + } + } + + return success; +} + + +static void +add_new_ap_to_device_list (NMDevice80211Wireless *dev, + NMAccessPoint *ap) +{ + gboolean new = FALSE; + gboolean strength_changed = FALSE; + GTimeVal cur_time; + NMData * app_data; + + g_return_if_fail (dev != NULL); + g_return_if_fail (ap != NULL); + + g_get_current_time (&cur_time); + nm_ap_set_last_seen (ap, &cur_time); + + /* If the AP is not broadcasting its ESSID, try to fill it in here from our + * allowed list where we cache known MAC->ESSID associations. + */ + app_data = nm_device_get_app_data (NM_DEVICE (dev)); + if (!nm_ap_get_essid (ap)) + nm_ap_list_copy_one_essid_by_address (ap, app_data->allowed_ap_list); + + /* Add the AP to the device's AP list */ + if (nm_ap_list_merge_scanned_ap (nm_device_802_11_wireless_ap_list_get (dev), ap, &new, &strength_changed)) + { + DBusConnection *con = app_data->dbus_connection; + /* Handle dbus signals that we need to broadcast when the AP is added to the list or changes strength */ + if (new) + nm_dbus_signal_wireless_network_change (con, dev, ap, NETWORK_STATUS_APPEARED, -1); + else if (strength_changed) + { + nm_dbus_signal_wireless_network_change (con, dev, ap, NETWORK_STATUS_STRENGTH_CHANGED, + nm_ap_get_strength (ap)); + } + } +} + +static gboolean +process_scan_results (NMDevice80211Wireless *dev, + const guint8 *res_buf, + guint32 res_buf_len) +{ + char *pos, *end, *custom, *genie, *gpos, *gend; + NMAccessPoint *ap = NULL; + size_t clen; + struct iw_event iwe_buf, *iwe = &iwe_buf; + + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (res_buf != NULL, FALSE); + g_return_val_if_fail (res_buf_len > 0, FALSE); + + pos = (char *) res_buf; + end = (char *) res_buf + res_buf_len; + + while (pos + IW_EV_LCP_LEN <= end) + { + int ssid_len; + + /* Event data may be unaligned, so make a local, aligned copy + * before processing. */ + memcpy (&iwe_buf, pos, IW_EV_LCP_LEN); + if (iwe->len <= IW_EV_LCP_LEN) + break; + + custom = pos + IW_EV_POINT_LEN; + if (dev->priv->we_version > 18 && + (iwe->cmd == SIOCGIWESSID || + iwe->cmd == SIOCGIWENCODE || + iwe->cmd == IWEVGENIE || + iwe->cmd == IWEVCUSTOM)) + { + /* WE-19 removed the pointer from struct iw_point */ + char *dpos = (char *) &iwe_buf.u.data.length; + int dlen = dpos - (char *) &iwe_buf; + memcpy (dpos, pos + IW_EV_LCP_LEN, sizeof (struct iw_event) - dlen); + } + else + { + memcpy (&iwe_buf, pos, sizeof (struct iw_event)); + custom += IW_EV_POINT_OFF; + } + + switch (iwe->cmd) + { + case SIOCGIWAP: + /* New access point record */ + + /* Merge previous AP */ + if (ap) + { + add_new_ap_to_device_list (dev, ap); + nm_ap_unref (ap); + ap = NULL; + } + + /* New AP with some defaults */ + ap = nm_ap_new (); + nm_ap_set_address (ap, (const struct ether_addr *)(iwe->u.ap_addr.sa_data)); + break; + case SIOCGIWMODE: + switch (iwe->u.mode) + { + case IW_MODE_ADHOC: + nm_ap_set_mode (ap, IW_MODE_ADHOC); + break; + case IW_MODE_MASTER: + case IW_MODE_INFRA: + nm_ap_set_mode (ap, IW_MODE_INFRA); + break; + default: + break; + } + break; + case SIOCGIWESSID: + ssid_len = iwe->u.essid.length; + if (custom + ssid_len > end) + break; + if (iwe->u.essid.flags && (ssid_len > 0) && (ssid_len <= IW_ESSID_MAX_SIZE)) + { + gboolean set = TRUE; + char *essid = g_malloc (IW_ESSID_MAX_SIZE + 1); + memcpy (essid, custom, ssid_len); + essid[ssid_len] = '\0'; + if (!strlen(essid)) + set = FALSE; + else if ((strlen (essid) == 8) && (strcmp (essid, "") == 0)) /* Stupid ipw drivers use */ + set = FALSE; + if (set) + nm_ap_set_essid (ap, essid); + g_free (essid); + } + break; + case SIOCGIWFREQ: + nm_ap_set_freq (ap, iw_freq2float(&(iwe->u.freq))); + break; + case IWEVQUAL: + nm_ap_set_strength (ap, wireless_qual_to_percent (&(iwe->u.qual), + (const iwqual *)(&dev->priv->max_qual), + (const iwqual *)(&dev->priv->avg_qual))); + break; + case SIOCGIWENCODE: + if (!(iwe->u.data.flags & IW_ENCODE_DISABLED)) + nm_ap_add_capabilities_for_wep (ap); + break; +#if 0 + case SIOCGIWRATE: + custom = pos + IW_EV_LCP_LEN; + clen = iwe->len; + if (custom + clen > end) + break; + maxrate = 0; + while (((ssize_t) clen) >= sizeof(struct iw_param)) { + /* Note: may be misaligned, make a local, + * aligned copy */ + memcpy(&p, custom, sizeof(struct iw_param)); + if (p.value > maxrate) + maxrate = p.value; + clen -= sizeof(struct iw_param); + custom += sizeof(struct iw_param); + } + results[ap_num].maxrate = maxrate; + break; +#endif + case IWEVGENIE: + gpos = genie = custom; + gend = genie + iwe->u.data.length; + if (gend > end) + { + nm_warning ("get_scan_results(): IWEVGENIE overflow."); + break; + } + while ((gpos + 1 < gend) && (gpos + 2 + (guint8) gpos[1] <= gend)) + { + guint8 ie = gpos[0], ielen = gpos[1] + 2; + if (ielen > WPA_MAX_IE_LEN) + { + gpos += ielen; + continue; + } + switch (ie) + { + case WPA_GENERIC_INFO_ELEM: + if ((ielen < 2 + 4) || (memcmp (&gpos[2], "\x00\x50\xf2\x01", 4) != 0)) + break; + nm_ap_add_capabilities_from_ie (ap, (const guint8 *)gpos, ielen); + break; + case WPA_RSN_INFO_ELEM: + nm_ap_add_capabilities_from_ie (ap, (const guint8 *)gpos, ielen); + break; + } + gpos += ielen; + } + break; + case IWEVCUSTOM: + clen = iwe->u.data.length; + if (custom + clen > end) + break; + if (clen > 7 && ((strncmp (custom, "wpa_ie=", 7) == 0) || (strncmp (custom, "rsn_ie=", 7) == 0))) + { + char *spos; + int bytes; + char *ie_buf; + + spos = custom + 7; + bytes = custom + clen - spos; + if (bytes & 1) + break; + bytes /= 2; + if (bytes > WPA_MAX_IE_LEN) + { + nm_warning ("get_scan_results(): IE was too long (%d bytes).", bytes); + break; + } + ie_buf = g_malloc0 (bytes); + hexstr2bin (spos, ie_buf, bytes); + if (strncmp (custom, "wpa_ie=", 7) == 0) + nm_ap_add_capabilities_from_ie (ap, (const guint8 *)ie_buf, bytes); + else if (strncmp (custom, "rsn_ie=", 7) == 0) + nm_ap_add_capabilities_from_ie (ap, (const guint8 *)ie_buf, bytes); + g_free (ie_buf); + } + break; + default: + break; + } + + pos += iwe->len; + } + + if (ap) + { + add_new_ap_to_device_list (dev, ap); + nm_ap_unref (ap); + ap = NULL; + } + + return TRUE; +} + +/*****************************************/ +/* End code ripped from wpa_supplicant */ +/*****************************************/ diff --git a/src/nm-device-802-11-wireless.h b/src/nm-device-802-11-wireless.h new file mode 100644 index 0000000000..97f4d0df4f --- /dev/null +++ b/src/nm-device-802-11-wireless.h @@ -0,0 +1,125 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef NM_DEVICE_802_11_WIRELESS_H +#define NM_DEVICE_802_11_WIRELESS_H + +#include +#include +#include + + +#include "nm-device.h" +#include "NetworkManagerAP.h" + +struct NMAccessPointList; + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_802_11_WIRELESS (nm_device_802_11_wireless_get_type ()) +#define NM_DEVICE_802_11_WIRELESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_802_11_WIRELESS, NMDevice80211Wireless)) +#define NM_DEVICE_802_11_WIRELESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_802_11_WIRELESS, NMDevice80211WirelessClass)) +#define NM_IS_DEVICE_802_11_WIRELESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_802_11_WIRELESS)) +#define NM_IS_DEVICE_802_11_WIRELESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_802_11_WIRELESS)) +#define NM_DEVICE_802_11_WIRELESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_802_11_WIRELESS, NMDevice80211WirelessClass)) + +#ifndef NM_DEVICE_802_11_WIRELESS_DEFINED +#define NM_DEVICE_802_11_WIRELESS_DEFINED +typedef struct _NMDevice80211Wireless NMDevice80211Wireless; +#endif + +typedef struct _NMDevice80211WirelessClass NMDevice80211WirelessClass; +typedef struct _NMDevice80211WirelessPrivate NMDevice80211WirelessPrivate; + +struct _NMDevice80211Wireless +{ + NMDevice parent; + + /*< private >*/ + NMDevice80211WirelessPrivate *priv; +}; + +struct _NMDevice80211WirelessClass +{ + NMDeviceClass parent; +}; + + +GType nm_device_802_11_wireless_get_type (void); + +NMDevice80211Wireless * nm_device_802_11_wireless_new (void); + + +static inline gboolean nm_device_is_802_11_wireless (NMDevice *dev); +static inline gboolean nm_device_is_802_11_wireless (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return (G_OBJECT_TYPE (dev) == NM_TYPE_DEVICE_802_11_WIRELESS); +} + +void nm_device_802_11_wireless_set_essid (NMDevice80211Wireless *self, + const char *essid); + +void nm_device_802_11_wireless_get_address (NMDevice80211Wireless *dev, + struct ether_addr *addr); + +void nm_device_802_11_wireless_get_bssid (NMDevice80211Wireless *dev, + struct ether_addr *bssid); + +NMAccessPoint * nm_device_802_11_wireless_get_best_ap (NMDevice80211Wireless *dev); + +NMAccessPoint * nm_device_802_11_wireless_get_activation_ap (NMDevice80211Wireless *dev, + const char *essid, + NMAPSecurity *security); + +void nm_device_802_11_wireless_set_wep_enc_key (NMDevice80211Wireless *dev, + const char *key, + int auth_method); + +void nm_device_802_11_wireless_set_scan_interval (struct NMData *data, + NMDevice80211Wireless *dev, + NMWirelessScanInterval interval); + +void nm_device_802_11_wireless_copy_allowed_to_dev_list (NMDevice80211Wireless *self, + struct NMAccessPointList *allowed_list); + +struct NMAccessPointList * nm_device_802_11_wireless_ap_list_get (NMDevice80211Wireless *dev); + +NMAccessPoint * nm_device_802_11_wireless_ap_list_get_ap_by_obj_path (NMDevice80211Wireless *dev, + const char *obj_path); + +NMAccessPoint * nm_device_802_11_wireless_ap_list_get_ap_by_bssid (NMDevice80211Wireless *dev, + const struct ether_addr *bssid); + +NMAccessPoint * nm_device_802_11_wireless_ap_list_get_ap_by_essid (NMDevice80211Wireless *dev, + const char *essid); + +int nm_device_802_11_wireless_get_mode (NMDevice80211Wireless *self); + +gint8 nm_device_802_11_wireless_get_signal_strength (NMDevice80211Wireless *self); + +void nm_device_802_11_wireless_update_signal_strength (NMDevice80211Wireless *self); + + +G_END_DECLS + +#endif /* NM_DEVICE_802_11_WIRELESS_H */ diff --git a/src/nm-device-802-3-ethernet.c b/src/nm-device-802-3-ethernet.c new file mode 100644 index 0000000000..ab560056ed --- /dev/null +++ b/src/nm-device-802-3-ethernet.c @@ -0,0 +1,349 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "nm-device-802-3-ethernet.h" +#include "nm-device-private.h" +#include "NetworkManagerMain.h" +#include "nm-activation-request.h" +#include "NetworkManagerUtils.h" +#include "nm-utils.h" + +#define NM_DEVICE_802_3_ETHERNET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_802_3_ETHERNET, NMDevice8023EthernetPrivate)) + +struct _NMDevice8023EthernetPrivate +{ + gboolean dispose_has_run; + + struct ether_addr hw_addr; +}; + +static gboolean supports_mii_carrier_detect (NMDevice8023Ethernet *dev); +static gboolean supports_ethtool_carrier_detect (NMDevice8023Ethernet *dev); + + +static void +nm_device_802_3_ethernet_init (NMDevice8023Ethernet * self) +{ + self->priv = NM_DEVICE_802_3_ETHERNET_GET_PRIVATE (self); + self->priv->dispose_has_run = FALSE; + + memset (&(self->priv->hw_addr), 0, sizeof (struct ether_addr)); +} + + +/* + * nm_device_get_hw_address + * + * Get a device's hardware address + * + */ +void +nm_device_802_3_ethernet_get_address (NMDevice8023Ethernet *self, struct ether_addr *addr) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (addr != NULL); + + memcpy (addr, &(self->priv->hw_addr), sizeof (struct ether_addr)); +} + + +static guint32 +real_discover_generic_capabilities (NMDevice *dev) +{ + NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (dev); + guint32 caps = NM_DEVICE_CAP_NONE; + const char * udi = NULL; + char * usb_test = NULL; + NMData * app_data; + + /* cipsec devices are also explicitly unsupported at this time */ + if (strstr (nm_device_get_iface (dev), "cipsec")) + return NM_DEVICE_CAP_NONE; + + /* Ignore Ethernet-over-USB devices too for the moment (Red Hat #135722) */ + app_data = nm_device_get_app_data (dev); + udi = nm_device_get_udi (dev); + if ( libhal_device_property_exists (app_data->hal_ctx, udi, "usb.interface.class", NULL) + && (usb_test = libhal_device_get_property_string (app_data->hal_ctx, udi, "usb.interface.class", NULL))) + { + libhal_free_string (usb_test); + return NM_DEVICE_CAP_NONE; + } + + if (supports_ethtool_carrier_detect (self) || supports_mii_carrier_detect (self)) + caps |= NM_DEVICE_CAP_CARRIER_DETECT; + + return caps; +} + +static gboolean +real_activation_config (NMDevice *dev, NMActRequest *req) +{ + NMData * data; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + return TRUE; +} + + +static gboolean +real_probe_link (NMDevice *dev) +{ + NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (dev); + gboolean link = FALSE; + gchar * contents; + gchar * carrier_path; + gsize length; + guint32 caps; + + if (nm_device_get_removed (dev)) + return FALSE; + + carrier_path = g_strdup_printf ("/sys/class/net/%s/carrier", nm_device_get_iface (dev)); + if (g_file_get_contents (carrier_path, &contents, &length, NULL)) + { + link = (gboolean) atoi (contents); + g_free (contents); + } + g_free (carrier_path); + + /* We say that non-carrier-detect devices always have a link, because + * they never get auto-selected by NM. User has to force them on us, + * so we just hope the user knows whether or not the cable's plugged in. + */ + caps = nm_device_get_capabilities (dev); + if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT)) + link = TRUE; + + return link; + +} + +static void +nm_device_802_3_ethernet_dispose (GObject *object) +{ + NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (object); + NMDevice8023EthernetClass * klass = NM_DEVICE_802_3_ETHERNET_GET_CLASS (object); + NMDeviceClass * parent_class; + + if (self->priv->dispose_has_run) + /* If dispose did already run, return. */ + return; + + /* Make sure dispose does not run twice. */ + self->priv->dispose_has_run = TRUE; + + /* + * In dispose, you are supposed to free all types referenced from this + * object which might themselves hold a reference to self. Generally, + * the most simple solution is to unref all members on which you own a + * reference. + */ + + /* Chain up to the parent class */ + parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +nm_device_802_3_ethernet_finalize (GObject *object) +{ + NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (object); + NMDevice8023EthernetClass * klass = NM_DEVICE_802_3_ETHERNET_GET_CLASS (object); + NMDeviceClass * parent_class; + + /* Chain up to the parent class */ + parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +static void +nm_device_802_3_ethernet_class_init (NMDevice8023EthernetClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + + object_class->dispose = nm_device_802_3_ethernet_dispose; + object_class->finalize = nm_device_802_3_ethernet_finalize; + + parent_class->activation_config = real_activation_config; + parent_class->discover_generic_capabilities = real_discover_generic_capabilities; + parent_class->probe_link = real_probe_link; + + g_type_class_add_private (object_class, sizeof (NMDevice8023EthernetPrivate)); +} + +GType +nm_device_802_3_ethernet_get_type (void) +{ + static GType type = 0; + if (type == 0) + { + static const GTypeInfo info = + { + sizeof (NMDevice8023EthernetClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) nm_device_802_3_ethernet_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (NMDevice8023Ethernet), + 0, /* n_preallocs */ + (GInstanceInitFunc) nm_device_802_3_ethernet_init + }; + type = g_type_register_static (NM_TYPE_DEVICE, + "NMDevice8023Ethernet", + &info, 0); + } + return type; +} + + +/**************************************/ +/* Ethtool capability detection */ +/**************************************/ +#include +#include + +static gboolean +supports_ethtool_carrier_detect (NMDevice8023Ethernet *self) +{ + NMSock * sk; + struct ifreq ifr; + gboolean supports_ethtool = FALSE; + struct ethtool_cmd edata; + const char * iface; + + g_return_val_if_fail (self != NULL, FALSE); + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_GENERAL, __func__, NULL)) == NULL) + { + nm_warning ("cannot open socket on interface %s for ethtool detect; errno=%d", + iface, errno); + return FALSE; + } + + strncpy (ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1); + edata.cmd = ETHTOOL_GLINK; + ifr.ifr_data = (char *) &edata; +#ifdef IOCTL_DEBUG + nm_info ("%s: About to ETHTOOL\n", iface); +#endif + if (ioctl (nm_dev_sock_get_fd (sk), SIOCETHTOOL, &ifr) == -1) + goto out; + + supports_ethtool = TRUE; + +out: +#ifdef IOCTL_DEBUG + nm_info ("%s: Done with ETHTOOL\n", iface); +#endif + nm_dev_sock_close (sk); + return supports_ethtool; +} + + + +/**************************************/ +/* MII capability detection */ +/**************************************/ +#include + +static int +mdio_read (NMDevice8023Ethernet *self, NMSock *sk, struct ifreq *ifr, int location) +{ + struct mii_ioctl_data *mii; + int val = -1; + const char * iface; + + g_return_val_if_fail (sk != NULL, -1); + g_return_val_if_fail (ifr != NULL, -1); + + iface = nm_device_get_iface (NM_DEVICE (self)); + + mii = (struct mii_ioctl_data *) &(ifr->ifr_data); + mii->reg_num = location; + +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET MIIREG\n", iface); +#endif + if (ioctl (nm_dev_sock_get_fd (sk), SIOCGMIIREG, ifr) >= 0) + val = mii->val_out; +#ifdef IOCTL_DEBUG + nm_info ("%s: Done with GET MIIREG\n", iface); +#endif + + return val; +} + +static gboolean +supports_mii_carrier_detect (NMDevice8023Ethernet *self) +{ + NMSock * sk; + struct ifreq ifr; + int bmsr; + gboolean supports_mii = FALSE; + int err; + const char * iface; + + g_return_val_if_fail (self != NULL, FALSE); + + iface = nm_device_get_iface (NM_DEVICE (self)); + if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_GENERAL, __FUNCTION__, NULL)) == NULL) + { + nm_warning ("cannot open socket on interface %s for MII detect; errno=%d", + iface, errno); + return FALSE; + } + + strncpy (ifr.ifr_name, iface, sizeof (ifr.ifr_name) - 1); +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET MIIPHY\n", iface); +#endif + err = ioctl (nm_dev_sock_get_fd (sk), SIOCGMIIPHY, &ifr); +#ifdef IOCTL_DEBUG + nm_info ("%s: Done with GET MIIPHY\n", iface); +#endif + if (err < 0) + goto out; + + /* If we can read the BMSR register, we assume that the card supports MII link detection */ + bmsr = mdio_read (self, sk, &ifr, MII_BMSR); + supports_mii = (bmsr != -1) ? TRUE : FALSE; + +out: + nm_dev_sock_close (sk); + return supports_mii; +} diff --git a/src/nm-device-802-3-ethernet.h b/src/nm-device-802-3-ethernet.h new file mode 100644 index 0000000000..62d96c4b54 --- /dev/null +++ b/src/nm-device-802-3-ethernet.h @@ -0,0 +1,77 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef NM_DEVICE_802_3_ETHERNET_H +#define NM_DEVICE_802_3_ETHERNET_H + +#include +#include +#include + + +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_802_3_ETHERNET (nm_device_802_3_ethernet_get_type ()) +#define NM_DEVICE_802_3_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_802_3_ETHERNET, NMDevice8023Ethernet)) +#define NM_DEVICE_802_3_ETHERNET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_802_3_ETHERNET, NMDevice8023EthernetClass)) +#define NM_IS_DEVICE_802_3_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_802_3_ETHERNET)) +#define NM_IS_DEVICE_802_3_ETHERNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_802_3_ETHERNET)) +#define NM_DEVICE_802_3_ETHERNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_802_3_ETHERNET, NMDevice8023EthernetClass)) + +typedef struct _NMDevice8023Ethernet NMDevice8023Ethernet; +typedef struct _NMDevice8023EthernetClass NMDevice8023EthernetClass; +typedef struct _NMDevice8023EthernetPrivate NMDevice8023EthernetPrivate; + +struct _NMDevice8023Ethernet +{ + NMDevice parent; + + /*< private >*/ + NMDevice8023EthernetPrivate *priv; +}; + +struct _NMDevice8023EthernetClass +{ + NMDeviceClass parent; +}; + + +GType nm_device_802_3_ethernet_get_type (void); + +NMDevice8023Ethernet * nm_device_802_3_ethernet_new (void); + + +static inline gboolean nm_device_is_802_3_ethernet (NMDevice *dev); +static inline gboolean nm_device_is_802_3_ethernet (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return (G_OBJECT_TYPE (dev) == NM_TYPE_DEVICE_802_3_ETHERNET); +} + +void nm_device_802_3_ethernet_get_address (NMDevice8023Ethernet *dev, + struct ether_addr *addr); + +G_END_DECLS + +#endif /* NM_DEVICE_802_3_ETHERNET_H */ diff --git a/src/nm-device-private.h b/src/nm-device-private.h new file mode 100644 index 0000000000..67c1d4d7ca --- /dev/null +++ b/src/nm-device-private.h @@ -0,0 +1,38 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef NM_DEVICE_PRIVATE_H +#define NM_DEVICE_PRIVATE_H + +#include "nm-device.h" + + +void nm_device_set_udi (NMDevice *dev, + const char *udi); + +void nm_device_set_device_type (NMDevice *self, + const NMDeviceType type); + +gboolean nm_device_is_activated (NMDevice *dev); + +GMainContext * nm_device_get_main_context (NMDevice *dev); + +#endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/nm-device.c b/src/nm-device.c new file mode 100644 index 0000000000..110d6d1d35 --- /dev/null +++ b/src/nm-device.c @@ -0,0 +1,1979 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include + +#include "nm-device.h" +#include "nm-device-private.h" +#include "nm-device-802-3-ethernet.h" +#include "nm-device-802-11-wireless.h" +#include "NetworkManagerDbus.h" +#include "NetworkManagerPolicy.h" +#include "NetworkManagerUtils.h" +#include "NetworkManagerSystem.h" +#include "nm-vpn-manager.h" +#include "nm-dhcp-manager.h" +#include "nm-dbus-nmi.h" +#include "nm-utils.h" +#include "autoip.h" + +#define NM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE, NMDevicePrivate)) + +struct _NMDevicePrivate +{ + gboolean dispose_has_run; + + char * udi; + char * iface; + NMDeviceType type; + guint32 capabilities; + char * driver; + gboolean removed; + + gboolean link_active; + guint32 ip4_address; + struct in6_addr ip6_address; + NMData * app_data; + + NMActRequest * act_request; + gboolean quit_activation; + + /* IP configuration info */ + void * system_config_data; /* Distro-specific config data (parsed config file, etc) */ + gboolean use_dhcp; + NMIP4Config * ip4_config; /* Config from DHCP, PPP, or system config files */ + + GMainContext * context; + GMainLoop * loop; + GThread * worker; + gboolean worker_started; +}; + +static gpointer nm_device_worker (gpointer user_data); + +static void nm_device_activate_schedule_stage3_ip_config_start (NMActRequest *req); +static void nm_device_activate_schedule_stage5_ip_config_commit (NMActRequest *req); + +static void nm_device_schedule_activation_handle_cancel (NMActRequest *req); + + +/* + * nm_device_test_wireless_extensions + * + * Test whether a given device is a wireless one or not. + * + */ +static NMDeviceType +discover_device_type (const char *iface) +{ + int err = -1; + char ioctl_buf[64]; + int fd; + int len; + + g_return_val_if_fail (iface != NULL, FALSE); + + ioctl_buf[63] = 0; + len = strlen (iface); + len = len > 63 ? 63 : len; + strncpy (ioctl_buf, iface, len); + + if ((fd = iw_sockets_open ()) >= 0) + { +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET IWNAME\n", iface); +#endif + err = ioctl (fd, SIOCGIWNAME, ioctl_buf); +#ifdef IOCTL_DEBUG + nm_info ("%s: Done with GET IWNAME\n", iface); +#endif + close (fd); + } + return err == 0 ? DEVICE_TYPE_802_11_WIRELESS : DEVICE_TYPE_802_3_ETHERNET; +} + +/* + * nm_get_device_driver_name + * + * Get the device's driver name from HAL. + * + */ +static char * +nm_get_device_driver_name (LibHalContext *ctx, const char *udi) +{ + char * driver_name = NULL; + char * physdev_udi = NULL; + + g_return_val_if_fail (ctx != NULL, NULL); + g_return_val_if_fail (udi != NULL, NULL); + + physdev_udi = libhal_device_get_property_string (ctx, udi, "net.physical_device", NULL); + if (physdev_udi && libhal_device_property_exists (ctx, physdev_udi, "info.linux.driver", NULL)) + { + char *drv = libhal_device_get_property_string (ctx, physdev_udi, "info.linux.driver", NULL); + driver_name = g_strdup (drv); + g_free (drv); + } + g_free (physdev_udi); + + return driver_name; +} + + +NMDevice * +nm_device_new (const char *iface, + const char *udi, + gboolean test_dev, + NMDeviceType test_dev_type, + NMData *app_data) +{ + NMDevice * dev; + NMDeviceType type; + + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (udi != NULL, NULL); + g_return_val_if_fail (strlen (iface) > 0, NULL); + g_return_val_if_fail (app_data != NULL, NULL); + + type = discover_device_type (iface); + switch (type) + { + case DEVICE_TYPE_802_11_WIRELESS: + dev = NM_DEVICE (g_object_new (NM_TYPE_DEVICE_802_11_WIRELESS, NULL)); + break; + case DEVICE_TYPE_802_3_ETHERNET: + dev = NM_DEVICE (g_object_new (NM_TYPE_DEVICE_802_3_ETHERNET, NULL)); + break; + + default: + g_assert_not_reached (); + } + + dev->priv->iface = g_strdup (iface); + dev->priv->udi = g_strdup (udi); + dev->priv->driver = nm_get_device_driver_name (app_data->hal_ctx, udi); + dev->priv->app_data = app_data; + dev->priv->type = type; + + /* Call type-specific initialization */ + NM_DEVICE_GET_CLASS (dev)->init (dev); + + return dev; +} + + +static void +nm_device_init (NMDevice * self) +{ + self->priv = NM_DEVICE_GET_PRIVATE (self); + self->priv->dispose_has_run = FALSE; + self->priv->udi = NULL; + self->priv->iface = NULL; + self->priv->type = DEVICE_TYPE_UNKNOWN; + self->priv->capabilities = NM_DEVICE_CAP_NONE; + self->priv->driver = NULL; + self->priv->removed = FALSE; + + self->priv->link_active = FALSE; + self->priv->ip4_address = 0; + memset (&self->priv->ip6_address, 0, sizeof (struct in6_addr)); + self->priv->app_data = NULL; + + self->priv->act_request = NULL; + self->priv->quit_activation = FALSE; + + self->priv->system_config_data = NULL; + self->priv->use_dhcp = TRUE; + self->priv->ip4_config = NULL; + + self->priv->context = NULL; + self->priv->loop = NULL; + self->priv->worker = NULL; + self->priv->worker_started = FALSE; +} + +static guint32 +real_discover_generic_capabilities (NMDevice *dev) +{ + return 0; +} + +static void +real_init (NMDevice *self) +{ + nm_completion_args args; + + self->priv->capabilities |= NM_DEVICE_GET_CLASS (self)->discover_generic_capabilities (self); + + /* Device thread's main loop */ + self->priv->context = g_main_context_new (); + self->priv->loop = g_main_loop_new (self->priv->context, FALSE); + + /* Have to bring the device up before checking link status and other stuff */ + nm_device_bring_up_wait (self, 0); + +// nm_device_set_active_link (self, nm_device_probe_link_state (self)); +// nm_device_update_ip4_address (self); +/* FIXME */ +#if 0 + nm_device_update_hw_address (self); +#endif + + /* Grab IP config data for this device from the system configuration files */ + self->priv->system_config_data = nm_system_device_get_system_config (self); + self->priv->use_dhcp = nm_system_device_get_use_dhcp (self); + + nm_print_device_capabilities (self); + + self->priv->worker = g_thread_create (nm_device_worker, self, TRUE, NULL); + g_assert (self->priv->worker); + g_object_ref (G_OBJECT (self)); /* For the worker thread */ + + /* Block until our device thread has actually had a chance to start. */ + args[0] = &self->priv->worker_started; + args[1] = (gpointer) "nm_device_init(): waiting for device's worker thread to start"; + args[2] = GINT_TO_POINTER (LOG_INFO); + args[3] = GINT_TO_POINTER (0); + nm_wait_for_completion (NM_COMPLETION_TRIES_INFINITY, + G_USEC_PER_SEC / 20, nm_completion_boolean_test, NULL, args); + + nm_info ("nm_device_init(): device's worker thread started, continuing."); +} + + +static void +real_start (NMDevice *dev) +{ +} + + +/* + * nm_device_worker + * + * Main thread of the device. + * + */ +static gpointer +nm_device_worker (gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + + g_assert (self); + + NM_DEVICE_GET_CLASS (self)->start (self); + + self->priv->worker_started = TRUE; + g_main_loop_run (self->priv->loop); + + g_main_loop_unref (self->priv->loop); + g_main_context_unref (self->priv->context); + + self->priv->loop = NULL; + self->priv->context = NULL; + + g_object_unref (G_OBJECT (self)); + + return NULL; +} + + +void +nm_device_worker_thread_stop (NMDevice *self) +{ + g_return_if_fail (self != NULL); + + if (self->priv->loop) + g_main_loop_quit (self->priv->loop); + if (self->priv->worker) + { + g_thread_join (self->priv->worker); + self->priv->worker = NULL; + } +} + +GMainContext * +nm_device_get_main_context (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return self->priv->context; +} + + +/* + * nm_get_device_by_udi + * + * Search through the device list for a device with a given UDI. + * + * NOTE: the caller MUST hold the device list mutex already to make + * this routine thread-safe. + * + */ +NMDevice * +nm_get_device_by_udi (NMData *data, + const char *udi) +{ + GSList *elt; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (udi != NULL, NULL); + + for (elt = data->dev_list; elt; elt = g_slist_next (elt)) + { + NMDevice *dev = NULL; + if ((dev = NM_DEVICE (elt->data))) + { + if (nm_null_safe_strcmp (nm_device_get_udi (dev), udi) == 0) + return dev; + } + } + + return NULL; +} + + +/* + * nm_get_device_by_iface + * + * Search through the device list for a device with a given iface. + * + * NOTE: the caller MUST hold the device list mutex already to make + * this routine thread-safe. + * + */ +NMDevice * +nm_get_device_by_iface (NMData *data, + const char *iface) +{ + GSList *elt; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (iface != NULL, NULL); + + for (elt = data->dev_list; elt; elt = g_slist_next (elt)) + { + NMDevice *dev = NULL; + if ((dev = NM_DEVICE (elt->data))) + { + if (nm_null_safe_strcmp (nm_device_get_iface (dev), iface) == 0) + return dev; + } + } + + return NULL; +} + + +/* + * Get/set functions for UDI + */ +const char * +nm_device_get_udi (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return self->priv->udi; +} + +void +nm_device_set_udi (NMDevice *self, + const char *udi) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (udi != NULL); + + if (self->priv->udi) + g_free (self->priv->udi); + self->priv->udi = g_strdup (udi); +} + + +/* + * Get/set functions for iface + */ +const char * +nm_device_get_iface (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return self->priv->iface; +} + + +/* + * Get/set functions for driver + */ +const char * +nm_device_get_driver (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return self->priv->driver; +} + + +/* + * Get/set functions for type + */ +NMDeviceType +nm_device_get_device_type (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, DEVICE_TYPE_UNKNOWN); + + return self->priv->type; +} + +void +nm_device_set_device_type (NMDevice *self, const NMDeviceType type) +{ + g_return_if_fail (self != NULL); + + self->priv->type = type; +} + + +static gboolean +real_is_test_device (NMDevice *dev) +{ + return FALSE; +} + +gboolean +nm_device_is_test_device (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return NM_DEVICE_GET_CLASS (self)->is_test_device (self); +} + +/* + * Accessor for capabilities + */ +guint32 +nm_device_get_capabilities (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NM_DEVICE_CAP_NONE); + + return self->priv->capabilities; +} + +/* + * Accessor for type-specific capabilities + */ +guint32 +nm_device_get_type_capabilities (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NM_DEVICE_CAP_NONE); + + return NM_DEVICE_GET_CLASS (self)->get_type_capabilities (self); +} + +static guint32 +real_get_type_capabilities (NMDevice *self) +{ + return NM_DEVICE_CAP_NONE; +} + + +/* + * nm_device_get_app_data + * + */ +struct NMData * +nm_device_get_app_data (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return self->priv->app_data; +} + + +/* + * Get/Set for "removed" flag + */ +gboolean +nm_device_get_removed (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, TRUE); + + return self->priv->removed; +} + +void +nm_device_set_removed (NMDevice *self, + const gboolean removed) +{ + g_return_if_fail (self != NULL); + + self->priv->removed = removed; +} + + +/* + * nm_device_get_act_request + * + * Return the devices activation request, if any. + * + */ +NMActRequest * +nm_device_get_act_request (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return self->priv->act_request; +} + + +/* + * Get/set functions for link_active + */ +gboolean +nm_device_has_active_link (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return self->priv->link_active; +} + +void +nm_device_set_active_link (NMDevice *self, + const gboolean link_active) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (self->priv->app_data != NULL); + + if (self->priv->link_active != link_active) + { + self->priv->link_active = link_active; + + /* Deactivate a currently active device */ + if (!link_active && self->priv->act_request) + { + nm_device_deactivate (self); + nm_policy_schedule_device_change_check (self->priv->app_data); + } + else if (link_active && !self->priv->act_request) + { + NMDevice * act_dev = nm_get_active_device (self->priv->app_data); + NMActRequest * act_dev_req = act_dev ? nm_device_get_act_request (act_dev) : NULL; + + /* Should we switch to this device now that it has a link? + * + * Only auto-switch for wired devices, AND... + * + * only switch to fully-supported devices, since ones that don't have carrier detection + * capability usually report the carrier as "always on" even if its not really on. User + * must manually choose semi-supported devices. + * + */ + if (nm_device_is_802_3_ethernet (self) && (nm_device_get_capabilities (self) & NM_DEVICE_CAP_CARRIER_DETECT)) + { + gboolean do_switch = act_dev ? FALSE : TRUE; /* If no currently active device, switch to this one */ + NMActRequest * act_req; + + /* If active device is wireless, switch to this one */ + if (act_dev && nm_device_is_802_11_wireless (act_dev) && act_dev_req && !nm_act_request_get_user_requested (act_dev_req)) + do_switch = TRUE; + + if (do_switch && (act_req = nm_act_request_new (self->priv->app_data, self, NULL, TRUE))) + { + nm_info ("Will activate wired connection '%s' because it now has a link.", nm_device_get_iface (self)); + nm_policy_schedule_device_activation (act_req); + } + } + } + nm_dbus_schedule_device_status_change_signal (self->priv->app_data, self, NULL, link_active ? DEVICE_CARRIER_ON : DEVICE_CARRIER_OFF); + } +} + + +static gboolean +real_probe_link (NMDevice *dev) +{ + return FALSE; +} + +/* + * nm_device_probe_link_state + * + * Return the current link state of the device. + * + */ +gboolean +nm_device_probe_link_state (NMDevice *self) +{ + gboolean link = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + + if (!nm_device_is_up (self)) + nm_device_bring_up (self); + + link = NM_DEVICE_GET_CLASS (self)->probe_link (self); + +#if 0 + if (nm_device_is_802_11_wireless (dev)) + { + link = nm_device_probe_wireless_link_state (dev); + nm_device_update_signal_strength (dev); + } + else if (nm_device_is_802_3_ethernet (dev)) + link = nm_device_probe_wired_link_state (dev); +#endif + + return link; +} + + +/* + * nm_device_activation_start + * + * Tell the device thread to begin activation. + * + * Returns: TRUE on success activation beginning + * FALSE on error beginning activation (bad params, couldn't create thread) + * + */ +gboolean +nm_device_activation_start (NMActRequest *req) +{ + NMData * data = NULL; + NMDevice * self = NULL; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + self = nm_act_request_get_dev (req); + g_assert (self); + + g_return_val_if_fail (!nm_device_is_activating (self), TRUE); /* Return if activation has already begun */ + + nm_act_request_ref (req); + self->priv->act_request = req; + self->priv->quit_activation = FALSE; + + nm_info ("Activation (%s) started...", nm_device_get_iface (self)); + + nm_act_request_set_stage (req, NM_ACT_STAGE_DEVICE_PREPARE); + nm_device_activate_schedule_stage1_device_prepare (req); + + nm_schedule_state_change_signal_broadcast (data); + nm_dbus_schedule_device_status_change_signal (data, self, NULL, DEVICE_ACTIVATING); + + return TRUE; +} + + +/* + * nm_device_activate_stage1_device_prepare + * + * Prepare for device activation + * + */ +static gboolean +nm_device_activate_stage1_device_prepare (NMActRequest *req) +{ + NMDevice * self; + NMData * data; + NMAccessPoint *ap; + NMAPSecurity * security; + const char * iface; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + self = nm_act_request_get_dev (req); + g_assert (self); + + iface = nm_device_get_iface (self); + nm_info ("Activation (%s) Stage 1 (Device Prepare) started...", iface); + + NM_DEVICE_GET_CLASS (self)->activation_prepare (self, req); + + if (nm_device_activation_should_cancel (self)) + nm_device_schedule_activation_handle_cancel (req); + else + nm_device_activate_schedule_stage2_device_config (req); + + nm_info ("Activation (%s) Stage 1 (Device Prepare) complete.", iface); + return FALSE; +} + + +/* + * nm_device_activate_schedule_stage1_device_prepare + * + * Prepare a device for activation + * + */ +void +nm_device_activate_schedule_stage1_device_prepare (NMActRequest *req) +{ + GSource * source = NULL; + NMDevice * self = NULL; + + g_return_if_fail (req != NULL); + + self = nm_act_request_get_dev (req); + g_assert (self); + + nm_act_request_set_stage (req, NM_ACT_STAGE_DEVICE_PREPARE); + nm_info ("Activation (%s) Stage 1 (Device Prepare) scheduled...", nm_device_get_iface (self)); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage1_device_prepare, req, NULL); + g_source_attach (source, self->priv->context); + g_source_unref (source); +} + +static gboolean +real_activation_prepare (NMDevice *dev, NMActRequest *req) +{ + /* Nothing to do */ + return TRUE; +} + +static gboolean +real_activation_config (NMDevice *dev, NMActRequest *req) +{ + /* Nothing to do */ + return TRUE; +} + + +/* + * nm_device_activate_stage2_device_config + * + * Determine device parameters and set those on the device, ie + * for wireless devices, set essid, keys, etc. + * + */ +static gboolean +nm_device_activate_stage2_device_config (NMActRequest *req) +{ + NMDevice * self; + NMData * data; + const char * iface; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + self = nm_act_request_get_dev (req); + g_assert (self); + + iface = nm_device_get_iface (self); + nm_info ("Activation (%s) Stage 2 (Device Configure) starting...", iface); + + /* Bring the device up */ + if (!nm_device_is_up (self)) + nm_device_bring_up (self); + + if (nm_device_activation_should_cancel (self)) + { + nm_device_schedule_activation_handle_cancel (req); + goto out; + } + + if (!NM_DEVICE_GET_CLASS (self)->activation_config (self, req)) + { + nm_policy_schedule_activation_failed (req); + goto out; + } + + nm_info ("Activation (%s) Stage 2 (Device Configure) successful.", iface); + nm_device_activate_schedule_stage3_ip_config_start (req); + + if (nm_device_activation_should_cancel (self)) + nm_device_schedule_activation_handle_cancel (req); + +out: + nm_info ("Activation (%s) Stage 2 (Device Configure) complete.", iface); + return FALSE; +} + + +/* + * nm_device_activate_schedule_stage2_device_config + * + * Schedule setup of the hardware device + * + */ +void +nm_device_activate_schedule_stage2_device_config (NMActRequest *req) +{ + GSource * source = NULL; + NMDevice * self = NULL; + + g_return_if_fail (req != NULL); + + self = nm_act_request_get_dev (req); + g_assert (self); + + nm_act_request_set_stage (req, NM_ACT_STAGE_DEVICE_CONFIG); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage2_device_config, req, NULL); + g_source_attach (source, self->priv->context); + g_source_unref (source); + nm_info ("Activation (%s) Stage 2 (Device Configure) scheduled...", nm_device_get_iface (self)); +} + + +/* + * nm_device_activate_stage3_ip_config_start + * + * Begin IP configuration with either DHCP or static IP. + * + */ +static gboolean +nm_device_activate_stage3_ip_config_start (NMActRequest *req) +{ + NMData * data = NULL; + NMDevice * self = NULL; + NMAccessPoint * ap = NULL; + const char * iface; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + self = nm_act_request_get_dev (req); + g_assert (self); + + iface = nm_device_get_iface (self); + nm_info ("Activation (%s) Stage 3 (IP Configure Start) started...", iface); + + if (nm_device_activation_should_cancel (self)) + { + nm_device_schedule_activation_handle_cancel (req); + goto out; + } + + if (nm_device_is_802_11_wireless (self)) + ap = nm_act_request_get_ap (req); + + if (!(ap && nm_ap_get_user_created (ap)) && nm_device_get_use_dhcp (self)) + { + /* Begin a DHCP transaction on the interface */ + if (!nm_dhcp_manager_begin_transaction (data->dhcp_manager, req)) + nm_policy_schedule_activation_failed (req); + goto out; + } + + if (nm_device_activation_should_cancel (self)) + { + nm_device_schedule_activation_handle_cancel (req); + goto out; + } + + /* Static IP and user-created wireless networks skip directly to IP configure stage */ + nm_device_activate_schedule_stage4_ip_config_get (req); + +out: + nm_info ("Activation (%s) Stage 3 (IP Configure Start) complete.", iface); + return FALSE; +} + + +/* + * nm_device_activate_schedule_stage3_ip_config_start + * + * Schedule IP configuration start + */ +static void +nm_device_activate_schedule_stage3_ip_config_start (NMActRequest *req) +{ + GSource * source = NULL; + NMDevice * self = NULL; + + g_return_if_fail (req != NULL); + + self = nm_act_request_get_dev (req); + g_assert (self); + + nm_act_request_set_stage (req, NM_ACT_STAGE_IP_CONFIG_START); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage3_ip_config_start, req, NULL); + g_source_attach (source, self->priv->context); + g_source_unref (source); + nm_info ("Activation (%s) Stage 3 (IP Configure Start) scheduled.", nm_device_get_iface (self)); +} + + +/* + * nm_device_new_ip4_autoip_config + * + * Build up an IP config with a Link Local address + * + */ +static NMIP4Config * +nm_device_new_ip4_autoip_config (NMDevice *self) +{ + struct in_addr ip; + NMIP4Config * config = NULL; + + g_return_val_if_fail (self != NULL, NULL); + + if (get_autoip (self, &ip)) + { + #define LINKLOCAL_BCAST 0xa9feffff + + config = nm_ip4_config_new (); + + nm_ip4_config_set_address (config, (guint32)(ip.s_addr)); + nm_ip4_config_set_netmask (config, (guint32)(ntohl (0xFFFF0000))); + nm_ip4_config_set_broadcast (config, (guint32)(ntohl (LINKLOCAL_BCAST))); + nm_ip4_config_set_gateway (config, 0); + } + + return config; +} + + +/* + * nm_device_activate_stage4_ip_config_get + * + * Retrieve the correct IP config. + * + */ +static gboolean +nm_device_activate_stage4_ip_config_get (NMActRequest *req) +{ + NMData * data = NULL; + NMDevice * self = NULL; + NMAccessPoint * ap = NULL; + NMIP4Config * ip4_config = NULL; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + self = nm_act_request_get_dev (req); + g_assert (self); + + if (nm_device_is_802_11_wireless (self)) + { + ap = nm_act_request_get_ap (req); + g_assert (ap); + } + + nm_info ("Activation (%s) Stage 4 (IP Configure Get) started...", nm_device_get_iface (self)); + + if (nm_device_activation_should_cancel (self)) + { + nm_device_schedule_activation_handle_cancel (req); + goto out; + } + + if (ap && nm_ap_get_user_created (ap)) + ip4_config = nm_device_new_ip4_autoip_config (self); + else if (nm_device_get_use_dhcp (self)) + ip4_config = nm_dhcp_manager_get_ip4_config (data->dhcp_manager, req); + else + ip4_config = nm_system_device_new_ip4_system_config (self); + + if (nm_device_activation_should_cancel (self)) + { + nm_device_schedule_activation_handle_cancel (req); + goto out; + } + + if (ip4_config) + { + nm_act_request_set_ip4_config (req, ip4_config); + nm_device_activate_schedule_stage5_ip_config_commit (req); + } + else + { + /* Interfaces cannot be down if they are the active interface, + * otherwise we cannot use them for scanning or link detection. + */ + if (nm_device_is_802_11_wireless (self)) + { + NMDevice80211Wireless *wdev = NM_DEVICE_802_11_WIRELESS (self); + + nm_device_802_11_wireless_set_essid (wdev, ""); + nm_device_802_11_wireless_set_wep_enc_key (wdev, NULL, 0); + } + + if (!nm_device_is_up (self)) + nm_device_bring_up (self); + + nm_policy_schedule_activation_failed (req); + } + +out: + nm_info ("Activation (%s) Stage 4 (IP Configure Get) complete.", nm_device_get_iface (self)); + return FALSE; +} + + +/* + * nm_device_activate_schedule_stage4_ip_config_get + * + * Schedule creation of the IP config + * + */ +void +nm_device_activate_schedule_stage4_ip_config_get (NMActRequest *req) +{ + GSource * source = NULL; + NMDevice * self = NULL; + + g_return_if_fail (req != NULL); + + self = nm_act_request_get_dev (req); + g_assert (self); + + nm_act_request_set_stage (req, NM_ACT_STAGE_IP_CONFIG_GET); + nm_info ("Activation (%s) Stage 4 (IP Configure Get) scheduled...", + nm_device_get_iface (self)); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage4_ip_config_get, req, NULL); + g_source_attach (source, self->priv->context); + g_source_unref (source); +} + + +/* + * nm_device_activate_stage4_ip_config_timeout + * + * Retrieve the correct IP config. + * + */ +static gboolean +nm_device_activate_stage4_ip_config_timeout (NMActRequest *req) +{ + NMData * data = NULL; + NMDevice * self = NULL; + NMIP4Config * ip4_config = NULL; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + self = nm_act_request_get_dev (req); + g_assert (self); + + nm_info ("Activation (%s) Stage 4 (IP Configure Timeout) started...", + nm_device_get_iface (self)); + + if (nm_device_activation_should_cancel (self)) + { + nm_device_schedule_activation_handle_cancel (req); + goto out; + } + + if (nm_device_is_802_3_ethernet (self)) + { + /* Wired network, no DHCP reply. Let's get an IP via Zeroconf. */ + nm_info ("No DHCP reply received. Automatically obtaining IP via Zeroconf."); + ip4_config = nm_device_new_ip4_autoip_config (self); + } + else if (nm_device_is_802_11_wireless (self)) + { + NMAccessPoint *ap = nm_act_request_get_ap (req); + NMAPSecurity * security; + + g_assert (ap); + + security = nm_ap_get_security (ap); + + /* FIXME: should we only ask for a new key if the activation request is user-requested? */ + if (ap && (nm_ap_security_get_we_cipher (security) != IW_AUTH_CIPHER_NONE)) + { + /* Activation failed, we must have bad WEP key */ + nm_debug ("Activation (%s/wireless): could not get IP configuration info for '%s', asking for new key.", + nm_device_get_iface (self), nm_ap_get_essid (ap) ? nm_ap_get_essid (ap) : "(none)"); + nm_dbus_get_user_key_for_network (data->dbus_connection, req, TRUE); + } + else + { + /* + * Wireless, not encrypted, no DHCP Reply. Try Zeroconf. We do not do this in + * the encrypted case, because the problem could be (and more likely is) a bad key. + */ + nm_info ("No DHCP reply received. Automatically obtaining IP via Zeroconf."); + ip4_config = nm_device_new_ip4_autoip_config (self); + } + } + + if (ip4_config) + { + nm_act_request_set_ip4_config (req, ip4_config); + nm_device_activate_schedule_stage5_ip_config_commit (req); + } + +out: + nm_info ("Activation (%s) Stage 4 (IP Configure Timeout) complete.", + nm_device_get_iface (self)); + return FALSE; +} + + +/* + * nm_device_activate_schedule_stage4_ip_config_timeout + * + * Deal with a timed out DHCP transaction + * + */ +void +nm_device_activate_schedule_stage4_ip_config_timeout (NMActRequest *req) +{ + GSource * source = NULL; + NMDevice * self = NULL; + + g_return_if_fail (req != NULL); + + self = nm_act_request_get_dev (req); + g_assert (self); + + nm_act_request_set_stage (req, NM_ACT_STAGE_IP_CONFIG_GET); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage4_ip_config_timeout, req, NULL); + g_source_attach (source, self->priv->context); + g_source_unref (source); + nm_info ("Activation (%s) Stage 4 (IP Configure Timeout) scheduled...", nm_device_get_iface (self)); +} + + +/* + * nm_device_activate_stage5_ip_config_commit + * + * Commit the IP config on the device + * + */ +static gboolean +nm_device_activate_stage5_ip_config_commit (NMActRequest *req) +{ + NMData * data = NULL; + NMDevice * self = NULL; + NMIP4Config * ip4_config = NULL; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + self = nm_act_request_get_dev (req); + g_assert (self); + + ip4_config = nm_act_request_get_ip4_config (req); + g_assert (ip4_config); + + nm_info ("Activation (%s) Stage 5 (IP Configure Commit) started...", + nm_device_get_iface (self)); + + if (nm_device_activation_should_cancel (self)) + { + nm_device_schedule_activation_handle_cancel (req); + goto out; + } + + nm_device_set_ip4_config (self, ip4_config); + if (nm_system_device_set_from_ip4_config (self)) + { + nm_device_update_ip4_address (self); + nm_system_device_add_ip6_link_address (self); + nm_system_restart_mdns_responder (); + nm_system_activate_nis (self->priv->ip4_config); + nm_device_set_active_link (self, nm_device_probe_link_state (self)); + nm_policy_schedule_activation_finish (req); + } + else + nm_policy_schedule_activation_failed (req); + +out: + nm_info ("Activation (%s) Stage 5 (IP Configure Commit) complete.", + nm_device_get_iface (self)); + return FALSE; +} + + +/* + * nm_device_activate_schedule_stage5_ip_config_commit + * + * Schedule commit of the IP config + */ +static void +nm_device_activate_schedule_stage5_ip_config_commit (NMActRequest *req) +{ + GSource * source = NULL; + NMDevice * self = NULL; + + g_return_if_fail (req != NULL); + + self = nm_act_request_get_dev (req); + g_assert (self); + + nm_act_request_set_stage (req, NM_ACT_STAGE_IP_CONFIG_COMMIT); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage5_ip_config_commit, req, NULL); + g_source_attach (source, self->priv->context); + g_source_unref (source); + nm_info ("Activation (%s) Stage 5 (IP Configure Commit) scheduled...", nm_device_get_iface (self)); +} + + +/* + * nm_device_activation_handle_cancel + * + * Cancel activation on a device and clean up. + * + */ +static gboolean +nm_device_activation_handle_cancel (NMActRequest *req) +{ + NMDevice * self; + NMData * data; + + g_return_val_if_fail (req != NULL, FALSE); + + data = nm_act_request_get_data (req); + g_assert (data); + + self = nm_act_request_get_dev (req); + g_assert (self); + + if ((req = nm_device_get_act_request (self)) && nm_device_is_activating (self)) + { + self->priv->act_request = NULL; + nm_act_request_unref (req); + } + nm_schedule_state_change_signal_broadcast (self->priv->app_data); + + nm_info ("Activation (%s) cancellation handled.", nm_device_get_iface (self)); + return FALSE; +} + + +/* + * nm_device_schedule_activation_handle_cancel + * + * Schedule the activation cancel handler + * + */ +static void +nm_device_schedule_activation_handle_cancel (NMActRequest *req) +{ + NMDevice * self; + NMData * data; + GSource * source; + + g_return_if_fail (req != NULL); + + data = nm_act_request_get_data (req); + g_assert (data); + + self = nm_act_request_get_dev (req); + g_assert (self); + + nm_info ("Activation (%s) cancellation handler scheduled...", nm_device_get_iface (self)); + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_device_activation_handle_cancel, req, NULL); + g_source_attach (source, self->priv->context); + g_source_unref (source); +} + + +/* + * nm_device_activation_cancel + * + * Signal activation worker that it should stop and die. + * + */ +void +nm_device_activation_cancel (NMDevice *self) +{ + NMDeviceClass * klass; + + g_return_if_fail (self != NULL); + + klass = NM_DEVICE_CLASS (g_type_class_peek (NM_TYPE_DEVICE)); + klass->cancel_activation (self); +} + +static +gboolean nm_ac_test (int tries, + nm_completion_args args) +{ + NMDevice * self = args[0]; + + g_return_val_if_fail (self != NULL, TRUE); + + if (nm_device_is_activating (self)) + { + if (tries % 20 == 0) + nm_info ("Activation (%s): waiting for device to cancel activation.", nm_device_get_iface (self)); + return FALSE; + } + + return TRUE; +} + +static void +real_cancel_activation (NMDevice *self) +{ + nm_completion_args args; + NMData * app_data; + + g_return_if_fail (self != NULL); + + g_assert (self->priv->app_data); + app_data = self->priv->app_data; + + if (nm_device_is_activating (self)) + { + NMActRequest * req = nm_device_get_act_request (self); + gboolean clear_act_request = FALSE; + + nm_info ("Activation (%s): cancelling...", nm_device_get_iface (self)); + self->priv->quit_activation = TRUE; + + /* If the device is waiting for DHCP or a user key, force its current request to stop. */ + if (nm_act_request_get_stage (req) == NM_ACT_STAGE_NEED_USER_KEY) + { + nm_dbus_cancel_get_user_key_for_network (app_data->dbus_connection, req); + clear_act_request = TRUE; + } + else if (nm_act_request_get_stage (req) == NM_ACT_STAGE_IP_CONFIG_START) + { + nm_dhcp_manager_cancel_transaction (app_data->dhcp_manager, req); + clear_act_request = TRUE; + } + + if (clear_act_request) + { + self->priv->act_request = NULL; + nm_act_request_unref (req); + } + + /* Spin until cancelled. Possible race conditions or deadlocks here. + * The other problem with waiting here is that we hold up dbus traffic + * that we should respond to. + */ + args[0] = self; + nm_wait_for_completion (NM_COMPLETION_TRIES_INFINITY, G_USEC_PER_SEC / 20, nm_ac_test, NULL, args); + nm_info ("Activation (%s): cancelled.", nm_device_get_iface (self)); + nm_schedule_state_change_signal_broadcast (app_data); + self->priv->quit_activation = FALSE; + } +} + + +/* + * nm_device_deactivate_quickly + * + * Quickly deactivate a device, for things like sleep, etc. Doesn't + * clean much stuff up, and nm_device_deactivate() should be called + * on the device eventually. + * + */ +gboolean +nm_device_deactivate_quickly (NMDevice *self) +{ + NMData * app_data; + NMActRequest * act_request; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (self->priv->app_data != NULL, FALSE); + + nm_system_shutdown_nis (); + + app_data = self->priv->app_data; + nm_vpn_manager_deactivate_vpn_connection (app_data->vpn_manager, self); + + if (nm_device_is_activated (self)) + nm_dbus_schedule_device_status_change_signal (app_data, self, NULL, DEVICE_NO_LONGER_ACTIVE); + else if (nm_device_is_activating (self)) + nm_device_activation_cancel (self); + + /* Tear down an existing activation request, which may not have happened + * in nm_device_activation_cancel() above, for various reasons. + */ + if ((act_request = nm_device_get_act_request (self))) + { + nm_dhcp_manager_cancel_transaction (app_data->dhcp_manager, act_request); + nm_act_request_unref (act_request); + self->priv->act_request = NULL; + } + + return TRUE; +} + +/* + * nm_device_deactivate + * + * Remove a device's routing table entries and IP address. + * + */ +void +nm_device_deactivate (NMDevice *self) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (self->priv->app_data != NULL); + + + NM_DEVICE_GET_CLASS (self)->deactivate (self); + nm_schedule_state_change_signal_broadcast (self->priv->app_data); +} + +static void +real_deactivate (NMDevice *self) +{ + NMData * app_data; + NMIP4Config * config; + + g_return_if_fail (self->priv->app_data != NULL); + + nm_info ("Deactivating device %s.", nm_device_get_iface (self)); + + nm_device_deactivate_quickly (self); + + if (!(nm_device_get_capabilities (self) & NM_DEVICE_CAP_NM_SUPPORTED)) + return; + + app_data = self->priv->app_data; + + /* Remove any device nameservers and domains */ + if ((config = nm_device_get_ip4_config (self))) + { + nm_named_manager_remove_ip4_config (app_data->named_manager, config); + nm_device_set_ip4_config (self, NULL); + } + + /* Take out any entries in the routing table and any IP address the device had. */ + nm_system_device_flush_routes (self); + nm_system_device_flush_addresses (self); + nm_device_update_ip4_address (self); + +} + + +/* + * nm_device_is_activating + * + * Return whether or not the device is currently activating itself. + * + */ +gboolean +nm_device_is_activating (NMDevice *dev) +{ + NMActRequest * req; + NMActStage stage; + gboolean activating = FALSE; + + g_return_val_if_fail (dev != NULL, FALSE); + + if (!(req = nm_device_get_act_request (dev))) + return FALSE; + + stage = nm_act_request_get_stage (req); + switch (stage) + { + case NM_ACT_STAGE_DEVICE_PREPARE: + case NM_ACT_STAGE_DEVICE_CONFIG: + case NM_ACT_STAGE_NEED_USER_KEY: + case NM_ACT_STAGE_IP_CONFIG_START: + case NM_ACT_STAGE_IP_CONFIG_GET: + case NM_ACT_STAGE_IP_CONFIG_COMMIT: + activating = TRUE; + break; + + case NM_ACT_STAGE_ACTIVATED: + case NM_ACT_STAGE_FAILED: + case NM_ACT_STAGE_CANCELLED: + case NM_ACT_STAGE_UNKNOWN: + default: + break; + } + + return activating; +} + + +/* + * nm_device_is_activated + * + * Return whether or not the device is successfully activated. + * + */ +gboolean +nm_device_is_activated (NMDevice *dev) +{ + NMActRequest * req; + NMActStage stage; + gboolean activated = FALSE; + + g_return_val_if_fail (dev != NULL, FALSE); + + if (!(req = nm_device_get_act_request (dev))) + return FALSE; + + stage = nm_act_request_get_stage (req); + switch (stage) + { + case NM_ACT_STAGE_ACTIVATED: + activated = TRUE; + break; + + case NM_ACT_STAGE_DEVICE_PREPARE: + case NM_ACT_STAGE_DEVICE_CONFIG: + case NM_ACT_STAGE_NEED_USER_KEY: + case NM_ACT_STAGE_IP_CONFIG_START: + case NM_ACT_STAGE_IP_CONFIG_GET: + case NM_ACT_STAGE_IP_CONFIG_COMMIT: + case NM_ACT_STAGE_FAILED: + case NM_ACT_STAGE_CANCELLED: + case NM_ACT_STAGE_UNKNOWN: + default: + break; + } + + return activated; +} + + +/* + * nm_device_activation_should_cancel + * + * Return whether or not we've been told to cancel activation + * + */ +gboolean +nm_device_activation_should_cancel (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return (self->priv->quit_activation); +} + + +/* IP Configuration stuff */ + +gboolean +nm_device_get_use_dhcp (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return self->priv->use_dhcp; +} + +void +nm_device_set_use_dhcp (NMDevice *self, + gboolean use_dhcp) +{ + g_return_if_fail (self != NULL); + + self->priv->use_dhcp = use_dhcp; +} + + +NMIP4Config * +nm_device_get_ip4_config (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return self->priv->ip4_config; +} + + +void +nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config) +{ + NMIP4Config *old_config; + + g_return_if_fail (self != NULL); + + old_config = self->priv->ip4_config; + if (config) + nm_ip4_config_ref (config); + self->priv->ip4_config = config; + if (old_config) + nm_ip4_config_unref (old_config); +} + + +/* + * nm_device_get_ip4_address + * + * Get a device's IPv4 address + * + */ +guint32 +nm_device_get_ip4_address (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, 0); + + return self->priv->ip4_address; +} + + +void +nm_device_update_ip4_address (NMDevice *self) +{ + guint32 new_address; + struct ifreq req; + NMSock * sk; + int err; + const char * iface; + + g_return_if_fail (self != NULL); + g_return_if_fail (self->priv->app_data != NULL); + g_return_if_fail (nm_device_get_iface (self) != NULL); + + /* Test devices get a nice, bogus IP address */ + if (nm_device_is_test_device (self)) + { + self->priv->ip4_address = 0x07030703; + return; + } + + if ((sk = nm_dev_sock_open (self, DEV_GENERAL, __FUNCTION__, NULL)) == NULL) + return; + + iface = nm_device_get_iface (self); + memset (&req, 0, sizeof (struct ifreq)); + strncpy (req.ifr_name, iface, sizeof (req.ifr_name) - 1); +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET IFADDR.", iface); +#endif + err = ioctl (nm_dev_sock_get_fd (sk), SIOCGIFADDR, &req); +#ifdef IOCTL_DEBUG + nm_info ("%s: Done with GET IFADDR.", iface); +#endif + nm_dev_sock_close (sk); + if (err != 0) + return; + + new_address = ((struct sockaddr_in *)(&req.ifr_addr))->sin_addr.s_addr; + if (new_address != nm_device_get_ip4_address (self)) + self->priv->ip4_address = new_address; +} + + +/* + * nm_device_set_up_down + * + * Set the up flag on the device on or off + * + */ +static void +nm_device_set_up_down (NMDevice *self, + gboolean up) +{ + g_return_if_fail (self != NULL); + + nm_system_device_set_up_down (self, up); + + /* Make sure we have a valid MAC address, some cards reload firmware when they + * are brought up. + */ +/* FIXME */ +#if 0 + if (!nm_ethernet_address_is_valid (&(self->priv->hw_addr))) + nm_device_update_hw_address (self); +#endif +} + + +/* + * Interface state functions: bring up, down, check + * + */ +gboolean +nm_device_is_up (NMDevice *self) +{ + NMSock * sk; + struct ifreq ifr; + int err; + + g_return_val_if_fail (self != NULL, FALSE); + + if ((sk = nm_dev_sock_open (self, DEV_GENERAL, __FUNCTION__, NULL)) == NULL) + return (FALSE); + + /* Get device's flags */ + strncpy (ifr.ifr_name, nm_device_get_iface (self), sizeof (ifr.ifr_name) - 1); +#ifdef IOCTL_DEBUG + nm_info ("%s: About to GET IFFLAGS.", nm_device_get_iface (self)); +#endif + err = ioctl (nm_dev_sock_get_fd (sk), SIOCGIFFLAGS, &ifr); +#ifdef IOCTL_DEBUG + nm_info ("%s: Done with GET IFFLAGS.", nm_device_get_iface (self)); +#endif + nm_dev_sock_close (sk); + if (!err) + return (!((ifr.ifr_flags^IFF_UP) & IFF_UP)); + + if (errno != ENODEV) + { + nm_warning ("nm_device_is_up() could not get flags for device %s. errno = %d", + nm_device_get_iface (self), errno ); + } + + return FALSE; +} + +/* I really wish nm_v_wait_for_completion_or_timeout could translate these + * to first class args instead of a all this void * arg stuff, so these + * helpers could be nice and _tiny_. */ +static gboolean +nm_completion_device_is_up_test (int tries, + nm_completion_args args) +{ + NMDevice *self = NM_DEVICE (args[0]); + gboolean *err = args[1]; + gboolean cancelable = GPOINTER_TO_INT (args[2]); + + g_return_val_if_fail (self != NULL, TRUE); + g_return_val_if_fail (err != NULL, TRUE); + + *err = FALSE; + if (cancelable && nm_device_activation_should_cancel (self)) { + *err = TRUE; + return TRUE; + } + if (nm_device_is_up (self)) + return TRUE; + return FALSE; +} + +void +nm_device_bring_up (NMDevice *self) +{ + g_return_if_fail (self != NULL); + + nm_device_set_up_down (self, TRUE); +} + +gboolean +nm_device_bring_up_wait (NMDevice *self, + gboolean cancelable) +{ + gboolean err = FALSE; + nm_completion_args args; + + g_return_val_if_fail (self != NULL, TRUE); + + nm_device_bring_up (self); + + args[0] = self; + args[1] = &err; + args[2] = GINT_TO_POINTER (cancelable); + nm_wait_for_completion (400, G_USEC_PER_SEC / 200, NULL, nm_completion_device_is_up_test, args); + if (err) + nm_info ("failed to bring up device %s", self->priv->iface); + return err; +} + +void +nm_device_bring_down (NMDevice *self) +{ + g_return_if_fail (self != NULL); + + nm_device_set_up_down (self, FALSE); +} + +static gboolean +nm_completion_device_is_down_test (int tries, + nm_completion_args args) +{ + NMDevice *self = NM_DEVICE (args[0]); + gboolean *err = args[1]; + gboolean cancelable = GPOINTER_TO_INT (args[2]); + + g_return_val_if_fail (self != NULL, TRUE); + g_return_val_if_fail (err != NULL, TRUE); + + *err = FALSE; + if (cancelable && nm_device_activation_should_cancel (self)) { + *err = TRUE; + return TRUE; + } + if (!nm_device_is_up (self)) + return TRUE; + return FALSE; +} + +gboolean +nm_device_bring_down_wait (NMDevice *self, + gboolean cancelable) +{ + gboolean err = FALSE; + nm_completion_args args; + + g_return_val_if_fail (self != NULL, TRUE); + + nm_device_bring_down (self); + + args[0] = self; + args[1] = &err; + args[2] = GINT_TO_POINTER (cancelable); + nm_wait_for_completion(400, G_USEC_PER_SEC / 200, NULL, + nm_completion_device_is_down_test, args); + if (err) + nm_info ("failed to bring down device %s", self->priv->iface); + return err; +} + + +/* + * nm_device_get_system_config_data + * + * Return distro-specific system configuration data for this device. + * + */ +void * +nm_device_get_system_config_data (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return self->priv->system_config_data; +} + + +static void +nm_device_dispose (GObject *object) +{ + NMDevice * self = NM_DEVICE (object); + NMDeviceClass * klass; + GObjectClass * parent_class; + + if (self->priv->dispose_has_run) + /* If dispose did already run, return. */ + return; + + /* Make sure dispose does not run twice. */ + self->priv->dispose_has_run = TRUE; + + /* + * In dispose, you are supposed to free all types referenced from this + * object which might themselves hold a reference to self. Generally, + * the most simple solution is to unref all members on which you own a + * reference. + */ + + nm_device_worker_thread_stop (self); + nm_device_bring_down (self); + + nm_system_device_free_system_config (self, self->priv->system_config_data); + if (self->priv->ip4_config) + { + nm_ip4_config_unref (self->priv->ip4_config); + self->priv->ip4_config = NULL; + } + + if (self->priv->act_request) + { + nm_act_request_unref (self->priv->act_request); + self->priv->act_request = NULL; + } + + /* Chain up to the parent class */ + klass = NM_DEVICE_CLASS (g_type_class_peek (NM_TYPE_DEVICE)); + parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); + parent_class->dispose (object); +} + +static void +nm_device_finalize (GObject *object) +{ + NMDevice * self = NM_DEVICE (object); + NMDeviceClass * klass; + GObjectClass * parent_class; + + g_free (self->priv->udi); + g_free (self->priv->iface); + g_free (self->priv->driver); + + /* Chain up to the parent class */ + klass = NM_DEVICE_CLASS (g_type_class_peek (NM_TYPE_DEVICE)); + parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); + parent_class->finalize (object); +} + + +static void +nm_device_class_init (NMDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = nm_device_dispose; + object_class->finalize = nm_device_finalize; + + klass->is_test_device = real_is_test_device; + klass->deactivate = real_deactivate; + klass->cancel_activation = real_cancel_activation; + klass->get_type_capabilities = real_get_type_capabilities; + klass->discover_generic_capabilities = real_discover_generic_capabilities; + klass->init = real_init; + klass->start = real_start; + klass->activation_prepare = real_activation_prepare; + klass->activation_config = real_activation_config; + klass->probe_link = real_probe_link; + + g_type_class_add_private (object_class, sizeof (NMDevicePrivate)); +} + +GType +nm_device_get_type (void) +{ + static GType type = 0; + if (type == 0) + { + static const GTypeInfo info = + { + sizeof (NMDeviceClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) nm_device_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (NMDevice), + 0, /* n_preallocs */ + (GInstanceInitFunc) nm_device_init + }; + type = g_type_register_static (G_TYPE_OBJECT, + "NMDevice", + &info, 0); + } + return type; +} + + diff --git a/src/nm-device.h b/src/nm-device.h new file mode 100644 index 0000000000..1d55793f7b --- /dev/null +++ b/src/nm-device.h @@ -0,0 +1,173 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef NM_DEVICE_H +#define NM_DEVICE_H + +#include +#include +#include + +#include "NetworkManager.h" +#include "nm-ip4-config.h" + +#if 0 +#define IOCTL_DEBUG +#endif + +typedef enum NMWirelessScanInterval +{ + NM_WIRELESS_SCAN_INTERVAL_INIT = 0, + NM_WIRELESS_SCAN_INTERVAL_ACTIVE, + NM_WIRELESS_SCAN_INTERVAL_INACTIVE +} NMWirelessScanInterval; + + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE (nm_device_get_type ()) +#define NM_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE, NMDevice)) +#define NM_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE, NMDeviceClass)) +#define NM_IS_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE)) +#define NM_IS_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE)) +#define NM_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE, NMDeviceClass)) + +typedef struct _NMDevice NMDevice; +typedef struct _NMDeviceClass NMDeviceClass; +typedef struct _NMDevicePrivate NMDevicePrivate; + +struct _NMDevice +{ + GObject parent; + + /*< private >*/ + NMDevicePrivate *priv; +}; + +struct NMData; +struct NMActRequest; + +struct _NMDeviceClass +{ + GObjectClass parent; + + gboolean (* is_test_device) (NMDevice *self); + + const char * (* has_active_link) (NMDevice *self); + void (* set_active_link) (NMDevice *self, gboolean active); + gboolean (* probe_link) (NMDevice *self); + + guint32 (* get_ip4_address) (NMDevice *self); + struct in6_addr * (* get_ip6_address) (NMDevice *self); + + void (* bring_up) (NMDevice *self); + void (* bring_down) (NMDevice *self); + gboolean (* is_up) (NMDevice *self); + + guint32 (* get_type_capabilities) (NMDevice *self); + guint32 (* discover_generic_capabilities) (NMDevice *self); + + void (* init) (NMDevice *self); + void (* start) (NMDevice *self); + gboolean (* activation_prepare) (NMDevice *self, struct NMActRequest * req); + gboolean (* activation_config) (NMDevice *self, struct NMActRequest * req); + void (* deactivate) (NMDevice *self); + void (* cancel_activation) (NMDevice *self); +}; + + +GType nm_device_get_type (void); + +NMDevice * nm_device_new (const char *iface, + const char *udi, + gboolean test_dev, + NMDeviceType test_dev_type, + struct NMData *app_data); + +void nm_device_worker_thread_stop (NMDevice *self); + +const char * nm_device_get_udi (NMDevice *dev); + +const char * nm_device_get_iface (NMDevice *dev); + +const char * nm_device_get_driver (NMDevice *dev); + +NMDeviceType nm_device_get_device_type (NMDevice *dev); +guint32 nm_device_get_capabilities (NMDevice *dev); +guint32 nm_device_get_type_capabilities (NMDevice *dev); + +struct NMData * nm_device_get_app_data (NMDevice *dev); + +gboolean nm_device_get_removed (NMDevice *dev); +void nm_device_set_removed (NMDevice *dev, + const gboolean removed); + +gboolean nm_device_has_active_link (NMDevice *dev); +void nm_device_set_active_link (NMDevice *dev, + const gboolean active); +gboolean nm_device_probe_link_state (NMDevice *dev); + +guint32 nm_device_get_ip4_address (NMDevice *dev); +void nm_device_update_ip4_address (NMDevice *dev); +struct in6_addr * nm_device_get_ip6_address (NMDevice *dev); + +gboolean nm_device_get_use_dhcp (NMDevice *dev); +void nm_device_set_use_dhcp (NMDevice *dev, + gboolean use_dhcp); + +NMIP4Config * nm_device_get_ip4_config (NMDevice *dev); +void nm_device_set_ip4_config (NMDevice *dev, + NMIP4Config *config); + +void nm_device_bring_up (NMDevice *dev); +gboolean nm_device_bring_up_wait (NMDevice *self, + gboolean cancelable); +void nm_device_bring_down (NMDevice *dev); +gboolean nm_device_bring_down_wait (NMDevice *self, + gboolean cancelable); +gboolean nm_device_is_up (NMDevice *dev); + +void * nm_device_get_system_config_data (NMDevice *dev); + +struct NMActRequest * nm_device_get_act_request (NMDevice *dev); + +/* Utility routines */ +NMDevice * nm_get_device_by_udi (struct NMData *data, + const char *udi); +NMDevice * nm_get_device_by_iface (struct NMData *data, + const char *iface); + +gboolean nm_device_is_test_device (NMDevice *dev); + +gboolean nm_device_activation_start (struct NMActRequest *req); +void nm_device_activate_schedule_stage1_device_prepare (struct NMActRequest *req); +void nm_device_activate_schedule_stage2_device_config (struct NMActRequest *req); +void nm_device_activate_schedule_stage4_ip_config_get (struct NMActRequest *req); +void nm_device_activate_schedule_stage4_ip_config_timeout (struct NMActRequest *req); +void nm_device_deactivate (NMDevice *dev); +gboolean nm_device_deactivate_quickly (NMDevice *dev); +gboolean nm_device_is_activating (NMDevice *dev); +void nm_device_activation_cancel (NMDevice *dev); +gboolean nm_device_activation_should_cancel (NMDevice *self); + +G_END_DECLS + +#endif /* NM_DEVICE_H */ diff --git a/src/vpn-manager/nm-dbus-vpn.c b/src/vpn-manager/nm-dbus-vpn.c index 41caef9e9b..df956fcf03 100644 --- a/src/vpn-manager/nm-dbus-vpn.c +++ b/src/vpn-manager/nm-dbus-vpn.c @@ -22,7 +22,7 @@ #include #include #include "NetworkManagerMain.h" -#include "NetworkManagerDevice.h" +#include "nm-device.h" #include "NetworkManagerDbus.h" #include "NetworkManagerUtils.h" #include "NetworkManagerVPN.h" diff --git a/src/vpn-manager/nm-vpn-act-request.c b/src/vpn-manager/nm-vpn-act-request.c index 269495f283..b335453be1 100644 --- a/src/vpn-manager/nm-vpn-act-request.c +++ b/src/vpn-manager/nm-vpn-act-request.c @@ -64,7 +64,7 @@ NMVPNActRequest *nm_vpn_act_request_new (NMVPNManager *manager, NMVPNService *se req->stage = NM_VPN_ACT_STAGE_PREPARE; req->manager = manager; - nm_device_ref (parent_dev); + g_object_ref (G_OBJECT (parent_dev)); req->parent_dev = parent_dev; nm_vpn_service_ref (service); req->service = service; @@ -95,7 +95,7 @@ void nm_vpn_act_request_unref (NMVPNActRequest *req) req->refcount--; if (req->refcount == 0) { - nm_device_unref (req->parent_dev); + g_object_unref (G_OBJECT (req->parent_dev)); nm_vpn_service_unref (req->service); nm_vpn_connection_unref (req->vpn); diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 403c9379d7..3311246fd2 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -96,7 +96,7 @@ void nm_vpn_connection_unref (NMVPNConnection *connection) g_free (connection->service_name); if (connection->parent_dev) - nm_device_unref (connection->parent_dev); + g_object_unref (G_OBJECT (connection->parent_dev)); if (connection->ip4_config) nm_ip4_config_unref (connection->ip4_config); g_free (connection->vpn_iface); @@ -228,13 +228,13 @@ static void nm_vpn_connection_set_parent_device (NMVPNConnection *con, NMDevice if (con->parent_dev) { - nm_device_unref (con->parent_dev); + g_object_unref (G_OBJECT (con->parent_dev)); con->parent_dev = NULL; } if (parent_dev) { - nm_device_ref (parent_dev); + g_object_unref (G_OBJECT (parent_dev)); con->parent_dev = parent_dev; } } diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h index bc9b36854d..a043e45039 100644 --- a/src/vpn-manager/nm-vpn-connection.h +++ b/src/vpn-manager/nm-vpn-connection.h @@ -20,7 +20,8 @@ #ifndef NM_VPN_CONNECTION_H #define NM_VPN_CONNECTION_H -#include "NetworkManagerDevice.h" +#include "nm-device.h" +#include "nm-named-manager.h" typedef struct NMVPNConnection NMVPNConnection; diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c index e9d1ef92c7..0751b3e632 100644 --- a/src/vpn-manager/nm-vpn-manager.c +++ b/src/vpn-manager/nm-vpn-manager.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "nm-vpn-manager.h" #include "NetworkManager.h"