On Tue, Apr 21, 2009 at 3:53 AM, Iain Hibbert <[email protected]> wrote:
> On Mon, 20 Apr 2009, Maksim Yevmenkin wrote:
>
>> >> 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 :)
>
> Ok also in bt_devrecv()
>        - return type should be ssize_t
>        - size cannot be < 0 (use "size == 0")?

sure. i changed it.

> and what of validation of received data here?  It could be worth checking
> that the buffer is not truncated so that the caller does not have to worry
> about it, but that does require checking the packet type..

why not? :) i added it as well.

>> > 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.
>
> Mm, its a good point - there are arguments either way (bloat vs guaranteed
> success) but I think since the difference between devreq() and devrecv()
> is that devreq() handles all the fiddly details for you, I think its worth
> doing that aswell..

fine. it now sets and restores filter :)

>> > 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.
>
> My thought was that some of the 'fields' do seem to cross over into
> multiple bytes (eg the service class flags in the default format type) and
> perhaps its easier to interpret as a single value where bits can be tested
> in host order by such as (class & (1 << N))? I don't know how much that
> helps but the assigned numbers document does seem to show it as a bit
> array. (I'm not having a strong opinion either :)

left it as 3 bytes array for now.

>> > 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.
>
> No, I mean to specifically mention ".Xr free 3" as the method used to
> dispose of the buffer.

ah, i see. man page was updated.

the revised diff is attached. please review.

thanks,
max
Index: hci.c
===================================================================
--- hci.c       (revision 191329)
+++ hci.c       (working copy)
@@ -30,15 +30,497 @@
  * $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 && param != NULL) || (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);
+}
+
+ssize_t
+bt_devrecv(int s, void *buf, size_t size, time_t to)
+{
+       fd_set          rfd;
+       struct timeval  tv;
+       ssize_t         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);
+       }
+
+       switch (*((uint8_t *) buf)) {
+       case NG_HCI_CMD_PKT: {
+               ng_hci_cmd_pkt_t        *h = (ng_hci_cmd_pkt_t *) buf;
+
+               if (n >= sizeof(*h) && n == (sizeof(*h) + h->length))
+                       return (n);
+               } break;
+
+       case NG_HCI_ACL_DATA_PKT: {
+               ng_hci_acldata_pkt_t    *h = (ng_hci_acldata_pkt_t *) buf;
+
+               if (n >= sizeof(*h) && n == (sizeof(*h) + le16toh(h->length)))
+                       return (n);
+               } break;
+
+       case NG_HCI_SCO_DATA_PKT: {
+               ng_hci_scodata_pkt_t    *h = (ng_hci_scodata_pkt_t *) buf;
+
+               if (n >= sizeof(*h) && n == (sizeof(*h) + h->length))
+                       return (n);
+               } break;
+
+       case NG_HCI_EVENT_PKT: {
+               ng_hci_event_pkt_t      *h = (ng_hci_event_pkt_t *) buf;
+
+               if (n >= sizeof(*h) && n == (sizeof(*h) + h->length))
+                       return (n);
+               } break;
+       }
+
+       errno = EIO;
+       return (-1);
+}
+
+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);
+       struct bt_devfilter             old, new;
+       time_t                          t_end;
+       uint16_t                        opcode;
+       ssize_t                         n;
+       int                             error;
+
+       if (s < 0 || r == NULL || to < 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if ((r->rlen == 0 && r->rparam != NULL) ||
+           (r->rlen > 0 && r->rparam == NULL)) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       memset(&new, 0, sizeof(new));
+       bt_devfilter_pkt_set(&new, NG_HCI_EVENT_PKT);
+       bt_devfilter_evt_set(&new, NG_HCI_EVENT_COMMAND_COMPL);
+       bt_devfilter_evt_set(&new, NG_HCI_EVENT_COMMAND_STATUS);
+       if (r->event != 0)
+               bt_devfilter_evt_set(&new, r->event);
+
+       if (bt_devfilter(s, &new, &old) < 0)
+               return (-1);
+
+       error = 0;
+
+       n = bt_devsend(s, r->opcode, r->cparam, r->clen);
+       if (n < 0) {
+               error = errno;
+               goto out;       
+       }
+
+       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) {
+                       error = errno;
+                       goto out;
+               }
+
+               if (e->type != NG_HCI_EVENT_PKT) {
+                       error = EIO;
+                       goto out;
+               }
+
+               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);
+                               }
+
+                               goto out;
+                       }
+                       break;
+
+               case NG_HCI_EVENT_COMMAND_STATUS:
+                       if (cs->opcode == opcode) {
+                               if (r->event != NG_HCI_EVENT_COMMAND_STATUS) {
+                                       if (cs->status != 0) {
+                                               error = EIO;
+                                               goto out;
+                                       }
+                               } else {
+                                       if (r->rlen >= n) {
+                                               r->rlen = n;
+                                               memcpy(r->rparam, cs, r->rlen);
+                                       }
+
+                                       goto out;
+                               }
+                       }
+                       break;
+
+               default:
+                       if (e->event == r->event) {
+                               if (r->rlen >= n) {
+                                       r->rlen = n;
+                                       memcpy(r->rparam, e + 1, r->rlen);
+                               }
+
+                               goto out;
+                       }
+                       break;
+               }
+       } while (to > 0);
+
+       error = ETIMEDOUT;
+out:
+       bt_devfilter(s, &old, NULL);
+
+       if (error != 0) {
+               errno = error;
+               return (-1);
+       }
+
+       return (0);
+}
+
+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, uint8_t type)
+{
+       bit_set(filter->packet_mask, type - 1);
+}
+
+void
+bt_devfilter_pkt_clr(struct bt_devfilter *filter, uint8_t type)
+{
+       bit_clear(filter->packet_mask, type - 1);
+}
+
+int
+bt_devfilter_pkt_tst(struct bt_devfilter const *filter, uint8_t type)
+{
+       return (bit_test(filter->packet_mask, type - 1));
+}
+
+void
+bt_devfilter_evt_set(struct bt_devfilter *filter, uint8_t event)
+{
+       bit_set(filter->event_mask, event - 1);
+}
+
+void
+bt_devfilter_evt_clr(struct bt_devfilter *filter, uint8_t event)
+{
+       bit_clear(filter->event_mask, event - 1);
+}
+
+int
+bt_devfilter_evt_tst(struct bt_devfilter const *filter, uint8_t 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 +535,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 +543,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 +608,7 @@
 
        rval = 0;
 bad:
-       close(s);
+       bt_devclose(s);
 
        return (rval);
 }
@@ -205,6 +675,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 191329)
+++ 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 ssize_t
+.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" "uint8_t type"
+.Ft void
+.Fn bt_devfilter_pkt_clt "struct bt_devfilter *filter" "uint8_t type"
+.Ft int
+.Fn bt_devfilter_pkt_tst "struct bt_devfilter const *filter" "uint8_t type"
+.Ft void
+.Fn bt_devfilter_evt_set "struct bt_devfilter *filter" "uint8_t event"
+.Ft void
+.Fn bt_devfilter_evt_clt "struct bt_devfilter *filter" "uint8_t event"
+.Ft int
+.Fn bt_devfilter_evt_tst "struct bt_devfilter const *filter" "uint8_t 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,237 @@
 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, otherwise it should be set to zero.
+The
+.Dv HCI
+Command Complete and Command Status events are enabled by default.
+The
+.Fa rparam
+and
+.Fa rlen
+parameters specify buffer and buffer size respectively where return
+parameters should be placed.
+The
+.Fn bt_devreq
+function temporarily modifies 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,
+using
+.Xr calloc 3 ,
+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 using
+.Xr free 3
+call.
+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 +718,6 @@
 .Sh AUTHORS
 .An Maksim Yevmenkin Aq [email protected]
 .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 191329)
+++ 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);
+ssize_t                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, uint8_t type);
+void           bt_devfilter_pkt_clr(struct bt_devfilter *filter, uint8_t type);
+int            bt_devfilter_pkt_tst(struct bt_devfilter const *filter, uint8_t 
type);
+void           bt_devfilter_evt_set(struct bt_devfilter *filter, uint8_t 
event);
+void           bt_devfilter_evt_clr(struct bt_devfilter *filter, uint8_t 
event);
+int            bt_devfilter_evt_tst(struct bt_devfilter const *filter, uint8_t 
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 191329)
+++ 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
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "[email protected]"

Reply via email to