Re: libhci update

View: New views
20 Messages — Rating Filter:   Alert me  
< Prev | 1 - 2 - 3 | Next >

Parent Message unknown Re: libhci update

by Maksim Yevmenkin-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Bruce,

> So I decided to just go ahead and reimplement Markus Brueffer's libhci.
> I've attached a tarball of the Hg repository.

thanks!

> It would be great to have feedback from you about this.

right, a few things.

- dev_id is kinda gross, imo. Iain and i discussed this and agreed
that devname is the way to go. mapping between dev_id and devname can
be (has to be) done and i have no objection to this, however, all the
native api probably should use devname and not dev_id;

- all the hci_xxx functions (with possible exception of inquiry)
should probably be left out of the library. there is really not enough
consumers for them;

- i not sure i like, hci_xxx names; Iain and i have been discussing
this before and agreed that, bt_XXX and bt_devXXXX are better names;

i'm attaching the diffs that was sitting in my queue (still need to
update man pages). please take a look at it and let me know what you
think.

> The API is now compatible with the current BlueZ SVN code. One of the
> trade-offs involved was choosing an identifier which would fit in an 'int'
> type, as BlueZ identifies its devices using uint16_t.
>
> As a compromise, I wrote code which emulates BlueZ device enumeration
> using the Netgraph node ID (32 bits wide). Unfortunately this introduces
> a dependency on -lnetgraph, unless the Bluetooth stack is itself taught to
> produce such an identifier (and supply it via an ioctl()).

i actually went this route before :) but i opted for much simpler scheme:

#define hci_devid2type(id)      (((id) >> 12) & 0x0f)
#define hci_devid2unit(id)      ((id) & 0x0fff)
#define hci_mkdevid(type, unit) ((((type) & 0x0f) << 12) | (unit & 0x0fff))

struct hci_type2prefix {
        int             type;
        char const      *prefix;
};

static struct hci_type2prefix const     type2prefix[] =
{
        { .type = HCI_VIRTUAL,  .prefix = NULL,    },
        { .type = HCI_USB,      .prefix = "ubt",   },
        { .type = HCI_PCCARD,   .prefix = "btccc", },
        { .type = HCI_UART,     .prefix = "h4",    },
        { .type = HCI_RS232,    .prefix = NULL,    },
        { .type = HCI_PCI,      .prefix = NULL,    },
        { .type = HCI_SDIO,     .prefix = NULL,    },
        { .type = -1,           .prefix = NULL,    },   /* should be last */
};

static int
hci_name2devid(char const *name)
{
        struct hci_type2prefix const    *t;
        int                             plen, unit;
        char                            *ep;

        for (t = &type2prefix[0]; t->type != -1; t ++) {
                if (t->prefix == NULL)
                        continue;

                plen = strlen(t->prefix);
                if (strncmp(name, t->prefix, plen) != 0)
                        continue;

                unit = strtoul(name + plen, &ep, 10);
                if (*ep != '\0' &&
                    strcmp(ep, "hci") != 0 &&
                    strcmp(ep, "l2cap") != 0) {
                        errno = ENODEV;
                        return (-1);
                }

                return (hci_mkdevid(t->type, unit));
        }

        errno = ENODEV;

        return (-1);
}

static char *
hci_devid2name(int dev_id, char *name, int namelen)
{
        struct hci_type2prefix const    *t;
        int                             type, unit;

        if (dev_id >= 0) {
                type = hci_devid2type(dev_id);
                unit = hci_devid2unit(dev_id);

                for (t = &type2prefix[0]; t->type != -1; t ++) {
                        if (t->type == type && t->prefix != NULL) {
                                snprintf(name, namelen, "%s%uhci",
                                        t->prefix, unit);
                                return (name);
                        }
                }
        }

        errno = EINVAL;

        return (NULL);
}

this code is left out for now. not sure if i like it :)

> I noticed during the port that periodic inquiry doesn't actually buy us
> anything
> at all. With a CSR BlueCore4-ROM dongle, the microcontroller will not
> raise any other events *at all* at the HCI layer during inquiry.
>
> Mind you, I haven't tried any of the Bluetooth HCI 2.0/EDR commands,
> many of these are not yet implemented in the FreeBSD stack, am I right?

well, most of 2.0 commands do not need any implementation. just need
to add defines and typedefs. some events might need handling, i.e.
inquiry with rssi. but generally it should just work.

> I also had a crack at porting NetBSD's 'btconfig'. I haven't included it in
> this drop, however, it does depend on the libhci functions I have written.

how about just fixing hcicontrol(8) do to that you want? is this too much work?

> I see that NetBSD's libsdp does support 128 bit UUIDs. Whilst this is
> highly desirable, it is also a prerequisite for any of the high level
> language
> wrappers (e.g. PyBlueZ, BlueCove) which make use of SDP.

ok, i will take a look at the diffs to see what is different.

> Anyway, let me know what you think. I am eager to get the SDP issues
> knocked on the head ASAP.

right, that would likely be complete replacement of libsdp and sdpd.

thanks,
max

Index: hci.c
===================================================================
--- hci.c (revision 190594)
+++ 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.h
===================================================================
--- bluetooth.h (revision 190594)
+++ 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,11 +131,46 @@
  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);
 
+
 /*
  * bdaddr utility functions (from NetBSD)
  */

_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Bruce Simpson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Maksim Yevmenkin wrote:
>
> right, a few things.
>
> - dev_id is kinda gross, imo. Iain and i discussed this and agreed
> that devname is the way to go. mapping between dev_id and devname can
> be (has to be) done and i have no objection to this, however, all the
> native api probably should use devname and not dev_id;
>  

I agree with you here, but that doesn't change the fact that we are
potentially
being Betamax'd by BlueZ, even if not intentionally ;-)

FYI if you are not familiar with the story of Betamax: it was the
technological
superior of the VHS video cassette standard, bot of course VHS got the
dominant
market share, and therefore won out in the end.


> - all the hci_xxx functions (with possible exception of inquiry)
> should probably be left out of the library. there is really not enough
> consumers for them;
>  

I disagree. I did a fairly in-depth code audit of PyBlueZ, LightBlue, and
BlueCove. All of them use BlueZ hci_* APIs for a number of things, mostly
to do with querying properties of the local interfaces.

This might not be the case for Bluetooth daemons in the base system, and
much of what is in BlueZ, is used by its daemons.

Given that I've read a lot of BlueZ code now, I can't entirely claim that my
implementation of the API is truly clean-room.

> - i not sure i like, hci_xxx names; Iain and i have been discussing
> this before and agreed that, bt_XXX and bt_devXXXX are better names;
>  

Well, the thing is, folk have already gone off and started building
high-level
language APIs on top of the BlueZ C language APIs. I understand from the
'code purity' point of view why one would be keen to adopt this kind of
compartmentalization in terms of naming conventions.

The problem is that the horse has already left the cart. There have been
books
published on how to use Bluetooth from Java and other higher level languages
than C. It seems unreasonable, in my view, to expect folk developing
applications
in a commercial model, to have to adapt their code for BSD targets
beyond say
2 or 3 ifdef's.

I realize this might be an inelegant approach, but it's based on
observation of
harsh commercial realities.

> i'm attaching the diffs that was sitting in my queue (still need to
> update man pages). please take a look at it and let me know what you
> think.
>  

Looks very similar in places to some of the code Markus wrote which I
worked with.

We certainly need an easy to use API which doesn't concern high level
language users
with too many of the specifics of low level I/O event handling.

>> The API is now compatible with the current BlueZ SVN code. One of the
>> trade-offs involved was choosing an identifier which would fit in an 'int'
>> type, as BlueZ identifies its devices using uint16_t.
>>
>> As a compromise, I wrote code which emulates BlueZ device enumeration
>> using the Netgraph node ID (32 bits wide). Unfortunately this introduces
>> a dependency on -lnetgraph, unless the Bluetooth stack is itself taught to
>> produce such an identifier (and supply it via an ioctl()).
>>    
>
> i actually went this route before :) but i opted for much simpler scheme:
> <SNIP>
>  

Thanks for this. I would far rather not introduce a runtime or link-time
dependency
on -lnetgraph if I can possibly avoid it. I'll digest further and try to
see if this can
be incorporated.

> ...
>> raise any other events *at all* at the HCI layer during inquiry.
>>
>> Mind you, I haven't tried any of the Bluetooth HCI 2.0/EDR commands,
>> many of these are not yet implemented in the FreeBSD stack, am I right?
>>    
>
> well, most of 2.0 commands do not need any implementation. just need
> to add defines and typedefs. some events might need handling, i.e.
> inquiry with rssi. but generally it should just work.
>  

I agree with you up to the point where 'it should just work'. A lot of
what goes
on with Bluetooth is actually going on behind closed doors. There are
individuals
(whom I won't name here to defend them from any possible litigation) who
have
found it necessary to disassemble what's actually going on with the 16-bit
microcontrollers found in most Bluetooth devices.

There have also been moves on the part of the Bluetooth SIG to make it
harder
to find information about Bluetooth's actual operation itself, as I am
also sure
you are aware. Nevertheless, that's largely orthogonal to the issues of
implementing
Bluetooth 2.0/EDR compatibility. What is clear is that the BlueZ API has
moved
with the times, and ours hasn't. My hope is that by actually using
Bluetooth for
interesting applications, that will help to drive interest forward.

One observation I make from the current state of the BlueZ SVN code is
that their
primary focus is on desktop integration. If they were really serious,
this work would
already have been completed. As things stand, BlueZ as a platform is
missing a few
things which would make it easier to build Bluetooth server applications.

...
Back to periodic inquiry: I am very surprised that given Bluetooth's
value as a highly
localized network, that the implementation of periodic inquiry, a
feature pretty much
essential to building endpoint discovery in a highly dynamic network
environment,
would tie up the whole microcontroller for the duration of the inquiry.

I looked at the Bluetooth specs and I can see that the inquiry sequence
doesn't hog
all of the radio spectrum in use, but the implementation on the CSR
dongles won't
raise any other events whilst the inquiry is in progress. It's a bit of
a cop out, to be
sure, and we can certainly work around this by using a dedicated dongle
to perform
neighbor discovery. But why didn't they think about this in the spec?
That begs
the question.

>  
>> I also had a crack at porting NetBSD's 'btconfig'. I haven't included it in
>> this drop, however, it does depend on the libhci functions I have written.
>>    
>
> how about just fixing hcicontrol(8) do to that you want? is this too much work?
>  

Whilst hccontrol(8) is an excellent and very complete tool, it is
perhaps too complete
for its own good. It captures a fairly complete set of the HCI commands
normally
used to manipulate Bluetooth host controller devices. However, it isn't
terribly
user friendly.

My motivation in porting NetBSD's btconfig was more to do with the fact
that it
captures common use cases much like Linux BlueZ's hcitool -- i.e. folk
familiar
with UNIX in general become familiar with ifconfig(8), and btconfig has very
similar semantics.

Whilst in the FreeBSD case this isn't terribly important -- the
devd.conf integration
is thorough and works at boot-time just fine for building appliances --
it's not great
for operational use i.e. debugging or manual config where it's needed.

I would agree with the view that ifconfig(8) has become something of a
kitchen
sink, and whilst I wouldn't initially attempt to integrate Bluetooth
functionality
with that tool, I wouldn't rule it out, either.

>  
>> I see that NetBSD's libsdp does support 128 bit UUIDs. Whilst this is
>> highly desirable, it is also a prerequisite for any of the high level
>> language
>> wrappers (e.g. PyBlueZ, BlueCove) which make use of SDP.
>>    
>
> ok, i will take a look at the diffs to see what is different.
>  

Yeah, talk about two arrows going in opposite directions :-) I found
when hacking
with BlueCove on Windows, I had to tell it *explicity* to use 16-bit UUIDs
so that most phones could see the services it was advertising.

The SDP story is a mess, to be sure, and could do with better APIs
everywhere.

What developers tend to do, in my experience, is to avoid dealing with
platform
specifics -- *unless they absolutely have to* -- and focus on delivering the
solution with APIs that they can readily grasp.

Sadly, the SDP APIs on all platforms are sorely missing this casual
ease-of-use.

>> Anyway, let me know what you think. I am eager to get the SDP issues
>> knocked on the head ASAP.
>>    
>
> right, that would likely be complete replacement of libsdp and sdpd.
>  

If that's what it amounts to, I'll get my hands dirty. It's just
essential for what
my partner and I are trying to do, that we have high-level language bindings
for Bluetooth features essential to building a server application, working
on FreeBSD.

I am willing to help out in any way I can to drive this forward.

thanks and regards,
BMS
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Charles Oppermann-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wednesday 08 April 2009 5:27:14 pm Bruce Simpson wrote:

> I agree with you here, but that doesn't change the fact that we are
> potentially being Betamax'd by BlueZ, even if not intentionally ;-)
>
> FYI if you are not familiar with the story of Betamax: it was the
> technological superior of the VHS video cassette standard, bot of
> course VHS got the dominant market share, and therefore won
> out in the end.  

Common misconception.  The Betamax was only marginally of better quality, and any differences were not discernable to consumers.

People bought VHS-format VCR's because the first publically available recorders could record up to go 2 hours, vs. Sony's 1 hour maximum for Betamax.  When the major use of VCR's was to record movies off of cable for repeated viewings, the recording time was a major factor.  Every time Sony came up with longer recording times, JVC and RCA would stay ahead.

Sony tried very hard to position Betamax as the higher quality alternative, but Sony's 2-hour long tapes made the same compromises as VHS did.  SuperBeta tapes were higher quality than VHS, but the format war was over by the time they were available along with recorders.
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Iain Hibbert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, 9 Apr 2009, Bruce Simpson wrote:

> I disagree. I did a fairly in-depth code audit of PyBlueZ, LightBlue, and
> BlueCove. All of them use BlueZ hci_* APIs for a number of things, mostly
> to do with querying properties of the local interfaces.

I looked briefly at BlueCove the other day and it seems to use a module to
interface with the BlueZ/Linux API but it also has Windows and Mac modules
amongst others. If it needs a FreeBSD or NetBSD module then that doesn't
seem so difficult?

I looked at LightBlue but I don't remember anything about it, was it
perchance really incomplete and very BlueZ/Linux based?

> The problem is that the horse has already left the cart.

That happened many years ago when Microsoft was the leader in the
marketplace. If you want to stay with the horse, use Windows.

> There have been books published on how to use Bluetooth from Java and
> other higher level languages than C. It seems unreasonable, in my view,
> to expect folk developing applications in a commercial model, to have to
> adapt their code for BSD targets beyond say 2 or 3 ifdef's.

so write a module that interfaces (for example) the Java (BlueCove?) API
to the FreeBSD OS layer. Its not that different from the BlueZ/Linux API
and you can probably just do some copy and paste work. Thats how the GPL
world works. Yes, you will not be able to integrate that work directly
into FreeBSD but then I doubt a Java interface is ever going to be
accepted into base anyway. Donate it to BlueCove.

> I realize this might be an inelegant approach, but it's based on
> observation of harsh commercial realities.

If its commercial, get those companies to contribute some BSD code.

> We certainly need an easy to use API which doesn't concern high level
> language users with too many of the specifics of low level I/O event
> handling.

as you say, the Java API is one such.

> Thanks for this. I would far rather not introduce a runtime or link-time
> dependency on -lnetgraph if I can possibly avoid it. I'll digest further
> and try to see if this can be incorporated.

But I thought, on FreeBSD the whole bluetooth stack is netgraph based..?

My stance on the compatibility issue is that there are some things in the
BlueZ/Linux C API (the major thing being 'devid' to address the radio)
that are tied to the actual OS support and are unsupportable unless you
provide exactly the same API in the OS. But, OS support is way too low
level for an application to deal (with as you say), and a higher level API
is needed that does not contain such specifics.

The BlueZ guys are, I think, working on a dbus API that will be used by
GNOME and KDE and hopefully it won't be tied to the Linux OS API so
closely, so that we can write dbus modules and have applications just work
on our OS.  I have not been providing any input or review of that API
though, it would be good if somebody would step up and point out where the
API is tied too closely to the Linux OS interface and get them to make it
a bit more generic.

> I looked at the Bluetooth specs and I can see that the inquiry sequence
> doesn't hog all of the radio spectrum in use, but the implementation on
> the CSR dongles won't raise any other events whilst the inquiry is in
> progress.

Is this purely a CSR problem?  My laptop has a Broadcom chip in and I
notice that it can make multiple connections concurrently in that on
bootup, it connects to both my mouse and keyboard by itself sometimes -
the CSR dongle I used previously would connect to the keyboard fine but
always fail the second connect with "Command Disallowed".  So much so that
I thought perhaps about serialising connection attempts in the kernel.

I've never looked at periodic inquiry though..

> > right, that would likely be complete replacement of libsdp and sdpd.
>
> If that's what it amounts to, I'll get my hands dirty. It's just
> essential for what my partner and I are trying to do, that we have
> high-level language bindings for Bluetooth features essential to
> building a server application, working on FreeBSD.

I have written at least a set of SDP primitives that I'm intending to
import to NetBSD 'soon' (I have only one computer and am concentrating on
5.0 release first because running different OS versions is messy)

I think the latest archive was at

  http://www.netbsd.org/~plunky/sdp-20090227.tar.gz

iain
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Maksim Yevmenkin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Apr 9, 2009 at 12:00 AM, Iain Hibbert <plunky@...> wrote:

> On Thu, 9 Apr 2009, Bruce Simpson wrote:
>
>> I disagree. I did a fairly in-depth code audit of PyBlueZ, LightBlue, and
>> BlueCove. All of them use BlueZ hci_* APIs for a number of things, mostly
>> to do with querying properties of the local interfaces.
>
> I looked briefly at BlueCove the other day and it seems to use a module to
> interface with the BlueZ/Linux API but it also has Windows and Mac modules
> amongst others. If it needs a FreeBSD or NetBSD module then that doesn't
> seem so difficult?

right, that is something i kinda wondering too. of course, i have no
idea how hard it would be to plug new bluetooth module into bluecove.
perhaps cost of adding the new bluetooth module more than implementing
something that looks like bluez?

>> The problem is that the horse has already left the cart.
>
> That happened many years ago when Microsoft was the leader in the
> marketplace. If you want to stay with the horse, use Windows.

the real question is: do we really want to follow the horse? :)
personally, i think that we should keep an eye on bluez etc. to see
where its going, but blindly follow it, is not something we want to
do, imo,

having said that, we have to recognize the fact that there is lots of
code that is bluez specific. so, how about we separate flies from
meatballs, and, meet halfway:

1) we put bsd-style bluetooth api and make sure it is shared with as
many bsd's (and possibly other os's) as possible. i  personally would
like to continue to work with Iain and get his input. this api is
going into the base system and will be bsd-licensed. obviously, we
will keep an eye on bluez while designing and implementing bsd
bluetooth api.

2) to ensure compatibility with bluez we create a separate library and
put it into the ports/ collection. it can even use original libhci
headers and re-use original libhci code if needed. missing/different
parts will have to be re-implemented in terms of bsd bluetooth api.
this way it would probably be easier to play catch up game with bluez
and it will be less of pain for folks who use bsd bluetooth api.
basically, if you choose bluez api be prepared to change your code
every time bluez folks change something.

>> There have been books published on how to use Bluetooth from Java and
>> other higher level languages than C. It seems unreasonable, in my view,
>> to expect folk developing applications in a commercial model, to have to
>> adapt their code for BSD targets beyond say 2 or 3 ifdef's.
>
> so write a module that interfaces (for example) the Java (BlueCove?) API
> to the FreeBSD OS layer. Its not that different from the BlueZ/Linux API
> and you can probably just do some copy and paste work. Thats how the GPL
> world works. Yes, you will not be able to integrate that work directly
> into FreeBSD but then I doubt a Java interface is ever going to be
> accepted into base anyway. Donate it to BlueCove.

well, it depends on how hard it is to add such module. i can certainly
see and understand yours and Bruce's point.

>> I realize this might be an inelegant approach, but it's based on
>> observation of harsh commercial realities.
>
> If its commercial, get those companies to contribute some BSD code.

oh, well, sometimes it is not as easy as it sounds.

>> Thanks for this. I would far rather not introduce a runtime or link-time
>> dependency on -lnetgraph if I can possibly avoid it. I'll digest further
>> and try to see if this can be incorporated.
>
> But I thought, on FreeBSD the whole bluetooth stack is netgraph based..?

yes, but in userspace you almost never need to use anything netgraph
related. almost everything can be done through sockets.

> My stance on the compatibility issue is that there are some things in the
> BlueZ/Linux C API (the major thing being 'devid' to address the radio)
> that are tied to the actual OS support and are unsupportable unless you
> provide exactly the same API in the OS. But, OS support is way too low
> level for an application to deal (with as you say), and a higher level API
> is needed that does not contain such specifics.

mostly agreed. its not really that bad with devid. we could invent
some "static" mapping between devname and devid. Bruce used id's from
netgraph,  i used (dev_type|unit_no) for mapping, and, i'm sure, you
can find something as simple as this. it really does not matter that
much as long as the application that uses devid's is not making any
assumptions about them (for example does not hardwire devid 0 - or
whatever - anywhere to talk to the first available bluetooth device).

> The BlueZ guys are, I think, working on a dbus API that will be used by
> GNOME and KDE and hopefully it won't be tied to the Linux OS API so
> closely, so that we can write dbus modules and have applications just work
> on our OS.  I have not been providing any input or review of that API
> though, it would be good if somebody would step up and point out where the
> API is tied too closely to the Linux OS interface and get them to make it
> a bit more generic.

right, and that is a very good point. that is something that i have to
deal with every day at $realjob. things in linux world change very
rapidly. from commercial point of view it is very annoying. its not
that uncommon that entire subsystems are being thrown away and
re-written from scratch without too much consideration. that is why i
think having a separate libhci/ port is making more sense here.

>> I looked at the Bluetooth specs and I can see that the inquiry sequence
>> doesn't hog all of the radio spectrum in use, but the implementation on
>> the CSR dongles won't raise any other events whilst the inquiry is in
>> progress.
>
> Is this purely a CSR problem?  My laptop has a Broadcom chip in and I
> notice that it can make multiple connections concurrently in that on
> bootup, it connects to both my mouse and keyboard by itself sometimes -
> the CSR dongle I used previously would connect to the keyboard fine but
> always fail the second connect with "Command Disallowed".  So much so that
> I thought perhaps about serialising connection attempts in the kernel.

that's right, some dongles would not do 2 or more create_connection
commands at the same time. i do not think specification actually
mandates this, so it is probably vendor/chip/firmware specific.

as far as periodic inquiry goes, its probably not the rf spectrum
hogging. its probably related to the way hardware and/or link manager
is implemented, i.e. from specification

<quote>

A unit that wants to discover other Bluetooth units enters an inquiry substate.
In this substate, it continuously transmits the inquiry message (which is the ID
packet, see Section 4.4.1.1 on page 55) at different hop frequencies. The
inquiry hop sequence is always derived from the LAP of the GIAC. Thus, even
when DIACs are used, the applied hopping sequence is generated from the
GIAC LAP.

</quote>

the key thing is that device has to continuously transmits the inquiry
message at different hop frequencies. at the same time the same device
may participate in another connection (which may require hopping as
well).

> I've never looked at periodic inquiry though..

me too. but now i'm interested :)

thanks
max
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Bruce Simpson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi guys,

I really hate to be long-winded with this... but it seems there are a
number of thorny issues
in the Bluetooth area which we need to carefully consider and act upon
going forward.

Iain Hibbert wrote:
> I looked briefly at BlueCove the other day and it seems to use a module to
> interface with the BlueZ/Linux API but it also has Windows and Mac modules
> amongst others. If it needs a FreeBSD or NetBSD module then that doesn't
> seem so difficult?
>  

I had literally spent two evenings before staring at
PyBluez/LightBlue/BlueCove
code on my ThinkPad, whilst lying on my mother's sofa, and after hacking
MLDv2
into FreeBSD-CURRENT's IPv6 stack.

When I hacked on libhci I was on a train from Glasgow to London last
Thursday evening, and let me tell you, I was staring at KScope a lot!

Of course it's also to do with the fact that BlueZ libhci is an API which is
being used by a number of apps out there, so I had more example material
to work
from, having waded into this knowing NOTHING about the existing APIs.

If you look at the differences between netbt, FreeBSD bluetooth, and BlueZ,
it's ifdef city. Nothing is all that different under the hood in terms
of meaning,
or role within the stack, but every possible thing is named differently.

In terms of porting/compatibility, my focus has been on developing shims
for the BlueZ API, given its relative wide adoption in the open source
software available for Bluetooth, rather than hacking BSD native support
code,
as this just seemed like the quicker path towards my goal: Python support
for building Bluetooth server apps, on a FreeBSD based system.

I also wanted to minimize the diff sets required for interoperability. In my
experience, the smaller patches are, the more likely third parties are to
take them on upstream.


> I looked at LightBlue but I don't remember anything about it, was it
> perchance really incomplete and very BlueZ/Linux based?
>  

Yes, LightBlue is actually quite incomplete, although it is intended to
be dog simple.

Some technical detail follows:

LightBlue relies on PyBlueZ as a prerequisite, and uses a handful of
libhci functions, as well
as requiring OpenOBEX. It is also GPLv3'd which is off-putting to say
the least
for commercial use.

Trouble is, PyBlueZ is actually very tied to some BlueZ specifics, i.e.
the HCI interface
in particular. Any time we need to reach down to baseband, which you end
up doing to
implement neighbor discovery, you need to use HCI. SDP alone just
doesn't cut it;
paging every device in the immediate vicinity is quite an expensive
operation.

It is the only Python native binding I know of which ties OBEX on top of
Bluetooth
in a similar way to that of Java JSR-82's 'SessionNotifier' interface --
which is what we
really need for building Bluetooth server apps. We found Python's
HTTPServer very
useful indeed, and having something like an OBEXServer would be just
right for us.

However, LightBlue has the limitation that it doesn't have any support
for multiple
devices/enumeration, unless you go directly to PyBlueZ, and doesn't
support a
event driven interface for Bluetooth server apps -- its APIs are
strictly synchronous
function calls.
Same for its OBEXClient class, however at least that can have some
methods overridden,
but still isn't as flexible as we would like it to be.

To be fair, it isn't a lot of code, and implementing a new Python API
similar to
LightBlue would not take too much time, provided the foundations are in
place.

The real fly in the soup is the fact that the BlueZ bindings I've seen,
are all tied
to BlueZ's use of a 16 bit wide identifier for each local Bluetooth
device in
device enumeration. These end up leaking into the APIs. That's just
unavoidable,
as it is still reasonable that there is a means of referring to devices
without
opening them. In an ideal world we'd be able to use a string identifier, but
that is not what's happened NOW.

JSR-82 is less tied up in this way, but it still assumes that there is
an integer
device ID unique to each local device which will fit in a Java JNI jint
type.

...

To summarize: I'm just concerned that in focusing too much on building a
clean / BSD native API, we risk sidelining ourselves. There has been a
lot of Bluetooth
activity in the Linux community, and by not having at least some degree of
source level compatibility, we risk not being able to leverage and make use
of that work which we could otherwise benefit from for small change cost.

There is no 'standard' for high level Bluetooth APIs that I am aware of,
other than
JSR-82, and wider adoption of a platform tends to wind up with it being
'de-facto'
standard. Whether we like it or not, it's a harsh reality of software work.
Hence my comparison to Betamax/VHS in my original reply.

I myself, I just get sick and tired of having to HACK HACK HACK every time
someone writes a neato little app for BlueZ. This situation is endemic
simply
because Linux has a popularity which the BSDs don't, as such it can
potentially
attract a greater number of folk getting into software dev for the first
time,
or on a hobbyist basis. I realize that this might be an unpopular view
in the BSD
camp, but that is how it looks from where I'm standing.

[I've been living on the edge with this stuff for months, and I really
just want
to make progress so I can focus on more fun things in life than fscking
computers!!]

> so write a module that interfaces (for example) the Java (BlueCove?) API
> to the FreeBSD OS layer. Its not that different from the BlueZ/Linux API
> and you can probably just do some copy and paste work. Thats how the GPL
> world works. Yes, you will not be able to integrate that work directly
> into FreeBSD but then I doubt a Java interface is ever going to be
> accepted into base anyway. Donate it to BlueCove.
>  

Well, that's exactly my point, I am not for one moment suggesting we
fold JSR-82
into any base system... but time is critical and we need to work with
what's already there,
unless someone comes up with a compelling alternative NOW.

> If its commercial, get those companies to contribute some BSD code.
>  

That's a reasonable statement, but for the fact that...

...The companies either don't exist or are potential competitors who aren't
using BSD or Linux -- or, WE are the potential companies!

My partner and I are already working on this, so it is very much a matter of
beg borrow or steal. There seems no sense, to my mind, in reinventing
wheels...

There are competing interests in this space, but they've had the CapEx to go
off and implement their own platforms. As to the business end of it, whether
that's a tax write-off for investment purposes I know and care not, it's
just
what any new player would be up against in the Bluetooth space.

>  
>> Thanks for this. I would far rather not introduce a runtime or link-time
>> dependency on -lnetgraph if I can possibly avoid it. I'll digest further
>> and try to see if this can be incorporated.
>>    
>
> But I thought, on FreeBSD the whole bluetooth stack is netgraph based..?
>  

It is, but generally the libbluetooth / libsdp libraries 'get away' with
not touching
Netgraph directly, as the Netgraph ng_btsocket node exposes a number of
socket options
and ioctls which require no knowledge/linkage to Netgraph in order to use.

I just ended up going to Netgraph to perform BlueZ style device
enumeration, which
needs an integer handle (a bit like an ifnet ifindex in the network
stack), rather than
a textual name.

The code which Maksim posted would help us to side step this in any
prospective
libhci compatibility library.

> My stance on the compatibility issue is that there are some things in the
> BlueZ/Linux C API (the major thing being 'devid' to address the radio)
> that are tied to the actual OS support and are unsupportable unless you
> provide exactly the same API in the OS. But, OS support is way too low
> level for an application to deal (with as you say), and a higher level API
> is needed that does not contain such specifics.
>  

Sure, but I don't have free time to come up with such a higher level
API, and as such,
I need to work with what's already out there.

Of course, if anyone else is willing to volunteer to work on this, they
are more than
welcome to do so, but the problem with assembling a product / strategy
based on that,
is, we need to know how much it's going to cost, and how much time it's
going to take,
i.e. when will it be ready.

Hence my interest in leveraging what is already out there *NOW*. It is
in no way a
technical or political endorsement of any particular approach, camp,
product, or
philosophy, it is a purely pragmatic approach to the reality of working with
limited resources and time. :-)

As I say, I'm not trying to tread on anyone's toes, or otherwise rule
out good and
technically valid solutions. We just needed this thing months ago and
it's not there.

> The BlueZ guys are, I think, working on a dbus API that will be used by
> GNOME and KDE and hopefully it won't be tied to the Linux OS API so
> closely, so that we can write dbus modules and have applications just work
> on our OS.  I have not been providing any input or review of that API
> though, it would be good if somebody would step up and point out where the
> API is tied too closely to the Linux OS interface and get them to make it
> a bit more generic.
>  

Yes they are, however, as I've hinted at before, they seem focused on
this and little
else. Back in January my colleague Alexei (Cc'd)and I did some work with
the latest
BlueZ bluetoothd frm SVN. We were astonished and dismayed to find that
operations
critical to the receiving of files had completely changed, i.e. the
'inquiry scan'
setting, and the documentation had not been updated.

Whilst we had discovered and found the problem, and documented a workaround,
we had a demo suffer from a technical hitch because of this issue.

Of course, it is fair to argue that we get what we deserve for trying to
work with
the bleeding edge of development. However, this wasn't just a few minor
changes,
the entire configuration mechanism had been rewritten, with no documentation
other than the code.

I could care less about Linux or BSD specifics at this point. If folk
want to create
new APIs, please do so -- I ain't stopping you! And if I can help out, I
will.

I'm certainly receptive to everyone's ideas here given their technical
merit, but it
should be borne in mind that we have a very specific goal.


>  
>> I looked at the Bluetooth specs and I can see that the inquiry sequence
>> doesn't hog all of the radio spectrum in use, but the implementation on
>> the CSR dongles won't raise any other events whilst the inquiry is in
>> progress.
>>    
>
> Is this purely a CSR problem?  My laptop has a Broadcom chip in and I
> notice that it can make multiple connections concurrently in that on
> bootup, it connects to both my mouse and keyboard by itself sometimes -
> the CSR dongle I used previously would connect to the keyboard fine but
> always fail the second connect with "Command Disallowed".  So much so that
> I thought perhaps about serialising connection attempts in the kernel.
>  

I doubt that the issue with inquiry tying up the controller is limited
to CSR dongles,
but it's one area where we either need to engage the vendor directly and
ask them what
the story is, or conduct experiments to map out the behaviour in the
time domain
amongst different vendors and models (very time consuming).

If you look at the specs, inquiry keeps the controller quite busy. There
are several different
inquiry variants, and they all involve frequency hopping, and the
transmission of the
inquiry sequence. It's mostly baseband stuff and doesn't involve e.g.
L2CAP layer.

The inquiry sub-state, as described in the spec, doesn't preclude other
HCI events
during the inquiry, however it does recommend that ACL transports be parked,
as it only reserves slots for SCO.

I haven't delved deep enough to see if FreeBSD Bluetooth is doing ACL
park when
periodic inquiry is active, I wager it doesn't, and what we're actually
seeing is the
client device attempting to reconnect after the inquiry sub-state is
left, after
seeing no reply.


> I've never looked at periodic inquiry though..
>  

Periodic inquiry is basically the same as regular inquiry, with the
exception that the
periodic timer is hosted by the microcontroller itself. When the timer
fires, it will
drop just about everything else that it's doing, mind you I've seen with
OBEX sessions
running at the same time, it will either pick them up once inquiry has
finished, or
finish the OBEX session (RFCOMM) before starting inquiry.

Of course given that it will not generate any event upcall at HCI layer
for any other
baseband protocol event during the inquiry, it's of very limited
usefulness for real apps.

The only application I've seen which uses it is the Bluetooth
scanner/sniffer/brute forcer
'Fine Tooth Comb' from shmoo.com.

> I have written at least a set of SDP primitives that I'm intending to
> import to NetBSD 'soon' (I have only one computer and am concentrating on
> 5.0 release first because running different OS versions is messy)
>
> I think the latest archive was at
>   http://www.netbsd.org/~plunky/sdp-20090227.tar.gz
>  

Thanks for this, I'll be sure to take a look once I can download it.

I don't seem to be able to reach www.netbsd.org at the moment, either
from my home
ISP connection, or from freefall.freebsd.org. :-(

I am very grateful for your input and feedback, and hope that we can get
this
ball rolling faster.

cheers,
BMS
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Bruce Simpson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Maksim Yevmenkin wrote:

> On Thu, Apr 9, 2009 at 12:00 AM, Iain Hibbert <plunky@...> wrote:
>  
>> I looked briefly at BlueCove the other day and it seems to use a module to
>> interface with the BlueZ/Linux API but it also has Windows and Mac modules
>> amongst others. If it needs a FreeBSD or NetBSD module then that doesn't
>> seem so difficult?
>>    
>
> right, that is something i kinda wondering too. of course, i have no
> idea how hard it would be to plug new bluetooth module into bluecove.
> perhaps cost of adding the new bluetooth module more than implementing
> something that looks like bluez?
>  

That's exactly the question I set about reading code in order to answer.

The short version is, yes, in my opinion it's easier to just crib the
existing APIs
rather than rewrite the OS support code for all of these higher layer
Bluetooth
APIs completely from scratch.

Dealing with JNI code can be a bit messy. I don't do Java on a daily
basis so I'm
less inclined to get my hands dirty with ant build.xml files. Other
folks' mileage
may vary.

>  
> having said that, we have to recognize the fact that there is lots of
> code that is bluez specific. so, how about we separate flies from
> meatballs, and, meet halfway:
>  

A bit of background:

The whole reason we migrated to BSD in the first place was simply because it
offered a faster route to building an appliance-like product than
customizing Linux,
unless we purchased an expensive license for a Linux derived embedded
distribution.

There are alternatives in the Linux space to this too, but even they
have a high degree
of change cost associated with them.

We're talking about the difference between 1.5 man- days and 10
man-days. From
a business point of view, that's a no brainer.

If you look at the libhci drop I provided, you'll see I've tried to keep
the BlueZ and
NetBT compatibility shims separate from the core API. It is ifdef city.

Iain: If you want to see this code give me a shout and I'll throw it up
somewhere.

I would hope to do the same for libsdp.

> 1) we put bsd-style bluetooth api and make sure it is shared with as
> many bsd's (and possibly other os's) as possible. i  personally would
> like to continue to work with Iain and get his input. this api is
> going into the base system and will be bsd-licensed. obviously, we
> will keep an eye on bluez while designing and implementing bsd
> bluetooth api.
>  

The thing is, if we go down this road, it would be wise to name the BSD
libraries, structs and functions completely differently from their Linux
counterparts,
due to exactly the situation you describe so well below.

As I say, I am happy to play along and adapt what I'm doing to the base
system work
that you guys want to do, however, the crucial part is that we are able
to develop
something without having to go directly to C/C++ every time. Doing this
kind of work
to the standard required, and on time, is difficult, and not all folk
working as developers
in this space have the requisite skills, nor the time to battle-test
such code.

Also, hardcore C/C++ comms software developers are not folk you can just
pick up
on a recruitment milk round. ;-)

Accessibility is paramount. Projects like PyBlueZ already go far towards
achieving
this goal, which is why they are important. It's much easier to
prototype, test, and
design in Python, than it is in C. The development cycle is much shorter.

> 2) to ensure compatibility with bluez we create a separate library and
> put it into the ports/ collection. it can even use original libhci
> headers and re-use original libhci code if needed. missing/different
> parts will have to be re-implemented in terms of bsd bluetooth api.
> this way it would probably be easier to play catch up game with bluez
> and it will be less of pain for folks who use bsd bluetooth api.
> basically, if you choose bluez api be prepared to change your code
> every time bluez folks change something.
>
>  

Yes. BlueCove actually already has to do this for some SDP specifics -- it
will do a dlopen() of libhci, look for a given function name, and it
will use
different SDP calls if a certain function isn't present.

Some Linux-related projects have had something of a poor track record as
regards
change control and versioning of APIs. Yes, they do push further and
faster, but
we are then left with a legacy of kludge, much like GLIBC, which just
gets in
the way when trying to deliver product.

I agree that it's reasonable to push a compatibility layer into ports.
If you look
at what Luigi Rizzo did with Linux USB webcam drivers, you'll see this
too --
it saves code churn on the FreeBSD SVN repository. And separate change
control for this kind of project is preferable for all sorts of reasons.


>> But I thought, on FreeBSD the whole bluetooth stack is netgraph based..?
>>    
>
> yes, but in userspace you almost never need to use anything netgraph
> related. almost everything can be done through sockets.
>  

Provided the ioctls are there :-) I have not needed to touch Netgraph
specifics apart
from this one thorny problem of getting a unique integer ID for each
interface.

Of course, persistence of the identifier between reboots / changes is a
whole other
matter -- and it affects e.g. Ethernet interfaces too.

The way BlueZ has chosen to deal with this problem, in the 4.x/SVN
train, is to
keep bluetoothd state under /var/lib/bluetooth/ma:ca:dd:re:ss/*. But it
still means
that the dev_id has to be looked up at runtime, and thence the device
opened.

To be fair, this is no different e.g. from a standards-aware IP
multicast application
having to be aware of each individual link configured in the system,
although a lot
of grotty code in open-source land still isn't doing this (even though
it's been in the
RFCs for WAYYY over 5 years -- Come on guys, it's even in the
textbooks... and
the more TCP and Torrent saturated the 'Net gets, the more multicast
matters!!)

I would love to hear everyone's thoughts on how to deal with this issue.

>  
>> My stance on the compatibility issue is that there are some things in the
>> BlueZ/Linux C API (the major thing being 'devid' to address the radio)
>> that are tied to the actual OS support and are unsupportable unless you
>> provide exactly the same API in the OS. But, OS support is way too low
>> level for an application to deal (with as you say), and a higher level API
>> is needed that does not contain such specifics.
>>    
>
> mostly agreed. its not really that bad with devid. we could invent
> some "static" mapping between devname and devid. Bruce used id's from
> netgraph,  i used (dev_type|unit_no) for mapping, and, i'm sure, you
> can find something as simple as this. it really does not matter that
> much as long as the application that uses devid's is not making any
> assumptions about them (for example does not hardwire devid 0 - or
> whatever - anywhere to talk to the first available bluetooth device).
>
>  

That seems reasonable.

I should point out that a lot of the BlueZ consumer code I've looked at is
using 'hci_get_route(NULL)' to get a dev_id for the first available dongle.

It's actually a deceptively named API because it does not perform a
'route lookup'
as such, it doesn't look at neighbour caches, LMP connection handles, etc.

It just looks for the first dongle which doesn't correspond to the
argument provided.


... re DBus:
> right, and that is a very good point. that is something that i have to
> deal with every day at $realjob. things in linux world change very
> rapidly. from commercial point of view it is very annoying. its not
> that uncommon that entire subsystems are being thrown away and
> re-written from scratch without too much consideration. that is why i
> think having a separate libhci/ port is making more sense here.
>  

That is exactly the barrier which Alexei and I ran head first into back
in January,
when we seriously started looking at this space.

Again, the chaotic approach will let one push forward thick and fast, but it
doesn't always yield the best long term result.

As I say, I haven't had time to look at the DBus integration to figure
out in which
respects it differs, or is Linux/BlueZ specific. The BlueZ project team
focus at
the moment seems to be on DBus.

What is clear is that the KDE bluetooth subsystem had to be completely
rewritten for the new DBus semantics.

...
> that's right, some dongles would not do 2 or more create_connection
> commands at the same time. i do not think specification actually
> mandates this, so it is probably vendor/chip/firmware specific.
>  

It is most likely a case of 'you get the Bluetooth LMP stack you pay
for'. ;-)

If you look at the list of Bluetooth SIG members, most of them aren't in
a pure software play,
but have invested in doing the baseband and microcontroller work from
the ground up.

CSR and Broadcom are manufacturing mass-market Bluetooth devices. I'm
sure they
supply specialized product line to the mobile phone industry, but in the
main, Bluetooth
chipsets intended for use with PCs are probably more limited in what
they can do than
what is actually possible with what's inside the plastic.

This is another reason why Iain's suggestion that we appeal to such
companies to contribute
BSD code may fall down -- the chances are, if they are looking to
dominate the space, they
have probably already invested in proprietary OS solutions for building
platforms.

Although I certainly can't speak for Iain's relationship with Itronix, I
am most interested
and curious about their reasons for diving into the Bluetooth space, and
why NetBSD
of all platforms  ;-)  ...given who their main customer base is.

Also, there has been a movement in terms of strategy by technology
companies to
adopt GPLv2 as an alternative, not because they believe it gives them
some open
source credibility, although that is part of the smokescreen sometimes
-- more because
the terms of the GPLv2 force potential competitors to give you their code,
if they derive their work from yours.

That isn't cut and dried fact, it's just based on observation of who is
doing what and why.


> as far as periodic inquiry goes, its probably not the rf spectrum
> hogging. its probably related to the way hardware and/or link manager
> is implemented, i.e. from specification
> ...
>
> the key thing is that device has to continuously transmits the inquiry
> message at different hop frequencies. at the same time the same device
> may participate in another connection (which may require hopping as
> well).
>  

Yup, please see my other recent reply to Iain where I noted down the bit
in the specs
about it being *suggests* that ACLs are held/parked/sniffed, however,
the spec
does not make this mandatory -- except for eSCO frames, which have
reserved time
slots at the Bluetooth baseband layer.

At the moment, FreeBSD's stack doesn't do SCO, to my knowledge, nor do my
colleague or I make use of SCO yet.
it is something we'd want to play with in the not so distant future, though.

cheers,
BMS
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Speeding up device discovery: paper

by Bruce Simpson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi all,

I found this paper an interesting skim, even if only for the numbers and
timings:
   
http://faculty.cs.byu.edu/~knutson/publications/IrDA_Assisted_BT_Discovery.pdf

It is very much a rehash of the old broadcast vs point-to-point dichotomy.

I don't think IrDA is the answer for most deployments, but it's an
interesting piece of research
as it sheds light on how the discovery mechanisms operate (without
having to read the entire
specification), and how these might be sped up or worked around.

I keep wishing Bluetooth had passive scanning like 802.11 does.

cheers...
BMS
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Maksim Yevmenkin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Apr 9, 2009 at 11:36 AM, Bruce Simpson <bms@...> wrote:
> Maksim Yevmenkin wrote:

[...]

>>  having said that, we have to recognize the fact that there is lots of
>> code that is bluez specific. so, how about we separate flies from
>> meatballs, and, meet halfway:
>>
>
> A bit of background:
>
> The whole reason we migrated to BSD in the first place was simply because it
> offered a faster route to building an appliance-like product than
> customizing Linux,
> unless we purchased an expensive license for a Linux derived embedded
> distribution.
>
> There are alternatives in the Linux space to this too, but even they have a
> high degree
> of change cost associated with them.
>
> We're talking about the difference between 1.5 man- days and 10 man-days.
> From
> a business point of view, that's a no brainer.
>
> If you look at the libhci drop I provided, you'll see I've tried to keep the
> BlueZ and
> NetBT compatibility shims separate from the core API. It is ifdef city.
>
> Iain: If you want to see this code give me a shout and I'll throw it up
> somewhere.

yes, i looked at it. i saw what are you talking about.

believe me, i know *exactly* what are you talking about here. that is
why i suggested to put your existing code to ports/. this way you get
to use it right now and avoid re-hacking things all the time. hell, if
we were talking only about freebsd here, i would probably not object
to put it into the base right now. however, i really, really want to
keep compatibility and consistency here. at least with other bsd's.
i'm still kicking myself for putting all those ng_ prefixes everywhere
in userland code and not choosing location for headers wisely (it was
long time ago and i was not a committer back then, so everything was
developed outside of the main tree). i wish someone would point it to
me back then.

anyway, the last thing i want to do is to introduce even more
differences. most likely (and correct me if i wrong here) Iain would
never accept something like libhci into base. at least not in its
current form.

> 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.

>> 1) we put bsd-style bluetooth api and make sure it is shared with as
>> many bsd's (and possibly other os's) as possible. i  personally would
>> like to continue to work with Iain and get his input. this api is
>> going into the base system and will be bsd-licensed. obviously, we
>> will keep an eye on bluez while designing and implementing bsd
>> bluetooth api.
>
> The thing is, if we go down this road, it would be wise to name the BSD
> libraries, structs and functions completely differently from their Linux
> counterparts,
> due to exactly the situation you describe so well below.

yes, unfortunately that is true, but that is where libhci compat port
comes to the rescue. yes, it would not be pretty. yes, most functions
will just copy data and silly stuff like that. but it least it will be
separate and will be maintainable (or so i hope).

> As I say, I am happy to play along and adapt what I'm doing to the base
> system work
> that you guys want to do, however, the crucial part is that we are able to
> develop
> something without having to go directly to C/C++ every time. Doing this kind
> of work
> to the standard required, and on time, is difficult, and not all folk
> working as developers
> in this space have the requisite skills, nor the time to battle-test such
> code.

i understand and can relate to what you are saying. again, we do not
keep things like python, gmake, autoconf, etc. etc. in base. we do
keep them in ports/. so, imo, it makes sense to keep libhci compat
layer in ports/ too. you get to use bluez libhci and we get to keep
our base tree clean. its a win-win to me :)

>> 2) to ensure compatibility with bluez we create a separate library and
>> put it into the ports/ collection. it can even use original libhci
>> headers and re-use original libhci code if needed. missing/different
>> parts will have to be re-implemented in terms of bsd bluetooth api.
>> this way it would probably be easier to play catch up game with bluez
>> and it will be less of pain for folks who use bsd bluetooth api.
>> basically, if you choose bluez api be prepared to change your code
>> every time bluez folks change something.
>
> Yes. BlueCove actually already has to do this for some SDP specifics -- it
> will do a dlopen() of libhci, look for a given function name, and it will
> use
> different SDP calls if a certain function isn't present.

why even bother with that? just install compat library and have all
the symbols available, no?

> I agree that it's reasonable to push a compatibility layer into ports. If
> you look
> at what Luigi Rizzo did with Linux USB webcam drivers, you'll see this too
> --
> it saves code churn on the FreeBSD SVN repository. And separate change
> control for this kind of project is preferable for all sorts of reasons.

great!

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).

>>> But I thought, on FreeBSD the whole bluetooth stack is netgraph based..?
>>
>> yes, but in userspace you almost never need to use anything netgraph
>> related. almost everything can be done through sockets.
>
> Provided the ioctls are there :-) I have not needed to touch Netgraph
> specifics apart
> from this one thorny problem of getting a unique integer ID for each
> interface.

let me know what is missing and i will add it :)

> Of course, persistence of the identifier between reboots / changes is a
> whole other
> matter -- and it affects e.g. Ethernet interfaces too.

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.

> The way BlueZ has chosen to deal with this problem, in the 4.x/SVN train, is
> to
> keep bluetoothd state under /var/lib/bluetooth/ma:ca:dd:re:ss/*. But it
> still means
> that the dev_id has to be looked up at runtime, and thence the device
> opened.
>
> To be fair, this is no different e.g. from a standards-aware IP multicast
> application
> having to be aware of each individual link configured in the system,
> although a lot
> of grotty code in open-source land still isn't doing this (even though it's
> been in the
> RFCs for WAYYY over 5 years -- Come on guys, it's even in the textbooks...
> and
> the more TCP and Torrent saturated the 'Net gets, the more multicast
> matters!!)
>
> I would love to hear everyone's thoughts on how to deal with this issue.

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?

>>> My stance on the compatibility issue is that there are some things in the
>>> BlueZ/Linux C API (the major thing being 'devid' to address the radio)
>>> that are tied to the actual OS support and are unsupportable unless you
>>> provide exactly the same API in the OS. But, OS support is way too low
>>> level for an application to deal (with as you say), and a higher level
>>> API
>>> is needed that does not contain such specifics.
>>
>> mostly agreed. its not really that bad with devid. we could invent
>> some "static" mapping between devname and devid. Bruce used id's from
>> netgraph,  i used (dev_type|unit_no) for mapping, and, i'm sure, you
>> can find something as simple as this. it really does not matter that
>> much as long as the application that uses devid's is not making any
>> assumptions about them (for example does not hardwire devid 0 - or
>> whatever - anywhere to talk to the first available bluetooth device).
>
> That seems reasonable.
>
> I should point out that a lot of the BlueZ consumer code I've looked at is
> using 'hci_get_route(NULL)' to get a dev_id for the first available dongle.
>
> It's actually a deceptively named API because it does not perform a 'route
> lookup'
> as such, it doesn't look at neighbour caches, LMP connection handles, etc.
>
> It just looks for the first dongle which doesn't correspond to the argument
> provided.

yep, the whole devid vs. devname difference only matters when you have
more than 1 radio connected to the system. 99% of the people have only
1 radio, so it does not matter that much.

[...]

>> that's right, some dongles would not do 2 or more create_connection
>> commands at the same time. i do not think specification actually
>> mandates this, so it is probably vendor/chip/firmware specific.
>
> It is most likely a case of 'you get the Bluetooth LMP stack you pay for'.
> ;-)
>
> If you look at the list of Bluetooth SIG members, most of them aren't in a
> pure software play,
> but have invested in doing the baseband and microcontroller work from the
> ground up.
>
> CSR and Broadcom are manufacturing mass-market Bluetooth devices. I'm sure
> they
> supply specialized product line to the mobile phone industry, but in the
> main, Bluetooth
> chipsets intended for use with PCs are probably more limited in what they
> can do than
> what is actually possible with what's inside the plastic.

i actually have a hands on experience with csr bluecore chips. i did
some work with csr bluecore chips and csr bluelab sdk. i'm not sure if
you know, but bluecore chips are actually bluetooth system-on-chip.
that is you can run custom application on the chip itself. before
bluecore5 the application was running inside the virtual machine
running on bluecore. starting with bluecore5 you actually have a
choice to run application natively or run it inside vm.

firmware for bluecore chips comes in few flavors: low end goes up to
hci layer only. that is what you will find in almost all consumer
bluetooth dongles that use csr bluecore. in fact, almost all of them
are based on bluecore-rom reference designs that are available from
csr. high end goes up to rfcomm and hid layers. then you also have
bluecoreX-mm (multimedia) chips that have dsp on board. those are
typically used in mid/high end bluetooth headsets. the whole headset
profile is actually running on bluecore chip. no external
microcontroller is required.

some dongles have dual personality - typical for hid dongles, i.e. you
can have it to act as usb hub with keyboard and mouse (hid) or you can
boot it into hci-only mode and it will look like regular bluetooth
device.

[...]

> At the moment, FreeBSD's stack doesn't do SCO, to my knowledge, nor do my
> colleague or I make use of SCO yet.
> it is something we'd want to play with in the not so distant future, though.

there are some bits and pieces in various degree of working'ness :)

thanks,
max
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Bruce Simpson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Maksim Yevmenkin wrote:

> believe me, i know *exactly* what are you talking about here. that is
> why i suggested to put your existing code to ports/. this way you get
> to use it right now and avoid re-hacking things all the time. hell, if
> we were talking only about freebsd here, i would probably not object
> to put it into the base right now. however, i really, really want to
> keep compatibility and consistency here. at least with other bsd's.
> i'm still kicking myself for putting all those ng_ prefixes everywhere
> in userland code and not choosing location for headers wisely (it was
> long time ago and i was not a committer back then, so everything was
> developed outside of the main tree). i wish someone would point it to
> me back then.
>  

well said :-)  It takes balls to admit our mistakes :-)
but we all make them, it's called "learning"... :-)

> anyway, the last thing i want to do is to introduce even more
> differences. most likely (and correct me if i wrong here) Iain would
> never accept something like libhci into base. at least not in its
> current form.
>  

Yup, base system addition isn't really my intent :-)

>  
>> 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.

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?

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.

> i understand and can relate to what you are saying. again, we do not
> keep things like python, gmake, autoconf, etc. etc. in base. we do
> keep them in ports/. so, imo, it makes sense to keep libhci compat
> layer in ports/ too. you get to use bluez libhci and we get to keep
> our base tree clean. its a win-win to me :)
>  

Yup. Shipping in ports means we ship more quickly.

We've had to overcome some hurdles with 7.2-RELEASE, to be sure, but
most of what we
needed in the NOW, has been dealt with, and it's in FreeBSD 7.2 which
will be shipping
any minute now.

I loathe autotools with a passion, having had to hack with it
extensively for a living.

[re BlueCove dlopen() lameness]
> why even bother with that? just install compat library and have all
> the symbols available, no?
>  

Now that you mention it, if libhci gets folded off into ports (hey,
let's call it comms/libhci),
it gets much easier...

>  
>> I agree that it's reasonable to push a compatibility layer into ports. If
>> you look
>> at what Luigi Rizzo did with Linux USB webcam drivers, you'll see this too
>> --
>> it saves code churn on the FreeBSD SVN repository. And separate change
>> control for this kind of project is preferable for all sorts of reasons.
>>    
>
> great!
>
> 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.

We are tracking SVN stable/7 here, so even if it doesn't make it into
7.2-RELEASE,
all is not lost for what my partner and I are trying to do.

[ioctls]
> let me know what is missing and i will add it :)
>  

What's the easiest way to get the unit number?
...

I think your non-Netgraph based solution is simpler and more elegant,
although it was nice to have
the exercise of getting my hands dirtier with Netgraph :-)

>  
> 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).

    BTW: I should point out that FreeBSD doesn't actually do this for
network interfaces at the moment
in the base system in any automated way. The udev mechanisms in Linux
distributions do have
some provision for this. You can tell it to tie down instances to
specific PCI fields, usually vendor/chip.

    It does bite ifnets in particular because FreeBSD's NEWBUS code
generally probes PCI buses
in the opposite order from Linux -- so dual-booted systems end up with a
different device tree,
as the unit numbers are assigned in inverse order.
    The way people tend to work around this in practice is to construct
some sort of device registry
of their own, on top of what's already in base. I know previous clients
of mine have been doing
this, without naming names, and I know pfSense does something like this.

> 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.

...
> yep, the whole devid vs. devname difference only matters when you have
> more than 1 radio connected to the system. 99% of the people have only
> 1 radio, so it does not matter that much.
>  

Absolutely.

Only when you actually want to do something that is a bit more
complicated than uploading
your home-made pornography to your laptop, does having more than 1
Bluetooth radio
get important.

;-D

> [...]
>
>
>  
> some dongles have dual personality - typical for hid dongles, i.e. you
> can have it to act as usb hub with keyboard and mouse (hid) or you can
> boot it into hci-only mode and it will look like regular bluetooth
> device.
>  

I saw this when using dfutool under Linux to flash a generic
BlueCore4-EXT dongle with the
generic CSR firmware. It turned out this image was extracted from a
MacBook integrated
Bluetooth dongle, so it presented itself as a USB HID device.

_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Maksim Yevmenkin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Apr 9, 2009 at 1:48 PM, Bruce Simpson <bms@...> 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

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

_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Iain Hibbert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, 9 Apr 2009, Maksim Yevmenkin wrote:

> On Thu, Apr 9, 2009 at 1:48 PM, Bruce Simpson <bms@...> wrote:
> > 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.

My view is that the on-the-wire format is not actually difficult to deal
with :) Certainly at the C level where the application programmer must
generally deal with data formats directly anyway. and the library handles
the common cases of talking to a remote device and fetching the data you
need.

Yes, I think it is desireable to create a higher level object oriented
class based API (Python, C++, Java etc) but any such can build on top of
the data manipulation primitives I've made (and, I'm a C programmer so its
likely not me that will define it :) or use its own.

> yes, we can. i was actually thinking to merge add the sdp stuff into
> libbluetooth.

definitely this and its not that difficult.

> and while i'm at it, move bluetooth.h and sdp.h into
> include/bluetooth/ where it belongs.

this is more problematic though and I don't think it is necessary. Because
include files are only needed at build time, the fact of filenames
conflicting with build environment can be worked around by adjusting the
build environment. (I think pkgsrc manages this, if ports does not then it
needs to :)

> 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.

You could just use the enumeration number as device_id although that
causes problems if you remove a device as it will change.

Or, just assign an incrementing number for every device inserted. I don't
see why you would have to care that the device had previously been
inserted or try to produce the same number, as trying to manage a truly
dynamic hardware configuration is going to be a nightmare however you look
at it and I don't see why we should try to encourage it :)

(nor do I concede in any way that requiring the user to *ever* provide a
'device number' is a good idea)

> >>  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?

In fact FreeBSD does this already, you can just list the device bdaddr in
your hosts file and refer to it as 'white_dongle' or whatever you want. I
resisted this in NetBSD (somebody asked for it once but he didn't want to
have a public discussion about it so I remained unconvinced) and provided
bt_devaddr(3) as I think it could be better to have a generic method of
device mapping rather than a bunch of subsystem hacks.

> > and also, BlueCove/JSR-82, PyBlueZ and the other high level language
> > stuff currently wants to use dev_id as the unique endpoint identifier.
> > :-(

I don't understand this; BlueCove is a Java API and I don't see (looking
at the website) anything about device_id in the API? They provide
LocalDevice class which is obscure - it might use dev_id internally in the
BlueZ module but surely the Windows module does not?

iain
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: Speeding up device discovery: paper

by Iain Hibbert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, 9 Apr 2009, Bruce Simpson wrote:

> I keep wishing Bluetooth had passive scanning like 802.11 does.

I always thought that was what 'periodic inquiry' was supposed to be, that
a device would take time every n seconds to do a quick neighbor
discovery..

btw something you might run into with multiple radios is that I find
creating a baseband link does not always work first time, but if the radio
has seen the other device recently via inquiry, it can connect very
quickly. I'm not sure if this is the radio recording some information
about the remote device or that the OS reusing the clock offset is
helping, but neither will help if you have one radio doing the inquiry and
the other doing the paging..

iain
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: Speeding up device discovery: paper

by Bruce Simpson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Iain Hibbert wrote:
> On Thu, 9 Apr 2009, Bruce Simpson wrote:
>  
>> I keep wishing Bluetooth had passive scanning like 802.11 does.
>>    
> I always thought that was what 'periodic inquiry' was supposed to be, that
> a device would take time every n seconds to do a quick neighbor
> discovery..
>  

Over the last 24 hours or so I've digested a number of interesting
research papers on the subject...

    What is clear is that inquiry is perhaps the most expensive
Bluetooth operation possible, in terms of power and baseband behaviour.
The IrDA paper makes it clear that session initiation may still be
faster if you can communicate the BD_ADDR of the station using a
side-band, in this case, IrDA.

    However, this paper makes it clear that the 10.24s inquiry time
quoted by the Bluetooth spec may be excessive, although their figures
are based on models, not experimental work:

   Bluetooth Inquiry Time Characterization and Selection
   Peterson/Baldwin/Kharoufeh
   http://netlab.cs.ucla.edu/wiki/files/01661527.pdf

    In this paper they do mention that using the Bluetooth V1.2
'Interlaced Inquiry Scan' feature can improve discovery times for each
station by several *seconds*, but of course making sure it's turned on
depends entirely on your station vendor.

...of course, every time you want to turn stuff like this on, you are
either relying on the host controller to turn it on for you, or you need
to send explicit HCI commands to the HC to bring it up (Errg, libhci!)

    It is also a pity that you never get an HCI event from your HC when
it enters Inquiry Scan state and actually responds to an inquiry -- but
then again the Inquiry protocol is asymmetric, it's not peer-to-peer,
it's a bit like ARP without any source/destination field on a purely
broadcast medium, and you never get to find out anything about who
inquires or why, so Inquiry presents no opportunities for passive
endpoint discovery. Yuck.

    I haven't read far enough to determine what kind of admission
control exists, if any, for preventing pre-V1.2 station(s) from forming
an adjacency with the station(s) which one is running.
    It seems analogous to the problems caused by admitting 802.11b STAs
into an 802.11a/g capable ESS. It would be nice if EDR use could be
forced, although obviously that isn't backwards compatible.

Of course, if any of this stuff were easy, everyone would be doing it by
now.

> btw something you might run into with multiple radios is that I find
> creating a baseband link does not always work first time, but if the radio
> has seen the other device recently via inquiry, it can connect very
> quickly. I'm not sure if this is the radio recording some information
> about the remote device or that the OS reusing the clock offset is
> helping, but neither will help if you have one radio doing the inquiry and
> the other doing the paging..
>  

    That probably needs further inspection at baseband layer to figure
out what's going on. It is more than likely that the host controller is
tracking some info about the peer in some internal cache...

    I find that PalmOS 5 devices always try to inquire first, even if
you have an entry in the persistent neighbour cache with which you could
page. Paging is always more efficient than Inquiry, but of course
requires you know the BD_ADDR. Nokia Series 60 handsets seem to do much
better and can page with what they already have, in fact, out of most of
the handsets I've worked with, Nokia's Bluetooth support seems more mature.

cheers
BMS
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

BlueZ dbus binding is device dependent

by Bruce Simpson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

So, just to confirm, I read the code examples in this BlueZ Wiki article;
and it does indeed appear that the naming convention BlueZ uses in DBus
is BlueZ dependent:-
    http://wiki.bluez.org/wiki/HOWTO/DiscoveringDevices

Hmmm! Whatever do we do about that.
BMS
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: BlueZ dbus binding is device dependent

by Iain Hibbert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sat, 11 Apr 2009, Bruce Simpson wrote:

> So, just to confirm, I read the code examples in this BlueZ Wiki article;
> and it does indeed appear that the naming convention BlueZ uses in DBus is
> BlueZ dependent:-
>    http://wiki.bluez.org/wiki/HOWTO/DiscoveringDevices

first, that API may not be the same as the BlueZ 4.x series which I think
has been evolving. The wiki main page says the API is best defined by the
documents in the bluez releases.

second, I'm not sure if it is a total disaster. The device being
referenced is at least a string "/org/bluez/hci0" rather than the integer
dev_id that the bluez library uses. That can be worked on fairly easily,
plus I might have seen a comment on the bluez list (which I subscribed to
but don't really read) that hardcoded defs are to be frowned on, I think
there is a way to find local devices.

Then, the module name "org.bluez" is probably not needed to change - for
instance if a GNOME application uses the bluez dbus module, I think that
all calls end up passed to bluetoothd and 'all that is required' is having
a bluez compatible bluetoothd. Whether the bluez bluetoothd can be easily
patched or if a fork or a rewrite is required I don't know. I looked at
the bluez sources but I don't have any context for it so am just
confused..

iain
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Maksim Yevmenkin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

dear freebsd-bluetoth@ users,

please find attached patch that implements more compatibility shims.
any comments are greatly appreciated.

thanks
max

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

_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Iain Hibbert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, 15 Apr 2009, Maksim Yevmenkin wrote:

> please find attached patch that implements more compatibility shims.
> any comments are greatly appreciated.

+int
+bt_devsend(int s, uint16_t ogf, uint16_t ocf, int plen, void *param)

One thing that I did when writing the NetBSD stack which IMHO made source
somewhat cleaner was provide HCI_CMD_xxxx definintions that included the
OGF and OCF directly, eg

#define HCI_OGF_LINK_CONTROL 0x01
#define HCI_OCF_INQUIRY 0x0001
#define HCI_CMD_INQUIRY 0x0401

It could be considered a remote possibility of a namespace conflict (ie
same command in different groups) but I doubt that it will ever happen
(and would be easily handled). That would make this into

+int
+bt_devsend(int s, uint16_t cmd, int plen, void *param)

thoughts?

Also, plen should be a size_t and it should come after the pointer, see
write, read, memcpy, snprintf etc for prior art :)

+int
+bt_devrecv(int s, uint8_t *buf, int size, time_t to)

and ditto for size_t here

+int
+bt_devinquiry(char const *devname, int length, int num_rsp,
+ uint8_t const *lap, struct bt_devinquiry **ii)

I wonder if allowing for a different LAP is at all useful?  I would say,
for the very remote possibility that somebody wants to do that, they could
just cut and past the code..

Also with inquiry, would it make sense to just pass a time_t and calculate
the 'inquiry length' internally?

+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;
+};

Does this structure need to be a direct copy of the inquiry result?
page_scan_period_mode and page_scan_mode are deprecated since a long time
so its probably not worth providing the values (most devices return 0
that I've seen).

We also need to [be able] to handle the inquiry-result-with-rssi which
gives an extra int8_t RSSI value, and the 2.1 extended inquiry result
data. For both of those, I think its ok if they are zero if not provided.
(ie actual support can be added later)

struct bt_devinquiry {
        bdaddr_t bdaddr;
        uint8_t pscan_rep_mode;
        uint8_t class[HCI_CLASS_SIZE];
        uint16_t clock_offset;
        int8_t rssi;
        uint8_t data[HCI_EXTENDED_INQUIRY_DATA_SIZE];
};

?

+int
+bt_devfilter(int s, struct bt_devfilter const *new, struct bt_devfilter *old)

And finally, the HCI filter is slightly different in NetBSD (I provided
independent PKT and EVT filters each of 256 bits) and I'm going to think
about that..

regards,
iain
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Iain Hibbert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, 16 Apr 2009, Iain Hibbert wrote:

> +int
> +bt_devfilter(int s, struct bt_devfilter const *new, struct bt_devfilter *old)
>
> And finally, the HCI filter is slightly different in NetBSD (I provided
> independent PKT and EVT filters each of 256 bits) and I'm going to think
> about that..

Ok, I'm not objecting in priniciple to coupling the two filters together
but I think that bt_devfilter should be opaque enough that the API does
not depend about its internal structure. Ie, requiring the caller to
subtract 1 and manage the bitwise manipulation

+ f.event_mask |= (1 << (NG_HCI_EVENT_INQUIRY_COMPL - 1));
+ f.event_mask |= (1 << (NG_HCI_EVENT_INQUIRY_RESULT - 1));

is too specific and makes the callers somewhat messy. Can we provide some
kind of accessor functions to do that?  I include below what I used in
NetBSD for an example..

Also, at least for events, the full 256 bits is required because there are
events such as 0xfe (BT Logo) and 0xff (Vendor) that may currently be
returned and the highest value (in 2.1 spec) is 0x3d, dangerously close to
the 64 bit limit. Although its not likely that there will be many packet
types added, it could be that some manufacturers would introduce custom
packet types with similarly high end values.. (eg for private device
configuration?)

regards,
iain

/*
 * HCI socket filter and get/set routines
 *
 * for ease of use, we filter 256 possible events/packets
 */
struct hci_filter {
        uint32_t mask[8]; /* 256 bits */
};

static __inline void
hci_filter_set(uint8_t bit, struct hci_filter *filter)
{
        uint8_t off = bit - 1;

        off >>= 5;
        filter->mask[off] |= (1 << ((bit - 1) & 0x1f));
}

static __inline void
hci_filter_clr(uint8_t bit, struct hci_filter *filter)
{
        uint8_t off = bit - 1;

        off >>= 5;
        filter->mask[off] &= ~(1 << ((bit - 1) & 0x1f));
}

static __inline int
hci_filter_test(uint8_t bit, struct hci_filter *filter)
{
        uint8_t off = bit - 1;

        off >>= 5;
        return (filter->mask[off] & (1 << ((bit - 1) & 0x1f)));
}
_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."

Re: libhci update

by Maksim Yevmenkin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Apr 16, 2009 at 5:15 AM, Iain Hibbert <plunky@...> wrote:

> On Thu, 16 Apr 2009, Iain Hibbert wrote:
>
>> +int
>> +bt_devfilter(int s, struct bt_devfilter const *new, struct bt_devfilter *old)
>>
>> And finally, the HCI filter is slightly different in NetBSD (I provided
>> independent PKT and EVT filters each of 256 bits) and I'm going to think
>> about that..
>
> Ok, I'm not objecting in priniciple to coupling the two filters together
> but I think that bt_devfilter should be opaque enough that the API does
> not depend about its internal structure. Ie, requiring the caller to
> subtract 1 and manage the bitwise manipulation
>
> +       f.event_mask |= (1 << (NG_HCI_EVENT_INQUIRY_COMPL - 1));
> +       f.event_mask |= (1 << (NG_HCI_EVENT_INQUIRY_RESULT - 1));
>
> is too specific and makes the callers somewhat messy. Can we provide some
> kind of accessor functions to do that?  I include below what I used in
> NetBSD for an example..
>
> Also, at least for events, the full 256 bits is required because there are
> events such as 0xfe (BT Logo) and 0xff (Vendor) that may currently be
> returned and the highest value (in 2.1 spec) is 0x3d, dangerously close to
> the 64 bit limit. Although its not likely that there will be many packet
> types added, it could be that some manufacturers would introduce custom
> packet types with similarly high end values.. (eg for private device
> configuration?)
thanks for the feedback. i'm attaching revisited patch. please take a
look and let me know if this is something you happy with.

thanks,
max

Index: hci.c
===================================================================
--- hci.c (revision 191012)
+++ 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, uint8_t *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 191012)
+++ 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" "uint8_t *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,211 @@
 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 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        opcode;
+        uint16_t        event;
+        void            *cparam;
+        int             clen;
+        void            *rparam;
+        int             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 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 +692,6 @@
 .Sh AUTHORS
 .An Maksim Yevmenkin Aq m_evmenkin@...
 .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 191012)
+++ 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;
+ uint16_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, uint8_t *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 191012)
+++ 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

_______________________________________________
freebsd-bluetooth@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth
To unsubscribe, send any mail to "freebsd-bluetooth-unsubscribe@..."
< Prev | 1 - 2 - 3 | Next >