From a518536785ff3f96234ce8bfdfe002d6eee330d5 Mon Sep 17 00:00:00 2001
From: Raymond Liu <raymond.liu@intel.com>
Date: Tue, 20 Jan 2009 13:47:12 +0800
Subject: [PATCH] Add framework code for SAP

---
 Makefile.am         |    2 +-
 acinclude.m4        |    6 ++
 configure.ac        |    1 +
 plugins/Makefile.am |    2 +
 sap/Makefile.am     |   21 +++++
 sap/device.c        |  219 +++++++++++++++++++++++++++++++++++++++++++++++++++
 sap/device.h        |   28 +++++++
 sap/main.c          |   59 ++++++++++++++
 sap/manager.c       |  130 ++++++++++++++++++++++++++++++
 sap/manager.h       |   26 ++++++
 10 files changed, 493 insertions(+), 1 deletions(-)
 create mode 100644 sap/Makefile.am
 create mode 100644 sap/device.c
 create mode 100644 sap/device.h
 create mode 100644 sap/main.c
 create mode 100644 sap/manager.c
 create mode 100644 sap/manager.h

diff --git a/Makefile.am b/Makefile.am
index f2d1ca7..c6899d2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
 
 SUBDIRS = include lib sbc gdbus common src client\
-	plugins network serial input audio \
+	plugins network serial input audio sap \
 	tools rfcomm compat cups test scripts doc
 
 EXTRA_DIST = bluez.m4
diff --git a/acinclude.m4 b/acinclude.m4
index 372833e..704c9ee 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -186,6 +186,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	input_enable=yes
 	serial_enable=yes
 	network_enable=yes
+	sap_enable=yes
 	service_enable=yes
 	tools_enable=yes
 	hidd_enable=no
@@ -226,6 +227,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 		audio_enable=${enableval}
 	])
 
+	AC_ARG_ENABLE(sap, AC_HELP_STRING([--disable-sap], [disable sap plugin]), [
+		sap_enable=${enableval}
+	])
+
 	AC_ARG_ENABLE(service, AC_HELP_STRING([--disable-service], [disable service plugin]), [
 		service_enable=${enableval}
 	])
@@ -344,6 +349,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	AM_CONDITIONAL(INPUTPLUGIN, test "${input_enable}" = "yes")
 	AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
 	AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
+	AM_CONDITIONAL(SAPPLUGIN, test "${sap_enable}" = "yes")
 	AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
 	AM_CONDITIONAL(HIDD, test "${hidd_enable}" = "yes")
 	AM_CONDITIONAL(PAND, test "${pand_enable}" = "yes")
diff --git a/configure.ac b/configure.ac
index 84a6234..bc7cf6b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,6 +55,7 @@ AC_OUTPUT([
 	serial/Makefile
 	input/Makefile
 	audio/Makefile
+	sap/Makefile
 	tools/Makefile
 	rfcomm/Makefile
 	compat/Makefile
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 3b258a3..7ad76fe 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -46,6 +46,7 @@ all-local:
 	@$(LN_S) -f $(top_srcdir)/audio/.libs/audio.so
 	@$(LN_S) -f $(top_srcdir)/serial/.libs/serial.so
 	@$(LN_S) -f $(top_srcdir)/network/.libs/network.so
+	@$(LN_S) -f $(top_srcdir)/sap/.libs/sap.so
 	@$(LN_S) -f .libs/service.so
 	@$(LN_S) -f .libs/hal.so
 
@@ -56,3 +57,4 @@ clean-local:
 	@rm -f serial.so
 	@rm -f audio.so
 	@rm -f input.so
+	@rm -f sap.so
diff --git a/sap/Makefile.am b/sap/Makefile.am
new file mode 100644
index 0000000..aad95f3
--- /dev/null
+++ b/sap/Makefile.am
@@ -0,0 +1,21 @@
+
+if SAPPLUGIN
+plugindir = $(libdir)/bluetooth/plugins
+
+plugin_LTLIBRARIES = sap.la
+
+sap_la_SOURCES = main.c manager.h manager.c \
+		device.h device.c
+
+LDADD = $(top_builddir)/common/libhelper.a \
+		@GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+endif
+
+AM_LDFLAGS = -module -avoid-version -no-undefined \
+			-export-symbols-regex bluetooth_plugin_desc
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/sap/device.c b/sap/device.c
new file mode 100644
index 0000000..b3c4a0a
--- /dev/null
+++ b/sap/device.c
@@ -0,0 +1,219 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2009 Intel Corporation
+ *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "../src/dbus-common.h"
+
+#include "logging.h"
+#include "glib-helper.h"
+
+#include "device.h"
+
+#define SAP_CLIENT_INTERFACE	"org.bluez.SimAccess"
+
+struct sap_device {
+	DBusConnection	*conn;
+	bdaddr_t	src;		/* Source (local) address */
+	bdaddr_t	dst;		/* Destination address */
+	char		*path;		/* Device path */
+	uint8_t		channel;	/* SAP server's rfcomm channel */
+};
+
+static GSList *devices = NULL;
+
+static struct sap_device *find_device(GSList *devices, const char *path)
+{
+	GSList *l;
+
+	for (l = devices; l != NULL; l = l->next) {
+		struct sap_device *device = l->data;
+
+		if (!strcmp(device->path, path))
+			return device;
+	}
+
+	return NULL;
+}
+
+static void sap_device_free(struct sap_device *device)
+{
+	g_free(device->path);
+	if (device->conn)
+		dbus_connection_unref(device->conn);
+	g_free(device);
+}
+
+static void path_unregister(void *data)
+{
+	struct sap_device *device = data;
+
+	info("Unregistered interface %s on path %s", SAP_CLIENT_INTERFACE,
+		device->path);
+
+	devices = g_slist_remove(devices, device);
+	sap_device_free(device);
+}
+
+static DBusMessage *sap_connect(DBusConnection *conn,
+				DBusMessage *msg, void *data)
+{
+	return NULL;
+}
+
+static DBusMessage *sap_disconnect(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	return NULL;
+}
+
+static DBusMessage *sap_send_apdu(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	return NULL;
+}
+
+static DBusMessage *sap_power_on(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	return NULL;
+}
+
+static DBusMessage *sap_power_off(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	return NULL;
+}
+
+static DBusMessage *sap_reset(DBusConnection *conn,
+				DBusMessage *msg, void *data)
+{
+	return NULL;
+}
+
+static DBusMessage *sap_set_protocol(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	return NULL;
+}
+
+static DBusMessage *sap_get_properties(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	return NULL;
+}
+
+static GDBusMethodTable sap_methods[] = {
+	{ "Connect",		"",	"",	sap_connect,
+						G_DBUS_METHOD_FLAG_ASYNC },
+	{ "Disconnect",		"",	"",	sap_disconnect,
+						G_DBUS_METHOD_FLAG_ASYNC },
+	{ "SendAPDU",		"ay",	"ay",	sap_send_apdu,
+						G_DBUS_METHOD_FLAG_ASYNC },
+	{ "PowerOff",		"",	"",	sap_power_off,
+						G_DBUS_METHOD_FLAG_DEPRECATED },
+	{ "PowerOn",		"",	"",	sap_power_on,
+						G_DBUS_METHOD_FLAG_DEPRECATED },
+	{ "Reset",		"",	"",	sap_reset,
+						G_DBUS_METHOD_FLAG_DEPRECATED },
+	{ "SetProtocol",	"y",	"",	sap_set_protocol,
+						G_DBUS_METHOD_FLAG_DEPRECATED },
+	{ "GetProperties",	"",	"a{sv}",sap_get_properties },
+	{ NULL, NULL, NULL, NULL }
+};
+
+static GDBusSignalTable sap_signals[] = {
+	{ "PropertyChanged",		"sv"	},
+	{ NULL, NULL }
+};
+
+static struct sap_device *create_sap_device(DBusConnection *conn,
+					const char *path, bdaddr_t *src,
+					bdaddr_t *dst, uint8_t channel)
+{
+	struct sap_device *device;
+
+	device = g_new0(struct sap_device, 1);
+	device->conn = dbus_connection_ref(conn);
+	bacpy(&device->dst, dst);
+	bacpy(&device->src, src);
+	device->path = g_strdup(path);
+	device->channel = channel;
+
+	if (!g_dbus_register_interface(conn, path,
+				SAP_CLIENT_INTERFACE,
+				sap_methods, sap_signals, NULL,
+				device, path_unregister)) {
+		error("D-Bus failed to register %s interface",
+				SAP_CLIENT_INTERFACE);
+		sap_device_free(device);
+		return NULL;
+	}
+
+	info("Registered interface %s on path %s",
+		SAP_CLIENT_INTERFACE, path);
+
+	return device;
+}
+
+int sap_device_register(DBusConnection *conn, const char *path, bdaddr_t *src,
+			  bdaddr_t *dst, const char *uuid, uint8_t channel)
+{
+	struct sap_device *device;
+
+	device = find_device(devices, path);
+	if (!device) {
+		device = create_sap_device(conn, path, src, dst, channel);
+		if (!device)
+			return -1;
+		devices = g_slist_append(devices, device);
+	}
+
+	return 0;
+}
+
+int sap_device_unregister(const char *path)
+{
+	struct sap_device *device;
+
+	device = find_device(devices, path);
+	if (!device)
+		return -ENOENT;
+
+	g_dbus_unregister_interface(device->conn, path, SAP_CLIENT_INTERFACE);
+
+	return 0;
+}
diff --git a/sap/device.h b/sap/device.h
new file mode 100644
index 0000000..e9f95b1
--- /dev/null
+++ b/sap/device.h
@@ -0,0 +1,28 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2009 Intel Corporation
+ *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int sap_device_register(DBusConnection *conn, const char *path, bdaddr_t *src,
+		  bdaddr_t *dst, const char *name, uint8_t channel);
+
+int sap_device_unregister(const char *path);
diff --git a/sap/main.c b/sap/main.c
new file mode 100644
index 0000000..f7b5857
--- /dev/null
+++ b/sap/main.c
@@ -0,0 +1,59 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2009 Intel Corporation
+ *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection;
+
+static int sap_init(void)
+{
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+	if (connection == NULL)
+		return -EIO;
+
+	if (sap_manager_init(connection) < 0) {
+		dbus_connection_unref(connection);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void sap_exit(void)
+{
+	sap_manager_exit();
+
+	dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE("sap", sap_init, sap_exit)
diff --git a/sap/manager.c b/sap/manager.c
new file mode 100644
index 0000000..90ff789
--- /dev/null
+++ b/sap/manager.c
@@ -0,0 +1,130 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2009 Intel Corporation
+ *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <gdbus.h>
+
+#include "logging.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+
+#include "manager.h"
+#include "device.h"
+
+
+#define SAP_UUID_STR		"0000112D-0000-1000-8000-00805F9B34FB"
+
+static DBusConnection *connection = NULL;
+
+static int sap_client_probe(struct btd_device *device, const char *uuid)
+{
+	struct btd_adapter *adapter = device_get_adapter(device);
+	const gchar *path = device_get_path(device);
+	sdp_list_t *protos;
+	int ch;
+	bdaddr_t src, dst;
+	const sdp_record_t *rec;
+
+	DBG("path %s: %s", path, uuid);
+
+	rec = btd_device_get_record(device, uuid);
+	if (!rec)
+		return -EINVAL;
+
+	if (sdp_get_access_protos(rec, &protos) < 0)
+		return -EINVAL;
+
+	ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+	sdp_list_free(protos, NULL);
+
+	if (ch < 1 || ch > 30) {
+		error("Channel out of range: %d", ch);
+		return -EINVAL;
+	}
+
+	adapter_get_address(adapter, &src);
+	device_get_address(device, &dst);
+
+	return sap_device_register(connection, path, &src, &dst, uuid, ch);
+}
+
+static void sap_client_remove(struct btd_device *device)
+{
+	const gchar *path = device_get_path(device);
+
+	DBG("path %s", path);
+
+	sap_device_unregister(path);
+}
+
+
+static int client_probe(struct btd_device *device, GSList *uuids)
+{
+	while (uuids) {
+		sap_client_probe(device, uuids->data);
+		uuids = uuids->next;
+	}
+
+	return 0;
+}
+
+static void client_remove(struct btd_device *device)
+{
+	return sap_client_remove(device);
+}
+
+static struct btd_device_driver sap_client_driver = {
+	.name	= "sap-client",
+	.uuids	= BTD_UUIDS(SAP_UUID_STR),
+	.probe	= client_probe,
+	.remove	= client_remove,
+};
+
+int sap_manager_init(DBusConnection *conn)
+{
+	connection = dbus_connection_ref(conn);
+
+	btd_register_device_driver(&sap_client_driver);
+
+	return 0;
+}
+
+void sap_manager_exit(void)
+{
+	btd_unregister_device_driver(&sap_client_driver);
+
+	dbus_connection_unref(connection);
+	connection = NULL;
+}
diff --git a/sap/manager.h b/sap/manager.h
new file mode 100644
index 0000000..f9162a3
--- /dev/null
+++ b/sap/manager.h
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2009 Intel Corporation
+ *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int sap_manager_init(DBusConnection *conn);
+void sap_manager_exit(void);
-- 
1.5.6.3

