Commit 1cc2f8c3 authored by Dan Williams's avatar Dan Williams
Browse files

2005-02-11 Dan Williams <dcbw@redhat.com>

	* dhcpcd/client.c
		- (dhcp_init): only print out client ID and class ID if they are specified

	* src/NetworkManagerDbus.[ch]
	  src/nm-dbus-nm.[ch]
	  src/nm-dbus-device.[ch]
	  src/nm-dbus-net.[ch]
		- Move NM, Device, and Net functions to separate files and use the
			dbus method list stuff in NetworkManagerDbusUtils.c to do
			method dispatching

	* src/NetworkManagerDbusUtils.c
		- Add new validate_method called before each dispatch (if present)
			that can validate the method call

	* src/NetworkManagerWireless.c
		- (nm_wireless_qual_to_percent): Fix misplaced "!" that caused signal
			levels never to be evaluated

	Patch from j@bootlab.org
	* src/NetworkManagerDevice.c
		- Add typedef for "u64"

	* src/backends/NetworkManagerDebian.c
		- Copy in Dave Woodhouse's fixes for IPv6


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@438 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
parent 8fb3b075
2005-02-11 Dan Williams <dcbw@redhat.com>
* dhcpcd/client.c
- (dhcp_init): only print out client ID and class ID if they are specified
* src/NetworkManagerDbus.[ch]
src/nm-dbus-nm.[ch]
src/nm-dbus-device.[ch]
src/nm-dbus-net.[ch]
- Move NM, Device, and Net functions to separate files and use the
dbus method list stuff in NetworkManagerDbusUtils.c to do
method dispatching
* src/NetworkManagerDbusUtils.c
- Add new validate_method called before each dispatch (if present)
that can validate the method call
* src/NetworkManagerWireless.c
- (nm_wireless_qual_to_percent): Fix misplaced "!" that caused signal
levels never to be evaluated
Patch from j@bootlab.org
* src/NetworkManagerDevice.c
- Add typedef for "u64"
* src/backends/NetworkManagerDebian.c
- Copy in Dave Woodhouse's fixes for IPv6
2005-02-11 Dan Williams <dcbw@redhat.com>
Patch from Dave Woodhouse for IPv6:
......
......@@ -726,11 +726,13 @@ int dhcp_init (dhcp_interface *iface)
release_dhcp_options (iface);
#ifdef DEBUG
syslog (LOG_DEBUG, "ClassID = \"%s\"", iface->cls_id);
syslog (LOG_DEBUG, "ClientID = \"%u.%u.%u.%02X.%02X.%02X.%02X.%02X.%02X\"\n",
iface->cli_id[0], iface->cli_id[1], iface->cli_id[2],
iface->cli_id[3], iface->cli_id[4], iface->cli_id[5],
iface->cli_id[6], iface->cli_id[7], iface->cli_id[8]);
if (iface->cls_id_len)
syslog (LOG_DEBUG, "ClassID = \"%s\"", iface->cls_id);
if (iface->cli_id_len)
syslog (LOG_DEBUG, "ClientID = \"%u.%u.%u.%02X.%02X.%02X.%02X.%02X.%02X\"\n",
iface->cli_id[0], iface->cli_id[1], iface->cli_id[2],
iface->cli_id[3], iface->cli_id[4], iface->cli_id[5],
iface->cli_id[6], iface->cli_id[7], iface->cli_id[8]);
#endif
if ( DebugFlag )
......
......@@ -13,6 +13,12 @@ NetworkManager_SOURCES = \
NetworkManagerDbus.h \
NetworkManagerDbusUtils.c \
NetworkManagerDbusUtils.h \
nm-dbus-nm.h \
nm-dbus-nm.c \
nm-dbus-device.h \
nm-dbus-device.c \
nm-dbus-net.h \
nm-dbus-net.c \
NetworkManagerDHCP.c \
NetworkManagerDHCP.h \
NetworkManagerDevice.c \
......
This diff is collapsed.
......@@ -70,4 +70,11 @@ gboolean nm_dbus_nmi_is_running (DBusConnection *connection);
char ** nm_dbus_get_networks (DBusConnection *connection, NMNetworkType type, int *num_networks);
DBusMessage * nm_dbus_create_error_message (DBusMessage *message, const char *exception_namespace,
const char *exception, const char *format, ...);
NMDevice * nm_dbus_get_device_from_object_path (NMData *data, const char *path);
char * nm_dbus_network_status_from_data (NMData *data);
#endif
......@@ -26,16 +26,20 @@
struct NMDbusMethodList
{
NMDbusMethod validate_method;
GHashTable *methods;
};
NMDbusMethodList * nm_dbus_method_list_new (void)
NMDbusMethodList * nm_dbus_method_list_new (NMDbusMethod validate_method)
{
NMDbusMethodList *list = g_malloc0 (sizeof (NMDbusMethodList));
if (list)
{
list->validate_method = validate_method;
list->methods = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
return list;
}
......@@ -72,7 +76,13 @@ gboolean nm_dbus_method_dispatch (NMDbusMethodList *list, DBusConnection *connec
if (!(callback = g_hash_table_lookup (list->methods, method)))
return FALSE;
temp_reply = (*callback) (connection, message, (NMDbusCBData *)user_data);
/* Call the optional validate method first, if it returns NULL then we
* actually dispatch the call.
*/
if (list->validate_method)
temp_reply = (*(list->validate_method)) (connection, message, (NMDbusCBData *)user_data);
if (!temp_reply)
temp_reply = (*callback) (connection, message, (NMDbusCBData *)user_data);
if (reply)
*reply = temp_reply;
......
......@@ -28,17 +28,19 @@
#include <dbus/dbus-glib.h>
#include "NetworkManagerMain.h"
#include "NetworkManagerDevice.h"
typedef struct NMDbusCBData
{
NMData *data;
NMDevice *dev;
NMData *data;
NMDevice *dev;
NMAccessPoint *ap;
} NMDbusCBData;
typedef DBusMessage* (*NMDbusMethod) (DBusConnection *, DBusMessage *, NMDbusCBData *);
NMDbusMethodList * nm_dbus_method_list_new (void);
NMDbusMethodList * nm_dbus_method_list_new (NMDbusMethod validate_method);
void nm_dbus_method_list_add_method (NMDbusMethodList *list, const char *method, NMDbusMethod callback);
......
......@@ -3618,6 +3618,7 @@ void nm_device_config_set_ip4_broadcast (NMDevice *dev, guint32 broadcast)
typedef u_int8_t u8;
typedef u_int16_t u16;
typedef u_int32_t u32;
typedef u_int64_t u64;
/**************************************/
......
......@@ -139,11 +139,11 @@ int nm_wireless_qual_to_percent (const struct iw_quality *qual, const struct iw_
g_return_val_if_fail (max_qual != NULL, -1);
g_return_val_if_fail (avg_qual != NULL, -1);
/*
#if IW_QUAL_DEBUG
syslog (LOG_DEBUG, "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X",
(__s8)qual->qual, qual->qual, qual->qual, (__s8)qual->level, qual->level, qual->level, (__s8)qual->noise, qual->noise, qual->noise,
(__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);
*/
#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
......@@ -164,13 +164,14 @@ syslog (LOG_DEBUG, "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X **
* If drivers don't conform to it, they are wrong and need to be fixed.
*/
/* Absolute power values (dBm) */
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 */
|| ((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
......@@ -190,23 +191,31 @@ syslog (LOG_DEBUG, "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X **
level_percent = (int)(100 - 70 *(
((double)max_level - (double)level) /
((double)max_level - (double)noise)));
/* syslog (LOG_DEBUG, "QL1: level_percent is %d. max_level %d, level %d, noise_floor %d.", level_percent, max_level, level, noise);*/
#if IW_QUAL_DEBUG
syslog (LOG_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));
/* syslog (LOG_DEBUG, "QL2: level_percent is %d. max_level %d, level %d.", level_percent, max_qual->level, level);*/
#if IW_QUAL_DEBUG
syslog (LOG_DEBUG, "QL2: level_percent is %d. max_level %d, level %d.", level_percent, max_qual->level, level);
#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;
/* syslog (LOG_DEBUG, "QL: Final quality %% is %d (%d).", percent, CLAMP (percent, 0, 100));*/
#if IW_QUAL_DEBUG
syslog (LOG_DEBUG, "QL: Final quality %% is %d (%d).", percent, CLAMP (percent, 0, 100));
#endif
return (CLAMP (percent, 0, 100));
}
......@@ -333,6 +333,23 @@ void nm_system_restart_mdns_responder (void)
*/
void nm_system_device_add_ip6_link_address (NMDevice *dev)
{
char *buf;
unsigned char eui[8];
nm_device_get_hw_address(dev, eui);
memmove(eui+5, eui+3, 3);
eui[3] = 0xff;
eui[4] = 0xfe;
eui[0] ^= 2;
/* Add the default link-local IPv6 address to a device */
buf = g_strdup_printf ("/sbin/ip -6 address add fe80::%x%02x:%x%02x:%x%02x:%x%02x/64 dev %s",
eui[0], eui[1], eui[2], eui[3],
eui[4], eui[5],
eui[6], eui[7], nm_device_get_iface (dev));
nm_spawn_process (buf);
g_free (buf);
}
......
/* NetworkManager -- Network link manager
*
* Dan Williams <dcbw@redhat.com>
*
* 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 <glib.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <dbus/dbus-glib.h>
#include <stdarg.h>
#include <syslog.h>
#include "NetworkManagerDevice.h"
#include "NetworkManagerDbus.h"
#include "NetworkManagerDbusUtils.h"
#include "NetworkManagerPolicy.h"
#include "nm-dbus-device.h"
static DBusMessage *nm_dbus_device_get_name (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
NMDevice *dev;
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_message_append_args (reply, DBUS_TYPE_STRING, nm_device_get_iface (dev), DBUS_TYPE_INVALID);
return reply;
}
static DBusMessage *nm_dbus_device_get_type (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
NMDevice *dev;
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_message_append_args (reply, DBUS_TYPE_INT32, nm_device_get_type (dev), DBUS_TYPE_INVALID);
return reply;
}
static DBusMessage *nm_dbus_device_get_hal_udi (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
NMDevice *dev;
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_message_append_args (reply, DBUS_TYPE_STRING, nm_device_get_udi (dev), DBUS_TYPE_INVALID);
return reply;
}
static DBusMessage *nm_dbus_device_get_ip4_address (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
NMDevice *dev;
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_message_append_args (reply, DBUS_TYPE_UINT32, nm_device_get_ip4_address (dev), DBUS_TYPE_INVALID);
return reply;
}
static DBusMessage *nm_dbus_device_get_mode (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
NMDevice *dev;
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_message_append_args (reply, DBUS_TYPE_UINT32, nm_device_get_mode (dev), DBUS_TYPE_INVALID);
return reply;
}
static DBusMessage *nm_dbus_device_get_link_active (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
NMDevice *dev;
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_message_append_args (reply, DBUS_TYPE_BOOLEAN, nm_device_get_link_active (dev), DBUS_TYPE_INVALID);
return reply;
}
static DBusMessage *nm_dbus_device_get_strength (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
NMDevice *dev;
g_return_val_if_fail (data && data->data && data->dev && connection && message, NULL);
/* Only wireless devices have signal strength */
dev = data->dev;
if (!nm_device_is_wireless (dev))
{
reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "DeviceNotWireless",
"Wired devices cannot have signal strength.");
}
else if ((reply = dbus_message_new_method_return (message)))
dbus_message_append_args (reply, DBUS_TYPE_INT32, nm_device_get_signal_strength (dev), DBUS_TYPE_INVALID);
return reply;
}
static DBusMessage *nm_dbus_device_get_active_network (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
gboolean success = FALSE;
NMDevice *dev;
g_return_val_if_fail (data && data->data && data->dev && connection && message, NULL);
/* Only wireless devices have an active network */
dev = data->dev;
if (!nm_device_is_wireless (dev))
{
reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "DeviceNotWireless",
"Wired devices cannot have active networks.");
}
else if ((reply = dbus_message_new_method_return (message)))
{
NMAccessPoint *best_ap;
/* Return the network associated with the ESSID the card is currently associated with,
* if any, and only if that network is the "best" network.
*/
if ((best_ap = nm_device_get_best_ap (dev)))
{
NMAccessPoint *tmp_ap;
char *object_path = g_strdup_printf ("%s/%s/Networks/", NM_DBUS_PATH_DEVICES, nm_device_get_iface (dev));
if ( (tmp_ap = nm_device_ap_list_get_ap_by_essid (dev, nm_ap_get_essid (best_ap)))
&& (object_path = nm_device_get_path_for_ap (dev, tmp_ap)))
{
dbus_message_append_args (reply, DBUS_TYPE_STRING, object_path, DBUS_TYPE_INVALID);
success = TRUE;
}
nm_ap_unref (best_ap);
g_free (object_path);
}
if (!success)
{
dbus_message_unref (reply);
reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "NoActiveNetwork",
"The device is not associated with any networks at this time.");
}
}
return reply;
}
static DBusMessage *nm_dbus_device_get_networks (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
NMDevice *dev;
g_return_val_if_fail (data && data->data && data->dev && connection && message, NULL);
/* Only wireless devices have networks */
dev = data->dev;
if (!nm_device_is_wireless (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)))
{
DBusMessageIter iter;
DBusMessageIter iter_array;
NMAccessPoint *ap = NULL;
gboolean success = FALSE;
NMAccessPointList *ap_list;
NMAPListIter *list_iter;
char *object_path;
dbus_message_iter_init (reply, &iter);
dbus_message_iter_append_array (&iter, &iter_array, DBUS_TYPE_STRING);
if ((ap_list = nm_device_ap_list_get (dev)))
{
if ((list_iter = nm_ap_list_iter_new (ap_list)))
{
while ((ap = nm_ap_list_iter_next (list_iter)))
{
if (nm_ap_get_essid (ap))
{
object_path = g_strdup_printf ("%s/%s/Networks/%s", NM_DBUS_PATH_DEVICES,
nm_device_get_iface (dev), nm_ap_get_essid (ap));
dbus_message_iter_append_string (&iter_array, object_path);
g_free (object_path);
success = TRUE;
}
}
nm_ap_list_iter_free (list_iter);
}
}
if (!success)
{
dbus_message_unref (reply);
reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "NoNetworks",
"The device cannot see any wireless networks.");
}
}
return reply;
}
static DBusMessage *nm_dbus_device_get_supports_carrier_detect (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
NMDevice *dev;
g_return_val_if_fail (data && data->data && data->dev && connection && message, NULL);
/* Wired devices only for now */
dev = data->dev;
if (!nm_device_is_wired (dev))
{
reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "DeviceNotWired",
"Carrier detection is only supported for wired devices.");
}
else if ((reply = dbus_message_new_method_return (message)))
dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, nm_device_get_supports_carrier_detect (dev), DBUS_TYPE_INVALID);
return reply;
}
static DBusMessage *nm_dbus_device_set_link_active (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data)
{
DBusMessage *reply = NULL;
NMDevice *dev;
g_return_val_if_fail (data && data->data && data->dev && connection && message, NULL);
/* Can only set link status for active devices */
dev = data->dev;
if (!nm_device_is_test_device (dev))
{
reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "NotTestDevice",
"Only test devices can have their link status set manually.");
}
else if ((reply = dbus_message_new_method_return (message)))
{
DBusError error;
gboolean link;
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_policy_schedule_state_update (data->data);
}
}
return reply;
}
/*
* nm_dbus_device_methods_setup
*
* Register handlers for dbus methods on the org.freedesktop.NetworkManager.Devices object.
*
*/
NMDbusMethodList *nm_dbus_device_methods_setup (void)
{
NMDbusMethodList *list = nm_dbus_method_list_new (NULL);
nm_dbus_method_list_add_method (list, "getName", nm_dbus_device_get_name);
nm_dbus_method_list_add_method (list, "getType", nm_dbus_device_get_type);
nm_dbus_method_list_add_method (list, "getHalUdi", nm_dbus_device_get_hal_udi);
nm_dbus_method_list_add_method (list, "getIP4Address", nm_dbus_device_get_ip4_address);
nm_dbus_method_list_add_method (list, "getMode", nm_dbus_device_get_mode);
nm_dbus_method_list_add_method (list, "getStrength", nm_dbus_device_get_strength);
nm_dbus_method_list_add_method (list, "getActiveNetwork", nm_dbus_device_get_active_network);
nm_dbus_method_list_add_method (list, "getNetworks", nm_dbus_device_get_networks);
nm_dbus_method_list_add_method (list, "getLinkActive", nm_dbus_device_get_link_active);
nm_dbus_method_list_add_method (list, "setLinkActive", nm_dbus_device_set_link_active);
nm_dbus_method_list_add_method (list, "getSupportsCarrierDetect", nm_dbus_device_get_supports_carrier_detect);
return (list);
}
/* NetworkManager -- Network link manager
*
* Dan Williams <dcbw@redhat.com>
*
* 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_DBUS_DEVICE_H
#define NM_DBUS_DEVICE_H
NMDbusMethodList *nm_dbus_device_methods_setup (void);
#endif
/* NetworkManager -- Network link manager
*
* Dan Williams <dcbw@redhat.com>
*
* 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.
*/