Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 15 May 2009 21:49:33 +0100 (BST)
From:      Iain Hibbert <plunky@rya-online.net>
To:        Maksim Yevmenkin <maksim.yevmenkin@gmail.com>
Cc:        freebsd-bluetooth@freebsd.org
Subject:   Re: libhci update
Message-ID:  <1242420574.009085.2429.nullmailer@galant.ukfsn.org>
In-Reply-To: <bb4a86c70905151021u2a42dd29m2edce0a011aba838@mail.gmail.com>
References:  <E1Lv5La-00058x-HH@smtpbarns01>  <bb4a86c70904211651m6127745ao9d4f26c91e428994@mail.gmail.com>  <1240386569.369073.696.nullmailer@galant.ukfsn.org>  <bb4a86c70904220909j5d047ce6x6260bd2e87b5b7bd@mail.gmail.com>  <1242294653.314348.1748.nullmailer@galant.ukfsn.org>  <bb4a86c70905140926n488cb2b5x5f5530e01d70bd66@mail.gmail.com>  <1242322384.832849.4269.nullmailer@galant.ukfsn.org>  <bb4a86c70905141140u2b1662fdrf528c157d5fe7c2e@mail.gmail.com>  <1242328962.345875.22296.nullmailer@galant.ukfsn.org>  <1242335731.252131.19040.nullmailer@galant.ukfsn.org> <bb4a86c70905151021u2a42dd29m2edce0a011aba838@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 15 May 2009, Maksim Yevmenkin wrote:

> On Thu, May 14, 2009 at 2:15 PM, Iain Hibbert <plunky@rya-online.net> wrote:
> > Hi Max,
> >        some more queries I'm not sure about..
> >
> > --- hci.c.orig  2009-05-14 21:11:04.000000000 +0100
> > +++ hci.c       2009-05-14 21:26:57.000000000 +0100
> > @@ -118,7 +118,7 @@ bt_devsend(int s, uint16_t opcode, void
> >                h.length = 0;
> >
> >        while (writev(s, iv, ivn) < 0) {
> > -               if (errno == EAGAIN || errno == EINTR)
> > +               if (errno == EINTR)
> >                        continue;
> >
> >                return (-1);
> > @@ -163,12 +163,15 @@ bt_devrecv(int s, void *buf, size_t size
> >        }
> >
> >        while ((n = read(s, buf, size)) < 0) {
> > -               if (errno == EAGAIN || errno == EINTR)
> > +               if (errno == EINTR)
> >                        continue;
> >
> >                return (-1);
> >
> > I think these two should not have EAGAIN because that can be returned if
> > the socket is set to nonblocking and we should just pass it back to the
> > caller rather than looping?
>
> i somewhat disagree. it is true that _internally_ libbluetooth does
> not set hci socket to the non-blocking mode. however,
> bt_devsend/recv() can be used with the hci socket that was created
> outside of libbluetooth.

Yes, thats the case I meant - actually I see the manpage says it should be
used with socket created by bt_devopen() but in the case where a socket
has NBIO set, bt_devrecv() will end up crazyfast looping (==bad) rather
than do poll/return as read() normally would if there is no data.

> [....]
>
> > +       if (n == 0)
> > +               return (0);
> > +
> >
> > the read() in bt_devrecv() can return 0 for EOF at least. ok it shouldn't
> > happen but do you think it would be proper to return it? (or call it an
> > error? I dunno)
>
> can it really return 0? i mean specifically when reading from
> bluetooth socket not in general. in any case the existing code will
> return EIO, i.e. error.  granted, it will try to parse data in buf,
> but it will always fail if n == 0.

Well I thought perhaps if a (eg) USB device was removed but it turns out
on NetBSD that doesn't cause the socket to EOF, it will just error out on
sending, perhaps I'm being too careful with the edge cases..

> > @@ -302,10 +307,11 @@ bt_devreq(int s, struct bt_devreq *r, ti
> >                        if (e->event == r->event) {
> >                                if (r->rlen >= n) {
> >                                        r->rlen = n;
> >                                        memcpy(r->rparam, e + 1, r->rlen);
> >                                }
> > +                               /* else what? */
> >
> > these three locations in bt_devreq() I'm not sure what should happen if
> > the provided buffer was not big enough. I suggest the following construct
> > instead:
> >
> >        if (r->rlen > n)
> >                r->rlen = n;
> >
> >        if (r->rlen > 0)
> >                memcpy(r->rparam, ..., r->rlen);
> >
> > which gives them as much as they asked for and discards the rest, how
> > would that look?
>
> i did not really know what to do here. practically, this just should
> not happen. caller is expected to know how big return parameters are
> and pass appropriately sized buffer. if the caller really does not
> care about return parameters, then no buffer should be passed.
> returning something that is incomplete is a bit broken, imo. i
> actually wrote the code like you suggested, but then decided not to do
> it this way. cant remember why :) i also considered to return EMSGSIZE
> in this case, but then deiced not do to it either. again i cant recall
> the exact reason :)
>
> since this is a relatively minor issue, lets agree on something and
> move on. i could go either way.

Well, there was a case of bad bluetooth device I saw mentioned once that
gives the inquiry_rssi_result with the wrong packet size but I can't
remember the details, perhaps you are right - in fact bt_devrecv()
explicitly makes sure that you have the complete packet so perhaps this
should just be the same. I think it should probably return an error (EIO)
though? eg

	if (r->rlen >= n) {
		r->rlen = n;
		memcpy(r->rparam, ..., r->rlen);
	} else if (r->rlen > 0) {
		error = EIO;
		goto out;
	}

> > Also, I'm thinking of the case where r->event=0 but a command_status is
> > returned. If status != 0, an error is produced but if status == 0 then we
> > should set rlen = 0 and return success?
>
> what is wrong with the existing code? it simply returns status code in
> the return parameters and let caller deal with it. why give special
> treatment to status == 0 code? as far as bt_devreq() is concern,
> request has completed, i.e. we send something  to the device and we
> got something back. since caller gave us no specifics (i.e. r->event
> == 0), caller should deal with the return parameters.

No I think you right I was misreading that, too many nestings :)

> > @@ -504,10 +510,16 @@ wait_for_more:
> >
> >        case NG_HCI_EVENT_INQUIRY_RESULT:
> >                ir = (ng_hci_inquiry_response *)(ep + 1);
> >
> >                for (n = 0; n < MIN(ep->num_responses, num_rsp); n ++) {
> >
> > I found while writing the inquiry routine in btconfig(8) that some devices
> > don't filter repeat addresses properly (or maybe its that some devices
> > continue to respond, I've seen that too). Perhaps its worth handling that
> > case inside the bt_devinquiry() function by discarding dupes?
>
> yes, i've seen that too. broadcom chips (at least in my case) have
> this behavior. how do you propose to detect the dupes? using bd_addr
> only? or match all/some parameters as well? i think it would be ok to
> remove dupes.

No just check bdaddr as it should be the same device. I've come up with
the following function to add results to the list.. to be called with
whichever data is present in relevant response and it overwrites the
earlier entry in case anything changed.

static void
bt__devresult(struct bt_devinquiry *ii, int *count, bdaddr_t *ba, uint8_t psrm,
    uint8_t pspm, uint8_t *cl, uint16_t co, int8_t rssi, uint8_t *data)
{
	int n;

	for (n = 0; n < *count; n++)
		if (bdaddr_same(&ii[n].bdaddr, ba))
			break;

	bdaddr_copy(&ii[n].bdaddr, ba);

	if (cl != NULL)
		memcpy(ii[n].dev_class, cl, HCI_CLASS_SIZE);

	ii[n].pscan_rep_mode = psrm;
	ii[n].pscan_period_mode = pspm;
	ii[n].clock_offset = le16toh(co);
	ii[n].rssi = rssi;

	if (data != NULL)
		memcpy(ii[n].data, data, 240);

	if (n == *count)
		(*count)++;
}

(I don't really like massive arglists but its better than duplicating the
code three times for inquiry_result, rssi_result and extended_result)

> > @@ -551,11 +563,11 @@ bt_devinfo(struct bt_devinfo *di)
> >                return (-1);
> >        }
> >
> >        s = bt_devopen(di->devname);
> >        if (s < 0)
> >                return (-1);
> >
> > I'm not sure if in FreeBSD you can connect() to a device that is not
> > marked up, but in NetBSD you can't. In any case, there is information in
> > the devinfo structure that is only available from activated devices so it
> > may fail?
>
> in freebsd, you can. bind()/connect() just sets device name in
> socket's pcb. in fact, in freebsd, you can bind/connect() hci socket
> to anything :)

yeah I let bind do any address since if it doesn't exist then you won't
get any messages but connect seemed wrong to connect to nothing. sendto()
also fails if the destination is unknown..

I presume that for inactive devices things like features, bdaddr and
buffer_size results will just be nil?

> >  This really relates to bt_devenum() as below, are we counting 'active'
> > devices or 'all' devices, as you ignored errors?
>
> in freebsd, we return the list of netgraph nodes. that is, device may
> be present (node exists) but not 'up'. that is what 'state' parameter
> in devinfo structure is telling you. so, in freebsd, devenum() will
> return the list of all devices.

Mm, I've fixed bt_devinfo() so it will work for inactive devices, will
think about the devenum some more. What is the 'state' parameter
containing is it just 0 = down, 1 = up or is there more?

I think devenum should probably return all devs as caller can check the
status but I'm not sure if its useful to have a socket connected to an
empty device and know no details in the down case.. what happens if you
send hci commands to a down device, nothing?

iain



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1242420574.009085.2429.nullmailer>