summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2006-08-23 14:33:58 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2006-08-23 14:33:58 +0000
commit684ba3688de17a3b8a6defd3139e1b8bf8971ef5 (patch)
treeab10267b189a8d6a26730e2dd5621a0eaa5b233a
parentd6faebdc8a88ed8338dc68beefbfbae7e303f895 (diff)
Add preliminary RFCOMM.Connect and RFCOMM.CancelConnect support
-rw-r--r--hcid/dbus-api.txt4
-rw-r--r--hcid/dbus-rfcomm.c126
-rw-r--r--hcid/dbus-sdp.c71
-rw-r--r--hcid/dbus.h4
4 files changed, 199 insertions, 6 deletions
diff --git a/hcid/dbus-api.txt b/hcid/dbus-api.txt
index 35d60264..825314a1 100644
--- a/hcid/dbus-api.txt
+++ b/hcid/dbus-api.txt
@@ -893,8 +893,8 @@ Object path /org/bluez/{hci0,hci1,...}
Methods string Connect(string address, string service)
This creates a connection to a remote RFCOMM based
- service. The service string can either be a UUID-16,
- a UUID-32, a UUID-128 or a service abbreviation.
+ service. The service string can either be a UUID-128,
+ a service abbreviation or a record handle.
The return value will be the path of the newly
created RFCOMM TTY device (for example /dev/rfcomm0).
diff --git a/hcid/dbus-rfcomm.c b/hcid/dbus-rfcomm.c
index f4215f92..61a0365f 100644
--- a/hcid/dbus-rfcomm.c
+++ b/hcid/dbus-rfcomm.c
@@ -33,11 +33,15 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <arpa/inet.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
#include <dbus/dbus.h>
@@ -452,18 +456,132 @@ static struct rfcomm_node *rfcomm_bind(bdaddr_t *src, const char *bda, uint8_t c
return node;
}
+static sdp_record_t *get_record_from_string (const char *dst,
+ const char *string)
+{
+ uuid_t short_uuid;
+ uuid_t *uuid;
+ sdp_record_t *rec = NULL;
+ unsigned int data0, data4;
+ unsigned short data1, data2, data3, data5;
+ long handle;
+
+ /* Check if the string is a service name */
+ short_uuid.value.uuid16 = sdp_str2svclass (string);
+
+ if (short_uuid.value.uuid16) {
+ short_uuid.type = SDP_UUID16;
+ uuid = sdp_uuid_to_uuid128 (&short_uuid);
+ rec = find_record_by_uuid (dst, uuid);
+ } else if (sscanf (string, "%8x-%4hx-%4hx-%4hx-%8x%4hx", &data0,
+ &data1, &data2, &data3, &data4, &data5) == 6) {
+ data0 = htonl(data0);
+ data1 = htons(data1);
+ data2 = htons(data2);
+ data3 = htons(data3);
+ data4 = htonl(data4);
+ data5 = htons(data5);
+
+ uuid = malloc (sizeof(uuid_t));
+ uuid->type = SDP_UUID128;
+ memcpy (&uuid->value.uuid128.data[0], &data0, 4);
+ memcpy (&uuid->value.uuid128.data[4], &data1, 2);
+ memcpy (&uuid->value.uuid128.data[6], &data2, 2);
+ memcpy (&uuid->value.uuid128.data[8], &data3, 2);
+ memcpy (&uuid->value.uuid128.data[10], &data4, 4);
+ memcpy (&uuid->value.uuid128.data[14], &data5, 2);
+
+ rec = find_record_by_uuid (dst, uuid);
+ } else if ((handle = strtol (string, (char **)NULL, 0))) {
+ rec = find_record_by_handle (dst, handle);
+ }
+
+ return rec;
+}
+
static DBusHandlerResult rfcomm_connect_req(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- error("RFCOMM.Connect not implemented");
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ int ch = -1;
+ const char *dst;
+ const char *string;
+ sdp_record_t *rec;
+ sdp_list_t *protos;
+ bdaddr_t bdaddr;
+ struct hci_dbus_data *dbus_data = data;
+ int err;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_STRING, &string,
+ DBUS_TYPE_INVALID))
+ return error_invalid_arguments(conn, msg);
+
+ hci_devba(dbus_data->dev_id, &bdaddr);
+
+ rec = get_record_from_string (dst, string);
+
+ if (!rec)
+ return error_record_does_not_exist (conn, msg);
+
+ if (sdp_get_access_protos(rec, &protos) == 0)
+ ch = sdp_get_proto_port (protos, RFCOMM_UUID);
+
+ if (ch == -1)
+ return error_record_does_not_exist (conn, msg);
+
+ if (find_pending_connect(dst, ch))
+ return error_connect_in_progress(conn, msg);
+
+ if (rfcomm_connect(conn, msg, &bdaddr, dst, NULL, ch, &err) < 0)
+ return error_failed(conn, msg, err);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult rfcomm_cancel_connect_req(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- error("RFCOMM.CancelConnect not implemented");
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ int ch = -1;
+ const char *dst;
+ const char *string;
+ sdp_record_t *rec;
+ sdp_list_t *protos;
+ bdaddr_t bdaddr;
+ struct hci_dbus_data *dbus_data = data;
+ DBusMessage *reply;
+ struct pending_connect *pending;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_STRING, &string,
+ DBUS_TYPE_INVALID))
+ return error_invalid_arguments(conn, msg);
+
+ hci_devba(dbus_data->dev_id, &bdaddr);
+
+ rec = get_record_from_string (dst, string);
+
+ if (!rec)
+ return error_record_does_not_exist (conn, msg);
+
+ if (sdp_get_access_protos(rec, &protos) == 0)
+ ch = sdp_get_proto_port (protos, RFCOMM_UUID);
+
+ if (ch == -1)
+ return error_record_does_not_exist (conn, msg);
+
+ reply = dbus_message_new_method_return (msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ pending = find_pending_connect(dst, ch);
+ if (!pending)
+ return error_connect_not_in_progress(conn, msg);
+
+ pending->canceled = 1;
+
+ return send_reply_and_unref(conn, reply);
}
static DBusHandlerResult rfcomm_connect_by_ch_req(DBusConnection *conn,
diff --git a/hcid/dbus-sdp.c b/hcid/dbus-sdp.c
index cfc4f4f2..2634a5ea 100644
--- a/hcid/dbus-sdp.c
+++ b/hcid/dbus-sdp.c
@@ -833,6 +833,77 @@ search_request:
}
+static int sdp_uuid_comp_func(const void *key1, const void *key2)
+{
+ const uuid_t *a = (const uuid_t *)key1;
+ const uuid_t *b = (const uuid_t *)key2;
+
+ if (a->type != b->type)
+ return 1;
+
+ switch (a->type) {
+ case SDP_UUID16:
+ return !(a->value.uuid16 == b->value.uuid16);
+ break;
+ case SDP_UUID32:
+ return !(a->value.uuid32 == b->value.uuid32);
+ break;
+ case SDP_UUID128:
+ return !memcmp(&a->value.uuid128, &b->value.uuid128,
+ sizeof(uint128_t));
+ break;
+ }
+ return 1;
+}
+
+sdp_record_t *find_record_by_uuid(const char *address, uuid_t *uuid)
+{
+ struct slist *lp, *lr;
+ struct service_provider *p;
+ struct service_record *r;
+ sdp_list_t *list = 0;
+
+
+ for (lp = sdp_cache; lp; lp = lp->next) {
+ p = lp->data;
+ if (strcmp(p->prov, address))
+ continue;
+
+ for (lr = p->lrec; lr; lr = lr->next) {
+ r = lr->data;
+ /* Check whether the record has the correct uuid */
+ if (sdp_get_service_classes(r->record, &list) !=0)
+ continue;
+
+ if (sdp_list_find (list, &uuid, sdp_uuid_comp_func))
+ return r->record;
+ }
+ }
+
+ return NULL;
+}
+
+sdp_record_t *find_record_by_handle(const char *address, int handle)
+{
+ struct slist *lp, *lr;
+ struct service_provider *p;
+ struct service_record *r;
+
+ for (lp = sdp_cache; lp; lp = lp->next) {
+ p = lp->data;
+ if (strcmp(p->prov, address))
+ continue;
+
+ for (lr = p->lrec; lr; lr = lr->next) {
+ r = lr->data;
+ if (r->record->handle == handle)
+ return r->record;
+ }
+ }
+
+ return NULL;
+}
+
static sdp_record_t *find_record(const char *address, int id)
{
struct slist *lp, *lr;
diff --git a/hcid/dbus.h b/hcid/dbus.h
index f33ebc3a..0e0e95bb 100644
--- a/hcid/dbus.h
+++ b/hcid/dbus.h
@@ -219,4 +219,8 @@ int disc_device_req_name(struct hci_dbus_data *dbus_data);
int discoverable_timeout_handler(void *data);
+sdp_record_t *find_record_by_uuid(const char *address, uuid_t *uuid);
+sdp_record_t *find_record_by_handle(const char *address, int handle);
+uint16_t sdp_str2svclass(const char *str);
+
#endif /* __H_BLUEZ_DBUS_H__ */