$NetBSD: patch-aj,v 1.1 2006/07/17 12:29:57 xtraeme Exp $

--- apps/bt_discovery.c.orig	2006-01-11 17:27:35.000000000 +0000
+++ apps/bt_discovery.c
@@ -10,6 +10,205 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 
+#ifdef __NetBSD__
+#include <bluetooth.h>
+#include <err.h>
+#include <errno.h>
+#include <sdp.h>
+
+#include "bt_discovery.h"
+
+/*
+ * Parse protocol descriptor list for the RFCOMM channel
+ *
+ * seq8 len8				2
+ *	seq8 len8			2
+ *		uuid16 value16		3	L2CAP
+ *	seq8 len8			2
+ *		uuid16 value16		3	RFCOMM
+ *		uint8 value8		2	channel
+ *				      ===
+ *				       14
+ */
+
+static int32_t
+parse_rfcomm_channel(sdp_attr_t *a)
+{
+	uint8_t	*ptr = a->value;
+	uint8_t	*end = a->value + a->vlen;
+	int32_t	 type, len, uuid, channel;
+
+	if (end - ptr < 14)
+		return (-1);
+
+	SDP_GET8(type, ptr);
+	switch (type) {
+	case SDP_DATA_SEQ8:
+		SDP_GET8(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ16:
+		SDP_GET16(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ32:
+		SDP_GET32(len, ptr);
+		break;
+
+	default:
+		return (-1);
+	}
+	if (ptr + len > end)
+		return (-1);
+
+	/* Protocol */
+	SDP_GET8(type, ptr);
+	switch (type) {
+	case SDP_DATA_SEQ8:
+		SDP_GET8(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ16:
+		SDP_GET16(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ32:
+		SDP_GET32(len, ptr);
+		break;
+
+	default:
+		return (-1);
+	}
+	if (ptr + len > end)
+		return (-1);
+
+	/* UUID */
+	if (ptr + 3 > end)
+		return (-1);
+	SDP_GET8(type, ptr);
+	switch (type) {
+	case SDP_DATA_UUID16:
+		SDP_GET16(uuid, ptr);
+		if (uuid != SDP_UUID_PROTOCOL_L2CAP)
+			return (-1);
+		break;
+
+	case SDP_DATA_UUID32:  /* XXX FIXME can we have 32-bit UUID */
+	case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
+	default:
+		return (-1);
+	}
+
+	/* Protocol */
+	SDP_GET8(type, ptr);
+	switch (type) {
+	case SDP_DATA_SEQ8:
+		SDP_GET8(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ16:
+		SDP_GET16(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ32:
+		SDP_GET32(len, ptr);
+		break;
+
+	default:
+		return (-1);
+	}
+	if (ptr + len > end)
+		return (-1);
+
+	/* UUID */
+	if (ptr + 3 > end)
+		return (-1);
+	SDP_GET8(type, ptr);
+	switch (type) {
+	case SDP_DATA_UUID16:
+		SDP_GET16(uuid, ptr);
+		if (uuid != SDP_UUID_PROTOCOL_RFCOMM)
+			return (-1);
+		break;
+
+	case SDP_DATA_UUID32:  /* XXX FIXME can we have 32-bit UUID */
+	case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
+	default:
+		return (-1);
+	}
+
+	/* channel */
+	if (ptr + 2 > end)
+		return (-1);
+
+	SDP_GET8(type, ptr);
+	if (type != SDP_DATA_UINT8)
+		return (-1);
+
+	SDP_GET8(channel, ptr);
+
+	return (channel);
+}
+
+int
+discover_bt(char *addr, char **res_bdaddr, int *res_channel)
+{
+	bdaddr_t laddr, raddr;
+	uint8_t buffer[256];
+	sdp_attr_t proto = { SDP_ATTR_INVALID, 0, sizeof(buffer), buffer };
+	uint16_t serv = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
+	uint32_t attr = SDP_ATTR_RANGE(SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+				       SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
+	void *ss;
+
+	/*
+	 * Convert given address to bdaddr. If not bdaddr,
+	 * look it up in hosts database.
+	 *
+	 * XXX original does an inquiry if no name is given,
+	 * XXX and matches against the name given or uses
+	 * XXX the first device found. Consider that.
+	 */
+	if (addr == NULL)
+		errx(1, "must have address");
+
+	if (!bt_aton(addr, &raddr)) {
+		struct hostent  *he = NULL;
+
+		if ((he = bt_gethostbyname(addr)) == NULL)
+			errx(1, "%s: %s",
+				addr, hstrerror(h_errno));
+
+		bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr);
+	}
+
+	*res_bdaddr = strdup(bt_ntoa(&raddr, NULL));
+	fprintf(stderr, "Browsing %s ...\n", *res_bdaddr);
+
+	/*
+	 * Connect to remote SDP server to find the channel
+	 * number to use for the OBEX_FILE_TRANSFER service
+	 */
+	bdaddr_copy(&laddr, BDADDR_ANY);
+	ss = sdp_open(&laddr, &raddr);
+	if (ss == NULL || (errno = sdp_error(ss)) != 0)
+		err(1, "%s", addr);
+
+	if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0)
+		errx(1, "sdp_search", strerror(sdp_error(ss)));
+
+	if (proto.flags != SDP_ATTR_OK)
+		errx(1, "sdp_search: File Transfer not available");
+
+	sdp_close(ss);
+
+	*res_channel = parse_rfcomm_channel(&proto);
+	if (*res_channel == -1)
+		errx(1, "sdp_search: No Channel #");
+
+	return 0;
+}
+#else
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
@@ -146,6 +345,7 @@ int discover_bt(char *addr, char **res_b
 
     return 0;
 }
+#endif
 
 #else
 #include "bt_discovery.h"
