libhci update

Maksim Yevmenkin maksim.yevmenkin at gmail.com
Thu Apr 9 15:37:02 PDT 2009


On Thu, Apr 9, 2009 at 1:48 PM, Bruce Simpson <bms at incunabulum.net> wrote:

[...]

>>> I would hope to do the same for libsdp.
>>
>> well, here is where things might get a bit tricky because of sdpd(8).
>> depending on what you want to do, you might need to bring both libsdp
>> and sdpd (or whatever it is called these days) from bluez.
>
> Yup, that's pretty scary because there are significant differences.
>
> If you look at all the APIs, they all end up building on-the-wire-records to
> advertise Bluetooth
> services via SDP -- be that L2CAP PSM's, RFCOMM channels, or anything else.

oh, no :) please do not open this can of worms :) Iain knows its a
very touchy subject with me :) i dislike *intensely* the fact that sdp
records have to be built in on-the-wire format. i just dont get why
any application has to know about uuid's, sequences and other low
level sdp stuff just to register the damn service. that is why i went
an extreme route (a bit too extreme perhaps :) and introduced
"pre-cooked" sdp records that are constructed on the fly. application
only transfers minimum information required to register the service.
the downside, of course, is that its not very flexible. in fact, its
pretty damn rigid. which means that if you want to introduce new
profile, you have to change sdp parts as well.

Iain and i beat this horse to death, imo. we think there is really no
good way around this and we can only improve api to be more user
friendly and require less typing, but the records, unfortunately,
would have to be in on-the-wire format (or something pretty damn close
to it).

> it is irksome that the SDP APIs between OSes differ so radically.
>
> So I'd make a radical suggestion here: can we change the existing BSD-space
> applications
> and daemons to use a different name e.g. libbtsdp for the base system?

yes, we can. i was actually thinking to merge add the sdp stuff into
libbluetooth. and while i'm at it, move bluetooth.h and sdp.h into
include/bluetooth/ where it belongs. i just want to get hci stuff out
the way first.

> That would be a big help for BlueZ compatibility... yes, it sucks, but it's
> a hackish fix to the
> namespace collision between these two radically different sets of libraries.

if we fix our sdp first to be more like bluez (i.e. use on-the-wire
format) then we can add compat bluez sdp library that would simply
translate bluez call to bsd calls. same route as with libhci.

[....]

>> i will try to clean up my patches and send them out one more time. i'd
>> like to get Iain's comments before putting them into the base. mfc can
>> be done quickly as well (if needed).
>
> OK. That would be great. I can look at such diffs too if need be. :-)
> I don't believe an MFC will be too difficult as long as we're in the 7.2
> slush.

thanks! i have attached the latest diff. its pretty much the same as
previous one, except i added documentation.

> [ioctls]
>>
>> let me know what is missing and i will add it :)
>
> What's the easiest way to get the unit number?
> ...

hci nodes do not really have unit numbers. they have names. hci nodes
are named as "device+unit+hci". device + unit comes from driver for a
particular device. in 99% of the cases it will be "ubtX", i.e. usb
dongle, but we also support h4 devices (currently broken due to new
tty) and btccc - 3com pccard.

so just enumerate all the radios (i.e. list all the hci nodes - there
is an ioctl for that) and unit will be the number before "hci" part of
the name. however, that will only work if if have devices of the same
type in the system (i.e. all the radios are bluetooth dongles).
otherwise, if, say, you have 3com pccard and bluetooth dongle, then
you will have btccc0hci and ubt0hci nodes both having 0 unit number.

>>  that is the thing. bd_addr is the only "unique" (it can't be easily
>> changed, but it still can be done) thing about bluetooth device. but
>> in order to get it, you need to address the device somehow. devname is
>> better, but still does not solve the problem as you pointed out it can
>> change.
>
> It would be nice to have a 'device name' registry or be able to
> renumber/rename the Bluetooth
> dongles in a manner similar to that of what folk end up doing for FreeBSD
> using ifconfig(8).

i'm not quite follow why is that needed?

[....]

>> why do you care so much about devid? i assume whatever it is you are
>> building, it will have multiple radios, right? are you planning to
>> setup different radios in different way?
>
> Because... (bad English ;o))
> yes we do want to use multiple radios -- inquiry is an expensive operation
> -- and also,
> BlueCove/JSR-82, PyBlueZ and the other high level language stuff currently
> wants to use
> dev_id as the unique endpoint identifier. :-(
>
> They do provide APIs to lookup dev_id from the MAC address, but if that is
> used as-is,
> any port would still have to maintain the kludge. It is irritating, but that
> is what has unfolded.

just a stupid idea - "hash" devname into devid? where "hash" does not
necessarily means use some real hash function :) could be partitioning
function (as in my previously posted code).

how wide is devid, you mentioned that it could be as narrow as unit16
and as wide as int? is that correct?

thanks,
max
-------------- next part --------------
Index: hci.c
===================================================================
--- hci.c	(revision 190870)
+++ hci.c	(working copy)
@@ -30,15 +30,421 @@
  * $FreeBSD$
  */
 
+#include <assert.h>
 #include <bluetooth.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
+static int    bt_devany_cb(int s, struct bt_devinfo const *di, void *xdevname);
 static char * bt_dev2node (char const *devname, char *nodename, int nnlen);
 
 int
+bt_devopen(char const *devname)
+{
+	struct sockaddr_hci	ha;
+	bdaddr_t		ba;
+	int			s;
+
+	if (devname == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	memset(&ha, 0, sizeof(ha));
+	ha.hci_len = sizeof(ha);
+	ha.hci_family = AF_BLUETOOTH;
+
+	if (bt_aton(devname, &ba)) {
+		if (!bt_devname(ha.hci_node, &ba))
+			return (-1);
+	} else if (bt_dev2node(devname, ha.hci_node,
+					sizeof(ha.hci_node)) == NULL) {
+		errno = ENXIO;
+		return (-1);
+	}
+
+	s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
+	if (s < 0)
+		return (-1);
+
+	if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 ||
+	    connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0) {
+		close(s);
+		return (-1);
+	}
+
+	return (s);
+}
+
+int
+bt_devclose(int s)
+{
+	return (close(s));
+}
+
+int
+bt_devsend(int s, uint16_t ogf, uint16_t ocf, int plen, void *param)
+{
+	ng_hci_cmd_pkt_t	h;
+	struct iovec		iv[2];
+	int			ivn;
+
+	if (plen < 0 || (plen > 0 && param == NULL)) { 
+		errno = EINVAL;
+		return (-1);
+	}
+
+	iv[0].iov_base = &h;
+	iv[0].iov_len = sizeof(h);
+	ivn = 1;
+
+	h.type = NG_HCI_CMD_PKT;
+	h.opcode = htole16(NG_HCI_OPCODE(ogf, ocf));
+	if (plen > 0) {
+		h.length = plen;
+
+		iv[1].iov_base = param;
+		iv[1].iov_len = plen;
+		ivn = 2;
+	} else
+		h.length = 0;
+
+	while (writev(s, iv, ivn) < 0) {
+		if (errno == EAGAIN || errno == EINTR)
+			continue;
+
+		return (-1);
+	}
+
+	return (0);
+}
+
+int
+bt_devrecv(int s, uint8_t *buf, int size, time_t to)
+{
+	fd_set		rfd;
+	struct timeval	tv;
+	int		n;
+
+	if (buf == NULL || size <= 0 || to < 0) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	FD_ZERO(&rfd);
+	FD_SET(s, &rfd);
+
+	tv.tv_sec = to;
+	tv.tv_usec = 0;
+
+	while ((n = select(s + 1, &rfd, NULL, NULL, &tv)) < 0) {
+		if (errno == EAGAIN || errno == EINTR)
+			continue;
+
+		return (-1);
+	}
+
+	if (n == 0) {
+		errno = ETIMEDOUT;
+		return (-1);
+	}
+
+	assert(FD_ISSET(s, &rfd));
+
+	while ((n = read(s, buf, size)) < 0) {
+		if (errno == EAGAIN || errno == EINTR)
+			continue;
+
+		return (-1);
+	}
+
+	return (n);
+}
+
+int
+bt_devreq(int s, struct bt_devreq *r, time_t to)
+{
+	uint8_t				buf[320]; /* more than enough */
+	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) buf;
+	ng_hci_command_compl_ep		*cc = (ng_hci_command_compl_ep *)(e+1);
+	ng_hci_command_status_ep	*cs = (ng_hci_command_status_ep*)(e+1);
+	uint16_t			opcode;
+	time_t				t_end;
+	int				n;
+
+	if (s < 0 || r == NULL || to < 0) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (r->rlen < 0 || (r->rlen > 0 && r->rparam == NULL)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	n = bt_devsend(s, r->ogf, r->ocf, r->clen, r->cparam);
+	if (n < 0)
+		return (-1);
+
+	opcode = htole16(NG_HCI_OPCODE(r->ogf, r->ocf));
+
+	t_end = time(NULL) + to;
+
+	do {
+		to = t_end - time(NULL);
+		if (to < 0)
+			to = 0;
+
+		n = bt_devrecv(s, buf, sizeof(buf), to);
+		if (n < 0)
+			return (-1);
+
+		if (n < sizeof(*e)) {
+			errno = EMSGSIZE;
+			return (-1);
+		}
+
+		if (e->type != NG_HCI_EVENT_PKT) {
+			errno = EIO;
+			return (-1);
+		}
+
+		n -= sizeof(*e);
+
+		switch (e->event) {
+		case NG_HCI_EVENT_COMMAND_COMPL:
+			if (cc->opcode == opcode) {
+				n -= sizeof(*cc);
+
+				if (r->rlen >= n) {
+					r->rlen = n;
+					memcpy(r->rparam, cc + 1, r->rlen);
+				}
+
+				return (0);
+			}
+			break;
+
+		case NG_HCI_EVENT_COMMAND_STATUS:
+			if (cs->opcode == opcode) {
+				if (r->event != NG_HCI_EVENT_COMMAND_STATUS) {
+					if (cs->status != 0) {
+						errno = EIO;
+						return (-1);
+					}
+				} else {
+					if (r->rlen >= n) {
+						r->rlen = n;
+						memcpy(r->rparam, cs, r->rlen);
+					}
+
+					return (0);
+				}
+			}
+			break;
+
+		default:
+			if (e->event == r->event) {
+				if (r->rlen >= n) {
+					r->rlen = n;
+					memcpy(r->rparam, e + 1, r->rlen);
+				}
+
+				return (0);
+			}
+			break;
+		}
+	} while (to > 0);
+
+	errno = ETIMEDOUT;
+
+	return (-1);
+}
+
+int
+bt_devfilter(int s, struct bt_devfilter const *new, struct bt_devfilter *old)
+{
+	struct ng_btsocket_hci_raw_filter	f;
+	socklen_t				len;
+	int					bit;
+
+	if (new == NULL && old == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (old != NULL) {
+		len = sizeof(f);
+		if (getsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER, &f, &len) < 0)
+			return (-1);
+
+		memset(old, 0, sizeof(*old));
+
+		for (bit = 0; bit < NG_HCI_EVENT_PKT; bit ++)
+			if (bit_test(f.packet_mask, bit))
+				old->packet_mask |= (1 << bit);
+
+		for (bit = 0; bit < NG_HCI_EVENT_MASK_SIZE * 8; bit ++)
+			if (bit_test(f.event_mask, bit))
+				old->event_mask |= (1 << bit);
+	}
+
+	if (new != NULL) {
+		memset(&f, 0, sizeof(f));
+
+		for (bit = 0; bit < NG_HCI_EVENT_PKT; bit ++)
+			if (new->packet_mask & (1 << bit))
+				bit_set(f.packet_mask, bit);
+
+		for (bit = 0; bit < (NG_HCI_EVENT_MASK_SIZE * 8); bit ++)
+			if (new->event_mask & (1 << bit))
+				bit_set(f.event_mask, bit);
+
+		len = sizeof(f);
+		if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER, &f, len) < 0)
+			return (-1);
+	}
+
+	return (0);
+}
+
+int
+bt_devinquiry(char const *devname, int length, int num_rsp,
+		uint8_t const *lap, struct bt_devinquiry **ii)
+{
+	uint8_t				buf[320];
+	char				_devname[HCI_DEVNAME_SIZE];
+	struct bt_devfilter		f;
+	ng_hci_inquiry_cp		*cp = (ng_hci_inquiry_cp *) buf;
+	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) buf;
+	ng_hci_inquiry_result_ep	*ep = (ng_hci_inquiry_result_ep *)(e+1);
+	ng_hci_inquiry_response		*ir;
+	struct bt_devinquiry		*i;
+	int				s, n;
+	time_t				to;
+
+	if (ii == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (devname == NULL) {
+		memset(_devname, 0, sizeof(_devname));
+		devname = _devname;
+
+		n = bt_devenum(bt_devany_cb, _devname);
+		if (n <= 0) {
+			if (n == 0)
+				*ii = NULL;
+
+			return (n);
+		}
+	}
+
+	s = bt_devopen(devname);
+	if (s < 0)
+		return (-1);
+
+	if (bt_devfilter(s, NULL, &f) < 0) {
+		bt_devclose(s);
+		return (-1);
+	}
+
+	f.event_mask |= (1 << (NG_HCI_EVENT_INQUIRY_COMPL - 1));
+	f.event_mask |= (1 << (NG_HCI_EVENT_INQUIRY_RESULT - 1));
+
+	if (bt_devfilter(s, &f, NULL) < 0) {
+		bt_devclose(s);
+		return (-1);
+	}
+
+	if (lap == NULL) {
+		cp->lap[0] = 0x33;
+		cp->lap[1] = 0x8b;
+		cp->lap[2] = 0x9e;
+	} else {
+		cp->lap[0] = lap[0];
+		cp->lap[1] = lap[1];
+		cp->lap[2] = lap[2];
+	}
+
+	if (length <= 0 || length > 255)
+		length = 4;	/* 5.12 seconds */
+	cp->inquiry_length = (uint8_t) length;
+
+	to = (time_t)((double) length * 1.28) + 1;
+
+	if (num_rsp <= 0 || num_rsp > 255)
+		num_rsp = 8;
+	cp->num_responses = (uint8_t) num_rsp;
+
+	i = *ii = calloc(num_rsp, sizeof(struct bt_devinquiry));
+	if (i == NULL) {
+		bt_devclose(s);
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	if (bt_devsend(s, NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_INQUIRY,
+			sizeof(*cp), cp) < 0) {
+		free(i);
+		bt_devclose(s);
+		return (-1);
+	}
+
+wait_for_more:
+
+	n = bt_devrecv(s, buf, sizeof(buf), to);
+	if (n < 0) {
+		free(i);
+		bt_devclose(s);
+		return (-1);
+	}
+
+	if (n < sizeof(ng_hci_event_pkt_t)) {
+		free(i);
+		bt_devclose(s);
+		errno = EIO;
+		return (-1);
+	}
+
+	switch (e->event) {
+	case NG_HCI_EVENT_INQUIRY_COMPL:
+		break;
+
+	case NG_HCI_EVENT_INQUIRY_RESULT:
+		ir = (ng_hci_inquiry_response *)(ep + 1);
+
+#undef	MIN
+#define	MIN(a, b)	(((a) < (b))? (a) : (b))
+
+		for (n = 0; n < MIN(ep->num_responses, num_rsp); n ++) {
+			bdaddr_copy(&i->bdaddr, &ir->bdaddr);
+			i->pscan_rep_mode = ir->page_scan_rep_mode;
+			i->pscan_period_mode = ir->page_scan_period_mode;
+			i->pscan_mode = ir->page_scan_mode;
+			memcpy(i->dev_class, ir->uclass, sizeof(i->dev_class));
+			i->clock_offset = le16toh(ir->clock_offset);
+
+			ir ++;
+			i ++;
+			num_rsp --;
+		}
+		/* FALLTHROUGH */
+
+	default:
+		goto wait_for_more;
+		/* NOT REACHED */
+	}
+
+	bt_devclose(s);
+		
+	return (i - *ii);
+}
+
+int
 bt_devinfo(struct bt_devinfo *di)
 {
 	union {
@@ -53,6 +459,7 @@
 		struct ng_btsocket_hci_raw_node_debug		r8;
 	}						rp;
 	struct sockaddr_hci				ha;
+	socklen_t					halen;
 	int						s, rval;
 
 	if (di == NULL) {
@@ -60,27 +467,14 @@
 		return (-1);
 	}
 
-	memset(&ha, 0, sizeof(ha));
-	ha.hci_len = sizeof(ha);
-	ha.hci_family = AF_BLUETOOTH;
-
-	if (bt_aton(di->devname, &rp.r1.bdaddr)) {
-		if (!bt_devname(ha.hci_node, &rp.r1.bdaddr))
-			return (-1);
-	} else if (bt_dev2node(di->devname, ha.hci_node,
-					sizeof(ha.hci_node)) == NULL) {
-		errno = ENXIO;
-		return (-1);
-	}
-
-	s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
+	s = bt_devopen(di->devname);
 	if (s < 0)
 		return (-1);
 
 	rval = -1;
 
-	if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 ||
-	    connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0)
+	halen = sizeof(ha);
+	if (getsockname(s, (struct sockaddr *) &ha, &halen) < 0)
 		goto bad;
 	strlcpy(di->devname, ha.hci_node, sizeof(di->devname));
 
@@ -138,7 +532,7 @@
 
 	rval = 0;
 bad:
-	close(s);
+	bt_devclose(s);
 
 	return (rval);
 }
@@ -205,6 +599,13 @@
 	return (count);
 }
 
+static int
+bt_devany_cb(int s, struct bt_devinfo const *di, void *xdevname)
+{
+	strlcpy((char *) xdevname, di->devname, HCI_DEVNAME_SIZE);
+	return (1);
+}
+
 static char *
 bt_dev2node(char const *devname, char *nodename, int nnlen)
 {
Index: bluetooth.3
===================================================================
--- bluetooth.3	(revision 190870)
+++ bluetooth.3	(working copy)
@@ -25,7 +25,7 @@
 .\" $Id: bluetooth.3,v 1.5 2003/05/20 23:04:30 max Exp $
 .\" $FreeBSD$
 .\"
-.Dd February 13, 2009
+.Dd April 9, 2009
 .Dt BLUETOOTH 3
 .Os
 .Sh NAME
@@ -41,6 +41,17 @@
 .Nm bt_endprotoent ,
 .Nm bt_aton ,
 .Nm bt_ntoa ,
+.Nm bt_devaddr ,
+.Nm bt_devname ,
+.Nm bt_devinfo ,
+.Nm bt_devenum ,
+.Nm bt_devopen ,
+.Nm bt_devclose ,
+.Nm bt_devsend ,
+.Nm bt_devrecv ,
+.Nm bt_devreq ,
+.Nm bt_devfilter ,
+.Nm bt_devinquiry ,
 .Nm bdaddr_same ,
 .Nm bdaddr_any ,
 .Nm bdaddr_copy
@@ -84,6 +95,20 @@
 .Ft int
 .Fn bt_devenum "bt_devenum_cb_t *cb" "void *arg"
 .Ft int
+.Fn bt_devopen "char const *devname"
+.Ft int
+.Fn bt_devclose "int s"
+.Ft int
+.Fn bt_devsend "int s" "uint16_t ogf" "uint16_t ocf" "int plen" "void *param"
+.Ft int
+.Fn bt_devrecv "int s" "uint8_t *buf" "int size" "time_t to"
+.Ft int
+.Fn bt_devreq "int s" "struct bt_devreq *r" "time_t to"
+.Ft int
+.Fn bt_devfilter "int s" "struct bt_devfilter const *new" "struct bt_devfilter *old"
+.Ft int
+.Fn bt_devinquiry "char const *devname" "int length" "int num_rsp" "uint8_t const *lap" "struct bt_devinquiry **ii"
+.Ft int
 .Fn bdaddr_same "const bdaddr_t *a" "const bdaddr_t *b"
 .Ft int
 .Fn bdaddr_any "const bdaddr_t *a"
@@ -311,6 +336,219 @@
 or -1 if an error occurred.
 .Pp
 The
+.Fn bt_devopen
+function opens Bluetooth device with the given
+.Fa devname
+and returns connected and bound
+.Dv HCI
+socket.
+The function returns -1 if an error has occurred.
+.Pp
+The
+.Fn bt_devclose
+closes passed
+.Dv HCI
+socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+.Pp
+The
+.Fn bt_devsend
+function sends Bluetooth
+.Dv HCI
+command with the OpCode Group Field
+.Fa ogf
+and
+OpCode Command Field
+.Fa ocf
+to the provided socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+The
+.Fa plen
+and
+.Fa param
+parameters specify command parameters.
+The function returns 0 on success,
+or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devrecv
+function receives one Bluetooth
+.Dv HCI
+event packet from the socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+The event packet is placed into the provided buffer
+.Fa buf
+of size
+.Fa size .
+The
+.Fa to
+parameter specifies receive timeout in seconds.
+The function returns total number of bytes recevied,
+or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devreq
+function makes Bluetooth
+.Dv HCI
+request to the socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+The function will send the specified command and will wait for the specified
+event,
+or timeout
+.Fa to
+seconds to occur.
+The
+.Vt bt_devreq
+structure is defined as follows
+.Bd -literal -offset indent
+struct bt_devreq
+{
+        uint16_t        ogf;
+        uint16_t        ocf;
+        int             event;
+        void            *cparam;
+        int             clen;
+        void            *rparam;
+        int             rlen;
+};
+.Ed
+.Pp
+The
+.Fa ogf
+and
+.Fa ocf
+fields specify OpCode Group and Command Field respectively.
+The
+.Fa cparam
+and
+.Fa clen
+fields specify command parameters data and command parameters data size
+respectively.
+The
+.Fa event
+field specifies which Bluetooth
+.Dv HCI
+event ID the function should wait for.
+The
+.Fa rparam
+and
+.Fa rlen
+parameters specify buffer and buffer size respectively where return
+parameters should be placed.
+The function returns 0 on success, or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devfilter
+controls the local
+.Dv HCI
+filter associated with the socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+Filtering can be done on packet types, i.e.
+.Dv ACL ,
+.Dv SCO or
+.Dv HCI
+event packets, and, in addition, on
+.Dv HCI
+event IDs.
+Before applying
+.Fa new
+filter (if provided) the function will try to obtain current filter
+from the socket
+.Fa s
+and place it into the
+.Fa old
+parameter (if provided).
+The
+.Vt bt_devfilter
+structure is defined as follows
+.Bd -literal -offset indent
+struct bt_devfilter {
+        uint64_t        event_mask;
+        uint8_t         packet_mask;
+};
+.Ed
+.Pp
+Both
+.Fa event_mask
+and
+.Fa packet_mask
+fields are bit masks.
+If a bit
+.Fa N
+is cleared in the
+.Fa event_mask
+then the corresponding Bluetooth
+.Dv HCI
+event ID
+.Fa N
+is filtered out.
+If a bit
+.Fa N
+is cleared in the
+.Fa packet_mask
+then all the packets with the corresponding packet indicator are filtered out.
+The function returns 0 on success, or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devinquiry
+function performs Bluetooth inquiry.
+The
+.Fa devname
+parameter specifies which local Bluetooth device should perform an inquiry.
+If not secified, i.e.
+.Dv NULL ,
+then first available device will be used.
+The
+.Fa length
+parameters specifies the total length of an inquiry in 1.28 second units.
+If not specified, i.e. 0, default value will be used.
+The
+.Fa num_rsp
+parameter specifies the number of responses that can be received before
+the inquiry is halted.
+If not specified, i.e. 0, default value will be used.
+The
+.Fa lap
+parameter contains the LAP from which the inquiry access code will be
+be derived when the inquiry procedure is made.
+If not specified, i.e.
+.Dv NULL ,
+then GIAC LAP 9e:8b:33 will be used.
+The
+.Fa ii
+parameter specifies where to place inquiry results.
+On success, the function will return total number of inquiry results,
+will allocate buffer to store all the inquiry results and
+will return pointer to the allocated buffer in the
+.Fa ii
+parameter.
+It is up to the caller of the function to dispose of the buffer.
+The function returns -1 if an error has occurred.
+The
+.Vt bt_devinquiry
+structure is defined as follows
+.Bd -literal -offset indent
+struct bt_devinquiry {
+        bdaddr_t        bdaddr;
+        uint8_t         pscan_rep_mode;
+        uint8_t         pscan_period_mode;
+        uint8_t         pscan_mode;
+        uint8_t         dev_class[3];
+        uint16_t        clock_offset;
+};
+.Ed
+.Pp
+The
 .Fn bdaddr_same ,
 .Fn bdaddr_any
 and
Index: bluetooth.h
===================================================================
--- bluetooth.h	(revision 190870)
+++ bluetooth.h	(working copy)
@@ -39,6 +39,7 @@
 #include <sys/endian.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/uio.h>
 #include <sys/un.h>
 #include <errno.h>
 #include <netdb.h>
@@ -46,6 +47,7 @@
 #include <netgraph/bluetooth/include/ng_hci.h>
 #include <netgraph/bluetooth/include/ng_l2cap.h>
 #include <netgraph/bluetooth/include/ng_btsocket.h>
+#include <time.h>
 
 __BEGIN_DECLS
 
@@ -129,8 +131,42 @@
 	uint8_t		_padding[20];	/* leave space for future additions */
 };
 
+struct bt_devreq
+{
+	uint16_t	ogf;
+	uint16_t	ocf;
+	int		event;
+	void		*cparam;
+	int		clen;
+	void		*rparam;
+	int		rlen;
+};
+
+struct bt_devfilter {
+	uint64_t	event_mask;
+	uint8_t		packet_mask;
+};
+
+struct bt_devinquiry {
+	bdaddr_t	bdaddr;
+	uint8_t		pscan_rep_mode;
+	uint8_t		pscan_period_mode;
+	uint8_t		pscan_mode;
+	uint8_t		dev_class[3];
+	uint16_t	clock_offset;
+};
+
 typedef int	(bt_devenum_cb_t)(int, struct bt_devinfo const *, void *);
 
+int		bt_devopen (char const *devname);
+int		bt_devclose(int s);
+int		bt_devsend (int s, uint16_t ogf, uint16_t ocf, int plen, void *param);
+int		bt_devrecv (int s, uint8_t *buf, int size, time_t to);
+int		bt_devreq  (int s, struct bt_devreq *r, time_t to);
+int		bt_devfilter(int s, struct bt_devfilter const *new,
+			     struct bt_devfilter *old);
+int		bt_devinquiry(char const *devname, int length, int num_rsp,
+			      uint8_t const *lap, struct bt_devinquiry **ii);
 int		bt_devinfo (struct bt_devinfo *di);
 int		bt_devenum (bt_devenum_cb_t *cb, void *arg);
 
Index: Makefile
===================================================================
--- Makefile	(revision 190870)
+++ Makefile	(working copy)
@@ -33,6 +33,13 @@
 MLINKS+=	bluetooth.3 bt_devinfo.3
 MLINKS+=	bluetooth.3 bt_devenum.3
 
+MLINKS+=	bluetooth.3 bt_devopen.3
+MLINKS+=	bluetooth.3 bt_devclose.3
+MLINKS+=	bluetooth.3 bt_devsend.3
+MLINKS+=	bluetooth.3 bt_devreq.3
+MLINKS+=	bluetooth.3 bt_devfilter.3
+MLINKS+=	bluetooth.3 bt_devinquiry.3
+
 MLINKS+=	bluetooth.3 bdaddr_same.3
 MLINKS+=	bluetooth.3 bdaddr_any.3
 MLINKS+=	bluetooth.3 bdaddr_copy.3


More information about the freebsd-bluetooth mailing list