libhci update

Maksim Yevmenkin maksim.yevmenkin at gmail.com
Mon Apr 20 17:53:27 UTC 2009


>> thanks for the feedback. i'm attaching revisited patch. please take a
>> look and let me know if this is something you happy with.
>
> (pls ignore typos & bad formatting, am on mobile device :)
>
> Bt_devrecv() should probably take void * for buffer?  Also manpage suggests it
> will only receive hci events. Do you think its worth doing some validation of received
> data? (eg return EIO for truncated reads?)

i will change uint8_t * to void *, no problem. i also updated man page
and removed 'event' word :)

> Bt_devinquiry() should probably  restore the filter after use? Also needs to ensure hci
> event packets are enabled?

its an implementation detail :) bt_devinqury() opens completely new
socket. in freebsd, filter is attached to the socket and is already
set to "sensible" defaults. so, all we need to do is to enable events
that we care about, i.e. inquiry result and inquiry complete. also
since bt_devinqury() is closing the socket after its done, there is no
need to restore original filter.

> Bt_devreq() needs to set/restore a filter too

well, maybe. bt_devreq() operates on already opened socket. the
assumption i'm making here is that application will set appropriate
filter before calling bt_devreq(). otherwise, application would have
to always set 'event' field to acceptable value (or zero). i could go
either way here. just need to document implemented behavior better.

> In bt_devreq structure event should be uint8_t? Also clen and rlen should be size_t

ok :) i was trying to get rid of hole with uint16_t event, but it does
not matter. also clen/rlen are size_t in bluetooth.h, its just i did
not update man page :)

> Do you think its worth to cook dev_class into a normalised host numeric value rather than 3 bytes ?

right, hmm, i guess we could turn dev_class into uint32_t in le16 byte
order (since everything else in bluetooth hci is in le16 order), but
maybe its too much? spec breaks out dev_class as 3 bytes array and
talks about bytes and bits within each byte. i'm kinda leaning towards
leaving it as is, because otherwise application would have to
translate byte/bit into uint32_t mask. it could be somewhat
convenient, i guess. again, no strong feeling about it. could go
either way.

> Probably need to specifically mention that the inquiry response to be released using free() in manpage?

it says so, i.e.

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.

> Something i thought about on the train yesterday but can't visualise on the small
> screen. For device inquiry did you consider using a callback method (as per devenum)
> in stead of returning the structure array? At least i recall my nokia would show the
> list building (but perhaps that was when it got the names) and this windows mobile
> device does show the raw list in progress (though stupidly just displays a list of
> 'unknown device' until it gets the names :)

yes, i thought about it. the only difference is that it would be not
so close to linux/bluez api. i guess, we could provide another
function?

i'm attaching revised diff for your review.

thanks,
max
-------------- next part --------------
Index: hci.c
===================================================================
--- hci.c	(revision 191328)
+++ hci.c	(working copy)
@@ -30,15 +30,445 @@
  * $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 opcode, void *param, size_t plen)
+{
+	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(opcode);
+	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, void *buf, size_t 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);
+	time_t				t_end;
+	uint16_t			opcode;
+	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->opcode, r->cparam, r->clen);
+	if (n < 0)
+		return (-1);
+
+	opcode = htole16(r->opcode);
+	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;
+
+	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));
+		memcpy(old->packet_mask, &f.packet_mask,
+			sizeof(old->packet_mask));
+		memcpy(old->event_mask, &f.event_mask,
+			sizeof(old->event_mask));
+	}
+
+	if (new != NULL) {
+		memset(&f, 0, sizeof(f));
+		memcpy(&f.packet_mask, new->packet_mask, sizeof(f.packet_mask));
+		memcpy(&f.event_mask, new->event_mask, sizeof(f.event_mask));
+
+		len = sizeof(f);
+		if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER, &f, len) < 0)
+			return (-1);
+	}
+
+	return (0);
+}
+
+void
+bt_devfilter_pkt_set(struct bt_devfilter *filter, int type)
+{
+	bit_set(filter->packet_mask, type - 1);
+}
+
+void
+bt_devfilter_pkt_clr(struct bt_devfilter *filter, int type)
+{
+	bit_clear(filter->packet_mask, type - 1);
+}
+
+int
+bt_devfilter_pkt_tst(struct bt_devfilter const *filter, int type)
+{
+	return (bit_test(filter->packet_mask, type - 1));
+}
+
+void
+bt_devfilter_evt_set(struct bt_devfilter *filter, int event)
+{
+	bit_set(filter->event_mask, event - 1);
+}
+
+void
+bt_devfilter_evt_clr(struct bt_devfilter *filter, int event)
+{
+	bit_clear(filter->event_mask, event - 1);
+}
+
+int
+bt_devfilter_evt_tst(struct bt_devfilter const *filter, int event)
+{
+	return (bit_test(filter->event_mask, event - 1));
+}
+
+int
+bt_devinquiry(char const *devname, time_t length, int num_rsp,
+		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);
+	}
+
+	bt_devfilter_evt_set(&f, NG_HCI_EVENT_INQUIRY_COMPL);
+	bt_devfilter_evt_set(&f, NG_HCI_EVENT_INQUIRY_RESULT);
+
+	if (bt_devfilter(s, &f, NULL) < 0) {
+		bt_devclose(s);
+		return (-1);
+	}
+
+	/* Always use GIAC LAP */
+	cp->lap[0] = 0x33;
+	cp->lap[1] = 0x8b;
+	cp->lap[2] = 0x9e;
+
+	/* Calculate inquire length in 1.28 second units */
+	to = (time_t) ((double) length / 1.28);
+	if (to <= 0)
+		cp->inquiry_length = 4;		/* 5.12 seconds */
+	else if (to > 254)
+		cp->inquiry_length = 255;	/* 326.40 seconds */
+	else
+		cp->inquiry_length = to + 1;
+
+	to = (time_t)((double) cp->inquiry_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_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_INQUIRY),
+			cp, sizeof(*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;
+			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 +483,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 +491,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 +556,7 @@
 
 	rval = 0;
 bad:
-	close(s);
+	bt_devclose(s);
 
 	return (rval);
 }
@@ -205,6 +623,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 191328)
+++ 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,23 @@
 .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_devfilter_pkt_set ,
+.Nm bt_devfilter_pkt_clr ,
+.Nm bt_devfilter_pkt_tst ,
+.Nm bt_devfilter_evt_set ,
+.Nm bt_devfilter_evt_clr ,
+.Nm bt_devfilter_evt_tst ,
+.Nm bt_devinquiry ,
 .Nm bdaddr_same ,
 .Nm bdaddr_any ,
 .Nm bdaddr_copy
@@ -84,6 +101,32 @@
 .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 opcode" "void *param" "size_t plen"
+.Ft int
+.Fn bt_devrecv "int s" "void *buf" "size_t 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 void
+.Fn bt_devfilter_pkt_set "struct bt_devfilter *filter" "int type"
+.Ft void
+.Fn bt_devfilter_pkt_clt "struct bt_devfilter *filter" "int type"
+.Ft int
+.Fn bt_devfilter_pkt_tst "struct bt_devfilter const *filter" "int type"
+.Ft void
+.Fn bt_devfilter_evt_set "struct bt_devfilter *filter" "int event"
+.Ft void
+.Fn bt_devfilter_evt_clt "struct bt_devfilter *filter" "int event"
+.Ft int
+.Fn bt_devfilter_evt_tst "struct bt_devfilter const *filter" "int event"
+.Ft int
+.Fn bt_devinquiry "char const *devname" "time_t length" "int num_rsp" "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 +354,229 @@
 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 given
+.Fa opcode
+to the provided socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+The
+.Fa opcode
+parameter is exppected to be in the host byte order.
+The
+.Fa param
+and
+.Fa plen
+parameters specify command parameters.
+The
+.Fn bt_devsend
+function does not modify
+.Dv HCI
+filter on the provided socket
+.Fa s .
+The function returns 0 on success,
+or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devrecv
+function receives one Bluetooth
+.Dv HCI
+packet from the socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+The packet is placed into the provided buffer
+.Fa buf
+of size
+.Fa size .
+The
+.Fa to
+parameter specifies receive timeout in seconds.
+The
+.Fn bt_devrecv
+function does not modify
+.Dv HCI
+filter on the provided socket
+.Fa s .
+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        opcode;
+        uint8_t         event;
+        void            *cparam;
+        size_t          clen;
+        void            *rparam;
+        size_t          rlen;
+};
+.Ed
+.Pp
+The
+.Fa opcode
+field specifies the command and is expected to be in the host byte order.
+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
+.Fn bt_devreq
+function does not modify filter on the provided
+.Dv HCI
+socket
+.Fa s .
+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 function returns 0 on success, or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devfilter_pkt_set ,
+.Fn bt_devfilter_pkt_clr 
+and
+.Fn bt_devfilter_pkt_tst
+functions can be used to modify and test
+.Dv HCI
+filter
+.Fa filter .
+The
+.Fa type
+parameter specifies
+.Dv HCI
+packet type.
+.Pp
+The
+.Fn bt_devfilter_evt_set ,
+.Fn bt_devfilter_evt_clr 
+and
+.Fn bt_devfilter_evt_tst
+functions can be used to modify and test
+.Dv HCI
+event filter
+.Fa filter .
+The
+.Fa event
+parameter specifies
+.Dv HCI
+event ID.
+.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 seconds.
+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 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         dev_class[3];
+        uint16_t        clock_offset;
+        int8_t          rssi;
+        uint8_t         data[240];
+};
+.Ed
+.Pp
+The
 .Fn bdaddr_same ,
 .Fn bdaddr_any
 and
@@ -444,6 +710,6 @@
 .Sh AUTHORS
 .An Maksim Yevmenkin Aq m_evmenkin at yahoo.com
 .Sh BUGS
-These functions use static data storage;
+Some of those functions use static data storage;
 if the data is needed for future use, it should be
 copied before any subsequent calls overwrite it.
Index: bluetooth.h
===================================================================
--- bluetooth.h	(revision 191328)
+++ 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,48 @@
 	uint8_t		_padding[20];	/* leave space for future additions */
 };
 
+struct bt_devreq
+{
+	uint16_t	opcode;
+	uint8_t		event;
+	void		*cparam;
+	size_t		clen;
+	void		*rparam;
+	size_t		rlen;
+};
+
+struct bt_devfilter {
+	bitstr_t	bit_decl(packet_mask, 8);
+	bitstr_t	bit_decl(event_mask, 256);
+};
+
+struct bt_devinquiry {
+	bdaddr_t        bdaddr;
+	uint8_t         pscan_rep_mode;
+	uint8_t         pscan_period_mode;
+	uint8_t         dev_class[3];
+	uint16_t        clock_offset;
+	int8_t          rssi;
+	uint8_t         data[240];
+};
+
 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 opcode, void *param, size_t plen);
+int		bt_devrecv (int s, void *buf, size_t 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);
+void		bt_devfilter_pkt_set(struct bt_devfilter *filter, int type);
+void		bt_devfilter_pkt_clr(struct bt_devfilter *filter, int type);
+int		bt_devfilter_pkt_tst(struct bt_devfilter const *filter, int type);
+void		bt_devfilter_evt_set(struct bt_devfilter *filter, int event);
+void		bt_devfilter_evt_clr(struct bt_devfilter *filter, int event);
+int		bt_devfilter_evt_tst(struct bt_devfilter const *filter, int event);
+int		bt_devinquiry(char const *devname, time_t length, int num_rsp,
+			      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 191328)
+++ Makefile	(working copy)
@@ -33,6 +33,19 @@
 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_devfilter_pkt_set.3
+MLINKS+=	bluetooth.3 bt_devfilter_pkt_clr.3
+MLINKS+=	bluetooth.3 bt_devfilter_pkt_tst.3
+MLINKS+=	bluetooth.3 bt_devfilter_evt_set.3
+MLINKS+=	bluetooth.3 bt_devfilter_evt_clr.3
+MLINKS+=	bluetooth.3 bt_devfilter_evt_tst.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