/* 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 2004 Red Hat, Inc. */ #include #include #include #include #include #include #include "NetworkManager.h" #include "NetworkManagerUtils.h" typedef struct MutexDesc { GMutex *mutex; char *desc; } MutexDesc; GSList *mutex_descs = NULL; /*#define LOCKING_DEBUG*/ static MutexDesc *nm_find_mutex_desc (GMutex *mutex) { GSList *elt; for (elt = mutex_descs; elt; elt = g_slist_next (elt)) { MutexDesc *desc = (MutexDesc *)(elt->data); if (desc && (desc->mutex == mutex)) return desc; } return NULL; } /* * nm_register_mutex_desc * * Associate a description with a particular mutex. * */ void nm_register_mutex_desc (GMutex *mutex, char *string) { if (!(nm_find_mutex_desc (mutex))) { MutexDesc *desc = g_malloc0 (sizeof (MutexDesc)); desc->mutex = mutex; desc->desc = g_strdup (string); mutex_descs = g_slist_append (mutex_descs, desc); } } /* * nm_try_acquire_mutex * * Tries to acquire a given mutex, sleeping a bit between tries. * * Returns: FALSE if mutex was not acquired * TRUE if mutex was successfully acquired */ gboolean nm_try_acquire_mutex (GMutex *mutex, const char *func) { g_return_val_if_fail (mutex != NULL, FALSE); if (g_mutex_trylock (mutex)) { #ifdef LOCKING_DEBUG if (func) { MutexDesc *desc = nm_find_mutex_desc (mutex); syslog (LOG_DEBUG, "MUTEX: <%s %p> acquired by %s", desc ? desc->desc : "(none)", mutex, func); } #endif return (TRUE); } #ifdef LOCKING_DEBUG if (func) { MutexDesc *desc = nm_find_mutex_desc (mutex); syslog (LOG_DEBUG, "MUTEX: <%s %p> FAILED to be acquired by %s", desc ? desc->desc : "(none)", mutex, func); } #endif return (FALSE); } /* * nm_lock_mutex * * Blocks until a mutex is grabbed, with debugging. * */ void nm_lock_mutex (GMutex *mutex, const char *func) { #ifdef LOCKING_DEBUG if (func) { MutexDesc *desc = nm_find_mutex_desc (mutex); syslog (LOG_DEBUG, "MUTEX: <%s %p> being acquired by %s", desc ? desc->desc : "(none)", mutex, func); } #endif g_mutex_lock (mutex); } /* * nm_unlock_mutex * * Simply unlocks a mutex, balances nm_try_acquire_mutex() * */ void nm_unlock_mutex (GMutex *mutex, const char *func) { g_return_if_fail (mutex != NULL); #ifdef LOCKING_DEBUG if (func) { MutexDesc *desc = nm_find_mutex_desc (mutex); syslog (LOG_DEBUG, "MUTEX: <%s %p> released by %s", desc ? desc->desc : "(none)", mutex, func); } #endif g_mutex_unlock (mutex); } /* * nm_null_safe_strcmp * * Doesn't freaking segfault if s1/s2 are NULL * */ int nm_null_safe_strcmp (const char *s1, const char *s2) { if (!s1 && !s2) return 0; if (!s1 && s2) return -1; if (s1 && !s2) return 1; return (strcmp (s1, s2)); } /* * nm_ethernet_address_is_valid * * Compares an ethernet address against known invalid addresses. * */ gboolean nm_ethernet_address_is_valid (struct ether_addr *test_addr) { gboolean valid = FALSE; struct ether_addr invalid_addr1 = { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} }; struct ether_addr invalid_addr2 = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; struct ether_addr invalid_addr3 = { {0x44, 0x44, 0x44, 0x44, 0x44, 0x44} }; g_return_val_if_fail (test_addr != NULL, FALSE); /* Compare the AP address the card has with invalid ethernet MAC addresses. */ if ( (memcmp(test_addr, &invalid_addr1, sizeof(struct ether_addr)) != 0) && (memcmp(test_addr, &invalid_addr2, sizeof(struct ether_addr)) != 0) && (memcmp(test_addr, &invalid_addr3, sizeof(struct ether_addr)) != 0)) valid = TRUE; return (valid); } /* * nm_dispose_scan_results * * Free memory used by the wireless scan results structure * */ void nm_dispose_scan_results (wireless_scan *result_list) { wireless_scan *tmp = result_list; while (tmp) { wireless_scan *tmp2 = tmp; tmp = tmp->next; free (tmp2); } } /* * nm_spawn_process * * Wrap g_spawn_sync in a usable manner * */ int nm_spawn_process (char *args) { gint num_args; char **argv = NULL; int exit_status = -1; GError *error = NULL; char *so = NULL; char *se = NULL; g_return_val_if_fail (args != NULL, -1); if (g_shell_parse_argv (args, &num_args, &argv, &error)) { GError *error2 = NULL; if (!g_spawn_sync ("/", argv, NULL, 0, NULL, NULL, &so, &se, &exit_status, &error2)) syslog (LOG_ERR, "nm_spawn_process('%s'): could not spawn process. (%s)\n", args, error2->message); if (so) g_free(so); if (se) g_free(se); if (argv) g_strfreev (argv); if (error2) g_error_free (error2); } else syslog (LOG_ERR, "nm_spawn_process('%s'): could not parse arguments (%s)\n", args, error->message); if (error) g_error_free (error); return (exit_status); } typedef struct driver_support { char *name; NMDriverSupportLevel level; } driver_support; /* Blacklist of unsupported wireless drivers */ static driver_support wireless_driver_blacklist[] = { {NULL, NM_DRIVER_UNSUPPORTED} }; /* Blacklist of unsupported wired drivers. Drivers/cards that don't support * link detection should be blacklisted. */ static driver_support wired_driver_blacklist[] = { /* Completely unsupported drivers */ {NULL, NM_DRIVER_UNSUPPORTED} }; /* * nm_get_device_driver_name * * */ char *nm_get_device_driver_name (LibHalContext *ctx, NMDevice *dev) { char *udi = NULL; char *driver_name = NULL; g_return_val_if_fail (ctx != NULL, NULL); g_return_val_if_fail (dev != NULL, NULL); if ( (udi = nm_device_get_udi (dev)) && hal_device_property_exists (ctx, udi, "net.linux.driver")) { driver_name = hal_device_get_property_string (ctx, udi, "net.linux.driver"); } return (driver_name); } /* * nm_get_wireless_driver_support_level * * Blacklist certain wireless devices. * */ NMDriverSupportLevel nm_get_wireless_driver_support_level (LibHalContext *ctx, NMDevice *dev) { NMDriverSupportLevel level = NM_DRIVER_FULLY_SUPPORTED; char *driver_name = NULL; g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (dev != NULL, FALSE); if ((driver_name = nm_get_device_driver_name (ctx, dev))) { driver_support *driver = &wireless_driver_blacklist[0]; while (driver->name != NULL) { if (!strcmp (driver->name, driver_name)) { level = driver->level; break; } driver++; } g_free (driver_name); } return (level); } /* * nm_get_wired_driver_support_level * * Blacklist certain devices. * */ NMDriverSupportLevel nm_get_wired_driver_support_level (LibHalContext *ctx, NMDevice *dev) { NMDriverSupportLevel level = NM_DRIVER_FULLY_SUPPORTED; char *driver_name = NULL; char *usb_test; char *udi; g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (dev != NULL, FALSE); if ((driver_name = nm_get_device_driver_name (ctx, dev))) { driver_support *driver = &wired_driver_blacklist[0]; while (driver->name != NULL) { if (!strcmp (driver->name, driver_name)) { level = driver->level; break; } driver++; } g_free (driver_name); } /* cipsec devices are also explicitly unsupported at this time */ if (strstr (nm_device_get_iface (dev), "cipsec")) level = NM_DRIVER_UNSUPPORTED; /* Ignore Ethernet-over-USB devices too for the moment (Red Hat #135722) */ udi = nm_device_get_udi (dev); if ( hal_device_property_exists (ctx, udi, "usb.interface.class") && (usb_test = hal_device_get_property_string (ctx, udi, "usb.interface.class"))) { hal_free_string (usb_test); level = NM_DRIVER_UNSUPPORTED; } return (level); } /* * nm_get_driver_support_level * * Return the driver support level for a particular device. * */ NMDriverSupportLevel nm_get_driver_support_level (LibHalContext *ctx, NMDevice *dev) { NMDriverSupportLevel level = NM_DRIVER_UNSUPPORTED; g_return_val_if_fail (ctx != NULL, NM_DRIVER_UNSUPPORTED); g_return_val_if_fail (dev != NULL, NM_DRIVER_UNSUPPORTED); if (nm_device_is_wireless (dev)) level = nm_get_wireless_driver_support_level (ctx, dev); else if (nm_device_is_wired (dev)) level = nm_get_wired_driver_support_level (ctx, dev); switch (level) { case NM_DRIVER_SEMI_SUPPORTED: syslog (LOG_INFO, "%s: Driver support level is semi-supported", nm_device_get_iface (dev)); break; case NM_DRIVER_FULLY_SUPPORTED: syslog (LOG_INFO, "%s: Driver support level is fully-supported", nm_device_get_iface (dev)); break; default: syslog (LOG_INFO, "%s: Driver support level is unsupported", nm_device_get_iface (dev)); break; } return (level); }