Index: include/NetworkManager.h
===================================================================
--- include/NetworkManager.h	(revision 2569)
+++ include/NetworkManager.h	(working copy)
@@ -33,6 +33,7 @@
 #define	NM_DBUS_INTERFACE_DEVICE	"org.freedesktop.NetworkManager.Device"
 #define NM_DBUS_INTERFACE_DEVICE_WIRED "org.freedesktop.NetworkManager.Device.Wired"
 #define NM_DBUS_INTERFACE_DEVICE_WIRELESS "org.freedesktop.NetworkManager.Device.Wireless"
+#define NM_DBUS_INTERFACE_DEVICE_BLUETOOTH "org.freedesktop.NetworkManager.Device.Bluetooth"
 #define NM_DBUS_PATH_ACCESS_POINT "/org/freedesktop/NetworkManager/AccessPoint"
 #define NM_DBUS_INTERFACE_ACCESS_POINT "org.freedesktop.NetworkManager.AccessPoint"
 
@@ -64,7 +65,8 @@
 {
 	DEVICE_TYPE_UNKNOWN = 0,
 	DEVICE_TYPE_802_3_ETHERNET,
-	DEVICE_TYPE_802_11_WIRELESS
+	DEVICE_TYPE_802_11_WIRELESS,
+	DEVICE_TYPE_BLUETOOTH
 } NMDeviceType;
 
 
Index: src/nm-bluez-manager.c
===================================================================
--- src/nm-bluez-manager.c	(revision 0)
+++ src/nm-bluez-manager.c	(revision 0)
@@ -0,0 +1,576 @@
+/* nm-bluez-manager.c - handle Bluetooth connections within NetworkManager's framework 
+ *
+ * Copyright (C) 2005 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, 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.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "nm-bluez-manager.h"
+#include "nm-dbus-manager.h"
+#include "nm-utils.h"
+#include "nm-device-bluetooth.h"
+
+#define NAP_UUID "NAP"
+#define GN_UUID "GN"
+#define NETWORK_CLASS 0x020000
+#define SCHEDULER_TIMEOUT 60000
+
+struct _NMBluezManager {
+	NMDBusManager *dbus_mgr;
+	NMManager *nm_manager;
+	NMData *nm_data;
+	GQueue *queue;
+	char *service;
+	char *path;
+	guint timeout;
+
+	gboolean nm_sleeping;
+};
+
+typedef struct {
+	char *address;
+	char *uuid;
+	char *path;
+	guint16 rssi;
+	guint32 klass;
+} NMBluezConnection;
+
+static int create_connection(NMBluezManager *manager, DBusPendingCallNotifyFunction cb);
+static void create_connection_reply(DBusPendingCall *call, void *data);
+static gboolean activate_service (NMBluezManager *manager, DBusPendingCallNotifyFunction cb);
+static void activate_service_reply (DBusPendingCall *call, void *data);
+
+static void
+btfree (gpointer data)
+{
+	NMBluezConnection *bt = data;
+
+	if (bt->address)
+		g_free (bt->address);
+
+	if (bt->uuid)
+		g_free (bt->uuid);
+
+	if (bt->path)
+		g_free (bt->path);
+
+	g_free (bt);
+	bt = NULL;
+}
+
+void
+queue_free (GQueue *queue)
+{
+	NMBluezConnection *bt;
+
+	while ((bt = g_queue_pop_head (queue)))
+		btfree (bt);
+
+	g_queue_free (queue);
+}
+
+gboolean
+timeout_func (gpointer data)
+{
+	NMBluezManager *manager = data;
+
+	if (!activate_service (manager, activate_service_reply))
+		return TRUE;
+
+	manager->timeout = 0;
+	return FALSE;
+}
+
+static void
+connect_reply (DBusPendingCall *call, void *data)
+{
+	DBusConnection *connection;
+	NMBluezManager *manager = data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusMessage *msg;
+	DBusError derr;
+	NMBluezConnection *bt;
+	const gchar *iface;
+
+	bt = g_queue_pop_head (manager->queue);
+	dbus_error_init(&derr);
+	if (!dbus_set_error_from_message(&derr, reply)) {
+		if (dbus_message_get_args(reply, &derr,
+			DBUS_TYPE_STRING, &iface,
+			DBUS_TYPE_INVALID)) {
+			goto ok;
+		}
+	}
+
+	msg = dbus_message_new_method_call(manager->service, "/org/bluez/network",
+			"org.bluez.network.Manager", "RemoveConnection");
+	if (!msg)
+		goto ok;
+
+	dbus_message_append_args(msg,
+			DBUS_TYPE_STRING, &bt->path,
+			DBUS_TYPE_INVALID);
+
+	dbus_error_init(&derr);
+
+	connection = nm_dbus_manager_get_dbus_connection (manager->dbus_mgr);
+
+	dbus_connection_send_with_reply_and_block(connection, msg, -1, &derr);
+	btfree (bt);
+ok:
+	if (dbus_error_is_set (&derr))
+		dbus_error_free (&derr);
+	dbus_message_unref(reply);
+	create_connection (manager, create_connection_reply);
+}
+
+static gboolean
+connection_connect (NMBluezManager *manager, const gchar *path,
+		DBusPendingCallNotifyFunction cb)
+{
+	DBusConnection *connection;
+	DBusMessage *msg;
+	DBusPendingCall *pending;
+	NMBluezConnection *bt;
+
+	bt = g_queue_peek_head (manager->queue);
+	msg = dbus_message_new_method_call(manager->service, path,
+			"org.bluez.network.Connection", "Connect");
+	if (!msg)
+		return FALSE;
+
+	bt->path = g_strdup (path);
+
+	connection = nm_dbus_manager_get_dbus_connection (manager->dbus_mgr);
+
+	if (dbus_connection_send_with_reply(connection, msg, &pending, -1) == FALSE)
+		return FALSE;
+
+	dbus_pending_call_set_notify(pending, cb, manager, NULL);
+	dbus_message_unref(msg);
+	dbus_pending_call_unref(pending);
+
+	return TRUE;
+}
+
+static void
+create_connection_reply (DBusPendingCall *call, void *data)
+{
+	NMBluezManager *manager = data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+	const gchar *path;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply))
+		goto fail;
+
+	if (!dbus_message_get_args(reply, &derr,
+				DBUS_TYPE_STRING, &path,
+				DBUS_TYPE_INVALID))
+		goto fail;
+
+	if (connection_connect (manager, path, connect_reply) < 0) {
+		goto fail;
+	}
+
+	dbus_message_unref(reply);
+	return;
+fail:
+	dbus_error_free(&derr);
+	dbus_message_unref(reply);
+	btfree (g_queue_pop_head (manager->queue));
+	create_connection (manager, create_connection_reply);
+}
+
+static gboolean
+create_connection (NMBluezManager *manager, DBusPendingCallNotifyFunction cb)
+{
+	DBusConnection *connection;
+	DBusMessage *msg;
+	DBusPendingCall *pending;
+	NMBluezConnection *bt;
+
+	if (manager->nm_sleeping) {
+		return FALSE;
+	}
+
+	if (!(bt = g_queue_peek_head (manager->queue))) {
+		manager->timeout = g_timeout_add (SCHEDULER_TIMEOUT, timeout_func, manager);
+		return FALSE;
+	}
+
+	msg = dbus_message_new_method_call(manager->service, "/org/bluez/network",
+			"org.bluez.network.Manager", "CreateConnection");
+	if (!msg)
+		return FALSE;
+
+	dbus_message_append_args(msg,
+			DBUS_TYPE_STRING, &bt->address,
+			DBUS_TYPE_STRING, &bt->uuid,
+			DBUS_TYPE_INVALID);
+
+	connection = nm_dbus_manager_get_dbus_connection (manager->dbus_mgr);
+
+	if (dbus_connection_send_with_reply(connection, msg, &pending, -1) == FALSE)
+		return FALSE;
+
+	dbus_pending_call_set_notify(pending, cb, manager, NULL);
+	dbus_message_unref(msg);
+	dbus_pending_call_unref(pending);
+
+	return TRUE;
+}
+
+static void
+activate_service_reply (DBusPendingCall *call, void *data)
+{
+	NMBluezManager *manager = data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+	const gchar *sid;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply))
+		goto fail;
+
+	if (!dbus_message_get_args(reply, &derr,
+				DBUS_TYPE_STRING, &sid,
+				DBUS_TYPE_INVALID))
+		goto fail;
+
+	if (manager->service && !g_str_equal (manager->service, sid)) {
+		g_free (manager->service);
+		manager->service = g_strdup (sid);
+	}
+	else if (!manager->service)
+		manager->service = g_strdup (sid);
+
+	if (!(create_connection(manager, create_connection_reply)))
+		goto fail;
+
+	dbus_message_unref(reply);
+	return;
+fail:
+	if (!manager->timeout)
+		manager->timeout = g_timeout_add (SCHEDULER_TIMEOUT, timeout_func, manager);
+	dbus_error_free(&derr);
+	dbus_message_unref(reply);
+}
+
+static gboolean
+activate_service (NMBluezManager *manager, DBusPendingCallNotifyFunction cb)
+{
+	DBusConnection *connection;
+	DBusMessage *msg;
+	DBusPendingCall *pending;
+	gchar network[8] = "network";
+	const gchar *pnetwork = network;
+
+	msg = dbus_message_new_method_call(BLUEZ_DBUS_SERVICE, BLUEZ_DBUS_PATH,
+			"org.bluez.Manager", "ActivateService");
+	if (!msg)
+		return FALSE;
+
+	dbus_message_append_args(msg,
+			DBUS_TYPE_STRING, &pnetwork,
+			DBUS_TYPE_INVALID);
+
+	connection = nm_dbus_manager_get_dbus_connection (manager->dbus_mgr);
+
+	if (dbus_connection_send_with_reply(connection, msg, &pending, -1) == FALSE)
+		return FALSE;
+
+	dbus_pending_call_set_notify(pending, cb, manager, NULL);
+	dbus_message_unref(msg);
+	dbus_pending_call_unref(pending);
+
+	return TRUE;
+}
+
+static gboolean
+nm_bluez_manager_init (NMBluezManager *manager)
+{
+	DBusConnection *connection;
+	DBusMessage *msg;
+	DBusMessage *reply;
+	DBusError derr;
+	const char *adapter;
+
+	msg = dbus_message_new_method_call(BLUEZ_DBUS_SERVICE, BLUEZ_DBUS_PATH,
+			"org.bluez.Manager", "DefaultAdapter");
+	if (!msg)
+		return FALSE;
+
+	dbus_error_init(&derr);
+
+	connection = nm_dbus_manager_get_dbus_connection (manager->dbus_mgr);
+	reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, &derr);
+
+	if (dbus_error_is_set (&derr))
+		goto fail;
+
+	if (!dbus_message_get_args(reply, &derr,
+				DBUS_TYPE_STRING, &adapter,
+				DBUS_TYPE_INVALID))
+		goto fail;
+
+	if (manager->path && !g_str_equal (manager->path, adapter)) {
+		g_free (manager->path);
+		manager->path = g_strdup (adapter);
+	}
+	else if (!manager->path)
+		manager->path = g_strdup (adapter);
+
+	dbus_message_unref (msg);
+
+	msg = dbus_message_new_method_call(BLUEZ_DBUS_SERVICE, manager->path,
+			"org.bluez.Adapter", "StartPeriodicDiscovery");
+	if (!msg)
+		return FALSE;
+
+	dbus_error_init(&derr);
+
+	reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, &derr);
+
+	if (dbus_error_is_set (&derr))
+		goto fail;
+
+	dbus_message_unref (msg);
+
+	if (!manager->queue)
+		manager->queue = g_queue_new ();
+
+	if (!manager->timeout)
+		manager->timeout = g_timeout_add (SCHEDULER_TIMEOUT, timeout_func, manager);
+
+	return TRUE;
+fail:
+	dbus_error_free (&derr);
+	dbus_message_unref (msg);
+	return FALSE;
+}
+
+static void
+nm_bluez_manager_deinit (NMBluezManager *manager)
+{
+	DBusConnection *connection;
+	DBusMessage *msg;
+	DBusError derr;
+
+	msg = dbus_message_new_method_call(BLUEZ_DBUS_SERVICE, manager->path,
+			"org.bluez.Adapter", "StopPeriodicDiscovery");
+	if (!msg)
+		return;
+
+	dbus_error_init(&derr);
+
+	connection = nm_dbus_manager_get_dbus_connection (manager->dbus_mgr);
+
+	dbus_connection_send_with_reply_and_block (connection, msg, -1, &derr);
+
+	dbus_message_unref (msg);
+
+}
+
+static int
+btcmp (NMBluezConnection *bt0, NMBluezConnection *bt1)
+{
+	return strcmp (bt0->address, bt1->address);
+}
+
+static gboolean
+is_connected (NMBluezManager *manager, NMBluezConnection *bt)
+{
+	GSList *devices;
+	GSList *iter;
+
+	if (g_queue_find_custom (manager->queue, bt, (GCompareFunc) btcmp))
+		return TRUE;
+
+	devices = nm_manager_get_devices (manager->nm_manager);
+
+	for (iter = devices; iter; iter = iter->next) {
+		NMDevice *device = iter->data;
+
+		if (NM_IS_DEVICE_BLUETOOTH (device)) {
+			char *addr;
+
+			g_object_get (device, NM_DEVICE_BLUETOOTH_HOST_ADDRESS, &addr, NULL);
+			if (!strcmp (bt->address, addr)) {
+				g_object_set (device, NM_DEVICE_BLUETOOTH_STRENGTH, bt->rssi, NULL);
+				return TRUE;
+			}
+		}
+	}
+
+	return FALSE;
+}
+
+gboolean
+nm_dbus_bluez_signal_handler (DBusConnection *connection,
+                              DBusMessage *message,
+                              gpointer user_data)
+{
+	NMBluezManager *manager = user_data;
+	gboolean handled = TRUE;
+
+	g_return_val_if_fail (manager != NULL, FALSE);
+
+	if (dbus_message_is_signal (message, BLUEZ_DBUS_INTERFACE, "DefaultAdapterChanged")) {
+		nm_bluez_manager_init (manager);
+	} else if (dbus_message_is_signal (message, BLUEZ_DBUS_INTERFACE, "RemoteDeviceFound")) {
+		NMBluezConnection *btnap;
+		NMBluezConnection *btgn;
+		char *address;
+
+		if (!manager->nm_sleeping) {
+			btnap = g_new0 (NMBluezConnection, 1);
+			btgn = g_new0 (NMBluezConnection, 1);
+			if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_UINT32, &btnap->klass, DBUS_TYPE_INT16, &btnap->rssi, DBUS_TYPE_INVALID))
+			{
+				btnap->address = g_strdup (address);
+				btnap->uuid = g_strdup (NAP_UUID);
+				btgn->address = g_strdup (address);
+				btgn->uuid = g_strdup (GN_UUID);
+				btgn->klass = btnap->klass;
+				btgn->rssi = btnap->rssi;
+
+				if (!(btnap->klass & NETWORK_CLASS) || is_connected (manager, btnap)) {
+					handled = FALSE;
+					btfree (btnap);
+					btfree (btgn);
+				} else {
+					g_queue_push_tail (manager->queue, (gpointer) btnap);
+					g_queue_push_tail (manager->queue, (gpointer) btgn);
+				}
+			}
+		}
+	} else
+		handled = FALSE;
+
+	return handled;
+}
+
+static void
+name_owner_changed (NMDBusManager *dbus_mgr,
+					DBusGConnection *connection,
+					const char *name,
+					const char *old,
+					const char *new,
+					gpointer user_data)
+{
+	NMBluezManager *manager = (NMBluezManager *) user_data;
+
+	/* Only care about signals from BLUEZ */
+	if (strcmp (name, "org.bluez"))
+		return;
+
+	if (!manager->nm_sleeping)
+		nm_bluez_manager_init (manager);
+}
+
+static void
+connection_changed (NMDBusManager *dbus_mgr,
+					DBusGConnection *connection,
+					gpointer user_data)
+{
+	NMBluezManager *manager = (NMBluezManager *) user_data;
+	char *owner;
+
+	if (!connection) {
+		return;
+	}
+
+	if ((owner = nm_dbus_manager_get_name_owner (dbus_mgr, "org.bluez"))) {
+		nm_bluez_manager_init (manager);
+		g_free (owner);
+	}
+}
+
+static void
+nm_manager_state_changed (NMManager *nm_manager, NMState state, gpointer user_data)
+{
+	NMBluezManager *manager = (NMBluezManager *) user_data;
+
+	if (state == NM_STATE_ASLEEP) {
+		/* Save the sleep state */
+		manager->nm_sleeping = TRUE;
+		nm_bluez_manager_deinit (manager);
+	} else if (manager->nm_sleeping) {
+		/* If the previous state was sleep, the next one means we just woke up */
+		manager->nm_sleeping = FALSE;
+		nm_bluez_manager_init (manager);
+	}
+}
+
+NMBluezManager *
+nm_bluez_manager_new (NMManager *nm_manager, NMData *nm_data)
+{
+	NMBluezManager *manager;
+	NMDBusManager *dbus_mgr;
+
+	g_return_val_if_fail (NM_IS_MANAGER (nm_manager), NULL);
+
+	dbus_mgr = nm_dbus_manager_get ();
+	if (!nm_dbus_manager_name_has_owner (dbus_mgr, "org.bluez")) {
+		nm_warning ("Could not initialize connection to the BLUEZ daemon.");
+		return NULL;
+	}
+
+	manager = g_slice_new0 (NMBluezManager);
+	manager->nm_manager = g_object_ref (nm_manager);
+	manager->dbus_mgr = dbus_mgr;
+	manager->nm_data = nm_data;
+
+	g_signal_connect (manager->dbus_mgr,
+					  "name-owner-changed",
+					  G_CALLBACK (name_owner_changed),
+					  manager);
+	g_signal_connect (manager->dbus_mgr,
+					  "dbus-connection-changed",
+					  G_CALLBACK (connection_changed),
+					  manager);
+	g_signal_connect (nm_manager,
+					  "state-change",
+					  G_CALLBACK (nm_manager_state_changed),
+					  manager);
+
+	nm_dbus_manager_register_signal_handler (dbus_mgr,
+											 BLUEZ_DBUS_INTERFACE,
+											 BLUEZ_DBUS_SERVICE,
+											 nm_dbus_bluez_signal_handler,
+											 manager);
+
+	nm_bluez_manager_init (manager);
+
+	return manager;
+}
+
+void
+nm_bluez_manager_destroy (NMBluezManager *manager)
+{
+	if (manager) {
+		g_object_unref (manager->nm_manager);
+
+		nm_bluez_manager_deinit (manager);
+		queue_free (manager->queue);
+		g_source_remove (manager->timeout);
+		g_slice_free (NMBluezManager, manager);
+	}
+}
Index: src/NetworkManagerDbus.c
===================================================================
--- src/NetworkManagerDbus.c	(revision 2569)
+++ src/NetworkManagerDbus.c	(working copy)
@@ -175,4 +175,3 @@
 
 	return handled;
 }
-
Index: src/nm-bluez-manager.h
===================================================================
--- src/nm-bluez-manager.h	(revision 0)
+++ src/nm-bluez-manager.h	(revision 0)
@@ -0,0 +1,36 @@
+/* nm-bluez-manager.h - handle bluetooth connections within NetworkManager's framework
+ *
+ * Copyright (C) 2005 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, 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.
+ */
+
+#ifndef NM_BLUEZ_MANAGER_H
+#define NM_BLUEZ_MANAGER_H
+
+#include "nm-manager.h"
+#include "NetworkManagerMain.h"
+
+#define BLUEZ_DBUS_SERVICE "org.bluez"
+#define BLUEZ_DBUS_PATH "/org/bluez"
+#define BLUEZ_DBUS_INTERFACE "org.bluez.Adapter"
+
+typedef struct _NMBluezManager NMBluezManager;
+
+NMBluezManager *nm_bluez_manager_new (NMManager *nm_manager, NMData *nm_data);
+void nm_bluez_manager_destroy (NMBluezManager *manager);
+
+#endif /* NM_BLUEZ_MANAGER_H */
Index: src/NetworkManagerDbus.h
===================================================================
--- src/NetworkManagerDbus.h	(revision 2569)
+++ src/NetworkManagerDbus.h	(working copy)
@@ -31,7 +31,6 @@
 #include "nm-device-802-11-wireless.h"
 #include "NetworkManagerAPList.h"
 
-
 static inline gboolean message_is_error (DBusMessage *msg)
 {
 	g_return_val_if_fail (msg != NULL, FALSE);
@@ -49,5 +48,8 @@
 gboolean nm_dbus_nmi_signal_handler (DBusConnection *connection,
                                      DBusMessage *message,
                                      gpointer user_data);
+gboolean nm_dbus_bluez_signal_handler (DBusConnection *connection,
+                                     DBusMessage *message,
+                                     gpointer user_data);
 
 #endif
Index: src/nm-hal-manager.c
===================================================================
--- src/nm-hal-manager.c	(revision 2569)
+++ src/nm-hal-manager.c	(working copy)
@@ -6,6 +6,7 @@
 #include "nm-utils.h"
 #include "nm-device-802-11-wireless.h"
 #include "nm-device-802-3-ethernet.h"
+#include "nm-device-bluetooth.h"
 
 struct _NMHalManager {
 	LibHalContext *hal_ctx;
@@ -53,22 +54,46 @@
 {
 	char *iface = NULL;
 
-	if (libhal_device_property_exists (ctx, udi, "net.interface", NULL) && 
-		libhal_device_property_exists (ctx, udi, "info.category", NULL)) {
-
-		char *category = libhal_device_get_property_string (ctx, udi, "info.category", NULL);
-		if (category && (!strcmp (category, "net.80203") || !strcmp (category, "net.80211"))) {
-			char *temp = libhal_device_get_property_string (ctx, udi, "net.interface", NULL);
-			iface = g_strdup (temp);
-			libhal_free_string (temp);
+	if (libhal_device_property_exists (ctx, udi, "net.interface", NULL)) {
+		if (libhal_device_property_exists (ctx, udi, "info.category", NULL)) {
+			char *category = libhal_device_get_property_string (ctx, udi, "info.category", NULL);
+			if (category && (!strcmp (category, "net.80203") ||
+				!strcmp (category, "net.80211") ||
+				!strcmp (category, "net.bluetooth"))) {
+				char *temp = libhal_device_get_property_string (ctx, udi, "net.interface", NULL);
+				iface = g_strdup (temp);
+				libhal_free_string (temp);
+			}
+			libhal_free_string (category);
 		}
-
-		libhal_free_string (category);
 	}
 
 	return iface;
 }
 
+static NMDeviceType
+discover_device_type (LibHalContext *ctx, const char *udi)
+{
+	char *category = NULL;
+
+	if (libhal_device_property_exists (ctx, udi, "info.category", NULL))
+		category = libhal_device_get_property_string (ctx, udi, "info.category", NULL);
+	if (category && (!strcmp (category, "net.bluetooth")))
+		return DEVICE_TYPE_BLUETOOTH;
+	if (category && (!strcmp (category, "net.80211")))
+		return DEVICE_TYPE_802_11_WIRELESS;
+	else if (category && (!strcmp (category, "net.80203")))
+		return DEVICE_TYPE_802_3_ETHERNET;
+
+	return DEVICE_TYPE_UNKNOWN;
+}
+
+/*
+ * 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)
 {
@@ -113,6 +138,7 @@
 	NMDevice *device;
 	char *iface;
 	char *driver;
+	NMDeviceType type;
 
 	iface = get_device_interface_from_hal (manager->hal_ctx, udi);
 	driver = nm_get_device_driver_name (manager->hal_ctx, udi);
@@ -162,6 +188,55 @@
 	return device;
 }
 
+static gboolean
+is_bluetooth_device (NMHalManager *manager, const char *udi)
+{
+	char *category;
+	gboolean is_bluetooth = FALSE;
+
+	if (libhal_device_property_exists (manager->hal_ctx, udi, "net.interface", NULL) &&
+		libhal_device_property_exists (manager->hal_ctx, udi, "info.category", NULL)) {
+
+		category = libhal_device_get_property_string (manager->hal_ctx, udi, "info.category", NULL);
+		if (category) {
+			is_bluetooth = strcmp (category, "net.bluetooth") == 0;
+			libhal_free_string (category);
+		}
+	}
+
+	return is_bluetooth;
+}
+
+NMDevice *
+bluetooth_device_creator (NMHalManager *manager, const char *udi)
+{
+	NMDevice *device;
+	char *iface;
+	char *driver;
+	char *name;
+	char *uuid;
+	char *address;
+
+	iface = get_device_interface_from_hal (manager->hal_ctx, udi);
+	driver = nm_get_device_driver_name (manager->hal_ctx, udi);
+	name = libhal_device_get_property_string (manager->hal_ctx, udi,
+												"net.bluetooth.name", NULL);
+	uuid = libhal_device_get_property_string (manager->hal_ctx, udi,
+												"net.bluetooth.uuid", NULL);
+	address = libhal_device_get_property_string (manager->hal_ctx, udi,
+												"net.bluetooth.address", NULL);
+	device = (NMDevice *) nm_device_bluetooth_new (iface, udi, driver, name,
+													uuid, address, FALSE, manager->nm_data);
+
+	g_free (iface);
+	g_free (driver);
+	g_free (name);
+	g_free (uuid);
+	g_free (address);
+
+	return device;
+}
+
 static void
 register_built_in_creators (NMHalManager *manager)
 {
@@ -180,6 +255,13 @@
 	creator->is_device_fn = is_wireless_device;
 	creator->creator_fn = wireless_device_creator;
 	manager->device_creators = g_slist_append (manager->device_creators, creator);
+
+	/* Bluetooth device */
+	creator = g_slice_new0 (DeviceCreator);
+	creator->capability_str = g_strdup ("net");
+	creator->is_device_fn = is_bluetooth_device;
+	creator->creator_fn = bluetooth_device_creator;
+	manager->device_creators = g_slist_append (manager->device_creators, creator);
 }
 
 static NMDevice *
@@ -205,7 +287,9 @@
 	dev = creator_fn (manager, udi);
 	if (dev) {
 		nm_info ("Now managing %s device '%s'.",
-				 NM_IS_DEVICE_802_11_WIRELESS (dev) ? "wireless (802.11)" : "wired Ethernet (802.3)",
+				 NM_IS_DEVICE_BLUETOOTH (dev) ? "bluetooth" :
+				 NM_IS_DEVICE_802_11_WIRELESS (dev) ? "wireless (802.11)" :
+				 "wired Ethernet (802.3)",
 				 nm_device_get_iface (dev));
 
 		nm_manager_add_device (manager->nm_manager, dev);
Index: src/NetworkManagerPolicy.c
===================================================================
--- src/NetworkManagerPolicy.c	(revision 2569)
+++ src/NetworkManagerPolicy.c	(working copy)
@@ -39,6 +39,7 @@
 #include "nm-device-interface.h"
 #include "nm-device-802-11-wireless.h"
 #include "nm-device-802-3-ethernet.h"
+#include "nm-device-bluetooth.h"
 #include "nm-dbus-manager.h"
 
 struct NMPolicy {
@@ -72,6 +73,8 @@
 	guint				best_wired_prio = 0;
 	NMDevice80211Wireless *	best_wireless_dev = NULL;
 	guint				best_wireless_prio = 0;
+	NMDeviceBluetooth *	best_bluetooth_dev = NULL;
+	guint				best_bluetooth_prio = 0;
 	NMDevice *			highest_priority_dev = NULL;
 
 	g_return_val_if_fail (ap != NULL, NULL);
@@ -130,6 +133,24 @@
 				best_wireless_prio = prio;
 			}
 		}
+		else if (NM_IS_DEVICE_BLUETOOTH (dev) &&
+				 nm_manager_bluetooth_enabled (policy->manager)) {
+
+			/* Bump by 1 so that _something_ gets chosen every time */
+			prio += 1;
+
+			if (link_active)
+				prio += 1;
+
+			if (nm_device_get_act_request (dev) && link_active)
+				prio += 3;
+
+			if (prio > best_bluetooth_prio)
+			{
+				best_bluetooth_dev = NM_DEVICE_BLUETOOTH (dev);
+				best_bluetooth_prio = prio;
+			}
+		}
 	}
 
 	if (best_wired_dev)
@@ -147,7 +168,8 @@
 		else if (can_activate == TRUE)
 			highest_priority_dev = NM_DEVICE (best_wireless_dev);
 	}
-
+	else if (best_wireless_dev)
+		highest_priority_dev = NM_DEVICE (best_bluetooth_dev);
 #if 0
 	nm_info ("AUTO: Best wired device = %s, best wireless device = %s (%s)", best_wired_dev ? nm_device_get_iface (best_wired_dev) : "(null)",
 			best_wireless_dev ? nm_device_get_iface (best_wireless_dev) : "(null)", (best_wireless_dev && *ap) ? nm_ap_get_essid (*ap) : "null" );
@@ -177,7 +199,11 @@
 
 		wireless->ssid = g_strdup (nm_ap_get_essid (ap));
 		wireless->mode = 1;
-	} else
+	} else if (NM_IS_DEVICE_BLUETOOTH (device)) {
+		nm_info ("Will activate connection '%s'.", nm_device_get_iface (device));
+		setting = nm_setting_bluetooth_new ();
+	}
+	else
 		nm_warning ("Unhandled device type '%s'", G_OBJECT_CLASS_NAME (device));
 
 	if (setting) {
@@ -324,6 +350,14 @@
  				if (!old_user_requested)
 					do_switch = TRUE;
 			}
+		} else if (NM_IS_DEVICE_BLUETOOTH (old_dev)) {
+			if ((!old_user_requested || !old_has_link) && (new_dev != old_dev)) {
+				nm_info ("SWITCH: found better connection '%s' than current "
+				         "connection '%s'.",
+				         nm_device_get_iface (new_dev),
+				         nm_device_get_iface (old_dev));
+				do_switch = TRUE;
+			}
 		}
 	}
 
Index: src/nm-manager.c
===================================================================
--- src/nm-manager.c	(revision 2569)
+++ src/nm-manager.c	(working copy)
@@ -5,6 +5,7 @@
 #include "nm-dbus-manager.h"
 #include "nm-device-interface.h"
 #include "nm-device-802-11-wireless.h"
+#include "nm-device-bluetooth.h"
 #include "NetworkManagerSystem.h"
 // #include "NetworkManagerDbus.h"
 
@@ -15,10 +16,12 @@
 
 static void manager_state_changed (NMManager *manager);
 static void manager_set_wireless_enabled (NMManager *manager, gboolean enabled);
+static void manager_set_bluetooth_enabled (NMManager *manager, gboolean enabled);
 
 typedef struct {
 	GSList *devices;
 	gboolean wireless_enabled;
+	gboolean bluetooth_enabled;
 	gboolean sleeping;
 } NMManagerPrivate;
 
@@ -40,6 +43,7 @@
 	PROP_0,
 	PROP_STATE,
 	PROP_WIRELESS_ENABLED,
+	PROP_BLUETOOTH_ENABLED,
 
 	LAST_PROP
 };
@@ -73,6 +77,9 @@
 	case PROP_WIRELESS_ENABLED:
 		manager_set_wireless_enabled (NM_MANAGER (object), g_value_get_boolean (value));
 		break;
+	case PROP_BLUETOOTH_ENABLED:
+		manager_set_bluetooth_enabled (NM_MANAGER (object), g_value_get_boolean (value));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -92,6 +99,9 @@
 	case PROP_WIRELESS_ENABLED:
 		g_value_set_boolean (value, priv->wireless_enabled);
 		break;
+	case PROP_BLUETOOTH_ENABLED:
+		g_value_set_boolean (value, priv->bluetooth_enabled);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -127,6 +137,14 @@
 							   TRUE,
 							   G_PARAM_READWRITE));
 
+	g_object_class_install_property
+		(object_class, PROP_BLUETOOTH_ENABLED,
+		 g_param_spec_boolean (NM_MANAGER_BLUETOOTH_ENABLED,
+							   "BluetoothEnabled",
+							   "Is bluetooth enabled",
+							   TRUE,
+							   G_PARAM_READWRITE));
+
 	/* signals */
 	signals[DEVICE_ADDED] =
 		g_signal_new ("device-added",
@@ -207,6 +225,28 @@
 }
 
 static void
+manager_set_bluetooth_enabled (NMManager *manager, gboolean enabled)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	GSList *iter;
+
+	if (priv->bluetooth_enabled == enabled)
+		return;
+
+	priv->bluetooth_enabled = enabled;
+
+	/* Tear down all bluetooth devices */
+	for (iter = priv->devices; iter; iter = iter->next) {
+		if (NM_IS_DEVICE_BLUETOOTH (iter->data)) {
+			if (enabled)
+				nm_device_bring_up (NM_DEVICE (iter->data), FALSE);
+			else
+				nm_device_bring_down (NM_DEVICE (iter->data), FALSE);
+		}
+	}
+}
+
+static void
 manager_device_added (NMManager *manager, NMDevice *device)
 {
 	g_signal_emit (manager, signals[DEVICE_ADDED], 0, device);
@@ -376,6 +416,18 @@
 	return enabled;
 }
 
+gboolean
+nm_manager_bluetooth_enabled (NMManager *manager)
+{
+	gboolean enabled;
+
+	g_return_val_if_fail (NM_IS_MANAGER (manager), FALSE);
+
+	g_object_get (manager, NM_MANAGER_BLUETOOTH_ENABLED, &enabled, NULL);
+
+	return enabled;
+}
+
 void
 nm_manager_sleep (NMManager *manager, gboolean sleep)
 {
Index: src/nm-manager.h
===================================================================
--- src/nm-manager.h	(revision 2569)
+++ src/nm-manager.h	(working copy)
@@ -15,6 +15,7 @@
 
 #define NM_MANAGER_STATE "state"
 #define NM_MANAGER_WIRELESS_ENABLED "wireless-enabled"
+#define NM_MANAGER_BLUETOOTH_ENABLED "bluetooth-enabled"
 
 typedef struct {
 	GObject parent;
@@ -41,6 +42,7 @@
 NMDevice *nm_manager_get_device_by_udi (NMManager *manager, const char *udi);
 NMState nm_manager_get_state (NMManager *manager);
 gboolean nm_manager_wireless_enabled (NMManager *manager);
+gboolean nm_manager_bluetooth_enabled (NMManager *manager);
 void nm_manager_sleep (NMManager *manager, gboolean sleep);
 
 NMDevice *nm_manager_get_active_device (NMManager *manager);
Index: src/NetworkManager.c
===================================================================
--- src/NetworkManager.c	(revision 2569)
+++ src/NetworkManager.c	(working copy)
@@ -57,6 +57,7 @@
 #include "nm-supplicant-manager.h"
 #include "nm-netlink-monitor.h"
 #include "nm-logging.h"
+#include "nm-bluez-manager.h"
 
 #define NM_DEFAULT_PID_FILE	LOCALSTATEDIR"/run/NetworkManager.pid"
 
@@ -304,6 +305,7 @@
 	NMHalManager *hal_manager = NULL;
 	NMVPNManager *vpn_manager = NULL;
 	NMDBusManager *	dbus_mgr;
+	NMBluezManager *bluez_mgr;
 	DBusConnection *dbus_connection;
 	NMSupplicantManager * sup_mgr = NULL;
 	int			exit_status = EXIT_FAILURE;
@@ -441,6 +443,8 @@
 	if (!hal_manager)
 		goto done;
 
+	bluez_mgr = nm_bluez_manager_new (manager, nm_data);
+
 	/* If NMI is running, grab allowed wireless network lists from it ASAP */
 	if (nm_dbus_manager_name_has_owner (dbus_mgr, NMI_DBUS_SERVICE))
 		nm_policy_schedule_allowed_ap_list_update (nm_data);
@@ -463,6 +467,7 @@
 	if (vpn_manager)
 		nm_vpn_manager_dispose (vpn_manager);
 
+	nm_bluez_manager_destroy (bluez_mgr);
 	nm_hal_manager_destroy (hal_manager);
 	nm_policy_destroy (policy);
 
Index: src/nm-device-bluetooth.c
===================================================================
--- src/nm-device-bluetooth.c	(revision 0)
+++ src/nm-device-bluetooth.c	(revision 0)
@@ -0,0 +1,342 @@
+/* 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 <glib/gi18n.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "nm-device-bluetooth.h"
+#include "nm-device-interface.h"
+#include "nm-device-private.h"
+#include "nm-activation-request.h"
+#include "NetworkManagerUtils.h"
+#include "nm-utils.h"
+
+#include "nm-device-bluetooth-glue.h"
+
+
+G_DEFINE_TYPE (NMDeviceBluetooth, nm_device_bluetooth, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_BLUETOOTH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_BLUETOOTH, NMDeviceBluetoothPrivate))
+
+typedef struct {
+	gboolean	dispose_has_run;
+
+	char *		name;
+	char *		uuid;
+	char *		address;
+	gint16		strength;
+	struct ether_addr	hw_addr;
+} NMDeviceBluetoothPrivate;
+
+enum {
+	PROP_0,
+	PROP_HW_ADDRESS,
+	PROP_NAME,
+	PROP_UUID,
+	PROP_HOST_ADDRESS,
+	PROP_STRENGTH,
+
+	LAST_PROP
+};
+
+static void
+nm_device_bluetooth_init (NMDeviceBluetooth * self)
+{
+	NMDeviceBluetoothPrivate *priv = NM_DEVICE_BLUETOOTH_GET_PRIVATE (self);
+
+	priv->dispose_has_run = FALSE;
+
+	memset (&(priv->hw_addr), 0, sizeof (struct ether_addr));
+	priv->name = NULL;
+
+	nm_device_set_device_type (NM_DEVICE (self), DEVICE_TYPE_BLUETOOTH);
+}
+
+static void
+real_update_link (NMDevice *dev)
+{
+	nm_device_set_active_link (dev, TRUE);
+}
+
+
+static gboolean
+real_bring_up (NMDevice *dev)
+{
+	NMDeviceBluetoothPrivate *priv = NM_DEVICE_BLUETOOTH_GET_PRIVATE (dev);
+	const char *iface;
+	guint32 caps;
+
+	iface = nm_device_get_iface (dev);
+
+	nm_device_set_active_link (dev, TRUE);
+
+	return TRUE;
+}
+
+
+static void
+real_bring_down (NMDevice *dev)
+{
+	const char *iface;
+
+	iface = nm_device_get_iface (dev);
+
+	nm_device_set_active_link (dev, TRUE);
+}
+
+static gboolean
+real_check_connection (NMDevice *dev, NMConnection *connection)
+{
+	return TRUE;
+}
+
+NMDeviceBluetooth *
+nm_device_bluetooth_new (const char *iface,
+						 const char *udi,
+						 const char *driver,
+						 const char *name,
+						 const char *uuid,
+						 const char *address,
+						 gboolean test_dev,
+						 NMData *app_data)
+{
+	GObject *obj;
+
+	g_return_val_if_fail (iface != NULL, NULL);
+	g_return_val_if_fail (udi != NULL, NULL);
+	g_return_val_if_fail (app_data != NULL, NULL);
+
+	obj = g_object_new (NM_TYPE_DEVICE_BLUETOOTH,
+						NM_DEVICE_INTERFACE_UDI, udi,
+						NM_DEVICE_INTERFACE_IFACE, iface,
+						NM_DEVICE_INTERFACE_DRIVER, driver,
+						NM_DEVICE_BLUETOOTH_NAME, name,
+						NM_DEVICE_BLUETOOTH_UUID, uuid,
+						NM_DEVICE_BLUETOOTH_HOST_ADDRESS, address,
+						NM_DEVICE_INTERFACE_APP_DATA, app_data,
+						NULL);
+
+	return NM_DEVICE_BLUETOOTH (obj);
+}
+
+
+/*
+ * nm_device_bluetooth_get_address
+ *
+ * Get a device's hardware address
+ *
+ */
+void
+nm_device_bluetooth_get_address (NMDeviceBluetooth *self, struct ether_addr *addr)
+{
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (addr != NULL);
+
+	memcpy (addr, &(NM_DEVICE_BLUETOOTH_GET_PRIVATE (self)->hw_addr), sizeof (struct ether_addr));
+}
+
+
+static void
+real_set_hw_address (NMDevice *dev)
+{
+	NMDeviceBluetooth *self = NM_DEVICE_BLUETOOTH (dev);
+	struct ifreq req;
+	NMSock *sk;
+	int ret;
+
+	sk = nm_dev_sock_open (nm_device_get_iface (dev), DEV_GENERAL, __FUNCTION__, NULL);
+	if (!sk)
+		return;
+
+	memset (&req, 0, sizeof (struct ifreq));
+	strncpy (req.ifr_name, nm_device_get_iface (dev), sizeof (req.ifr_name) - 1);
+
+	ret = ioctl (nm_dev_sock_get_fd (sk), SIOCGIFHWADDR, &req);
+	if (ret == 0)
+		memcpy (&(NM_DEVICE_BLUETOOTH_GET_PRIVATE (self)->hw_addr),
+				&(req.ifr_hwaddr.sa_data), sizeof (struct ether_addr));
+
+	nm_dev_sock_close (sk);
+}
+
+
+static guint32
+real_get_generic_capabilities (NMDevice *dev)
+{
+	NMDeviceBluetooth *self = NM_DEVICE_BLUETOOTH (dev);
+	guint32 caps = NM_DEVICE_CAP_NONE;
+
+	caps |= NM_DEVICE_CAP_NM_SUPPORTED;
+
+	return caps;
+}
+
+static gboolean
+real_can_interrupt_activation (NMDevice *dev)
+{
+	gboolean interrupt = FALSE;
+
+	return interrupt;
+}
+
+static void
+nm_device_bluetooth_finalize (GObject *object)
+{
+	NMDeviceBluetoothPrivate *priv = NM_DEVICE_BLUETOOTH_GET_PRIVATE (object);
+
+	if (priv->name)
+		g_free (priv->name);
+
+	if (priv->uuid)
+		g_free (priv->uuid);
+
+	G_OBJECT_CLASS (nm_device_bluetooth_parent_class)->finalize (object);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec)
+{
+	NMDeviceBluetoothPrivate *priv = NM_DEVICE_BLUETOOTH_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_NAME:
+		if (!priv->name)
+			priv->name = g_value_dup_string (value);
+		break;
+	case PROP_UUID:
+		if (!priv->uuid)
+			priv->uuid = g_value_dup_string (value);
+		break;
+	case PROP_HOST_ADDRESS:
+		if (!priv->address)
+			priv->address = g_value_dup_string (value);
+		break;
+	case PROP_STRENGTH:
+		priv->strength = g_value_get_int (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec)
+{
+	NMDeviceBluetooth *device = NM_DEVICE_BLUETOOTH (object);
+	NMDeviceBluetoothPrivate *priv = NM_DEVICE_BLUETOOTH_GET_PRIVATE (object);
+	struct ether_addr hw_addr;
+	char hw_addr_buf[20];
+
+	switch (prop_id) {
+	case PROP_HW_ADDRESS:
+		memset (hw_addr_buf, 0, 20);
+		nm_device_bluetooth_get_address (device, &hw_addr);
+		iw_ether_ntop (&hw_addr, hw_addr_buf);
+		g_value_set_string (value, &hw_addr_buf[0]);
+		break;
+	case PROP_NAME:
+		g_value_set_string (value, priv->name);
+		break;
+	case PROP_UUID:
+		g_value_set_string (value, priv->uuid);
+		break;
+	case PROP_HOST_ADDRESS:
+		g_value_set_string (value, priv->address);
+		break;
+	case PROP_STRENGTH:
+		g_value_set_int (value, priv->strength);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_device_bluetooth_class_init (NMDeviceBluetoothClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMDeviceBluetoothPrivate));
+
+	/* virtual methods */
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+	object_class->finalize = nm_device_bluetooth_finalize;
+
+	parent_class->get_generic_capabilities = real_get_generic_capabilities;
+	parent_class->bring_up = real_bring_up;
+	parent_class->bring_down = real_bring_down;
+	parent_class->update_link = real_update_link;
+	parent_class->can_interrupt_activation = real_can_interrupt_activation;
+	parent_class->set_hw_address = real_set_hw_address;
+	parent_class->check_connection = real_check_connection;
+
+	/* properties */
+	g_object_class_install_property
+		(object_class, PROP_HW_ADDRESS,
+		 g_param_spec_string (NM_DEVICE_BLUETOOTH_HW_ADDRESS,
+							  "MAC Address",
+							  "Hardware MAC address",
+							  NULL,
+							  G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_NAME,
+		 g_param_spec_string (NM_DEVICE_BLUETOOTH_NAME,
+							  "Name",
+							  "Name",
+							  NULL,
+							  G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_UUID,
+		 g_param_spec_string (NM_DEVICE_BLUETOOTH_UUID,
+							  "UUID",
+							  "UUID",
+							  NULL,
+							  G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_HOST_ADDRESS,
+		 g_param_spec_string (NM_DEVICE_BLUETOOTH_HOST_ADDRESS,
+							  "MAC Address",
+							  "Host MAC address",
+							  NULL,
+							  G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_STRENGTH,
+		 g_param_spec_int (NM_DEVICE_BLUETOOTH_STRENGTH,
+						   "Strength",
+						   "Strength",
+						   G_MININT, G_MAXINT, 0,
+						   G_PARAM_READWRITE));
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
+									 &dbus_glib_nm_device_bluetooth_object_info);
+}
Index: src/nm-device-bluetooth.h
===================================================================
--- src/nm-device-bluetooth.h	(revision 0)
+++ src/nm-device-bluetooth.h	(revision 0)
@@ -0,0 +1,74 @@
+/* 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_DEVICE_BLUETOOTH_H
+#define NM_DEVICE_BLUETOOTH_H
+
+#include <glib-object.h>
+
+#include "nm-device.h"
+#include "NetworkManagerMain.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_BLUETOOTH			(nm_device_bluetooth_get_type ())
+#define NM_DEVICE_BLUETOOTH(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_BLUETOOTH, NMDeviceBluetooth))
+#define NM_DEVICE_BLUETOOTH_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_DEVICE_BLUETOOTH, NMDeviceBluetoothClass))
+#define NM_IS_DEVICE_BLUETOOTH(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_BLUETOOTH))
+#define NM_IS_DEVICE_BLUETOOTH_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_BLUETOOTH))
+#define NM_DEVICE_BLUETOOTH_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_BLUETOOTH, NMDeviceBluetoothClass))
+
+#define NM_DEVICE_BLUETOOTH_HW_ADDRESS "hw-address"
+#define NM_DEVICE_BLUETOOTH_NAME "name"
+#define NM_DEVICE_BLUETOOTH_UUID "uuid"
+#define NM_DEVICE_BLUETOOTH_HOST_ADDRESS "host-address"
+#define NM_DEVICE_BLUETOOTH_STRENGTH "strength"
+
+typedef struct {
+	NMDevice parent;
+} NMDeviceBluetooth;
+
+typedef struct {
+	NMDeviceClass parent;
+} NMDeviceBluetoothClass;
+
+
+GType nm_device_bluetooth_get_type (void);
+
+
+NMDeviceBluetooth *nm_device_bluetooth_new (const char *iface,
+											const char *udi,
+											const char *driver,
+											const char *name,
+											const char *uuid,
+											const char *address,
+											gboolean test_dev,
+											NMData *app_data);
+
+void nm_device_bluetooth_activate (NMDeviceBluetooth *self,
+									gboolean user_requested);
+
+void nm_device_bluetooth_get_address (NMDeviceBluetooth *dev,
+										struct ether_addr *addr);
+
+G_END_DECLS
+
+#endif	/* NM_DEVICE_BLUETOOTH_H */
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision 2569)
+++ src/Makefile.am	(working copy)
@@ -23,6 +23,8 @@
 		nm-device-802-3-ethernet.h	\
 		nm-device-802-11-wireless.c	\
 		nm-device-802-11-wireless.h	\
+		nm-device-bluetooth.c		\
+		nm-device-bluetooth.h		\
 		NetworkManagerAP.c			\
 		NetworkManagerAP.h			\
 		NetworkManagerAPList.c		\
@@ -72,8 +74,11 @@
 		nm-marshal-main.c		\
 		kernel-types.h			\
 		wpa.c				\
-		wpa.h
+		wpa.h					\
+		nm-bluez-manager.c			\
+		nm-bluez-manager.h
 
+
 nm-marshal.h: Makefile.am nm-marshal.list
 	$(GLIB_GENMARSHAL) --prefix=nm_marshal $(srcdir)/nm-marshal.list --header > \
 		xgen-gmh \
@@ -103,6 +108,9 @@
 nm-device-802-11-wireless-glue.h: $(top_srcdir)/introspection/nm-device-802-11-wireless.xml
 	dbus-binding-tool --prefix=nm_device_802_11_wireless --mode=glib-server --output=nm-device-802-11-wireless-glue.h $(top_srcdir)/introspection/nm-device-802-11-wireless.xml
 
+nm-device-bluetooth-glue.h: $(top_srcdir)/introspection/nm-device-bluetooth.xml
+	dbus-binding-tool --prefix=nm_device_bluetooth --mode=glib-server --output=nm-device-bluetooth-glue.h $(top_srcdir)/introspection/nm-device-bluetooth.xml
+
 nm-ip4-config-glue.h: $(top_srcdir)/introspection/nm-ip4-config.xml
 	dbus-binding-tool --prefix=nm_ip4_config --mode=glib-server --output=nm-ip4-config-glue.h $(top_srcdir)/introspection/nm-ip4-config.xml
 
@@ -115,6 +123,7 @@
 	nm-device-interface-glue.h			\
 	nm-device-802-3-ethernet-glue.h			\
 	nm-device-802-11-wireless-glue.h		\
+	nm-device-bluetooth-glue.h		\
 	nm-ip4-config-glue.h				\
 	$(NULL)
 
@@ -145,7 +154,7 @@
 			$(HAL_LIBS)						\
 			$(IWLIB)							\
 			$(LIBNL_LIBS)						\
-			$(top_builddir)/utils/libnmutils.la	\
+		$(top_builddir)/utils/libnmutils.la	\
 			./named-manager/libnamed-manager.la	\
 			./vpn-manager/libvpn-manager.la		\
 			./dhcp-manager/libdhcp-manager.la		\
Index: introspection/nm-manager.xml
===================================================================
--- introspection/nm-manager.xml	(revision 2569)
+++ introspection/nm-manager.xml	(working copy)
@@ -15,6 +15,8 @@
     <property name="WirelessEnabled" type="b" access="readwrite"/>
     <property name="State" type="u" access="read"/>
 
+    <property name="BluetoothEnabled" type="b" access="readwrite"/>
+
     <signal name="StateChange">
       <arg name="state" type="u"/>
     </signal>
Index: introspection/nm-device-bluetooth.xml
===================================================================
--- introspection/nm-device-bluetooth.xml	(revision 0)
+++ introspection/nm-device-bluetooth.xml	(revision 0)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/">
+  <interface name="org.freedesktop.NetworkManager.Device.Bluetooth">
+    <property name="HwAddress" type="s" access="read"/>
+    <property name="Name" type="s" access="read"/>
+    <property name="Uuid" type="s" access="read"/>
+    <property name="HostAddress" type="s" access="read"/>
+    <property name="Strength" type="n" access="read"/>
+  </interface>
+</node>
Index: libnm-util/nm-connection.c
===================================================================
--- libnm-util/nm-connection.c	(revision 2569)
+++ libnm-util/nm-connection.c	(working copy)
@@ -13,6 +13,7 @@
 		{ "info",            nm_setting_info_new_from_hash      },
 		{ "802-3-ethernet",  nm_setting_wired_new_from_hash     },
 		{ "802-11-wireless", nm_setting_wireless_new_from_hash  },
+		{ "Bluetooth",       nm_setting_bluetooth_new_from_hash },
 		{ NULL, NULL}
 	};
 
Index: libnm-util/nm-setting.c
===================================================================
--- libnm-util/nm-setting.c	(revision 2569)
+++ libnm-util/nm-setting.c	(working copy)
@@ -399,3 +399,43 @@
 
 	return NULL;
 }
+
+static gboolean
+setting_bluetooth_verify (NMSetting *setting, GHashTable *all_settings)
+{
+	return TRUE;
+}
+
+static void
+setting_bluetooth_destroy (NMSetting *setting)
+{
+	NMSettingBluetooth *self = (NMSettingBluetooth *) setting;
+
+	g_slice_free (NMSettingBluetooth, self);
+}
+
+NMSetting *
+nm_setting_bluetooth_new (void)
+{
+	NMSetting *setting;
+
+	setting = (NMSetting *) g_slice_new0 (NMSettingBluetooth);
+
+	setting->name = g_strdup ("Bluetooth");
+	setting->verify_fn = setting_bluetooth_verify;
+	setting->destroy_fn = setting_bluetooth_destroy;
+
+	return setting;
+}
+
+NMSetting *
+nm_setting_bluetooth_new_from_hash (GHashTable *settings)
+{
+	NMSetting *setting;
+
+	g_return_val_if_fail (settings != NULL, NULL);
+
+	setting = nm_setting_bluetooth_new ();
+
+	return setting;
+}
Index: libnm-util/nm-setting.h
===================================================================
--- libnm-util/nm-setting.h	(revision 2569)
+++ libnm-util/nm-setting.h	(working copy)
@@ -59,4 +59,11 @@
 NMSetting *nm_setting_wireless_new (void);
 NMSetting *nm_setting_wireless_new_from_hash (GHashTable *settings);
 
+typedef struct {
+	NMSetting parent;
+} NMSettingBluetooth;
+
+NMSetting *nm_setting_bluetooth_new (void);
+NMSetting *nm_setting_bluetooth_new_from_hash (GHashTable *settings);
+
 #endif /* NM_SETTING_H */
Index: libnm-glib/nm-device-bluetooth.c
===================================================================
--- libnm-glib/nm-device-bluetooth.c	(revision 0)
+++ libnm-glib/nm-device-bluetooth.c	(revision 0)
@@ -0,0 +1,130 @@
+#include "nm-device-bluetooth.h"
+#include "nm-device-private.h"
+#include "nm-utils.h"
+
+#include "nm-device-bluetooth-bindings.h"
+
+G_DEFINE_TYPE (NMDeviceBluetooth, nm_device_bluetooth, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_BLUETOOTH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_BLUETOOTH, NMDeviceBluetoothPrivate))
+
+typedef struct {
+	DBusGProxy *bluetooth_proxy;
+
+	gboolean disposed;
+} NMDeviceBluetoothPrivate;
+
+
+static void
+nm_device_bluetooth_init (NMDeviceBluetooth *device)
+{
+	NMDeviceBluetoothPrivate *priv = NM_DEVICE_BLUETOOTH_GET_PRIVATE (device);
+
+	priv->disposed = FALSE;
+}
+
+static GObject*
+constructor (GType type,
+			 guint n_construct_params,
+			 GObjectConstructParam *construct_params)
+{
+	GObject *object;
+	NMDeviceBluetoothPrivate *priv;
+
+	object = G_OBJECT_CLASS (nm_device_bluetooth_parent_class)->constructor (type,
+																				  n_construct_params,
+																				  construct_params);
+	if (!object)
+		return NULL;
+
+	priv = NM_DEVICE_BLUETOOTH_GET_PRIVATE (object);
+
+	priv->bluetooth_proxy = dbus_g_proxy_new_for_name (nm_device_get_connection (NM_DEVICE (object)),
+													  NM_DBUS_SERVICE,
+													  nm_device_get_path (NM_DEVICE (object)),
+													  NM_DBUS_INTERFACE_DEVICE_BLUETOOTH);
+	return object;
+}
+
+static void
+dispose (GObject *object)
+{
+	NMDeviceBluetoothPrivate *priv = NM_DEVICE_BLUETOOTH_GET_PRIVATE (object);
+
+	if (priv->disposed)
+		return;
+
+	priv->disposed = TRUE;
+
+	g_object_unref (priv->bluetooth_proxy);
+
+	G_OBJECT_CLASS (nm_device_bluetooth_parent_class)->dispose (object);
+}
+
+static void
+nm_device_bluetooth_class_init (NMDeviceBluetoothClass *device_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (device_class);
+
+	g_type_class_add_private (device_class, sizeof (NMDeviceBluetoothPrivate));
+
+	/* virtual methods */
+	object_class->constructor = constructor;
+	object_class->dispose = dispose;
+}
+
+NMDeviceBluetooth *
+nm_device_bluetooth_new (DBusGConnection *connection, const char *path)
+{
+	g_return_val_if_fail (connection != NULL, NULL);
+	g_return_val_if_fail (path != NULL, NULL);
+
+	return (NMDeviceBluetooth *) g_object_new (NM_TYPE_DEVICE_BLUETOOTH,
+												NM_DEVICE_CONNECTION, connection,
+												NM_DEVICE_PATH, path,
+												NULL);
+}
+
+char *
+nm_device_bluetooth_get_hw_address (NMDeviceBluetooth *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE_BLUETOOTH (device), NULL);
+
+	return nm_dbus_get_string_property (nm_device_get_properties_proxy (NM_DEVICE (device)),
+										NM_DBUS_INTERFACE_DEVICE_BLUETOOTH, "HwAddress");
+}
+
+char *
+nm_device_bluetooth_get_name (NMDeviceBluetooth *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE_BLUETOOTH (device), NULL);
+
+	return nm_dbus_get_string_property (nm_device_get_properties_proxy (NM_DEVICE (device)),
+										NM_DBUS_INTERFACE_DEVICE_BLUETOOTH, "Name");
+}
+
+char *
+nm_device_bluetooth_get_uuid (NMDeviceBluetooth *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE_BLUETOOTH (device), NULL);
+
+	return nm_dbus_get_string_property (nm_device_get_properties_proxy (NM_DEVICE (device)),
+										NM_DBUS_INTERFACE_DEVICE_BLUETOOTH, "Uuid");
+}
+char *
+nm_device_bluetooth_get_host_address (NMDeviceBluetooth *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE_BLUETOOTH (device), NULL);
+
+	return nm_dbus_get_string_property (nm_device_get_properties_proxy (NM_DEVICE (device)),
+										NM_DBUS_INTERFACE_DEVICE_BLUETOOTH, "HostAddress");
+}
+
+gint16
+nm_device_bluetooth_get_strength (NMDeviceBluetooth *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE_BLUETOOTH (device), 0);
+
+	return nm_dbus_get_int_property (nm_device_get_properties_proxy (NM_DEVICE (device)),
+										NM_DBUS_INTERFACE_DEVICE_BLUETOOTH, "Strength");
+}
Index: libnm-glib/nm-device-bluetooth.h
===================================================================
--- libnm-glib/nm-device-bluetooth.h	(revision 0)
+++ libnm-glib/nm-device-bluetooth.h	(revision 0)
@@ -0,0 +1,31 @@
+#ifndef NM_DEVICE_BLUETOOTH_H
+#define NM_DEVICE_BLUETOOTH_H
+
+#include "nm-device.h"
+
+#define NM_TYPE_DEVICE_BLUETOOTH            (nm_device_bluetooth_get_type ())
+#define NM_DEVICE_BLUETOOTH(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_BLUETOOTH, NMDeviceBluetooth))
+#define NM_DEVICE_BLUETOOTH_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_BLUETOOTH, NMDeviceBluetoothClass))
+#define NM_IS_DEVICE_BLUETOOTH(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_BLUETOOTH))
+#define NM_IS_DEVICE_BLUETOOTH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_DEVICE_BLUETOOTH))
+#define NM_DEVICE_BLUETOOTH_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_BLUETOOTH, NMDeviceBluetoothClass))
+
+typedef struct {
+	NMDevice parent;
+} NMDeviceBluetooth;
+
+typedef struct {
+	NMDeviceClass parent;
+} NMDeviceBluetoothClass;
+
+GType nm_device_bluetooth_get_type (void);
+
+NMDeviceBluetooth *nm_device_bluetooth_new         (DBusGConnection *connection,
+													const char *path);
+char *			nm_device_bluetooth_get_hw_address	(NMDeviceBluetooth *device);
+char *			nm_device_bluetooth_get_name		(NMDeviceBluetooth *device);
+char *			nm_device_bluetooth_get_uuid		(NMDeviceBluetooth *device);
+char *			nm_device_bluetooth_get_host_address(NMDeviceBluetooth *device);
+gint16			nm_device_bluetooth_get_strength	(NMDeviceBluetooth *device);
+
+#endif /* NM_DEVICE_BLUETOOTH_H */
Index: libnm-glib/nm-client.c
===================================================================
--- libnm-glib/nm-client.c	(revision 2569)
+++ libnm-glib/nm-client.c	(working copy)
@@ -296,13 +296,16 @@
 		g_object_get (client, "connection", &connection, NULL);
 		type = nm_device_type_for_path (connection, path);
 
-		switch (type) {
+	switch (type) {
 		case DEVICE_TYPE_802_3_ETHERNET:
 			device = NM_DEVICE (nm_device_802_3_ethernet_new (connection, path));
 			break;
 		case DEVICE_TYPE_802_11_WIRELESS:
 			device = NM_DEVICE (nm_device_802_11_wireless_new (connection, path));
 			break;
+		case DEVICE_TYPE_BLUETOOTH:
+			device = NM_DEVICE (nm_device_bluetooth_new (connection, path));
+			break;
 		default:
 			device = nm_device_new (connection, path);
 		}
@@ -447,6 +450,39 @@
 						  &value);
 }
 
+gboolean
+nm_client_bluetooth_get_enabled (NMClient *client)
+{
+	GValue value = {0,};
+	gboolean enabled = FALSE;
+
+	g_return_val_if_fail (NM_IS_CLIENT (client), enabled);
+
+	if (nm_dbus_get_property (DBUS_G_PROXY (client),
+							  NM_DBUS_INTERFACE,
+							  "BluetoothEnabled",
+							  &value))
+		enabled = g_value_get_boolean (&value);
+
+	return enabled;
+}
+
+void
+nm_client_bluetooth_set_enabled (NMClient *client, gboolean enabled)
+{
+	GValue value = {0,};
+
+	g_return_if_fail (NM_IS_CLIENT (client));
+
+	g_value_init (&value, G_TYPE_BOOLEAN);
+	g_value_set_boolean (&value, enabled);
+	nm_dbus_set_property (DBUS_G_PROXY (client),
+						  NM_DBUS_INTERFACE,
+						  "BluetoothEnabled",
+						  &value);
+}
+
+
 NMState
 nm_client_get_state (NMClient *client)
 {
Index: libnm-glib/Makefile.am
===================================================================
--- libnm-glib/Makefile.am	(revision 2569)
+++ libnm-glib/Makefile.am	(working copy)
@@ -5,6 +5,7 @@
 	nm-device-bindings.h \
 	nm-device-802-3-ethernet-bindings.h \
 	nm-device-802-11-wireless-bindings.h \
+	nm-device-bluetooth-bindings.h \
 	nm-access-point-bindings.h \
 	nm-marshal.h \
 	nm-marshal.c
@@ -22,6 +23,7 @@
 	nm-device.h		\
 	nm-device-802-3-ethernet.h \
 	nm-device-802-11-wireless.h \
+	nm-device-bluetooth.h \
 	nm-access-point.h \
 	nm-ip4-config.h \
 	nm-vpn-connection.h
@@ -32,6 +34,7 @@
 	nm-device-private.h	\
 	nm-device-802-3-ethernet.c \
 	nm-device-802-11-wireless.c \
+	nm-device-bluetooth.c \
 	nm-access-point.c	\
 	nm-ip4-config.c		\
 	nm-utils.c		\
@@ -74,6 +77,9 @@
 nm-device-802-11-wireless-bindings.h: $(top_srcdir)/introspection/nm-device-802-11-wireless.xml
 	dbus-binding-tool --prefix=nm_device_802_11_wireless --mode=glib-client --output=nm-device-802-11-wireless-bindings.h $(top_srcdir)/introspection/nm-device-802-11-wireless.xml
 
+nm-device-bluetooth-bindings.h: $(top_srcdir)/introspection/nm-device-bluetooth.xml
+	dbus-binding-tool --prefix=nm_device_bluetooth --mode=glib-client --output=nm-device-bluetooth-bindings.h $(top_srcdir)/introspection/nm-device-bluetooth.xml
+
 nm-access-point-bindings.h: $(top_srcdir)/introspection/nm-access-point.xml
 	dbus-binding-tool --prefix=nm_access_point --mode=glib-client --output=nm-access-point-bindings.h $(top_srcdir)/introspection/nm-access-point.xml
 
Index: libnm-glib/nm-client.h
===================================================================
--- libnm-glib/nm-client.h	(revision 2569)
+++ libnm-glib/nm-client.h	(working copy)
@@ -47,6 +47,8 @@
 
 gboolean  nm_client_wireless_get_enabled (NMClient *client);
 void      nm_client_wireless_set_enabled (NMClient *client, gboolean enabled);
+gboolean  nm_client_bluetooth_get_enabled(NMClient *client);
+void      nm_client_bluetooth_set_enabled(NMClient *client, gboolean enabled);
 NMState   nm_client_get_state            (NMClient *client);
 void      nm_client_sleep                (NMClient *client, gboolean sleep);
 
