|
View:
New views
20 Messages
—
Rating Filter:
Alert me
|
| < Prev | 1 - 2 - 3 | Next > |
|
|
|
|
|
Re: libhci updateMaksim 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 updateOn 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 updateOn 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 updateOn 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 updateHi 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 updateMaksim 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: paperHi 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 updateOn 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 updateMaksim 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 updateOn 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. 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). [....] >> 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. 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 updateOn 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: paperOn 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: paperIain 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 dependentHi,
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 dependentOn 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 updatedear 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 updateOn 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 updateOn 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 updateOn 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?) 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 > |
| Free embeddable forum powered by Nabble | Forum Help |