diff options
| -rw-r--r-- | AUTHORS | 3 | ||||
| -rw-r--r-- | COPYING | 340 | ||||
| -rw-r--r-- | ChangeLog | 339 | ||||
| -rw-r--r-- | INSTALL | 236 | ||||
| -rw-r--r-- | Makefile.am | 18 | ||||
| -rw-r--r-- | NEWS | 0 | ||||
| -rw-r--r-- | README | 35 | ||||
| -rw-r--r-- | acinclude.m4 | 76 | ||||
| -rw-r--r-- | bluez.m4 | 40 | ||||
| -rw-r--r-- | bluez.pc.in | 10 | ||||
| -rwxr-xr-x | bootstrap | 7 | ||||
| -rwxr-xr-x | bootstrap-configure | 10 | ||||
| -rw-r--r-- | configure.in | 24 | ||||
| -rw-r--r-- | include/Makefile.am | 14 | ||||
| -rw-r--r-- | include/bluetooth.h | 149 | ||||
| -rw-r--r-- | include/bnep.h | 153 | ||||
| -rw-r--r-- | include/cmtp.h | 69 | ||||
| -rw-r--r-- | include/hci.h | 1842 | ||||
| -rw-r--r-- | include/hci_lib.h | 213 | ||||
| -rw-r--r-- | include/hidp.h | 85 | ||||
| -rw-r--r-- | include/l2cap.h | 204 | ||||
| -rw-r--r-- | include/rfcomm.h | 102 | ||||
| -rw-r--r-- | include/sco.h | 62 | ||||
| -rw-r--r-- | include/sdp.h | 503 | ||||
| -rw-r--r-- | include/sdp_lib.h | 619 | ||||
| -rw-r--r-- | src/Makefile.am | 9 | ||||
| -rw-r--r-- | src/bluetooth.c | 448 | ||||
| -rw-r--r-- | src/hci.c | 2489 | ||||
| -rw-r--r-- | src/sdp.c | 4421 | 
29 files changed, 12520 insertions, 0 deletions
| diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..2c545128 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +Maxim Krasnyansky <maxk@qualcomm.com> +Marcel Holtmann <marcel@holtmann.org> +Stephen Crane <steve.crane@rococosoft.com> diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..3912109b --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ +		    GNU GENERAL PUBLIC LICENSE +		       Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. +                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +			    Preamble + +  The licenses for most software are designed to take away your +freedom to share and change it.  By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users.  This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it.  (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.)  You can apply it to +your programs, too. + +  When we speak of free software, we are referring to freedom, not +price.  Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +  To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +  For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have.  You must make sure that they, too, receive or can get the +source code.  And you must show them these terms so they know their +rights. + +  We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +  Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software.  If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +  Finally, any free program is threatened constantly by software +patents.  We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary.  To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + +  The precise terms and conditions for copying, distribution and +modification follow. + +		    GNU GENERAL PUBLIC LICENSE +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +  0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License.  The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language.  (Hereinafter, translation is included without limitation in +the term "modification".)  Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope.  The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +  1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +  2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +    a) You must cause the modified files to carry prominent notices +    stating that you changed the files and the date of any change. + +    b) You must cause any work that you distribute or publish, that in +    whole or in part contains or is derived from the Program or any +    part thereof, to be licensed as a whole at no charge to all third +    parties under the terms of this License. + +    c) If the modified program normally reads commands interactively +    when run, you must cause it, when started running for such +    interactive use in the most ordinary way, to print or display an +    announcement including an appropriate copyright notice and a +    notice that there is no warranty (or else, saying that you provide +    a warranty) and that users may redistribute the program under +    these conditions, and telling the user how to view a copy of this +    License.  (Exception: if the Program itself is interactive but +    does not normally print such an announcement, your work based on +    the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole.  If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works.  But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +  3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +    a) Accompany it with the complete corresponding machine-readable +    source code, which must be distributed under the terms of Sections +    1 and 2 above on a medium customarily used for software interchange; or, + +    b) Accompany it with a written offer, valid for at least three +    years, to give any third party, for a charge no more than your +    cost of physically performing source distribution, a complete +    machine-readable copy of the corresponding source code, to be +    distributed under the terms of Sections 1 and 2 above on a medium +    customarily used for software interchange; or, + +    c) Accompany it with the information you received as to the offer +    to distribute corresponding source code.  (This alternative is +    allowed only for noncommercial distribution and only if you +    received the program in object code or executable form with such +    an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it.  For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable.  However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +  4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License.  Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +  5. You are not required to accept this License, since you have not +signed it.  However, nothing else grants you permission to modify or +distribute the Program or its derivative works.  These actions are +prohibited by law if you do not accept this License.  Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +  6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions.  You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +  7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License.  If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all.  For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices.  Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +  8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded.  In such case, this License incorporates +the limitation as if written in the body of this License. + +  9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time.  Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number.  If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation.  If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + +  10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission.  For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this.  Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + +			    NO WARRANTY + +  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +		     END OF TERMS AND CONDITIONS + +	    How to Apply These Terms to Your New Programs + +  If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +  To do so, attach the following notices to the program.  It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + +    <one line to give the program's name and a brief idea of what it does.> +    Copyright (C) <year>  <name of author> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + +    Gnomovision version 69, Copyright (C) year name of author +    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. +    This is free software, and you are welcome to redistribute it +    under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License.  Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary.  Here is a sample; alter the names: + +  Yoyodyne, Inc., hereby disclaims all copyright interest in the program +  `Gnomovision' (which makes passes at compilers) written by James Hacker. + +  <signature of Ty Coon>, 1 April 1989 +  Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs.  If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library.  If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..2ef82dcd --- /dev/null +++ b/ChangeLog @@ -0,0 +1,339 @@ +ver 3.36: +	Fix various includes for cross-compilation. + +ver 3.35: +	Add two additional company identifiers. + +ver 3.34: +	Replace various SDP functions with safe versions. +	Add additional length validation for incoming SDP packets. + +ver 3.33: +	Add functions for reading and writing the link policy settings. +	Add definition for authentication requirements. +	Enable PIE by default if supported. + +ver 3.32: +	Add OCF constants for synchronous flow control enabling. + +ver 3.31: +	Don't optimize when debug is enabled. + +ver 3.30: +	Add another company identifier. + +ver 3.29: +	Fix memory leak in sdp_get_uuidseq_attr function. + +ver 3.28: +	Add support for MCAP UUIDs. + +ver 3.27: +	Add another company identifier. + +ver 3.26: +	Fix compilation problem with USHRT_MAX and UCHAR_MAX. + +ver 3.25: +	Update copyright information. + +ver 3.24: +	Add definitions for MDP. + +ver 3.23: +	Fix remote name request handling bug. + +ver 3.22: +	Fix remote name request event handling. + +ver 3.21: +	Add constant for Bluetooth socket options level. + +ver 3.20: +	Add support for inquiry transmit power level. + +ver 3.19: +	Add L2CAP mode constants. + +ver 3.18: +	Don't allocate memory for the Bluetooth base UUID. + +ver 3.17: +	Fix supported commands bit calculation. + +ver 3.16: +	Update company identifier list. + +ver 3.15: +	Extract main service class for later use. + +ver 3.14: +	Add definitions and functions for Simple Pairing. + +ver 3.13: +	Update HCI command table. + +ver 3.12: +	Add missing HCI command text descriptions +	Add missing HCI commands structures. +	Add missing HCI event structures. +	Add common bachk() function. + +ver 3.11: +	Fix URL data size handling. + +ver 3.10: +	Add version code for Bluetooth 2.1 specification. +	Add ESCO_LINK connection type constant. +	Export sdp_uuid32_to_uuid128() function. + +ver 3.9: +	Update copyright information. + +ver 3.8: +	Add functions for registering binary records. + +ver 3.7: +	Add additional PDU length checks. +	Fix CSRC value for partial responses. + +ver 3.6: +	Fix issues with the asynchronous API for SDP. + +ver 3.5: +	Add asynchronous API for SDP. + +ver 3.4: +	Fix UUID128 string lookup handling. +	Fix malloc() versus bt_malloc() usage. + +ver 3.3: +	Remove kernel specific timeouts. +	Add additional private data field for SDP sessions. +	Add host controller to host flow control defines. +	Add host number of completed packets defines. +	Initialize various memory to zero before usage. + +ver 3.2: +	Fix handling of SDP strings. +	Add adapter type for SDIO cards. +	Add features bit for link supervision timeout. + +ver 3.1: +	Add missing placeholders for feature bits. + +ver 3.0: +	Fix broken behavior with EVT_CMD_STATUS. +	Add features bit for pause encryption. +	Add additional EIR error code. +	Add more company identifiers. +	Add another Phonebook Access identifier. +	Update sniff subrating data structures. + +ver 2.25: +	Add definitions for Apple Agent. +	Add support for record handle on service registration. + +ver 2.24: +	Add support for additional access protocols. + +ver 2.23: +	Add constants and definitions for sniff subrating. +	Add support for allocation of binary text elements. +	Fix service discovery deadlocks with Samsung D600 phones. + +ver 2.22: +	Decode reserved LMP feature bits. +	Fix errno overwrite problems. +	Fix profile descriptor problem with Samsung phones. +	Add compile time buffer checks (FORTIFY SOURCE). + +ver 2.21: +	Add support for identification of supported commands. +	Add missing OCF declarations for the security filter. +	Add two new company identifiers. + +ver 2.20: +	Add UUIDs for video distribution profile. +	Add UUIDs for phonebook access profile. +	Add attribute identifier for supported repositories. +	Add definitions for extended inquiry response. +	Add functions for extended inquiry response. + +ver 2.19: +	Fix the GCC 4.0 warnings. +	Fix the routing for dealing with raw devices. +	Add per device service record functions. + +ver 2.18: +	Add support for reading and writing the inquiry scan type. +	Add definitions for connection accept timeout and scan enable. +	Remove hci_vhci.h header file. +	Remove hci_uart.h header file. + +ver 2.17: +	Include stdio.h in bluetooth.h header file. +	Include sys/socket.h in the header files. +	Add functions for stored link keys. +	Add definitions for PIN type and unit key. +	Add SDP_WAIT_ON_CLOSE flag for sdp_connect(). + +ver 2.16: +	Fix buffer allocation for features to string conversion. +	Add function for reading local supported commands. +	Add function for reading local extended features. +	Add function for reading remote extended features. +	Add function for getting the remote name with a clock offset. +	Add function for extracting the OUI from a BD_ADDR. +	Add inquiry info structure with RSSI and page scan mode. +	Support inquiry with unlimited number of responses. + +ver 2.15: +	Use better way for unaligned access. +	Remove sdp_internal.h and its usage. +	Add deprecated functions for reading the name. +	Add function for reading the clock. +	Add function for reading the local Bluetooth address. +	Add function for reading the local supported features. + +ver 2.14: +	Add function for reading the RSSI. +	Add function for reading the link quality. +	Add function for reading the transmit power level. +	Add functions for the link supervision timeout. +	Remove deprecated functions. +	Update AM_PATH_BLUEZ macro. + +ver 2.13: +	Add Device ID and HID attribute definitions. +	Update the UUID constants and its translations. +	Update L2CAP socket option definitions. +	Update connection information definitions. + +ver 2.12: +	Correct kernel interface for CMTP and HIDP support. +	Add service classes and profile ids for WAP. +	Add simple AM_PATH_BLUEZ macro. + +ver 2.11: +	Initial support for the kernel security manager. +	Use bit zero for vendor packets in the filter type bitmask. +	Add SIM Access types for service discovery. +	Add more audio/video profile translations. +	Add another company identifier. +	Add the missing HCI error codes. +	Add RFCOMM socket options. +	Add definition for the SECURE link mode. +	Add functions for reading and writing the inquiry mode. +	Add functions for AFH related settings and information. +	Add version identifier for the Bluetooth 2.0 specification. + +ver 2.10: +	Fix and extend the unaligned access macros. +	Make compiling with debug information optional. +	Don't override CFLAGS from configure. + +ver 2.9: +	Add L2CAP info type and info result definitions. +	Add value for L2CAP_CONF_RFC_MODE. +	Change RSSI value to signed instead of unsigned. +	Allow UUID32 values as protocol identifiers. + +ver 2.8: +	Fix the event code of inquiry with RSSI. +	Add defines and UUID's for audio/video profiles. +	Add AVDTP protocol identifier. +	Add HIDP subclass field. +	Add PKGConfig support. +	Remove dummy SDP library. + +ver 2.7: +	Fix display of decoded LMP features. +	Update company identifiers. +	Add AFH related types. +	Add first bits from EDR prototyping specification. +	Add support for inquiry with RSSI. +	Add HCRP related SDP functions. +	Add HIDP header file. + +ver 2.6: +	Use R2 for default value of pscan_rep_mode. +	Add new company identifiers. +	Add BNEP and CMTP header files. +	Add the SDP library. + +ver 2.5: +	Add decoding of Bluetooth 1.2 features. +	Add link manager version parameter for Bluetooth 1.2. +	Add new company identifiers. +	Support for transmit power level. +	Support for park, sniff and hold mode. +	Support for role switch. +	Support for reading the clock offset. +	Use R1 for default value of pscan_rep_mode. + +ver 2.4: +	Added const qualifiers to appropriate function arguments. +	Minor fixes. + +ver 2.3: +	Fix hci_for_each_dev() for big endian machines. +	Support for voice settings. +	RPM package. + +ver 2.2: +	Updated RFCOMM header file. +	Additional HCI command and event defines. + +ver 2.1.1: +	Resurrect hci_remote_name. + +ver 2.1: +	New HCI functions: +		hci_{read, write}_class_of_dev(), +		hci_{read, write}_current_iac_lap(), +		hci_write_local_name() +	Added RFCOMM header file. +	Minor fixes. + +ver 2.0: +	Additional company IDs. +	Minor fixes. + +ver 2.0-pre10: +	Fix hci_inquiry function to return errors and accept user buffers. +	New functions hci_devba, hci_devid, hci_for_each_dev and hci_get_route. +	Additional company IDs. +	Makefile and other minor fixes. + +ver 2.0-pre9: +	LMP features to string translation support. +	Additional HCI command and event defines. +	Extended hci_filter API. + +ver 2.0-pre8: +	Additional HCI ioctls and defines. +	All strings and buffers are allocated dynamically. +	ba2str, str2ba automatically swap bdaddress. +	Minor fixes and cleanup. + +ver 2.0-pre7: +	Bluetooth libraries and header files is now a separate package. +	New build environment uses automake and libtool. +	Massive header files cleanup. + +ver 2.0-pre6: +	API cleanup and additions. + +ver 2.0-pre4: +	HCI filter enhancements. + +ver 2.0-pre3: +	Cleanup. + +ver 2.0-pre2: +	Additional HCI library functions. +	Documentation update. +	 +ver 2.0-pre1: +	Minor fixes and improvements. diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..56b077d6 --- /dev/null +++ b/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + +   The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation.  It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions.  Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + +   It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring.  (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + +   If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release.  If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + +   The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'.  You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + +  1. `cd' to the directory containing the package's source code and type +     `./configure' to configure the package for your system.  If you're +     using `csh' on an old version of System V, you might need to type +     `sh ./configure' instead to prevent `csh' from trying to execute +     `configure' itself. + +     Running `configure' takes awhile.  While running, it prints some +     messages telling which features it is checking for. + +  2. Type `make' to compile the package. + +  3. Optionally, type `make check' to run any self-tests that come with +     the package. + +  4. Type `make install' to install the programs and any data files and +     documentation. + +  5. You can remove the program binaries and object files from the +     source code directory by typing `make clean'.  To also remove the +     files that `configure' created (so you can compile the package for +     a different kind of computer), type `make distclean'.  There is +     also a `make maintainer-clean' target, but that is intended mainly +     for the package's developers.  If you use it, you may have to get +     all sorts of other programs in order to regenerate files that came +     with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about.  Run `./configure --help' for +details on some of the pertinent environment variables. + +   You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment.  Here +is an example: + +     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + +   *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory.  To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'.  `cd' to the +directory where you want the object files and executables to go and run +the `configure' script.  `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + +   If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory.  After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc.  You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PREFIX'. + +   You can specify separate installation prefixes for +architecture-specific files and architecture-independent files.  If you +give `configure' the option `--exec-prefix=PREFIX', the package will +use PREFIX as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + +   In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files.  Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + +   If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System).  The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + +   For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option.  TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + +     CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + +     OS KERNEL-OS + +   See the file `config.sub' for the possible values of each field.  If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + +   If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + +   If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists.  Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'.  However, some packages may run +configure again during the build, and the customized values of these +variables may be lost.  In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'.  For example: + +     ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script).  Here is a another example: + +     /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' +     Print a summary of the options to `configure', and exit. + +`--version' +`-V' +     Print the version of Autoconf used to generate the `configure' +     script, and exit. + +`--cache-file=FILE' +     Enable the cache: use and save the results of the tests in FILE, +     traditionally `config.cache'.  FILE defaults to `/dev/null' to +     disable caching. + +`--config-cache' +`-C' +     Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' +     Do not print messages saying which checks are being made.  To +     suppress all normal output, redirect it to `/dev/null' (any error +     messages will still be shown). + +`--srcdir=DIR' +     Look for the package's source code in directory DIR.  Usually +     `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options.  Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..b51795a0 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,18 @@ + +SUBDIRS = include src + +aclocaldir = $(datadir)/aclocal + +aclocal_DATA = bluez.m4 + +EXTRA_DIST = $(aclocal_DATA) + +pkgconfigdir = $(libdir)/pkgconfig + +pkgconfig_DATA = bluez.pc + +DISTCLEANFILES = $(pkgconfig_DATA) + +MAINTAINERCLEANFILES = Makefile.in \ +	aclocal.m4 configure config.h.in config.sub config.guess \ +	ltmain.sh depcomp missing install-sh mkinstalldirs @@ -0,0 +1,35 @@ +BlueZ - Bluetooth protocol stack for Linux +****************************************** + +Copyright (C) 2000-2001  Qualcomm Incorporated +Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> +Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + +Bluetooth libraries + + +Compilation and installation +============================ + +In order to compile Bluetooth libraries you need following software packages: +	- Linux Bluetooth protocol stack (BlueZ) +	- GCC compiler + +To configure run: +	./configure --prefix=/usr +  +Configure automatically searches for all required components and packages.  + +To compile and install run: +	make && make install + + +Information +=========== + +Mailing lists: +	bluez-users@lists.sf.net - BlueZ general questions and discussions +	bluez-devel@lists.sf.net - BlueZ development  + +For additional information about the project visit BlueZ web site: +	http://www.bluez.org diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 00000000..6242e390 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,76 @@ +AC_DEFUN([AC_PROG_CC_PIE], [ +	AC_CACHE_CHECK([whether ${CC-cc} accepts -fPIE], ac_cv_prog_cc_pie, [ +		echo 'void f(){}' > conftest.c +		if test -z "`${CC-cc} -fPIE -pie -c conftest.c 2>&1`"; then +			ac_cv_prog_cc_pie=yes +		else +			ac_cv_prog_cc_pie=no +		fi +		rm -rf conftest* +	]) +]) + +AC_DEFUN([AC_INIT_BLUEZ], [ +	AC_PREFIX_DEFAULT(/usr/local) + +	if (test "${CFLAGS}" = ""); then +		CFLAGS="-Wall -O2" +	fi + +	if (test "${prefix}" = "NONE"); then +		dnl no prefix and no sysconfdir, so default to /etc +		if (test "$sysconfdir" = '${prefix}/etc'); then +			AC_SUBST([sysconfdir], ['/etc']) +		fi + +		dnl no prefix and no mandir, so use ${prefix}/share/man as default +		if (test "$mandir" = '${prefix}/man'); then +			AC_SUBST([mandir], ['${prefix}/share/man']) +		fi + +		prefix="${ac_default_prefix}" +	fi + +	if (test "${libdir}" = '${exec_prefix}/lib'); then +		libdir="${prefix}/lib" +	fi + +	if (test "$sysconfdir" = '${prefix}/etc'); then +		configdir="${prefix}/etc/bluetooth" +	else +		configdir="${sysconfdir}/bluetooth" +	fi + +	AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}", [Directory for the configuration files]) +]) + +AC_DEFUN([AC_ARG_BLUEZ], [ +	debug_enable=no +	fortify_enable=yes +	pie_enable=yes + +	AC_ARG_ENABLE(fortify, AC_HELP_STRING([--disable-fortify], [disable compile time buffer checks]), [ +		fortify_enable=${enableval} +	]) + +	AC_ARG_ENABLE(pie, AC_HELP_STRING([--disable-pie], [enable position independent executables flag]), [ +		pie_enable=${enableval} +	]) + +	AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable compiling with debugging information]), [ +		debug_enable=${enableval} +	]) + +	if (test "${fortify_enable}" = "yes"); then +		CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" +	fi + +	if (test "${pie_enable}" = "yes" && test "${ac_cv_prog_cc_pie}" = "yes"); then +		CFLAGS="$CFLAGS -fPIC" +		LDFLAGS="$LDFLAGS -pie" +	fi + +	if (test "${debug_enable}" = "yes" && test "${ac_cv_prog_cc_g}" = "yes"); then +		CFLAGS="$CFLAGS -g -O0" +	fi +]) diff --git a/bluez.m4 b/bluez.m4 new file mode 100644 index 00000000..0257a3f6 --- /dev/null +++ b/bluez.m4 @@ -0,0 +1,40 @@ +AC_DEFUN([AM_PATH_BLUEZ], [ +	if (test "${prefix}" = "NONE"); then +		bluez_prefix=${ac_default_prefix} +	else +		bluez_prefix=${prefix} +	fi + +	AC_ARG_WITH(bluez, AC_HELP_STRING([--with-bluez=DIR], [BlueZ library is installed in DIR]), [ +		if (test "${withval}" != "yes"); then +			bluez_prefix=${withval} +		fi +	]) + +	ac_save_CPPFLAGS=$CPPFLAGS +	ac_save_LDFLAGS=$LDFLAGS + +	BLUEZ_CFLAGS="" +	test -d "${bluez_prefix}/include" && BLUEZ_CFLAGS="$BLUEZ_CFLAGS -I${bluez_prefix}/include" + +	CPPFLAGS="$CPPFLAGS $BLUEZ_CFLAGS" +	AC_CHECK_HEADER(bluetooth/bluetooth.h,, AC_MSG_ERROR(Bluetooth header files not found)) + +	BLUEZ_LIBS="" +	if (test "${ac_default_prefix}" = "${bluez_prefix}"); then +		test -d "${libdir}" && BLUEZ_LIBS="$BLUEZ_LIBS -L${libdir}" +	else +		test -d "${bluez_prefix}/lib64" && BLUEZ_LIBS="$BLUEZ_LIBS -L${bluez_prefix}/lib64" +		test -d "${bluez_prefix}/lib" && BLUEZ_LIBS="$BLUEZ_LIBS -L${bluez_prefix}/lib" +	fi + +	LDFLAGS="$LDFLAGS $BLUEZ_LIBS" +	AC_CHECK_LIB(bluetooth, hci_open_dev, BLUEZ_LIBS="$BLUEZ_LIBS -lbluetooth", AC_MSG_ERROR(Bluetooth library not found)) +	AC_CHECK_LIB(bluetooth, sdp_connect,, AC_CHECK_LIB(sdp, sdp_connect, BLUEZ_LIBS="$BLUEZ_LIBS -lsdp")) + +	CPPFLAGS=$ac_save_CPPFLAGS +	LDFLAGS=$ac_save_LDFLAGS + +	AC_SUBST(BLUEZ_CFLAGS) +	AC_SUBST(BLUEZ_LIBS) +]) diff --git a/bluez.pc.in b/bluez.pc.in new file mode 100644 index 00000000..3d6e5961 --- /dev/null +++ b/bluez.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +  +Name: BlueZ +Description: Bluetooth protocol stack for Linux +Version: @VERSION@ +Libs: -L${libdir} -lbluetooth +Cflags: -I${includedir} diff --git a/bootstrap b/bootstrap new file mode 100755 index 00000000..91756f94 --- /dev/null +++ b/bootstrap @@ -0,0 +1,7 @@ +#!/bin/sh + +aclocal && \ +    autoheader && \ +	libtoolize --automake --copy --force && \ +	    automake --add-missing --copy && \ +		autoconf diff --git a/bootstrap-configure b/bootstrap-configure new file mode 100755 index 00000000..b10a98e0 --- /dev/null +++ b/bootstrap-configure @@ -0,0 +1,10 @@ +#!/bin/sh + +if [ -f config.status ]; then +	make maintainer-clean +fi + +./bootstrap && \ +    ./configure --enable-maintainer-mode \ +		--enable-debug \ +		--prefix=/usr diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..1eeb7755 --- /dev/null +++ b/configure.in @@ -0,0 +1,24 @@ +AC_PREREQ(2.50) +AC_INIT() + +AM_INIT_AUTOMAKE(bluez-libs, 3.36) +AM_CONFIG_HEADER(config.h) + +AM_MAINTAINER_MODE + +AC_INIT_BLUEZ + +AC_LANG_C + +AC_PROG_CC +AC_PROG_CC_PIE +AC_PROG_INSTALL + +m4_define([_LT_AC_TAGCONFIG], []) +m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])]) + +AC_PROG_LIBTOOL + +AC_ARG_BLUEZ + +AC_OUTPUT(Makefile include/Makefile src/Makefile bluez.pc) diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 00000000..992e987b --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,14 @@ + +includedir = @includedir@/bluetooth + +include_HEADERS = \ +	bluetooth.h hci.h hci_lib.h sco.h l2cap.h \ +	sdp.h sdp_lib.h rfcomm.h bnep.h cmtp.h hidp.h + +MAINTAINERCLEANFILES = Makefile.in + +all-local: +	@if [ ! -e bluetooth ] ; then $(LN_S) $(top_srcdir)/include bluetooth ; fi + +clean-local: +	@rm -f bluetooth diff --git a/include/bluetooth.h b/include/bluetooth.h new file mode 100644 index 00000000..d886cb80 --- /dev/null +++ b/include/bluetooth.h @@ -0,0 +1,149 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2000-2001  Qualcomm Incorporated + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __BLUETOOTH_H +#define __BLUETOOTH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <endian.h> +#include <byteswap.h> + +#ifndef AF_BLUETOOTH +#define AF_BLUETOOTH	31 +#define PF_BLUETOOTH	AF_BLUETOOTH +#endif + +#ifndef SOL_BLUETOOTH +#define SOL_BLUETOOTH	274 +#endif + +#define BTPROTO_L2CAP	0 +#define BTPROTO_HCI	1 +#define BTPROTO_SCO	2 +#define BTPROTO_RFCOMM	3 +#define BTPROTO_BNEP	4 +#define BTPROTO_CMTP	5 +#define BTPROTO_HIDP	6 +#define BTPROTO_AVDTP	7 + +#define SOL_HCI		0 +#define SOL_L2CAP	6 +#define SOL_SCO		17 +#define SOL_RFCOMM	18 + +/* Connection and socket states */ +enum { +	BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */ +	BT_OPEN, +	BT_BOUND, +	BT_LISTEN, +	BT_CONNECT, +	BT_CONNECT2, +	BT_CONFIG, +	BT_DISCONN, +	BT_CLOSED +}; + +/* Byte order conversions */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define htobs(d)  (d) +#define htobl(d)  (d) +#define btohs(d)  (d) +#define btohl(d)  (d) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define htobs(d)  bswap_16(d) +#define htobl(d)  bswap_32(d) +#define btohs(d)  bswap_16(d) +#define btohl(d)  bswap_32(d) +#else +#error "Unknown byte order" +#endif + +/* Bluetooth unaligned access */ +#define bt_get_unaligned(ptr)			\ +({						\ +	struct __attribute__((packed)) {	\ +		typeof(*(ptr)) __v;		\ +	} *__p = (void *) (ptr);		\ +	__p->__v;				\ +}) + +#define bt_put_unaligned(val, ptr)		\ +do {						\ +	struct __attribute__((packed)) {	\ +		typeof(*(ptr)) __v;		\ +	} *__p = (void *) (ptr);		\ +	__p->__v = (val);			\ +} while(0) + +/* BD Address */ +typedef struct { +	uint8_t b[6]; +} __attribute__((packed)) bdaddr_t; + +#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) +#define BDADDR_ALL   (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}) +#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) + +/* Copy, swap, convert BD Address */ +static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2) +{ +	return memcmp(ba1, ba2, sizeof(bdaddr_t)); +} +static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src) +{ +	memcpy(dst, src, sizeof(bdaddr_t)); +} + +void baswap(bdaddr_t *dst, const bdaddr_t *src); +bdaddr_t *strtoba(const char *str); +char *batostr(const bdaddr_t *ba); +int ba2str(const bdaddr_t *ba, char *str); +int str2ba(const char *str, bdaddr_t *ba); +int ba2oui(const bdaddr_t *ba, char *oui); +int bachk(const char *str); + +int baprintf(const char *format, ...); +int bafprintf(FILE *stream, const char *format, ...); +int basprintf(char *str, const char *format, ...); +int basnprintf(char *str, size_t size, const char *format, ...); + +void *bt_malloc(size_t size); +void bt_free(void *ptr); + +int bt_error(uint16_t code); +char *bt_compidtostr(int id); + +#ifdef __cplusplus +} +#endif + +#endif /* __BLUETOOTH_H */ diff --git a/include/bnep.h b/include/bnep.h new file mode 100644 index 00000000..92c66c14 --- /dev/null +++ b/include/bnep.h @@ -0,0 +1,153 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __BNEP_H +#define __BNEP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <bluetooth/bluetooth.h> + +#ifndef ETH_ALEN +#define ETH_ALEN	6		/* from <net/ethernet.h> */ +#endif + +/* BNEP UUIDs */ +#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB +#define BNEP_UUID16    0x02 +#define BNEP_UUID32    0x04 +#define BNEP_UUID128   0x16 + +#define BNEP_SVC_PANU  0x1115 +#define BNEP_SVC_NAP   0x1116 +#define BNEP_SVC_GN    0x1117 + +/* BNEP packet types */ +#define BNEP_GENERAL               0x00 +#define BNEP_CONTROL               0x01 +#define BNEP_COMPRESSED            0x02 +#define BNEP_COMPRESSED_SRC_ONLY   0x03 +#define BNEP_COMPRESSED_DST_ONLY   0x04 + +/* BNEP control types */ +#define BNEP_CMD_NOT_UNDERSTOOD    0x00 +#define BNEP_SETUP_CONN_REQ        0x01 +#define BNEP_SETUP_CONN_RSP        0x02 +#define BNEP_FILTER_NET_TYPE_SET   0x03 +#define BNEP_FILTER_NET_TYPE_RSP   0x04 +#define BNEP_FILTER_MULT_ADDR_SET  0x05 +#define BNEP_FILTER_MULT_ADDR_RSP  0x06 + +/* BNEP response messages */ +#define BNEP_SUCCESS               0x00 + +#define BNEP_CONN_INVALID_DST      0x01 +#define BNEP_CONN_INVALID_SRC      0x02 +#define BNEP_CONN_INVALID_SVC      0x03 +#define BNEP_CONN_NOT_ALLOWED      0x04 + +#define BNEP_FILTER_UNSUPPORTED_REQ    0x01 +#define BNEP_FILTER_INVALID_RANGE      0x02 +#define BNEP_FILTER_INVALID_MCADDR     0x02 +#define BNEP_FILTER_LIMIT_REACHED      0x03 +#define BNEP_FILTER_DENIED_SECURITY    0x04 + +/* L2CAP settings */ +#define BNEP_MTU         1691 +#define BNEP_FLUSH_TO    0xffff +#define BNEP_CONNECT_TO  15 +#define BNEP_FILTER_TO   15 + +#ifndef BNEP_PSM +#define BNEP_PSM	 0x0f +#endif + +/* BNEP headers */ +#define BNEP_TYPE_MASK	 0x7f +#define BNEP_EXT_HEADER	 0x80 + +struct bnep_setup_conn_req { +	uint8_t  type; +	uint8_t  ctrl; +	uint8_t  uuid_size; +	uint8_t  service[0]; +} __attribute__((packed)); + +struct bnep_set_filter_req { +	uint8_t  type; +	uint8_t  ctrl; +	uint16_t len; +	uint8_t  list[0]; +} __attribute__((packed)); + +struct bnep_control_rsp { +	uint8_t  type; +	uint8_t  ctrl; +	uint16_t resp; +} __attribute__((packed)); + +struct bnep_ext_hdr { +	uint8_t  type; +	uint8_t  len; +	uint8_t  data[0]; +} __attribute__((packed)); + +/* BNEP ioctl defines */ +#define BNEPCONNADD	_IOW('B', 200, int) +#define BNEPCONNDEL	_IOW('B', 201, int) +#define BNEPGETCONNLIST	_IOR('B', 210, int) +#define BNEPGETCONNINFO	_IOR('B', 211, int) + +struct bnep_connadd_req { +	int      sock;		/* Connected socket */ +	uint32_t flags; +	uint16_t role; +	char     device[16];	/* Name of the Ethernet device */ +}; + +struct bnep_conndel_req { +	uint32_t flags; +	uint8_t  dst[ETH_ALEN]; +}; + +struct bnep_conninfo { +	uint32_t flags; +	uint16_t role; +	uint16_t state; +	uint8_t  dst[ETH_ALEN]; +	char     device[16]; +}; + +struct bnep_connlist_req { +	uint32_t cnum; +	struct bnep_conninfo *ci; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __BNEP_H */ diff --git a/include/cmtp.h b/include/cmtp.h new file mode 100644 index 00000000..16add1d2 --- /dev/null +++ b/include/cmtp.h @@ -0,0 +1,69 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __CMTP_H +#define __CMTP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* CMTP defaults */ +#define CMTP_MINIMUM_MTU 152 +#define CMTP_DEFAULT_MTU 672 + +/* CMTP ioctl defines */ +#define CMTPCONNADD	_IOW('C', 200, int) +#define CMTPCONNDEL	_IOW('C', 201, int) +#define CMTPGETCONNLIST	_IOR('C', 210, int) +#define CMTPGETCONNINFO	_IOR('C', 211, int) + +#define CMTP_LOOPBACK	0 + +struct cmtp_connadd_req { +	int sock;	/* Connected socket */ +	uint32_t flags; +}; + +struct cmtp_conndel_req { +	bdaddr_t bdaddr; +	uint32_t flags; +}; + +struct cmtp_conninfo { +	bdaddr_t bdaddr; +	uint32_t flags; +	uint16_t state; +	int      num; +}; + +struct cmtp_connlist_req { +	uint32_t cnum; +	struct cmtp_conninfo *ci; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __CMTP_H */ diff --git a/include/hci.h b/include/hci.h new file mode 100644 index 00000000..499f1bdd --- /dev/null +++ b/include/hci.h @@ -0,0 +1,1842 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2000-2001  Qualcomm Incorporated + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __HCI_H +#define __HCI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/socket.h> + +#define HCI_MAX_DEV	16 + +#define HCI_MAX_ACL_SIZE	1024 +#define HCI_MAX_SCO_SIZE	255 +#define HCI_MAX_EVENT_SIZE	260 +#define HCI_MAX_FRAME_SIZE	(HCI_MAX_ACL_SIZE + 4) + +/* HCI dev events */ +#define HCI_DEV_REG	1 +#define HCI_DEV_UNREG	2 +#define HCI_DEV_UP	3 +#define HCI_DEV_DOWN	4 +#define HCI_DEV_SUSPEND	5 +#define HCI_DEV_RESUME	6 + +/* HCI device types */ +#define HCI_VIRTUAL	0 +#define HCI_USB		1 +#define HCI_PCCARD	2 +#define HCI_UART	3 +#define HCI_RS232	4 +#define HCI_PCI		5 +#define HCI_SDIO	6 + +/* HCI device flags */ +enum { +	HCI_UP, +	HCI_INIT, +	HCI_RUNNING, + +	HCI_PSCAN, +	HCI_ISCAN, +	HCI_AUTH, +	HCI_ENCRYPT, +	HCI_INQUIRY, + +	HCI_RAW, + +	HCI_SECMGR +}; + +/* HCI ioctl defines */ +#define HCIDEVUP	_IOW('H', 201, int) +#define HCIDEVDOWN	_IOW('H', 202, int) +#define HCIDEVRESET	_IOW('H', 203, int) +#define HCIDEVRESTAT	_IOW('H', 204, int) + +#define HCIGETDEVLIST	_IOR('H', 210, int) +#define HCIGETDEVINFO	_IOR('H', 211, int) +#define HCIGETCONNLIST	_IOR('H', 212, int) +#define HCIGETCONNINFO	_IOR('H', 213, int) +#define HCIGETAUTHINFO	_IOR('H', 215, int) + +#define HCISETRAW	_IOW('H', 220, int) +#define HCISETSCAN	_IOW('H', 221, int) +#define HCISETAUTH	_IOW('H', 222, int) +#define HCISETENCRYPT	_IOW('H', 223, int) +#define HCISETPTYPE	_IOW('H', 224, int) +#define HCISETLINKPOL	_IOW('H', 225, int) +#define HCISETLINKMODE	_IOW('H', 226, int) +#define HCISETACLMTU	_IOW('H', 227, int) +#define HCISETSCOMTU	_IOW('H', 228, int) + +#define HCISETSECMGR	_IOW('H', 230, int) + +#define HCIINQUIRY	_IOR('H', 240, int) + +#ifndef __NO_HCI_DEFS + +/* HCI Packet types */ +#define HCI_COMMAND_PKT		0x01 +#define HCI_ACLDATA_PKT		0x02 +#define HCI_SCODATA_PKT		0x03 +#define HCI_EVENT_PKT		0x04 +#define HCI_VENDOR_PKT		0xff + +/* HCI Packet types */ +#define HCI_2DH1	0x0002 +#define HCI_3DH1	0x0004 +#define HCI_DM1		0x0008 +#define HCI_DH1		0x0010 +#define HCI_2DH3	0x0100 +#define HCI_3DH3	0x0200 +#define HCI_DM3		0x0400 +#define HCI_DH3		0x0800 +#define HCI_2DH5	0x1000 +#define HCI_3DH5	0x2000 +#define HCI_DM5		0x4000 +#define HCI_DH5		0x8000 + +#define HCI_HV1		0x0020 +#define HCI_HV2		0x0040 +#define HCI_HV3		0x0080 + +#define HCI_EV3		0x0008 +#define HCI_EV4		0x0010 +#define HCI_EV5		0x0020 +#define HCI_2EV3	0x0040 +#define HCI_3EV3	0x0080 +#define HCI_2EV5	0x0100 +#define HCI_3EV5	0x0200 + +#define SCO_PTYPE_MASK	(HCI_HV1 | HCI_HV2 | HCI_HV3) +#define ACL_PTYPE_MASK	(HCI_DM1 | HCI_DH1 | HCI_DM3 | HCI_DH3 | HCI_DM5 | HCI_DH5) + +/* HCI Error codes */ +#define HCI_UNKNOWN_COMMAND			0x01 +#define HCI_NO_CONNECTION			0x02 +#define HCI_HARDWARE_FAILURE			0x03 +#define HCI_PAGE_TIMEOUT			0x04 +#define HCI_AUTHENTICATION_FAILURE		0x05 +#define HCI_PIN_OR_KEY_MISSING			0x06 +#define HCI_MEMORY_FULL				0x07 +#define HCI_CONNECTION_TIMEOUT			0x08 +#define HCI_MAX_NUMBER_OF_CONNECTIONS		0x09 +#define HCI_MAX_NUMBER_OF_SCO_CONNECTIONS	0x0a +#define HCI_ACL_CONNECTION_EXISTS		0x0b +#define HCI_COMMAND_DISALLOWED			0x0c +#define HCI_REJECTED_LIMITED_RESOURCES		0x0d +#define HCI_REJECTED_SECURITY			0x0e +#define HCI_REJECTED_PERSONAL			0x0f +#define HCI_HOST_TIMEOUT			0x10 +#define HCI_UNSUPPORTED_FEATURE			0x11 +#define HCI_INVALID_PARAMETERS			0x12 +#define HCI_OE_USER_ENDED_CONNECTION		0x13 +#define HCI_OE_LOW_RESOURCES			0x14 +#define HCI_OE_POWER_OFF			0x15 +#define HCI_CONNECTION_TERMINATED		0x16 +#define HCI_REPEATED_ATTEMPTS			0x17 +#define HCI_PAIRING_NOT_ALLOWED			0x18 +#define HCI_UNKNOWN_LMP_PDU			0x19 +#define HCI_UNSUPPORTED_REMOTE_FEATURE		0x1a +#define HCI_SCO_OFFSET_REJECTED			0x1b +#define HCI_SCO_INTERVAL_REJECTED		0x1c +#define HCI_AIR_MODE_REJECTED			0x1d +#define HCI_INVALID_LMP_PARAMETERS		0x1e +#define HCI_UNSPECIFIED_ERROR			0x1f +#define HCI_UNSUPPORTED_LMP_PARAMETER_VALUE	0x20 +#define HCI_ROLE_CHANGE_NOT_ALLOWED		0x21 +#define HCI_LMP_RESPONSE_TIMEOUT		0x22 +#define HCI_LMP_ERROR_TRANSACTION_COLLISION	0x23 +#define HCI_LMP_PDU_NOT_ALLOWED			0x24 +#define HCI_ENCRYPTION_MODE_NOT_ACCEPTED	0x25 +#define HCI_UNIT_LINK_KEY_USED			0x26 +#define HCI_QOS_NOT_SUPPORTED			0x27 +#define HCI_INSTANT_PASSED			0x28 +#define HCI_PAIRING_NOT_SUPPORTED		0x29 +#define HCI_TRANSACTION_COLLISION		0x2a +#define HCI_QOS_UNACCEPTABLE_PARAMETER		0x2c +#define HCI_QOS_REJECTED			0x2d +#define HCI_CLASSIFICATION_NOT_SUPPORTED	0x2e +#define HCI_INSUFFICIENT_SECURITY		0x2f +#define HCI_PARAMETER_OUT_OF_RANGE		0x30 +#define HCI_ROLE_SWITCH_PENDING			0x32 +#define HCI_SLOT_VIOLATION			0x34 +#define HCI_ROLE_SWITCH_FAILED			0x35 +#define HCI_EIR_TOO_LARGE			0x36 +#define HCI_SIMPLE_PAIRING_NOT_SUPPORTED	0x37 +#define HCI_HOST_BUSY_PAIRING			0x38 + +/* ACL flags */ +#define ACL_CONT		0x01 +#define ACL_START		0x02 +#define ACL_ACTIVE_BCAST	0x04 +#define ACL_PICO_BCAST		0x08 + +/* Baseband links */ +#define SCO_LINK	0x00 +#define ACL_LINK	0x01 +#define ESCO_LINK	0x02 + +/* LMP features */ +#define LMP_3SLOT	0x01 +#define LMP_5SLOT	0x02 +#define LMP_ENCRYPT	0x04 +#define LMP_SOFFSET	0x08 +#define LMP_TACCURACY	0x10 +#define LMP_RSWITCH	0x20 +#define LMP_HOLD	0x40 +#define LMP_SNIFF	0x80 + +#define LMP_PARK	0x01 +#define LMP_RSSI	0x02 +#define LMP_QUALITY	0x04 +#define LMP_SCO		0x08 +#define LMP_HV2		0x10 +#define LMP_HV3		0x20 +#define LMP_ULAW	0x40 +#define LMP_ALAW	0x80 + +#define LMP_CVSD	0x01 +#define LMP_PSCHEME	0x02 +#define LMP_PCONTROL	0x04 +#define LMP_TRSP_SCO	0x08 +#define LMP_BCAST_ENC	0x80 + +#define LMP_EDR_ACL_2M	0x02 +#define LMP_EDR_ACL_3M	0x04 +#define LMP_ENH_ISCAN	0x08 +#define LMP_ILACE_ISCAN	0x10 +#define LMP_ILACE_PSCAN	0x20 +#define LMP_RSSI_INQ	0x40 +#define LMP_ESCO	0x80 + +#define LMP_EV4		0x01 +#define LMP_EV5		0x02 +#define LMP_AFH_CAP_SLV	0x08 +#define LMP_AFH_CLS_SLV	0x10 +#define LMP_EDR_3SLOT	0x80 + +#define LMP_EDR_5SLOT	0x01 +#define LMP_SNIFF_SUBR	0x02 +#define LMP_PAUSE_ENC	0x04 +#define LMP_AFH_CAP_MST	0x08 +#define LMP_AFH_CLS_MST	0x10 +#define LMP_EDR_ESCO_2M	0x20 +#define LMP_EDR_ESCO_3M	0x40 +#define LMP_EDR_3S_ESCO	0x80 + +#define LMP_EXT_INQ	0x01 +#define LMP_SIMPLE_PAIR	0x08 +#define LMP_ENCAPS_PDU	0x10 +#define LMP_ERR_DAT_REP	0x20 +#define LMP_NFLUSH_PKTS	0x40 + +#define LMP_LSTO	0x01 +#define LMP_INQ_TX_PWR	0x02 +#define LMP_EXT_FEAT	0x80 + +/* Link policies */ +#define HCI_LP_RSWITCH	0x0001 +#define HCI_LP_HOLD	0x0002 +#define HCI_LP_SNIFF	0x0004 +#define HCI_LP_PARK	0x0008 + +/* Link mode */ +#define HCI_LM_ACCEPT	0x8000 +#define HCI_LM_MASTER	0x0001 +#define HCI_LM_AUTH	0x0002 +#define HCI_LM_ENCRYPT	0x0004 +#define HCI_LM_TRUSTED	0x0008 +#define HCI_LM_RELIABLE	0x0010 +#define HCI_LM_SECURE	0x0020 + +/* -----  HCI Commands ----- */ + +/* Link Control */ +#define OGF_LINK_CTL		0x01 + +#define OCF_INQUIRY			0x0001 +typedef struct { +	uint8_t		lap[3]; +	uint8_t		length;		/* 1.28s units */ +	uint8_t		num_rsp; +} __attribute__ ((packed)) inquiry_cp; +#define INQUIRY_CP_SIZE 5 + +typedef struct { +	uint8_t		status; +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) status_bdaddr_rp; +#define STATUS_BDADDR_RP_SIZE 7 + +#define OCF_INQUIRY_CANCEL		0x0002 + +#define OCF_PERIODIC_INQUIRY		0x0003 +typedef struct { +	uint16_t	max_period;	/* 1.28s units */ +	uint16_t	min_period;	/* 1.28s units */ +	uint8_t		lap[3]; +	uint8_t		length;		/* 1.28s units */ +	uint8_t		num_rsp; +} __attribute__ ((packed)) periodic_inquiry_cp; +#define PERIODIC_INQUIRY_CP_SIZE 9 + +#define OCF_EXIT_PERIODIC_INQUIRY	0x0004 + +#define OCF_CREATE_CONN			0x0005 +typedef struct { +	bdaddr_t	bdaddr; +	uint16_t	pkt_type; +	uint8_t		pscan_rep_mode; +	uint8_t		pscan_mode; +	uint16_t	clock_offset; +	uint8_t		role_switch; +} __attribute__ ((packed)) create_conn_cp; +#define CREATE_CONN_CP_SIZE 13 + +#define OCF_DISCONNECT			0x0006 +typedef struct { +	uint16_t	handle; +	uint8_t		reason; +} __attribute__ ((packed)) disconnect_cp; +#define DISCONNECT_CP_SIZE 3 + +#define OCF_ADD_SCO			0x0007 +typedef struct { +	uint16_t	handle; +	uint16_t	pkt_type; +} __attribute__ ((packed)) add_sco_cp; +#define ADD_SCO_CP_SIZE 4 + +#define OCF_CREATE_CONN_CANCEL		0x0008 +typedef struct { +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) create_conn_cancel_cp; +#define CREATE_CONN_CANCEL_CP_SIZE 6 + +#define OCF_ACCEPT_CONN_REQ		0x0009 +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		role; +} __attribute__ ((packed)) accept_conn_req_cp; +#define ACCEPT_CONN_REQ_CP_SIZE	7 + +#define OCF_REJECT_CONN_REQ		0x000A +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		reason; +} __attribute__ ((packed)) reject_conn_req_cp; +#define REJECT_CONN_REQ_CP_SIZE	7 + +#define OCF_LINK_KEY_REPLY		0x000B +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		link_key[16]; +} __attribute__ ((packed)) link_key_reply_cp; +#define LINK_KEY_REPLY_CP_SIZE 22 + +#define OCF_LINK_KEY_NEG_REPLY		0x000C + +#define OCF_PIN_CODE_REPLY		0x000D +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		pin_len; +	uint8_t		pin_code[16]; +} __attribute__ ((packed)) pin_code_reply_cp; +#define PIN_CODE_REPLY_CP_SIZE 23 + +#define OCF_PIN_CODE_NEG_REPLY		0x000E + +#define OCF_SET_CONN_PTYPE		0x000F +typedef struct { +	uint16_t	 handle; +	uint16_t	 pkt_type; +} __attribute__ ((packed)) set_conn_ptype_cp; +#define SET_CONN_PTYPE_CP_SIZE 4 + +#define OCF_AUTH_REQUESTED		0x0011 +typedef struct { +	uint16_t	 handle; +} __attribute__ ((packed)) auth_requested_cp; +#define AUTH_REQUESTED_CP_SIZE 2 + +#define OCF_SET_CONN_ENCRYPT		0x0013 +typedef struct { +	uint16_t	handle; +	uint8_t		encrypt; +} __attribute__ ((packed)) set_conn_encrypt_cp; +#define SET_CONN_ENCRYPT_CP_SIZE 3 + +#define OCF_CHANGE_CONN_LINK_KEY	0x0015 +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) change_conn_link_key_cp; +#define CHANGE_CONN_LINK_KEY_CP_SIZE 2 + +#define OCF_MASTER_LINK_KEY		0x0017 +typedef struct { +	uint8_t		key_flag; +} __attribute__ ((packed)) master_link_key_cp; +#define MASTER_LINK_KEY_CP_SIZE 1 + +#define OCF_REMOTE_NAME_REQ		0x0019 +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		pscan_rep_mode; +	uint8_t		pscan_mode; +	uint16_t	clock_offset; +} __attribute__ ((packed)) remote_name_req_cp; +#define REMOTE_NAME_REQ_CP_SIZE 10 + +#define OCF_REMOTE_NAME_REQ_CANCEL	0x001A +typedef struct { +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) remote_name_req_cancel_cp; +#define REMOTE_NAME_REQ_CANCEL_CP_SIZE 6 + +#define OCF_READ_REMOTE_FEATURES	0x001B +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) read_remote_features_cp; +#define READ_REMOTE_FEATURES_CP_SIZE 2 + +#define OCF_READ_REMOTE_EXT_FEATURES	0x001C +typedef struct { +	uint16_t	handle; +	uint8_t		page_num; +} __attribute__ ((packed)) read_remote_ext_features_cp; +#define READ_REMOTE_EXT_FEATURES_CP_SIZE 3 + +#define OCF_READ_REMOTE_VERSION		0x001D +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) read_remote_version_cp; +#define READ_REMOTE_VERSION_CP_SIZE 2 + +#define OCF_READ_CLOCK_OFFSET		0x001F +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) read_clock_offset_cp; +#define READ_CLOCK_OFFSET_CP_SIZE 2 + +#define OCF_READ_LMP_HANDLE		0x0020 + +#define OCF_SETUP_SYNC_CONN		0x0028 +typedef struct { +	uint16_t	handle; +	uint32_t	tx_bandwith; +	uint32_t	rx_bandwith; +	uint16_t	max_latency; +	uint16_t	voice_setting; +	uint8_t		retrans_effort; +	uint16_t	pkt_type; +} __attribute__ ((packed)) setup_sync_conn_cp; +#define SETUP_SYNC_CONN_CP_SIZE 17 + +#define OCF_ACCEPT_SYNC_CONN_REQ	0x0029 +typedef struct { +	bdaddr_t	bdaddr; +	uint32_t	tx_bandwith; +	uint32_t	rx_bandwith; +	uint16_t	max_latency; +	uint16_t	voice_setting; +	uint8_t		retrans_effort; +	uint16_t	pkt_type; +} __attribute__ ((packed)) accept_sync_conn_req_cp; +#define ACCEPT_SYNC_CONN_REQ_CP_SIZE 21 + +#define OCF_REJECT_SYNC_CONN_REQ	0x002A +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		reason; +} __attribute__ ((packed)) reject_sync_conn_req_cp; +#define REJECT_SYNC_CONN_REQ_CP_SIZE 7 + +#define OCF_IO_CAPABILITY_REPLY		0x002B +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		capability; +	uint8_t		oob_data; +	uint8_t		authentication; +} __attribute__ ((packed)) io_capability_reply_cp; +#define IO_CAPABILITY_REPLY_CP_SIZE 9 + +#define OCF_USER_CONFIRM_REPLY		0x002C +typedef struct { +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) user_confirm_reply_cp; +#define USER_CONFIRM_REPLY_CP_SIZE 6 + +#define OCF_USER_CONFIRM_NEG_REPLY	0x002D + +#define OCF_USER_PASSKEY_REPLY		0x002E +typedef struct { +	bdaddr_t	bdaddr; +	uint32_t	passkey; +} __attribute__ ((packed)) user_passkey_reply_cp; +#define USER_PASSKEY_REPLY_CP_SIZE 10 + +#define OCF_USER_PASSKEY_NEG_REPLY	0x002F + +#define OCF_REMOTE_OOB_DATA_REPLY	0x0030 +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		hash[16]; +	uint8_t		randomizer[16]; +} __attribute__ ((packed)) remote_oob_data_reply_cp; +#define REMOTE_OOB_DATA_REPLY_CP_SIZE 38 + +#define OCF_REMOTE_OOB_DATA_NEG_REPLY	0x0033 + +#define OCF_IO_CAPABILITY_NEG_REPLY	0x0034 +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		reason; +} __attribute__ ((packed)) io_capability_neg_reply_cp; +#define IO_CAPABILITY_NEG_REPLY_CP_SIZE 7 + +/* Link Policy */ +#define OGF_LINK_POLICY		0x02 + +#define OCF_HOLD_MODE			0x0001 +typedef struct { +	uint16_t	handle; +	uint16_t	max_interval; +	uint16_t	min_interval; +} __attribute__ ((packed)) hold_mode_cp; +#define HOLD_MODE_CP_SIZE 6 + +#define OCF_SNIFF_MODE			0x0003 +typedef struct { +	uint16_t	handle; +	uint16_t	max_interval; +	uint16_t	min_interval; +	uint16_t	attempt; +	uint16_t	timeout; +} __attribute__ ((packed)) sniff_mode_cp; +#define SNIFF_MODE_CP_SIZE 10 + +#define OCF_EXIT_SNIFF_MODE		0x0004 +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) exit_sniff_mode_cp; +#define EXIT_SNIFF_MODE_CP_SIZE 2 + +#define OCF_PARK_MODE			0x0005 +typedef struct { +	uint16_t	handle; +	uint16_t	max_interval; +	uint16_t	min_interval; +} __attribute__ ((packed)) park_mode_cp; +#define PARK_MODE_CP_SIZE 6 + +#define OCF_EXIT_PARK_MODE		0x0006 +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) exit_park_mode_cp; +#define EXIT_PARK_MODE_CP_SIZE 2 + +#define OCF_QOS_SETUP			0x0007 +typedef struct { +	uint8_t		service_type;		/* 1 = best effort */ +	uint32_t	token_rate;		/* Byte per seconds */ +	uint32_t	peak_bandwidth;		/* Byte per seconds */ +	uint32_t	latency;		/* Microseconds */ +	uint32_t	delay_variation;	/* Microseconds */ +} __attribute__ ((packed)) hci_qos; +#define HCI_QOS_CP_SIZE 17 +typedef struct { +	uint16_t 	handle; +	uint8_t 	flags;			/* Reserved */ +	hci_qos 	qos; +} __attribute__ ((packed)) qos_setup_cp; +#define QOS_SETUP_CP_SIZE (3 + HCI_QOS_CP_SIZE) + +#define OCF_ROLE_DISCOVERY		0x0009 +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) role_discovery_cp; +#define ROLE_DISCOVERY_CP_SIZE 2 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		role; +} __attribute__ ((packed)) role_discovery_rp; +#define ROLE_DISCOVERY_RP_SIZE 4 + +#define OCF_SWITCH_ROLE			0x000B +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		role; +} __attribute__ ((packed)) switch_role_cp; +#define SWITCH_ROLE_CP_SIZE 7 + +#define OCF_READ_LINK_POLICY		0x000C +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) read_link_policy_cp; +#define READ_LINK_POLICY_CP_SIZE 2 +typedef struct { +	uint8_t 	status; +	uint16_t	handle; +	uint16_t	policy; +} __attribute__ ((packed)) read_link_policy_rp; +#define READ_LINK_POLICY_RP_SIZE 5 + +#define OCF_WRITE_LINK_POLICY		0x000D +typedef struct { +	uint16_t	handle; +	uint16_t	policy; +} __attribute__ ((packed)) write_link_policy_cp; +#define WRITE_LINK_POLICY_CP_SIZE 4 +typedef struct { +	uint8_t 	status; +	uint16_t	handle; +} __attribute__ ((packed)) write_link_policy_rp; +#define WRITE_LINK_POLICY_RP_SIZE 3 + +#define OCF_READ_DEFAULT_LINK_POLICY	0x000E + +#define OCF_WRITE_DEFAULT_LINK_POLICY	0x000F + +#define OCF_FLOW_SPECIFICATION		0x0010 + +#define OCF_SNIFF_SUBRATING		0x0011 +typedef struct { +	uint16_t	handle; +	uint16_t	max_latency; +	uint16_t	min_remote_timeout; +	uint16_t	min_local_timeout; +} __attribute__ ((packed)) sniff_subrating_cp; +#define SNIFF_SUBRATING_CP_SIZE 8 + +/* Host Controller and Baseband */ +#define OGF_HOST_CTL		0x03 + +#define OCF_SET_EVENT_MASK		0x0001 +typedef struct { +	uint8_t		mask[8]; +} __attribute__ ((packed)) set_event_mask_cp; +#define SET_EVENT_MASK_CP_SIZE 8 + +#define OCF_RESET			0x0003 + +#define OCF_SET_EVENT_FLT		0x0005 +typedef struct { +	uint8_t		flt_type; +	uint8_t		cond_type; +	uint8_t		condition[0]; +} __attribute__ ((packed)) set_event_flt_cp; +#define SET_EVENT_FLT_CP_SIZE 2 + +/* Filter types */ +#define FLT_CLEAR_ALL			0x00 +#define FLT_INQ_RESULT			0x01 +#define FLT_CONN_SETUP			0x02 +/* INQ_RESULT Condition types */ +#define INQ_RESULT_RETURN_ALL		0x00 +#define INQ_RESULT_RETURN_CLASS		0x01 +#define INQ_RESULT_RETURN_BDADDR	0x02 +/* CONN_SETUP Condition types */ +#define CONN_SETUP_ALLOW_ALL		0x00 +#define CONN_SETUP_ALLOW_CLASS		0x01 +#define CONN_SETUP_ALLOW_BDADDR		0x02 +/* CONN_SETUP Conditions */ +#define CONN_SETUP_AUTO_OFF		0x01 +#define CONN_SETUP_AUTO_ON		0x02 + +#define OCF_FLUSH			0x0008 + +#define OCF_READ_PIN_TYPE		0x0009 +typedef struct { +	uint8_t		status; +	uint8_t		pin_type; +} __attribute__ ((packed)) read_pin_type_rp; +#define READ_PIN_TYPE_RP_SIZE 2 + +#define OCF_WRITE_PIN_TYPE		0x000A +typedef struct { +	uint8_t		pin_type; +} __attribute__ ((packed)) write_pin_type_cp; +#define WRITE_PIN_TYPE_CP_SIZE 1 + +#define OCF_CREATE_NEW_UNIT_KEY		0x000B + +#define OCF_READ_STORED_LINK_KEY	0x000D +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		read_all; +} __attribute__ ((packed)) read_stored_link_key_cp; +#define READ_STORED_LINK_KEY_CP_SIZE 7 +typedef struct { +	uint8_t		status; +	uint16_t	max_keys; +	uint16_t	num_keys; +} __attribute__ ((packed)) read_stored_link_key_rp; +#define READ_STORED_LINK_KEY_RP_SIZE 5 + +#define OCF_WRITE_STORED_LINK_KEY	0x0011 +typedef struct { +	uint8_t		num_keys; +	/* variable length part */ +} __attribute__ ((packed)) write_stored_link_key_cp; +#define WRITE_STORED_LINK_KEY_CP_SIZE 1 +typedef struct { +	uint8_t		status; +	uint8_t		num_keys; +} __attribute__ ((packed)) write_stored_link_key_rp; +#define READ_WRITE_LINK_KEY_RP_SIZE 2 + +#define OCF_DELETE_STORED_LINK_KEY	0x0012 +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		delete_all; +} __attribute__ ((packed)) delete_stored_link_key_cp; +#define DELETE_STORED_LINK_KEY_CP_SIZE 7 +typedef struct { +	uint8_t		status; +	uint16_t	num_keys; +} __attribute__ ((packed)) delete_stored_link_key_rp; +#define DELETE_STORED_LINK_KEY_RP_SIZE 3 + +#define OCF_CHANGE_LOCAL_NAME		0x0013 +typedef struct { +	uint8_t		name[248]; +} __attribute__ ((packed)) change_local_name_cp; +#define CHANGE_LOCAL_NAME_CP_SIZE 248  + +#define OCF_READ_LOCAL_NAME		0x0014 +typedef struct { +	uint8_t		status; +	uint8_t		name[248]; +} __attribute__ ((packed)) read_local_name_rp; +#define READ_LOCAL_NAME_RP_SIZE 249  + +#define OCF_READ_CONN_ACCEPT_TIMEOUT	0x0015 +typedef struct { +	uint8_t		status; +	uint16_t	timeout; +} __attribute__ ((packed)) read_conn_accept_timeout_rp; +#define READ_CONN_ACCEPT_TIMEOUT_RP_SIZE 3 + +#define OCF_WRITE_CONN_ACCEPT_TIMEOUT	0x0016 +typedef struct { +	uint16_t	timeout; +} __attribute__ ((packed)) write_conn_accept_timeout_cp; +#define WRITE_CONN_ACCEPT_TIMEOUT_CP_SIZE 2 + +#define OCF_READ_PAGE_TIMEOUT		0x0017 +typedef struct { +	uint8_t		status; +	uint16_t	timeout; +} __attribute__ ((packed)) read_page_timeout_rp; +#define READ_PAGE_TIMEOUT_RP_SIZE 3 + +#define OCF_WRITE_PAGE_TIMEOUT		0x0018 +typedef struct { +	uint16_t	timeout; +} __attribute__ ((packed)) write_page_timeout_cp; +#define WRITE_PAGE_TIMEOUT_CP_SIZE 2 + +#define OCF_READ_SCAN_ENABLE		0x0019 +typedef struct { +	uint8_t		status; +	uint8_t		enable; +} __attribute__ ((packed)) read_scan_enable_rp; +#define READ_SCAN_ENABLE_RP_SIZE 2 + +#define OCF_WRITE_SCAN_ENABLE		0x001A +	#define SCAN_DISABLED		0x00 +	#define SCAN_INQUIRY		0x01 +	#define SCAN_PAGE		0x02 + +#define OCF_READ_PAGE_ACTIVITY		0x001B +typedef struct { +	uint8_t		status; +	uint16_t	interval; +	uint16_t	window; +} __attribute__ ((packed)) read_page_activity_rp; +#define READ_PAGE_ACTIVITY_RP_SIZE 5 + +#define OCF_WRITE_PAGE_ACTIVITY		0x001C +typedef struct { +	uint16_t	interval; +	uint16_t	window; +} __attribute__ ((packed)) write_page_activity_cp; +#define WRITE_PAGE_ACTIVITY_CP_SIZE 4 + +#define OCF_READ_INQ_ACTIVITY		0x001D +typedef struct { +	uint8_t		status; +	uint16_t	interval; +	uint16_t	window; +} __attribute__ ((packed)) read_inq_activity_rp; +#define READ_INQ_ACTIVITY_RP_SIZE 5 + +#define OCF_WRITE_INQ_ACTIVITY		0x001E +typedef struct { +	uint16_t	interval; +	uint16_t	window; +} __attribute__ ((packed)) write_inq_activity_cp; +#define WRITE_INQ_ACTIVITY_CP_SIZE 4 + +#define OCF_READ_AUTH_ENABLE		0x001F + +#define OCF_WRITE_AUTH_ENABLE		0x0020 +	#define AUTH_DISABLED		0x00 +	#define AUTH_ENABLED		0x01 + +#define OCF_READ_ENCRYPT_MODE		0x0021 + +#define OCF_WRITE_ENCRYPT_MODE		0x0022 +	#define ENCRYPT_DISABLED	0x00 +	#define ENCRYPT_P2P		0x01 +	#define ENCRYPT_BOTH		0x02 + +#define OCF_READ_CLASS_OF_DEV		0x0023 +typedef struct { +	uint8_t		status; +	uint8_t		dev_class[3]; +} __attribute__ ((packed)) read_class_of_dev_rp; +#define READ_CLASS_OF_DEV_RP_SIZE 4  + +#define OCF_WRITE_CLASS_OF_DEV		0x0024 +typedef struct { +	uint8_t		dev_class[3]; +} __attribute__ ((packed)) write_class_of_dev_cp; +#define WRITE_CLASS_OF_DEV_CP_SIZE 3 + +#define OCF_READ_VOICE_SETTING		0x0025 +typedef struct { +	uint8_t		status; +	uint16_t	voice_setting; +} __attribute__ ((packed)) read_voice_setting_rp; +#define READ_VOICE_SETTING_RP_SIZE 3 + +#define OCF_WRITE_VOICE_SETTING		0x0026 +typedef struct { +	uint16_t	voice_setting; +} __attribute__ ((packed)) write_voice_setting_cp; +#define WRITE_VOICE_SETTING_CP_SIZE 2 + +#define OCF_READ_AUTOMATIC_FLUSH_TIMEOUT	0x0027 + +#define OCF_WRITE_AUTOMATIC_FLUSH_TIMEOUT	0x0028 + +#define OCF_READ_NUM_BROADCAST_RETRANS	0x0029 + +#define OCF_WRITE_NUM_BROADCAST_RETRANS	0x002A + +#define OCF_READ_HOLD_MODE_ACTIVITY	0x002B + +#define OCF_WRITE_HOLD_MODE_ACTIVITY	0x002C + +#define OCF_READ_TRANSMIT_POWER_LEVEL	0x002D +typedef struct { +	uint16_t	handle; +	uint8_t		type; +} __attribute__ ((packed)) read_transmit_power_level_cp; +#define READ_TRANSMIT_POWER_LEVEL_CP_SIZE 3 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	int8_t		level; +} __attribute__ ((packed)) read_transmit_power_level_rp; +#define READ_TRANSMIT_POWER_LEVEL_RP_SIZE 4 + +#define OCF_READ_SYNC_FLOW_ENABLE	0x002E + +#define OCF_WRITE_SYNC_FLOW_ENABLE	0x002F + +#define OCF_SET_CONTROLLER_TO_HOST_FC	0x0031 + +#define OCF_HOST_BUFFER_SIZE		0x0033 +typedef struct { +	uint16_t	acl_mtu; +	uint8_t		sco_mtu; +	uint16_t	acl_max_pkt; +	uint16_t	sco_max_pkt; +} __attribute__ ((packed)) host_buffer_size_cp; +#define HOST_BUFFER_SIZE_CP_SIZE 7 + +#define OCF_HOST_NUM_COMP_PKTS		0x0035 +typedef struct { +	uint8_t		num_hndl; +	/* variable length part */ +} __attribute__ ((packed)) host_num_comp_pkts_cp; +#define HOST_NUM_COMP_PKTS_CP_SIZE 1 + +#define OCF_READ_LINK_SUPERVISION_TIMEOUT	0x0036 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint16_t	timeout; +} __attribute__ ((packed)) read_link_supervision_timeout_rp; +#define READ_LINK_SUPERVISION_TIMEOUT_RP_SIZE 5 + +#define OCF_WRITE_LINK_SUPERVISION_TIMEOUT	0x0037 +typedef struct { +	uint16_t	handle; +	uint16_t	timeout; +} __attribute__ ((packed)) write_link_supervision_timeout_cp; +#define WRITE_LINK_SUPERVISION_TIMEOUT_CP_SIZE 4 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +} __attribute__ ((packed)) write_link_supervision_timeout_rp; +#define WRITE_LINK_SUPERVISION_TIMEOUT_RP_SIZE 3 + +#define OCF_READ_NUM_SUPPORTED_IAC	0x0038 + +#define MAX_IAC_LAP 0x40 +#define OCF_READ_CURRENT_IAC_LAP	0x0039 +typedef struct { +	uint8_t		status; +	uint8_t		num_current_iac; +	uint8_t		lap[MAX_IAC_LAP][3]; +} __attribute__ ((packed)) read_current_iac_lap_rp; +#define READ_CURRENT_IAC_LAP_RP_SIZE 2+3*MAX_IAC_LAP + +#define OCF_WRITE_CURRENT_IAC_LAP	0x003A +typedef struct { +	uint8_t		num_current_iac; +	uint8_t		lap[MAX_IAC_LAP][3]; +} __attribute__ ((packed)) write_current_iac_lap_cp; +#define WRITE_CURRENT_IAC_LAP_CP_SIZE 1+3*MAX_IAC_LAP + +#define OCF_READ_PAGE_SCAN_PERIOD_MODE	0x003B + +#define OCF_WRITE_PAGE_SCAN_PERIOD_MODE	0x003C + +#define OCF_READ_PAGE_SCAN_MODE		0x003D + +#define OCF_WRITE_PAGE_SCAN_MODE	0x003E + +#define OCF_SET_AFH_CLASSIFICATION	0x003F +typedef struct { +	uint8_t		map[10]; +} __attribute__ ((packed)) set_afh_classification_cp; +#define SET_AFH_CLASSIFICATION_CP_SIZE 10 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) set_afh_classification_rp; +#define SET_AFH_CLASSIFICATION_RP_SIZE 1 + +#define OCF_READ_INQUIRY_SCAN_TYPE	0x0042 +typedef struct { +	uint8_t		status; +	uint8_t		type; +} __attribute__ ((packed)) read_inquiry_scan_type_rp; +#define READ_INQUIRY_SCAN_TYPE_RP_SIZE 2 + +#define OCF_WRITE_INQUIRY_SCAN_TYPE	0x0043 +typedef struct { +	uint8_t		type; +} __attribute__ ((packed)) write_inquiry_scan_type_cp; +#define WRITE_INQUIRY_SCAN_TYPE_CP_SIZE 1 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) write_inquiry_scan_type_rp; +#define WRITE_INQUIRY_SCAN_TYPE_RP_SIZE 1 + +#define OCF_READ_INQUIRY_MODE		0x0044 +typedef struct { +	uint8_t		status; +	uint8_t		mode; +} __attribute__ ((packed)) read_inquiry_mode_rp; +#define READ_INQUIRY_MODE_RP_SIZE 2 + +#define OCF_WRITE_INQUIRY_MODE		0x0045 +typedef struct { +	uint8_t		mode; +} __attribute__ ((packed)) write_inquiry_mode_cp; +#define WRITE_INQUIRY_MODE_CP_SIZE 1 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) write_inquiry_mode_rp; +#define WRITE_INQUIRY_MODE_RP_SIZE 1 + +#define OCF_READ_PAGE_SCAN_TYPE		0x0046 + +#define OCF_WRITE_PAGE_SCAN_TYPE	0x0047 + +#define OCF_READ_AFH_MODE		0x0048 +typedef struct { +	uint8_t		status; +	uint8_t		mode; +} __attribute__ ((packed)) read_afh_mode_rp; +#define READ_AFH_MODE_RP_SIZE 2 + +#define OCF_WRITE_AFH_MODE		0x0049 +typedef struct { +	uint8_t		mode; +} __attribute__ ((packed)) write_afh_mode_cp; +#define WRITE_AFH_MODE_CP_SIZE 1 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) write_afh_mode_rp; +#define WRITE_AFH_MODE_RP_SIZE 1 + +#define OCF_READ_EXT_INQUIRY_RESPONSE	0x0051 +typedef struct { +	uint8_t		status; +	uint8_t		fec; +	uint8_t		data[240]; +} __attribute__ ((packed)) read_ext_inquiry_response_rp; +#define READ_EXT_INQUIRY_RESPONSE_RP_SIZE 242 + +#define OCF_WRITE_EXT_INQUIRY_RESPONSE	0x0052 +typedef struct { +	uint8_t		fec; +	uint8_t		data[240]; +} __attribute__ ((packed)) write_ext_inquiry_response_cp; +#define WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE 241 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) write_ext_inquiry_response_rp; +#define WRITE_EXT_INQUIRY_RESPONSE_RP_SIZE 1 + +#define OCF_REFRESH_ENCRYPTION_KEY	0x0053 +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) refresh_encryption_key_cp; +#define REFRESH_ENCRYPTION_KEY_CP_SIZE 2 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) refresh_encryption_key_rp; +#define REFRESH_ENCRYPTION_KEY_RP_SIZE 1 + +#define OCF_READ_SIMPLE_PAIRING_MODE	0x0055 +typedef struct { +	uint8_t		status; +	uint8_t		mode; +} __attribute__ ((packed)) read_simple_pairing_mode_rp; +#define READ_SIMPLE_PAIRING_MODE_RP_SIZE 2 + +#define OCF_WRITE_SIMPLE_PAIRING_MODE	0x0056 +typedef struct { +	uint8_t		mode; +} __attribute__ ((packed)) write_simple_pairing_mode_cp; +#define WRITE_SIMPLE_PAIRING_MODE_CP_SIZE 1 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) write_simple_pairing_mode_rp; +#define WRITE_SIMPLE_PAIRING_MODE_RP_SIZE 1 + +#define OCF_READ_LOCAL_OOB_DATA		0x0057 +typedef struct { +	uint8_t		status; +	uint8_t		hash[16]; +	uint8_t		randomizer[16]; +} __attribute__ ((packed)) read_local_oob_data_rp; +#define READ_LOCAL_OOB_DATA_RP_SIZE 33 + +#define OCF_READ_INQUIRY_TRANSMIT_POWER_LEVEL	0x0058 +typedef struct { +	uint8_t		status; +	int8_t		level; +} __attribute__ ((packed)) read_inquiry_transmit_power_level_rp; +#define READ_INQUIRY_TRANSMIT_POWER_LEVEL_RP_SIZE 2 + +#define OCF_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL	0x0059 +typedef struct { +	int8_t		level; +} __attribute__ ((packed)) write_inquiry_transmit_power_level_cp; +#define WRITE_INQUIRY_TRANSMIT_POWER_LEVEL_CP_SIZE 1 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) write_inquiry_transmit_power_level_rp; +#define WRITE_INQUIRY_TRANSMIT_POWER_LEVEL_RP_SIZE 1 + +#define OCF_READ_DEFAULT_ERROR_DATA_REPORTING	0x005A +typedef struct { +	uint8_t		status; +	uint8_t		reporting; +} __attribute__ ((packed)) read_default_error_data_reporting_rp; +#define READ_DEFAULT_ERROR_DATA_REPORTING_RP_SIZE 2 + +#define OCF_WRITE_DEFAULT_ERROR_DATA_REPORTING	0x005B +typedef struct { +	uint8_t		reporting; +} __attribute__ ((packed)) write_default_error_data_reporting_cp; +#define WRITE_DEFAULT_ERROR_DATA_REPORTING_CP_SIZE 1 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) write_default_error_data_reporting_rp; +#define WRITE_DEFAULT_ERROR_DATA_REPORTING_RP_SIZE 1 + +#define OCF_ENHANCED_FLUSH		0x005F +typedef struct { +	uint16_t	handle; +	uint8_t		type; +} __attribute__ ((packed)) enhanced_flush_cp; +#define ENHANCED_FLUSH_CP_SIZE 3 + +#define OCF_SEND_KEYPRESS_NOTIFY	0x0060 +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		type; +} __attribute__ ((packed)) send_keypress_notify_cp; +#define SEND_KEYPRESS_NOTIFY_CP_SIZE 7 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) send_keypress_notify_rp; +#define SEND_KEYPRESS_NOTIFY_RP_SIZE 1 + +/* Informational Parameters */ +#define OGF_INFO_PARAM		0x04 + +#define OCF_READ_LOCAL_VERSION		0x0001 +typedef struct { +	uint8_t		status; +	uint8_t		hci_ver; +	uint16_t	hci_rev; +	uint8_t		lmp_ver; +	uint16_t	manufacturer; +	uint16_t	lmp_subver; +} __attribute__ ((packed)) read_local_version_rp; +#define READ_LOCAL_VERSION_RP_SIZE 9 + +#define OCF_READ_LOCAL_COMMANDS		0x0002 +typedef struct { +	uint8_t		status; +	uint8_t		commands[64]; +} __attribute__ ((packed)) read_local_commands_rp; +#define READ_LOCAL_COMMANDS_RP_SIZE 65 + +#define OCF_READ_LOCAL_FEATURES		0x0003 +typedef struct { +	uint8_t		status; +	uint8_t		features[8]; +} __attribute__ ((packed)) read_local_features_rp; +#define READ_LOCAL_FEATURES_RP_SIZE 9 + +#define OCF_READ_LOCAL_EXT_FEATURES	0x0004 +typedef struct { +	uint8_t		page_num; +} __attribute__ ((packed)) read_local_ext_features_cp; +#define READ_LOCAL_EXT_FEATURES_CP_SIZE 1 +typedef struct { +	uint8_t		status; +	uint8_t		page_num; +	uint8_t		max_page_num; +	uint8_t		features[8]; +} __attribute__ ((packed)) read_local_ext_features_rp; +#define READ_LOCAL_EXT_FEATURES_RP_SIZE 11 + +#define OCF_READ_BUFFER_SIZE		0x0005 +typedef struct { +	uint8_t		status; +	uint16_t	acl_mtu; +	uint8_t		sco_mtu; +	uint16_t	acl_max_pkt; +	uint16_t	sco_max_pkt; +} __attribute__ ((packed)) read_buffer_size_rp; +#define READ_BUFFER_SIZE_RP_SIZE 8 + +#define OCF_READ_COUNTRY_CODE		0x0007 + +#define OCF_READ_BD_ADDR		0x0009 +typedef struct { +	uint8_t		status; +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) read_bd_addr_rp; +#define READ_BD_ADDR_RP_SIZE 7 + +/* Status params */ +#define OGF_STATUS_PARAM	0x05 + +#define OCF_READ_FAILED_CONTACT_COUNTER		0x0001 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		counter; +} __attribute__ ((packed)) read_failed_contact_counter_rp; +#define READ_FAILED_CONTACT_COUNTER_RP_SIZE 4 + +#define OCF_RESET_FAILED_CONTACT_COUNTER	0x0002 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +} __attribute__ ((packed)) reset_failed_contact_counter_rp; +#define RESET_FAILED_CONTACT_COUNTER_RP_SIZE 4 + +#define OCF_READ_LINK_QUALITY		0x0003 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		link_quality; +} __attribute__ ((packed)) read_link_quality_rp; +#define READ_LINK_QUALITY_RP_SIZE 4 + +#define OCF_READ_RSSI			0x0005 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	int8_t		rssi; +} __attribute__ ((packed)) read_rssi_rp; +#define READ_RSSI_RP_SIZE 4 + +#define OCF_READ_AFH_MAP		0x0006 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		mode; +	uint8_t		map[10]; +} __attribute__ ((packed)) read_afh_map_rp; +#define READ_AFH_MAP_RP_SIZE 14 + +#define OCF_READ_CLOCK			0x0007 +typedef struct { +	uint16_t	handle; +	uint8_t		which_clock; +} __attribute__ ((packed)) read_clock_cp; +#define READ_CLOCK_CP_SIZE 3 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint32_t	clock; +	uint16_t	accuracy; +} __attribute__ ((packed)) read_clock_rp; +#define READ_CLOCK_RP_SIZE 9 + +/* Testing commands */ +#define OGF_TESTING_CMD		0x3e + +#define OCF_READ_LOOPBACK_MODE			0x0001 + +#define OCF_WRITE_LOOPBACK_MODE			0x0002 + +#define OCF_ENABLE_DEVICE_UNDER_TEST_MODE	0x0003 + +#define OCF_WRITE_SIMPLE_PAIRING_DEBUG_MODE	0x0004 +typedef struct { +	uint8_t		mode; +} __attribute__ ((packed)) write_simple_pairing_debug_mode_cp; +#define WRITE_SIMPLE_PAIRING_DEBUG_MODE_CP_SIZE 1 +typedef struct { +	uint8_t		status; +} __attribute__ ((packed)) write_simple_pairing_debug_mode_rp; +#define WRITE_SIMPLE_PAIRING_DEBUG_MODE_RP_SIZE 1 + +/* Vendor specific commands */ +#define OGF_VENDOR_CMD		0x3f + +/* ---- HCI Events ---- */ + +#define EVT_INQUIRY_COMPLETE		0x01 + +#define EVT_INQUIRY_RESULT		0x02 +typedef struct { +	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; +} __attribute__ ((packed)) inquiry_info; +#define INQUIRY_INFO_SIZE 14 + +#define EVT_CONN_COMPLETE		0x03 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	bdaddr_t	bdaddr; +	uint8_t		link_type; +	uint8_t		encr_mode; +} __attribute__ ((packed)) evt_conn_complete; +#define EVT_CONN_COMPLETE_SIZE 13 + +#define EVT_CONN_REQUEST		0x04 +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		dev_class[3]; +	uint8_t		link_type; +} __attribute__ ((packed)) evt_conn_request; +#define EVT_CONN_REQUEST_SIZE 10 + +#define EVT_DISCONN_COMPLETE		0x05 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		reason; +} __attribute__ ((packed)) evt_disconn_complete; +#define EVT_DISCONN_COMPLETE_SIZE 4 + +#define EVT_AUTH_COMPLETE		0x06 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +} __attribute__ ((packed)) evt_auth_complete; +#define EVT_AUTH_COMPLETE_SIZE 3 + +#define EVT_REMOTE_NAME_REQ_COMPLETE	0x07 +typedef struct { +	uint8_t		status; +	bdaddr_t	bdaddr; +	uint8_t		name[248]; +} __attribute__ ((packed)) evt_remote_name_req_complete; +#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255 + +#define EVT_ENCRYPT_CHANGE		0x08 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		encrypt; +} __attribute__ ((packed)) evt_encrypt_change; +#define EVT_ENCRYPT_CHANGE_SIZE 5 + +#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE	0x09 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +}  __attribute__ ((packed)) evt_change_conn_link_key_complete; +#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE_SIZE 3 + +#define EVT_MASTER_LINK_KEY_COMPLETE		0x0A +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		key_flag; +} __attribute__ ((packed)) evt_master_link_key_complete; +#define EVT_MASTER_LINK_KEY_COMPLETE_SIZE 4 + +#define EVT_READ_REMOTE_FEATURES_COMPLETE	0x0B +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		features[8]; +} __attribute__ ((packed)) evt_read_remote_features_complete; +#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11 + +#define EVT_READ_REMOTE_VERSION_COMPLETE	0x0C +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		lmp_ver; +	uint16_t	manufacturer; +	uint16_t	lmp_subver; +} __attribute__ ((packed)) evt_read_remote_version_complete; +#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8 + +#define EVT_QOS_SETUP_COMPLETE		0x0D +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		flags;			/* Reserved */ +	hci_qos		qos; +} __attribute__ ((packed)) evt_qos_setup_complete; +#define EVT_QOS_SETUP_COMPLETE_SIZE (4 + HCI_QOS_CP_SIZE) + +#define EVT_CMD_COMPLETE 		0x0E +typedef struct { +	uint8_t		ncmd; +	uint16_t	opcode; +} __attribute__ ((packed)) evt_cmd_complete; +#define EVT_CMD_COMPLETE_SIZE 3 + +#define EVT_CMD_STATUS 			0x0F +typedef struct { +	uint8_t		status; +	uint8_t		ncmd; +	uint16_t	opcode; +} __attribute__ ((packed)) evt_cmd_status; +#define EVT_CMD_STATUS_SIZE 4 + +#define EVT_HARDWARE_ERROR		0x10 +typedef struct { +	uint8_t		code; +} __attribute__ ((packed)) evt_hardware_error; +#define EVT_HARDWARE_ERROR_SIZE 1 + +#define EVT_FLUSH_OCCURRED		0x11 +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) evt_flush_occured; +#define EVT_FLUSH_OCCURRED_SIZE 2 + +#define EVT_ROLE_CHANGE			0x12 +typedef struct { +	uint8_t		status; +	bdaddr_t	bdaddr; +	uint8_t		role; +} __attribute__ ((packed)) evt_role_change; +#define EVT_ROLE_CHANGE_SIZE 8 + +#define EVT_NUM_COMP_PKTS		0x13 +typedef struct { +	uint8_t		num_hndl; +	/* variable length part */ +} __attribute__ ((packed)) evt_num_comp_pkts; +#define EVT_NUM_COMP_PKTS_SIZE 1 + +#define EVT_MODE_CHANGE			0x14 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		mode; +	uint16_t	interval; +} __attribute__ ((packed)) evt_mode_change; +#define EVT_MODE_CHANGE_SIZE 6 + +#define EVT_RETURN_LINK_KEYS		0x15 +typedef struct { +	uint8_t		num_keys; +	/* variable length part */ +} __attribute__ ((packed)) evt_return_link_keys; +#define EVT_RETURN_LINK_KEYS_SIZE 1 + +#define EVT_PIN_CODE_REQ		0x16 +typedef struct { +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) evt_pin_code_req; +#define EVT_PIN_CODE_REQ_SIZE 6 + +#define EVT_LINK_KEY_REQ		0x17 +typedef struct { +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) evt_link_key_req; +#define EVT_LINK_KEY_REQ_SIZE 6 + +#define EVT_LINK_KEY_NOTIFY		0x18 +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		link_key[16]; +	uint8_t		key_type; +} __attribute__ ((packed)) evt_link_key_notify; +#define EVT_LINK_KEY_NOTIFY_SIZE 23 + +#define EVT_LOOPBACK_COMMAND		0x19 + +#define EVT_DATA_BUFFER_OVERFLOW	0x1A +typedef struct { +	uint8_t		link_type; +} __attribute__ ((packed)) evt_data_buffer_overflow; +#define EVT_DATA_BUFFER_OVERFLOW_SIZE 1 + +#define EVT_MAX_SLOTS_CHANGE		0x1B +typedef struct { +	uint16_t	handle; +	uint8_t		max_slots; +} __attribute__ ((packed)) evt_max_slots_change; +#define EVT_MAX_SLOTS_CHANGE_SIZE 3 + +#define EVT_READ_CLOCK_OFFSET_COMPLETE	0x1C +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint16_t	clock_offset; +} __attribute__ ((packed)) evt_read_clock_offset_complete; +#define EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE 5 + +#define EVT_CONN_PTYPE_CHANGED		0x1D +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint16_t	ptype; +} __attribute__ ((packed)) evt_conn_ptype_changed; +#define EVT_CONN_PTYPE_CHANGED_SIZE 5 + +#define EVT_QOS_VIOLATION		0x1E +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) evt_qos_violation; +#define EVT_QOS_VIOLATION_SIZE 2 + +#define EVT_PSCAN_REP_MODE_CHANGE	0x20 +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		pscan_rep_mode; +} __attribute__ ((packed)) evt_pscan_rep_mode_change; +#define EVT_PSCAN_REP_MODE_CHANGE_SIZE 7 + +#define EVT_FLOW_SPEC_COMPLETE		0x21 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		flags; +	uint8_t		direction; +	hci_qos		qos; +} __attribute__ ((packed)) evt_flow_spec_complete; +#define EVT_FLOW_SPEC_COMPLETE_SIZE (5 + HCI_QOS_CP_SIZE) + +#define EVT_INQUIRY_RESULT_WITH_RSSI	0x22 +typedef struct { +	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; +} __attribute__ ((packed)) inquiry_info_with_rssi; +#define INQUIRY_INFO_WITH_RSSI_SIZE 14 +typedef struct { +	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; +	int8_t		rssi; +} __attribute__ ((packed)) inquiry_info_with_rssi_and_pscan_mode; +#define INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE 15 + +#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE	0x23 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		page_num; +	uint8_t		max_page_num; +	uint8_t		features[8]; +} __attribute__ ((packed)) evt_read_remote_ext_features_complete; +#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE 13 + +#define EVT_SYNC_CONN_COMPLETE		0x2C +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	bdaddr_t	bdaddr; +	uint8_t		link_type; +	uint8_t		trans_interval; +	uint8_t		retrans_window; +	uint16_t	rx_pkt_len; +	uint16_t	tx_pkt_len; +	uint8_t		air_mode; +} __attribute__ ((packed)) evt_sync_conn_complete; +#define EVT_SYNC_CONN_COMPLETE_SIZE 17 + +#define EVT_SYNC_CONN_CHANGED		0x2D +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint8_t		trans_interval; +	uint8_t		retrans_window; +	uint16_t	rx_pkt_len; +	uint16_t	tx_pkt_len; +} __attribute__ ((packed)) evt_sync_conn_changed; +#define EVT_SYNC_CONN_CHANGED_SIZE 9 + +#define EVT_SNIFF_SUBRATING		0x2E +typedef struct { +	uint8_t		status; +	uint16_t	handle; +	uint16_t	max_tx_latency; +	uint16_t	max_rx_latency; +	uint16_t	min_remote_timeout; +	uint16_t	min_local_timeout; +} __attribute__ ((packed)) evt_sniff_subrating; +#define EVT_SNIFF_SUBRATING_SIZE 11 + +#define EVT_EXTENDED_INQUIRY_RESULT	0x2F +typedef struct { +	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]; +} __attribute__ ((packed)) extended_inquiry_info; +#define EXTENDED_INQUIRY_INFO_SIZE 254 + +#define EVT_ENCRYPTION_KEY_REFRESH_COMPLETE	0x30 +typedef struct { +	uint8_t		status; +	uint16_t	handle; +} __attribute__ ((packed)) evt_encryption_key_refresh_complete; +#define EVT_ENCRYPTION_KEY_REFRESH_COMPLETE_SIZE 3 + +#define EVT_IO_CAPABILITY_REQUEST	0x31 +typedef struct { +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) evt_io_capability_request; +#define EVT_IO_CAPABILITY_REQUEST_SIZE 6 + +#define EVT_IO_CAPABILITY_RESPONSE	0x32 +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		capability; +	uint8_t		oob_data; +	uint8_t		authentication; +} __attribute__ ((packed)) evt_io_capability_response; +#define EVT_IO_CAPABILITY_RESPONSE_SIZE 9 + +#define EVT_USER_CONFIRM_REQUEST	0x33 +typedef struct { +	bdaddr_t	bdaddr; +	uint32_t	passkey; +} __attribute__ ((packed)) evt_user_confirm_request; +#define EVT_USER_CONFIRM_REQUEST_SIZE 10 + +#define EVT_USER_PASSKEY_REQUEST	0x34 +typedef struct { +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) evt_user_passkey_request; +#define EVT_USER_PASSKEY_REQUEST_SIZE 6 + +#define EVT_REMOTE_OOB_DATA_REQUEST	0x35 +typedef struct { +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) evt_remote_oob_data_request; +#define EVT_REMOTE_OOB_DATA_REQUEST_SIZE 6 + +#define EVT_SIMPLE_PAIRING_COMPLETE	0x36 +typedef struct { +	uint8_t		status; +	bdaddr_t	bdaddr; +} __attribute__ ((packed)) evt_simple_pairing_complete; +#define EVT_SIMPLE_PAIRING_COMPLETE_SIZE 7 + +#define EVT_LINK_SUPERVISION_TIMEOUT_CHANGED	0x38 +typedef struct { +	uint16_t	handle; +	uint16_t	timeout; +} __attribute__ ((packed)) evt_link_supervision_timeout_changed; +#define EVT_LINK_SUPERVISION_TIMEOUT_CHANGED_SIZE 4 + +#define EVT_ENHANCED_FLUSH_COMPLETE	0x39 +typedef struct { +	uint16_t	handle; +} __attribute__ ((packed)) evt_enhanced_flush_complete; +#define EVT_ENHANCED_FLUSH_COMPLETE_SIZE 2 + +#define EVT_USER_PASSKEY_NOTIFY		0x3B +typedef struct { +	bdaddr_t	bdaddr; +	uint32_t	passkey; +} __attribute__ ((packed)) evt_user_passkey_notify; +#define EVT_USER_PASSKEY_NOTIFY_SIZE 10 + +#define EVT_KEYPRESS_NOTIFY		0x3C +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		type; +} __attribute__ ((packed)) evt_keypress_notify; +#define EVT_KEYPRESS_NOTIFY_SIZE 7 + +#define EVT_REMOTE_HOST_FEATURES_NOTIFY	0x3D +typedef struct { +	bdaddr_t	bdaddr; +	uint8_t		features[8]; +} __attribute__ ((packed)) evt_remote_host_features_notify; +#define EVT_REMOTE_HOST_FEATURES_NOTIFY_SIZE 14 + +#define EVT_TESTING			0xFE + +#define EVT_VENDOR			0xFF + +/* Internal events generated by BlueZ stack */ +#define EVT_STACK_INTERNAL		0xFD +typedef struct { +	uint16_t	type; +	uint8_t		data[0]; +} __attribute__ ((packed)) evt_stack_internal; +#define EVT_STACK_INTERNAL_SIZE 2 + +#define EVT_SI_DEVICE	0x01 +typedef struct { +	uint16_t	event; +	uint16_t	dev_id; +} __attribute__ ((packed)) evt_si_device; +#define EVT_SI_DEVICE_SIZE 4 + +#define EVT_SI_SECURITY	0x02 +typedef struct { +	uint16_t	event; +	uint16_t	proto; +	uint16_t	subproto; +	uint8_t		incoming; +} __attribute__ ((packed)) evt_si_security; + +/* --------  HCI Packet structures  -------- */ +#define HCI_TYPE_LEN	1 + +typedef struct { +	uint16_t	opcode;		/* OCF & OGF */ +	uint8_t		plen; +} __attribute__ ((packed))	hci_command_hdr; +#define HCI_COMMAND_HDR_SIZE 	3 + +typedef struct { +	uint8_t		evt; +	uint8_t		plen; +} __attribute__ ((packed))	hci_event_hdr; +#define HCI_EVENT_HDR_SIZE 	2 + +typedef struct { +	uint16_t	handle;		/* Handle & Flags(PB, BC) */ +	uint16_t	dlen; +} __attribute__ ((packed))	hci_acl_hdr; +#define HCI_ACL_HDR_SIZE 	4 + +typedef struct { +	uint16_t	handle; +	uint8_t		dlen; +} __attribute__ ((packed))	hci_sco_hdr; +#define HCI_SCO_HDR_SIZE 	3 + +typedef struct { +	uint16_t	device; +	uint16_t	type; +	uint16_t	plen; +} __attribute__ ((packed))	hci_msg_hdr; +#define HCI_MSG_HDR_SIZE	6 + +/* Command opcode pack/unpack */ +#define cmd_opcode_pack(ogf, ocf)	(uint16_t)((ocf & 0x03ff)|(ogf << 10)) +#define cmd_opcode_ogf(op)		(op >> 10) +#define cmd_opcode_ocf(op)		(op & 0x03ff) + +/* ACL handle and flags pack/unpack */ +#define acl_handle_pack(h, f)	(uint16_t)((h & 0x0fff)|(f << 12)) +#define acl_handle(h)		(h & 0x0fff) +#define acl_flags(h)		(h >> 12) + +#endif /* _NO_HCI_DEFS */ + +/* HCI Socket options */ +#define HCI_DATA_DIR	1 +#define HCI_FILTER	2 +#define HCI_TIME_STAMP	3 + +/* HCI CMSG flags */ +#define HCI_CMSG_DIR	0x0001 +#define HCI_CMSG_TSTAMP	0x0002 + +struct sockaddr_hci { +	sa_family_t	hci_family; +	unsigned short	hci_dev; +}; +#define HCI_DEV_NONE	0xffff + +struct hci_filter { +	uint32_t type_mask; +	uint32_t event_mask[2]; +	uint16_t opcode; +}; + +#define HCI_FLT_TYPE_BITS	31 +#define HCI_FLT_EVENT_BITS	63 +#define HCI_FLT_OGF_BITS	63 +#define HCI_FLT_OCF_BITS	127 + +/* Ioctl requests structures */ +struct hci_dev_stats { +	uint32_t err_rx; +	uint32_t err_tx; +	uint32_t cmd_tx; +	uint32_t evt_rx; +	uint32_t acl_tx; +	uint32_t acl_rx; +	uint32_t sco_tx; +	uint32_t sco_rx; +	uint32_t byte_rx; +	uint32_t byte_tx; +}; + +struct hci_dev_info { +	uint16_t dev_id; +	char     name[8]; + +	bdaddr_t bdaddr; + +	uint32_t flags; +	uint8_t  type; + +	uint8_t  features[8]; + +	uint32_t pkt_type; +	uint32_t link_policy; +	uint32_t link_mode; + +	uint16_t acl_mtu; +	uint16_t acl_pkts; +	uint16_t sco_mtu; +	uint16_t sco_pkts; + +	struct   hci_dev_stats stat; +}; + +struct hci_conn_info { +	uint16_t handle; +	bdaddr_t bdaddr; +	uint8_t  type; +	uint8_t	 out; +	uint16_t state; +	uint32_t link_mode; +}; + +struct hci_dev_req { +	uint16_t dev_id; +	uint32_t dev_opt; +}; + +struct hci_dev_list_req { +	uint16_t dev_num; +	struct hci_dev_req dev_req[0];	/* hci_dev_req structures */ +}; + +struct hci_conn_list_req { +	uint16_t dev_id; +	uint16_t conn_num; +	struct hci_conn_info conn_info[0]; +}; + +struct hci_conn_info_req { +	bdaddr_t bdaddr; +	uint8_t  type; +	struct hci_conn_info conn_info[0]; +}; + +struct hci_auth_info_req { +	bdaddr_t bdaddr; +	uint8_t  type; +}; + +struct hci_inquiry_req { +	uint16_t dev_id; +	uint16_t flags; +	uint8_t  lap[3]; +	uint8_t  length; +	uint8_t  num_rsp; +}; +#define IREQ_CACHE_FLUSH 0x0001 + +struct hci_remotename_req { +	uint16_t dev_id; +	uint16_t flags; +	bdaddr_t bdaddr; +	uint8_t  name[248]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __HCI_H */ diff --git a/include/hci_lib.h b/include/hci_lib.h new file mode 100644 index 00000000..ccd155a5 --- /dev/null +++ b/include/hci_lib.h @@ -0,0 +1,213 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2000-2001  Qualcomm Incorporated + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __HCI_LIB_H +#define __HCI_LIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct hci_request { +	uint16_t ogf; +	uint16_t ocf; +	int      event; +	void     *cparam; +	int      clen; +	void     *rparam; +	int      rlen; +}; + +struct hci_version { +	uint16_t manufacturer; +	uint8_t  hci_ver; +	uint16_t hci_rev; +	uint8_t  lmp_ver; +	uint16_t lmp_subver; +}; + +int hci_open_dev(int dev_id); +int hci_close_dev(int dd); +int hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param); +int hci_send_req(int dd, struct hci_request *req, int timeout); + +int hci_create_connection(int dd, const bdaddr_t *bdaddr, uint16_t ptype, uint16_t clkoffset, uint8_t rswitch, uint16_t *handle, int to); +int hci_disconnect(int dd, uint16_t handle, uint8_t reason, int to); + +int hci_inquiry(int dev_id, int len, int num_rsp, const uint8_t *lap, inquiry_info **ii, long flags); +int hci_devinfo(int dev_id, struct hci_dev_info *di); +int hci_devba(int dev_id, bdaddr_t *bdaddr); +int hci_devid(const char *str); + +int hci_read_local_name(int dd, int len, char *name, int to); +int hci_write_local_name(int dd, const char *name, int to); +int hci_read_remote_name(int dd, const bdaddr_t *bdaddr, int len, char *name, int to); +int hci_read_remote_name_with_clock_offset(int dd, const bdaddr_t *bdaddr, uint8_t pscan_rep_mode, uint16_t clkoffset, int len, char *name, int to); +int hci_read_remote_name_cancel(int dd, const bdaddr_t *bdaddr, int to); +int hci_read_remote_version(int dd, uint16_t handle, struct hci_version *ver, int to); +int hci_read_remote_features(int dd, uint16_t handle, uint8_t *features, int to); +int hci_read_remote_ext_features(int dd, uint16_t handle, uint8_t page, uint8_t *max_page, uint8_t *features, int to); +int hci_read_clock_offset(int dd, uint16_t handle, uint16_t *clkoffset, int to); +int hci_read_local_version(int dd, struct hci_version *ver, int to); +int hci_read_local_commands(int dd, uint8_t *commands, int to); +int hci_read_local_features(int dd, uint8_t *features, int to); +int hci_read_local_ext_features(int dd, uint8_t page, uint8_t *max_page, uint8_t *features, int to); +int hci_read_bd_addr(int dd, bdaddr_t *bdaddr, int to); +int hci_read_class_of_dev(int dd, uint8_t *cls, int to); +int hci_write_class_of_dev(int dd, uint32_t cls, int to); +int hci_read_voice_setting(int dd, uint16_t *vs, int to); +int hci_write_voice_setting(int dd, uint16_t vs, int to); +int hci_read_current_iac_lap(int dd, uint8_t *num_iac, uint8_t *lap, int to); +int hci_write_current_iac_lap(int dd, uint8_t num_iac, uint8_t *lap, int to); +int hci_read_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to); +int hci_write_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t *key, int to); +int hci_delete_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to); +int hci_authenticate_link(int dd, uint16_t handle, int to); +int hci_encrypt_link(int dd, uint16_t handle, uint8_t encrypt, int to); +int hci_change_link_key(int dd, uint16_t handle, int to); +int hci_switch_role(int dd, bdaddr_t *bdaddr, uint8_t role, int to); +int hci_park_mode(int dd, uint16_t handle, uint16_t max_interval, uint16_t min_interval, int to); +int hci_exit_park_mode(int dd, uint16_t handle, int to); +int hci_read_inquiry_scan_type(int dd, uint8_t *type, int to); +int hci_write_inquiry_scan_type(int dd, uint8_t type, int to); +int hci_read_inquiry_mode(int dd, uint8_t *mode, int to); +int hci_write_inquiry_mode(int dd, uint8_t mode, int to); +int hci_read_afh_mode(int dd, uint8_t *mode, int to); +int hci_write_afh_mode(int dd, uint8_t mode, int to); +int hci_read_ext_inquiry_response(int dd, uint8_t *fec, uint8_t *data, int to); +int hci_write_ext_inquiry_response(int dd, uint8_t fec, uint8_t *data, int to); +int hci_read_simple_pairing_mode(int dd, uint8_t *mode, int to); +int hci_write_simple_pairing_mode(int dd, uint8_t mode, int to); +int hci_read_local_oob_data(int dd, uint8_t *hash, uint8_t *randomizer, int to); +int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to); +int hci_write_inquiry_transmit_power_level(int dd, int8_t level, int to); +int hci_read_transmit_power_level(int dd, uint16_t handle, uint8_t type, int8_t *level, int to); +int hci_read_link_policy(int dd, uint16_t handle, uint16_t *policy, int to); +int hci_write_link_policy(int dd, uint16_t handle, uint16_t policy, int to); +int hci_read_link_supervision_timeout(int dd, uint16_t handle, uint16_t *timeout, int to); +int hci_write_link_supervision_timeout(int dd, uint16_t handle, uint16_t timeout, int to); +int hci_set_afh_classification(int dd, uint8_t *map, int to); +int hci_read_link_quality(int dd, uint16_t handle, uint8_t *link_quality, int to); +int hci_read_rssi(int dd, uint16_t handle, int8_t *rssi, int to); +int hci_read_afh_map(int dd, uint16_t handle, uint8_t *mode, uint8_t *map, int to); +int hci_read_clock(int dd, uint16_t handle, uint8_t which, uint32_t *clock, uint16_t *accuracy, int to); + +int hci_local_name(int dd, int len, char *name, int to); +int hci_remote_name(int dd, const bdaddr_t *bdaddr, int len, char *name, int to); + +int hci_for_each_dev(int flag, int(*func)(int dd, int dev_id, long arg), long arg); +int hci_get_route(bdaddr_t *bdaddr); + +char *hci_dtypetostr(int type); +char *hci_dflagstostr(uint32_t flags); +char *hci_ptypetostr(unsigned int ptype); +int hci_strtoptype(char *str, unsigned int *val); +char *hci_scoptypetostr(unsigned int ptype); +int hci_strtoscoptype(char *str, unsigned int *val); +char *hci_lptostr(unsigned int ptype); +int hci_strtolp(char *str, unsigned int *val); +char *hci_lmtostr(unsigned int ptype); +int hci_strtolm(char *str, unsigned int *val); + +char *hci_cmdtostr(unsigned int cmd); +char *hci_commandstostr(uint8_t *commands, char *pref, int width); + +char *hci_vertostr(unsigned int ver); +int hci_strtover(char *str, unsigned int *ver); +char *lmp_vertostr(unsigned int ver); +int lmp_strtover(char *str, unsigned int *ver); + +char *lmp_featurestostr(uint8_t *features, char *pref, int width); + +static inline void hci_set_bit(int nr, void *addr) +{ +	*((uint32_t *) addr + (nr >> 5)) |= (1 << (nr & 31)); +} + +static inline void hci_clear_bit(int nr, void *addr) +{ +	*((uint32_t *) addr + (nr >> 5)) &= ~(1 << (nr & 31)); +} + +static inline int hci_test_bit(int nr, void *addr) +{ +	return *((uint32_t *) addr + (nr >> 5)) & (1 << (nr & 31)); +} + +/* HCI filter tools */ +static inline void hci_filter_clear(struct hci_filter *f) +{ +	memset(f, 0, sizeof(*f)); +} +static inline void hci_filter_set_ptype(int t, struct hci_filter *f) +{ +	hci_set_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask); +} +static inline void hci_filter_clear_ptype(int t, struct hci_filter *f) +{ +	hci_clear_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask); +} +static inline int hci_filter_test_ptype(int t, struct hci_filter *f) +{ +	return hci_test_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask); +} +static inline void hci_filter_all_ptypes(struct hci_filter *f) +{ +	memset((void *) &f->type_mask, 0xff, sizeof(f->type_mask)); +} +static inline void hci_filter_set_event(int e, struct hci_filter *f) +{ +	hci_set_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask); +} +static inline void hci_filter_clear_event(int e, struct hci_filter *f) +{ +	hci_clear_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask); +} +static inline int hci_filter_test_event(int e, struct hci_filter *f) +{ +	return hci_test_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask); +} +static inline void hci_filter_all_events(struct hci_filter *f) +{ +	memset((void *) f->event_mask, 0xff, sizeof(f->event_mask)); +} +static inline void hci_filter_set_opcode(int opcode, struct hci_filter *f) +{ +	f->opcode = opcode; +} +static inline void hci_filter_clear_opcode(struct hci_filter *f) +{ +	f->opcode = 0; +} +static inline int hci_filter_test_opcode(int opcode, struct hci_filter *f) +{ +	return (f->opcode == opcode); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __HCI_LIB_H */ diff --git a/include/hidp.h b/include/hidp.h new file mode 100644 index 00000000..74da6897 --- /dev/null +++ b/include/hidp.h @@ -0,0 +1,85 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2003-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __HIDP_H +#define __HIDP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* HIDP defaults */ +#define HIDP_MINIMUM_MTU 48 +#define HIDP_DEFAULT_MTU 48 + +/* HIDP ioctl defines */ +#define HIDPCONNADD	_IOW('H', 200, int) +#define HIDPCONNDEL	_IOW('H', 201, int) +#define HIDPGETCONNLIST	_IOR('H', 210, int) +#define HIDPGETCONNINFO	_IOR('H', 211, int) + +#define HIDP_VIRTUAL_CABLE_UNPLUG	0 +#define HIDP_BOOT_PROTOCOL_MODE		1 +#define HIDP_BLUETOOTH_VENDOR_ID	9 + +struct hidp_connadd_req { +	int ctrl_sock;		/* Connected control socket */ +	int intr_sock;		/* Connected interrupt socket */ +	uint16_t parser;	/* Parser version */ +	uint16_t rd_size;	/* Report descriptor size */ +	uint8_t *rd_data;	/* Report descriptor data */ +	uint8_t  country; +	uint8_t  subclass; +	uint16_t vendor; +	uint16_t product; +	uint16_t version; +	uint32_t flags; +	uint32_t idle_to; +	char name[128];		/* Device name */ +}; + +struct hidp_conndel_req { +	bdaddr_t bdaddr; +	uint32_t flags; +}; + +struct hidp_conninfo { +	bdaddr_t bdaddr; +	uint32_t flags; +	uint16_t state; +	uint16_t vendor; +	uint16_t product; +	uint16_t version; +	char name[128]; +}; + +struct hidp_connlist_req { +	uint32_t cnum; +	struct hidp_conninfo *ci; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __HIDP_H */ diff --git a/include/l2cap.h b/include/l2cap.h new file mode 100644 index 00000000..d54e74d2 --- /dev/null +++ b/include/l2cap.h @@ -0,0 +1,204 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2000-2001  Qualcomm Incorporated + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __L2CAP_H +#define __L2CAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/socket.h> + +/* L2CAP defaults */ +#define L2CAP_DEFAULT_MTU	672 +#define L2CAP_DEFAULT_FLUSH_TO	0xFFFF + +#define L2CAP_CONN_TIMEOUT	(HZ * 40) + +/* L2CAP socket address */ +struct sockaddr_l2 { +	sa_family_t	l2_family; +	unsigned short	l2_psm; +	bdaddr_t	l2_bdaddr; +}; + +/* L2CAP socket options */ +#define L2CAP_OPTIONS	0x01 +struct l2cap_options { +	uint16_t	omtu; +	uint16_t	imtu; +	uint16_t	flush_to; +	uint8_t		mode; +}; + +#define L2CAP_CONNINFO	0x02 +struct l2cap_conninfo { +	uint16_t	hci_handle; +	uint8_t		dev_class[3]; +}; + +#define L2CAP_LM	0x03 +#define L2CAP_LM_MASTER		0x0001 +#define L2CAP_LM_AUTH		0x0002 +#define L2CAP_LM_ENCRYPT	0x0004 +#define L2CAP_LM_TRUSTED	0x0008 +#define L2CAP_LM_RELIABLE	0x0010 +#define L2CAP_LM_SECURE		0x0020 + +/* L2CAP command codes */ +#define L2CAP_COMMAND_REJ	0x01 +#define L2CAP_CONN_REQ		0x02 +#define L2CAP_CONN_RSP		0x03 +#define L2CAP_CONF_REQ		0x04 +#define L2CAP_CONF_RSP		0x05 +#define L2CAP_DISCONN_REQ	0x06 +#define L2CAP_DISCONN_RSP	0x07 +#define L2CAP_ECHO_REQ		0x08 +#define L2CAP_ECHO_RSP		0x09 +#define L2CAP_INFO_REQ		0x0a +#define L2CAP_INFO_RSP		0x0b + +/* L2CAP structures */ +typedef struct { +	uint16_t	len; +	uint16_t	cid; +} __attribute__ ((packed)) l2cap_hdr; +#define L2CAP_HDR_SIZE 4 + +typedef struct { +	uint8_t		code; +	uint8_t		ident; +	uint16_t	len; +} __attribute__ ((packed)) l2cap_cmd_hdr; +#define L2CAP_CMD_HDR_SIZE 4 + +typedef struct { +	uint16_t	reason; +} __attribute__ ((packed)) l2cap_cmd_rej; +#define L2CAP_CMD_REJ_SIZE 2 + +typedef struct { +	uint16_t	psm; +	uint16_t	scid; +} __attribute__ ((packed)) l2cap_conn_req; +#define L2CAP_CONN_REQ_SIZE 4 + +typedef struct { +	uint16_t	dcid; +	uint16_t	scid; +	uint16_t	result; +	uint16_t	status; +} __attribute__ ((packed)) l2cap_conn_rsp; +#define L2CAP_CONN_RSP_SIZE 8 + +/* connect result */ +#define L2CAP_CR_SUCCESS	0x0000 +#define L2CAP_CR_PEND		0x0001 +#define L2CAP_CR_BAD_PSM	0x0002 +#define L2CAP_CR_SEC_BLOCK	0x0003 +#define L2CAP_CR_NO_MEM		0x0004 + +/* connect status */ +#define L2CAP_CS_NO_INFO	0x0000 +#define L2CAP_CS_AUTHEN_PEND	0x0001 +#define L2CAP_CS_AUTHOR_PEND	0x0002 + +typedef struct { +	uint16_t	dcid; +	uint16_t	flags; +	uint8_t		data[0]; +} __attribute__ ((packed)) l2cap_conf_req; +#define L2CAP_CONF_REQ_SIZE 4 + +typedef struct { +	uint16_t	scid; +	uint16_t	flags; +	uint16_t	result; +	uint8_t		data[0]; +} __attribute__ ((packed)) l2cap_conf_rsp; +#define L2CAP_CONF_RSP_SIZE 6 + +#define L2CAP_CONF_SUCCESS	0x0000 +#define L2CAP_CONF_UNACCEPT	0x0001 +#define L2CAP_CONF_REJECT	0x0002 +#define L2CAP_CONF_UNKNOWN	0x0003 + +typedef struct { +	uint8_t		type; +	uint8_t		len; +	uint8_t		val[0]; +} __attribute__ ((packed)) l2cap_conf_opt; +#define L2CAP_CONF_OPT_SIZE 2 + +#define L2CAP_CONF_MTU		0x01 +#define L2CAP_CONF_FLUSH_TO	0x02 +#define L2CAP_CONF_QOS		0x03 +#define L2CAP_CONF_RFC		0x04 +#define L2CAP_CONF_RFC_MODE	0x04 + +#define L2CAP_CONF_MAX_SIZE	22 + +#define L2CAP_MODE_BASIC	0x00 +#define L2CAP_MODE_RETRANS	0x01 +#define L2CAP_MODE_FLOWCTL	0x02 + +typedef struct { +	uint16_t	dcid; +	uint16_t	scid; +} __attribute__ ((packed)) l2cap_disconn_req; +#define L2CAP_DISCONN_REQ_SIZE 4 + +typedef struct { +	uint16_t	dcid; +	uint16_t	scid; +} __attribute__ ((packed)) l2cap_disconn_rsp; +#define L2CAP_DISCONN_RSP_SIZE 4 + +typedef struct { +	uint16_t	type; +} __attribute__ ((packed)) l2cap_info_req; +#define L2CAP_INFO_REQ_SIZE 2 + +typedef struct { +	uint16_t	type; +	uint16_t	result; +	uint8_t		data[0]; +} __attribute__ ((packed)) l2cap_info_rsp; +#define L2CAP_INFO_RSP_SIZE 4 + +/* info type */ +#define L2CAP_IT_CL_MTU		0x0001 +#define L2CAP_IT_FEAT_MASK	0x0002 + +/* info result */ +#define L2CAP_IR_SUCCESS	0x0000 +#define L2CAP_IR_NOTSUPP	0x0001 + +#ifdef __cplusplus +} +#endif + +#endif /* __L2CAP_H */ diff --git a/include/rfcomm.h b/include/rfcomm.h new file mode 100644 index 00000000..5c4751ea --- /dev/null +++ b/include/rfcomm.h @@ -0,0 +1,102 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __RFCOMM_H +#define __RFCOMM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/socket.h> + +/* RFCOMM defaults */ +#define RFCOMM_DEFAULT_MTU	127 + +#define RFCOMM_PSM 3 + +#define RFCOMM_CONN_TIMEOUT	(HZ * 30) +#define RFCOMM_DISC_TIMEOUT	(HZ * 20) + +/* RFCOMM socket address */ +struct sockaddr_rc { +	sa_family_t	rc_family; +	bdaddr_t	rc_bdaddr; +	uint8_t		rc_channel; +}; + +/* RFCOMM socket options */ +#define RFCOMM_CONNINFO	0x02 +struct rfcomm_conninfo { +	uint16_t	hci_handle; +	uint8_t		dev_class[3]; +}; + +#define RFCOMM_LM	0x03 +#define RFCOMM_LM_MASTER	0x0001 +#define RFCOMM_LM_AUTH		0x0002 +#define RFCOMM_LM_ENCRYPT	0x0004 +#define RFCOMM_LM_TRUSTED	0x0008 +#define RFCOMM_LM_RELIABLE	0x0010 +#define RFCOMM_LM_SECURE	0x0020 + +/* RFCOMM TTY support */ +#define RFCOMM_MAX_DEV	256 + +#define RFCOMMCREATEDEV		_IOW('R', 200, int) +#define RFCOMMRELEASEDEV	_IOW('R', 201, int) +#define RFCOMMGETDEVLIST	_IOR('R', 210, int) +#define RFCOMMGETDEVINFO	_IOR('R', 211, int) + +struct rfcomm_dev_req { +	int16_t		dev_id; +	uint32_t	flags; +	bdaddr_t	src; +	bdaddr_t	dst; +	uint8_t	channel; +}; +#define RFCOMM_REUSE_DLC	0 +#define RFCOMM_RELEASE_ONHUP	1 +#define RFCOMM_HANGUP_NOW	2 +#define RFCOMM_TTY_ATTACHED	3 + +struct rfcomm_dev_info { +	int16_t		id; +	uint32_t	flags; +	uint16_t	state; +	bdaddr_t	src; +	bdaddr_t	dst; +	uint8_t		channel; +}; + +struct rfcomm_dev_list_req { +	uint16_t	dev_num; +	struct rfcomm_dev_info dev_info[0]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __RFCOMM_H */ diff --git a/include/sco.h b/include/sco.h new file mode 100644 index 00000000..bce7098f --- /dev/null +++ b/include/sco.h @@ -0,0 +1,62 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __SCO_H +#define __SCO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* SCO defaults */ +#define SCO_DEFAULT_MTU		500 +#define SCO_DEFAULT_FLUSH_TO	0xFFFF + +#define SCO_CONN_TIMEOUT	(HZ * 40) +#define SCO_DISCONN_TIMEOUT	(HZ * 2) +#define SCO_CONN_IDLE_TIMEOUT	(HZ * 60) + +/* SCO socket address */ +struct sockaddr_sco { +	sa_family_t	sco_family; +	bdaddr_t	sco_bdaddr; +}; + +/* set/get sockopt defines */ +#define SCO_OPTIONS	0x01 +struct sco_options { +	uint16_t	mtu; +}; + +#define SCO_CONNINFO	0x02 +struct sco_conninfo { +	uint16_t	hci_handle; +	uint8_t		dev_class[3]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __SCO_H */ diff --git a/include/sdp.h b/include/sdp.h new file mode 100644 index 00000000..dd5b0e24 --- /dev/null +++ b/include/sdp.h @@ -0,0 +1,503 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2001-2002  Nokia Corporation + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __SDP_H +#define __SDP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +#define SDP_UNIX_PATH "/var/run/sdp" +#define SDP_RESPONSE_TIMEOUT	20 +#define SDP_REQ_BUFFER_SIZE	2048 +#define SDP_RSP_BUFFER_SIZE	65535 +#define SDP_PDU_CHUNK_SIZE	1024 + +/* + * All definitions are based on Bluetooth Assigned Numbers + * of the Bluetooth Specification + */ +#define SDP_PSM 		0x0001 + +/* + * Protocol UUIDs + */ +#define SDP_UUID	0x0001 +#define UDP_UUID	0x0002 +#define RFCOMM_UUID	0x0003 +#define TCP_UUID	0x0004 +#define TCS_BIN_UUID	0x0005 +#define TCS_AT_UUID	0x0006 +#define OBEX_UUID	0x0008 +#define IP_UUID		0x0009 +#define FTP_UUID	0x000a +#define HTTP_UUID	0x000c +#define WSP_UUID	0x000e +#define BNEP_UUID	0x000f +#define UPNP_UUID	0x0010 +#define HIDP_UUID	0x0011 +#define HCRP_CTRL_UUID	0x0012 +#define HCRP_DATA_UUID	0x0014 +#define HCRP_NOTE_UUID	0x0016 +#define AVCTP_UUID	0x0017 +#define AVDTP_UUID	0x0019 +#define CMTP_UUID	0x001b +#define UDI_UUID	0x001d +#define MCAP_CTRL_UUID	0x001e +#define MCAP_DATA_UUID	0x001f +#define L2CAP_UUID	0x0100 + +/* + * Service class identifiers of standard services and service groups + */ +#define SDP_SERVER_SVCLASS_ID		0x1000 +#define BROWSE_GRP_DESC_SVCLASS_ID	0x1001 +#define PUBLIC_BROWSE_GROUP		0x1002 +#define SERIAL_PORT_SVCLASS_ID		0x1101 +#define LAN_ACCESS_SVCLASS_ID		0x1102 +#define DIALUP_NET_SVCLASS_ID		0x1103 +#define IRMC_SYNC_SVCLASS_ID		0x1104 +#define OBEX_OBJPUSH_SVCLASS_ID		0x1105 +#define OBEX_FILETRANS_SVCLASS_ID	0x1106 +#define IRMC_SYNC_CMD_SVCLASS_ID	0x1107 +#define HEADSET_SVCLASS_ID		0x1108 +#define CORDLESS_TELEPHONY_SVCLASS_ID	0x1109 +#define AUDIO_SOURCE_SVCLASS_ID		0x110a +#define AUDIO_SINK_SVCLASS_ID		0x110b +#define AV_REMOTE_TARGET_SVCLASS_ID	0x110c +#define ADVANCED_AUDIO_SVCLASS_ID	0x110d +#define AV_REMOTE_SVCLASS_ID		0x110e +#define VIDEO_CONF_SVCLASS_ID		0x110f +#define INTERCOM_SVCLASS_ID		0x1110 +#define FAX_SVCLASS_ID			0x1111 +#define HEADSET_AGW_SVCLASS_ID		0x1112 +#define WAP_SVCLASS_ID			0x1113 +#define WAP_CLIENT_SVCLASS_ID		0x1114 +#define PANU_SVCLASS_ID			0x1115 +#define NAP_SVCLASS_ID			0x1116 +#define GN_SVCLASS_ID			0x1117 +#define DIRECT_PRINTING_SVCLASS_ID	0x1118 +#define REFERENCE_PRINTING_SVCLASS_ID	0x1119 +#define IMAGING_SVCLASS_ID		0x111a +#define IMAGING_RESPONDER_SVCLASS_ID	0x111b +#define IMAGING_ARCHIVE_SVCLASS_ID	0x111c +#define IMAGING_REFOBJS_SVCLASS_ID	0x111d +#define HANDSFREE_SVCLASS_ID		0x111e +#define HANDSFREE_AGW_SVCLASS_ID	0x111f +#define DIRECT_PRT_REFOBJS_SVCLASS_ID	0x1120 +#define REFLECTED_UI_SVCLASS_ID		0x1121 +#define BASIC_PRINTING_SVCLASS_ID	0x1122 +#define PRINTING_STATUS_SVCLASS_ID	0x1123 +#define HID_SVCLASS_ID			0x1124 +#define HCR_SVCLASS_ID			0x1125 +#define HCR_PRINT_SVCLASS_ID		0x1126 +#define HCR_SCAN_SVCLASS_ID		0x1127 +#define CIP_SVCLASS_ID			0x1128 +#define VIDEO_CONF_GW_SVCLASS_ID	0x1129 +#define UDI_MT_SVCLASS_ID		0x112a +#define UDI_TA_SVCLASS_ID		0x112b +#define AV_SVCLASS_ID			0x112c +#define SAP_SVCLASS_ID			0x112d +#define PBAP_PCE_SVCLASS_ID		0x112e +#define PBAP_PSE_SVCLASS_ID		0x112f +#define PBAP_SVCLASS_ID			0x1130 +#define PNP_INFO_SVCLASS_ID		0x1200 +#define GENERIC_NETWORKING_SVCLASS_ID	0x1201 +#define GENERIC_FILETRANS_SVCLASS_ID	0x1202 +#define GENERIC_AUDIO_SVCLASS_ID	0x1203 +#define GENERIC_TELEPHONY_SVCLASS_ID	0x1204 +#define UPNP_SVCLASS_ID			0x1205 +#define UPNP_IP_SVCLASS_ID		0x1206 +#define UPNP_PAN_SVCLASS_ID		0x1300 +#define UPNP_LAP_SVCLASS_ID		0x1301 +#define UPNP_L2CAP_SVCLASS_ID		0x1302 +#define VIDEO_SOURCE_SVCLASS_ID		0x1303 +#define VIDEO_SINK_SVCLASS_ID		0x1304 +#define VIDEO_DISTRIBUTION_SVCLASS_ID	0x1305 +#define MDP_SVCLASS_ID			0x1400 +#define MDP_SOURCE_SVCLASS_ID		0x1401 +#define MDP_SINK_SVCLASS_ID		0x1402 +#define APPLE_AGENT_SVCLASS_ID		0x2112 + +/* + * Standard profile descriptor identifiers; note these + * may be identical to some of the service classes defined above + */ +#define SDP_SERVER_PROFILE_ID		SDP_SERVER_SVCLASS_ID +#define BROWSE_GRP_DESC_PROFILE_ID	BROWSE_GRP_DESC_SVCLASS_ID +#define SERIAL_PORT_PROFILE_ID		SERIAL_PORT_SVCLASS_ID +#define LAN_ACCESS_PROFILE_ID		LAN_ACCESS_SVCLASS_ID +#define DIALUP_NET_PROFILE_ID		DIALUP_NET_SVCLASS_ID +#define IRMC_SYNC_PROFILE_ID		IRMC_SYNC_SVCLASS_ID +#define OBEX_OBJPUSH_PROFILE_ID		OBEX_OBJPUSH_SVCLASS_ID +#define OBEX_FILETRANS_PROFILE_ID	OBEX_FILETRANS_SVCLASS_ID +#define IRMC_SYNC_CMD_PROFILE_ID	IRMC_SYNC_CMD_SVCLASS_ID +#define HEADSET_PROFILE_ID		HEADSET_SVCLASS_ID +#define CORDLESS_TELEPHONY_PROFILE_ID	CORDLESS_TELEPHONY_SVCLASS_ID +#define AUDIO_SOURCE_PROFILE_ID		AUDIO_SOURCE_SVCLASS_ID +#define AUDIO_SINK_PROFILE_ID		AUDIO_SINK_SVCLASS_ID +#define AV_REMOTE_TARGET_PROFILE_ID	AV_REMOTE_TARGET_SVCLASS_ID +#define ADVANCED_AUDIO_PROFILE_ID	ADVANCED_AUDIO_SVCLASS_ID +#define AV_REMOTE_PROFILE_ID		AV_REMOTE_SVCLASS_ID +#define VIDEO_CONF_PROFILE_ID		VIDEO_CONF_SVCLASS_ID +#define INTERCOM_PROFILE_ID		INTERCOM_SVCLASS_ID +#define FAX_PROFILE_ID			FAX_SVCLASS_ID +#define HEADSET_AGW_PROFILE_ID		HEADSET_AGW_SVCLASS_ID +#define WAP_PROFILE_ID			WAP_SVCLASS_ID +#define WAP_CLIENT_PROFILE_ID		WAP_CLIENT_SVCLASS_ID +#define PANU_PROFILE_ID			PANU_SVCLASS_ID +#define NAP_PROFILE_ID			NAP_SVCLASS_ID +#define GN_PROFILE_ID			GN_SVCLASS_ID +#define DIRECT_PRINTING_PROFILE_ID	DIRECT_PRINTING_SVCLASS_ID +#define REFERENCE_PRINTING_PROFILE_ID	REFERENCE_PRINTING_SVCLASS_ID +#define IMAGING_PROFILE_ID		IMAGING_SVCLASS_ID +#define IMAGING_RESPONDER_PROFILE_ID	IMAGING_RESPONDER_SVCLASS_ID +#define IMAGING_ARCHIVE_PROFILE_ID	IMAGING_ARCHIVE_SVCLASS_ID +#define IMAGING_REFOBJS_PROFILE_ID	IMAGING_REFOBJS_SVCLASS_ID +#define HANDSFREE_PROFILE_ID		HANDSFREE_SVCLASS_ID +#define HANDSFREE_AGW_PROFILE_ID	HANDSFREE_AGW_SVCLASS_ID +#define DIRECT_PRT_REFOBJS_PROFILE_ID	DIRECT_PRT_REFOBJS_SVCLASS_ID +#define REFLECTED_UI_PROFILE_ID		REFLECTED_UI_SVCLASS_ID +#define BASIC_PRINTING_PROFILE_ID	BASIC_PRINTING_SVCLASS_ID +#define PRINTING_STATUS_PROFILE_ID	PRINTING_STATUS_SVCLASS_ID +#define HID_PROFILE_ID			HID_SVCLASS_ID +#define HCR_PROFILE_ID			HCR_SCAN_SVCLASS_ID +#define HCR_PRINT_PROFILE_ID		HCR_PRINT_SVCLASS_ID +#define HCR_SCAN_PROFILE_ID		HCR_SCAN_SVCLASS_ID +#define CIP_PROFILE_ID			CIP_SVCLASS_ID +#define VIDEO_CONF_GW_PROFILE_ID	VIDEO_CONF_GW_SVCLASS_ID +#define UDI_MT_PROFILE_ID		UDI_MT_SVCLASS_ID +#define UDI_TA_PROFILE_ID		UDI_TA_SVCLASS_ID +#define AV_PROFILE_ID			AV_SVCLASS_ID +#define SAP_PROFILE_ID			SAP_SVCLASS_ID +#define PBAP_PCE_PROFILE_ID		PBAP_PCE_SVCLASS_ID +#define PBAP_PSE_PROFILE_ID		PBAP_PSE_SVCLASS_ID +#define PBAP_PROFILE_ID			PBAP_SVCLASS_ID +#define PNP_INFO_PROFILE_ID		PNP_INFO_SVCLASS_ID +#define GENERIC_NETWORKING_PROFILE_ID	GENERIC_NETWORKING_SVCLASS_ID +#define GENERIC_FILETRANS_PROFILE_ID	GENERIC_FILETRANS_SVCLASS_ID +#define GENERIC_AUDIO_PROFILE_ID	GENERIC_AUDIO_SVCLASS_ID +#define GENERIC_TELEPHONY_PROFILE_ID	GENERIC_TELEPHONY_SVCLASS_ID +#define UPNP_PROFILE_ID			UPNP_SVCLASS_ID +#define UPNP_IP_PROFILE_ID		UPNP_IP_SVCLASS_ID +#define UPNP_PAN_PROFILE_ID		UPNP_PAN_SVCLASS_ID +#define UPNP_LAP_PROFILE_ID		UPNP_LAP_SVCLASS_ID +#define UPNP_L2CAP_PROFILE_ID		UPNP_L2CAP_SVCLASS_ID +#define VIDEO_SOURCE_PROFILE_ID		VIDEO_SOURCE_SVCLASS_ID +#define VIDEO_SINK_PROFILE_ID		VIDEO_SINK_SVCLASS_ID +#define VIDEO_DISTRIBUTION_PROFILE_ID	VIDEO_DISTRIBUTION_SVCLASS_ID +#define MDP_PROFILE_ID			MDP_SVCLASS_ID +#define MDP_SOURCE_PROFILE_ID		MDP_SROUCE_SVCLASS_ID +#define MDP_SINK_PROFILE_ID		MDP_SINK_SVCLASS_ID +#define APPLE_AGENT_PROFILE_ID		APPLE_AGENT_SVCLASS_ID + +/* + * Attribute identifier codes + */ +#define SDP_SERVER_RECORD_HANDLE		0x0000 + +/* + * Possible values for attribute-id are listed below. + * See SDP Spec, section "Service Attribute Definitions" for more details. + */ +#define SDP_ATTR_RECORD_HANDLE			0x0000 +#define SDP_ATTR_SVCLASS_ID_LIST		0x0001 +#define SDP_ATTR_RECORD_STATE			0x0002 +#define SDP_ATTR_SERVICE_ID			0x0003 +#define SDP_ATTR_PROTO_DESC_LIST		0x0004 +#define SDP_ATTR_BROWSE_GRP_LIST		0x0005 +#define SDP_ATTR_LANG_BASE_ATTR_ID_LIST		0x0006 +#define SDP_ATTR_SVCINFO_TTL			0x0007 +#define SDP_ATTR_SERVICE_AVAILABILITY		0x0008 +#define SDP_ATTR_PFILE_DESC_LIST		0x0009 +#define SDP_ATTR_DOC_URL			0x000a +#define SDP_ATTR_CLNT_EXEC_URL			0x000b +#define SDP_ATTR_ICON_URL			0x000c +#define SDP_ATTR_ADD_PROTO_DESC_LIST		0x000d + +#define SDP_ATTR_GROUP_ID			0x0200 +#define SDP_ATTR_IP_SUBNET			0x0200 +#define SDP_ATTR_VERSION_NUM_LIST		0x0200 +#define SDP_ATTR_SVCDB_STATE			0x0201 + +#define SDP_ATTR_SERVICE_VERSION		0x0300 +#define SDP_ATTR_EXTERNAL_NETWORK		0x0301 +#define SDP_ATTR_SUPPORTED_DATA_STORES_LIST	0x0301 +#define SDP_ATTR_FAX_CLASS1_SUPPORT		0x0302 +#define SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL	0x0302 +#define SDP_ATTR_FAX_CLASS20_SUPPORT		0x0303 +#define SDP_ATTR_SUPPORTED_FORMATS_LIST		0x0303 +#define SDP_ATTR_FAX_CLASS2_SUPPORT		0x0304 +#define SDP_ATTR_AUDIO_FEEDBACK_SUPPORT		0x0305 +#define SDP_ATTR_NETWORK_ADDRESS		0x0306 +#define SDP_ATTR_WAP_GATEWAY			0x0307 +#define SDP_ATTR_HOMEPAGE_URL			0x0308 +#define SDP_ATTR_WAP_STACK_TYPE			0x0309 +#define SDP_ATTR_SECURITY_DESC			0x030a +#define SDP_ATTR_NET_ACCESS_TYPE		0x030b +#define SDP_ATTR_MAX_NET_ACCESSRATE		0x030c +#define SDP_ATTR_IP4_SUBNET			0x030d +#define SDP_ATTR_IP6_SUBNET			0x030e +#define SDP_ATTR_SUPPORTED_CAPABILITIES		0x0310 +#define SDP_ATTR_SUPPORTED_FEATURES		0x0311 +#define SDP_ATTR_SUPPORTED_FUNCTIONS		0x0312 +#define SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY	0x0313 +#define SDP_ATTR_SUPPORTED_REPOSITORIES		0x0314 + +#define SDP_ATTR_SPECIFICATION_ID		0x0200 +#define SDP_ATTR_VENDOR_ID			0x0201 +#define SDP_ATTR_PRODUCT_ID			0x0202 +#define SDP_ATTR_VERSION			0x0203 +#define SDP_ATTR_PRIMARY_RECORD			0x0204 +#define SDP_ATTR_VENDOR_ID_SOURCE		0x0205 + +#define SDP_ATTR_HID_DEVICE_RELEASE_NUMBER	0x0200 +#define SDP_ATTR_HID_PARSER_VERSION		0x0201 +#define SDP_ATTR_HID_DEVICE_SUBCLASS		0x0202 +#define SDP_ATTR_HID_COUNTRY_CODE		0x0203 +#define SDP_ATTR_HID_VIRTUAL_CABLE		0x0204 +#define SDP_ATTR_HID_RECONNECT_INITIATE		0x0205 +#define SDP_ATTR_HID_DESCRIPTOR_LIST		0x0206 +#define SDP_ATTR_HID_LANG_ID_BASE_LIST		0x0207 +#define SDP_ATTR_HID_SDP_DISABLE		0x0208 +#define SDP_ATTR_HID_BATTERY_POWER		0x0209 +#define SDP_ATTR_HID_REMOTE_WAKEUP		0x020a +#define SDP_ATTR_HID_PROFILE_VERSION		0x020b +#define SDP_ATTR_HID_SUPERVISION_TIMEOUT	0x020c +#define SDP_ATTR_HID_NORMALLY_CONNECTABLE	0x020d +#define SDP_ATTR_HID_BOOT_DEVICE		0x020e + +/* + * These identifiers are based on the SDP spec stating that  + * "base attribute id of the primary (universal) language must be 0x0100" + * + * Other languages should have their own offset; e.g.: + * #define XXXLangBase yyyy + * #define AttrServiceName_XXX	0x0000+XXXLangBase + */ +#define SDP_PRIMARY_LANG_BASE 		0x0100 + +#define SDP_ATTR_SVCNAME_PRIMARY	0x0000 + SDP_PRIMARY_LANG_BASE +#define SDP_ATTR_SVCDESC_PRIMARY	0x0001 + SDP_PRIMARY_LANG_BASE +#define SDP_ATTR_PROVNAME_PRIMARY	0x0002 + SDP_PRIMARY_LANG_BASE + +/* + * The Data representation in SDP PDUs (pps 339, 340 of BT SDP Spec) + * These are the exact data type+size descriptor values + * that go into the PDU buffer. + * + * The datatype (leading 5bits) + size descriptor (last 3 bits) + * is 8 bits. The size descriptor is critical to extract the + * right number of bytes for the data value from the PDU. + * + * For most basic types, the datatype+size descriptor is + * straightforward. However for constructed types and strings, + * the size of the data is in the next "n" bytes following the + * 8 bits (datatype+size) descriptor. Exactly what the "n" is + * specified in the 3 bits of the data size descriptor. + * + * TextString and URLString can be of size 2^{8, 16, 32} bytes + * DataSequence and DataSequenceAlternates can be of size 2^{8, 16, 32} + * The size are computed post-facto in the API and are not known apriori + */ +#define SDP_DATA_NIL 		0x00 +#define SDP_UINT8  		0x08 +#define SDP_UINT16		0x09 +#define SDP_UINT32		0x0A +#define SDP_UINT64		0x0B +#define SDP_UINT128		0x0C +#define SDP_INT8		0x10 +#define SDP_INT16		0x11 +#define SDP_INT32		0x12 +#define SDP_INT64		0x13 +#define SDP_INT128		0x14 +#define SDP_UUID_UNSPEC		0x18 +#define SDP_UUID16		0x19 +#define SDP_UUID32		0x1A +#define SDP_UUID128		0x1C +#define SDP_TEXT_STR_UNSPEC	0x20 +#define SDP_TEXT_STR8		0x25 +#define SDP_TEXT_STR16		0x26 +#define SDP_TEXT_STR32		0x27 +#define SDP_BOOL		0x28 +#define SDP_SEQ_UNSPEC		0x30 +#define SDP_SEQ8		0x35 +#define SDP_SEQ16		0x36 +#define SDP_SEQ32		0x37 +#define SDP_ALT_UNSPEC		0x38 +#define SDP_ALT8		0x3D +#define SDP_ALT16		0x3E +#define SDP_ALT32		0x3F +#define SDP_URL_STR_UNSPEC	0x40 +#define SDP_URL_STR8		0x45 +#define SDP_URL_STR16		0x46 +#define SDP_URL_STR32		0x47 + +/* + * The PDU identifiers of SDP packets between client and server + */ +#define SDP_ERROR_RSP		0x01 +#define SDP_SVC_SEARCH_REQ	0x02 +#define SDP_SVC_SEARCH_RSP	0x03 +#define SDP_SVC_ATTR_REQ	0x04 +#define SDP_SVC_ATTR_RSP	0x05 +#define SDP_SVC_SEARCH_ATTR_REQ	0x06 +#define SDP_SVC_SEARCH_ATTR_RSP	0x07 + +/* + * Some additions to support service registration. + * These are outside the scope of the Bluetooth specification + */ +#define SDP_SVC_REGISTER_REQ	0x75 +#define SDP_SVC_REGISTER_RSP	0x76 +#define SDP_SVC_UPDATE_REQ	0x77 +#define SDP_SVC_UPDATE_RSP	0x78 +#define SDP_SVC_REMOVE_REQ	0x79 +#define SDP_SVC_REMOVE_RSP	0x80 + +/* + * SDP Error codes + */ +#define SDP_INVALID_VERSION		0x0001 +#define SDP_INVALID_RECORD_HANDLE	0x0002 +#define SDP_INVALID_SYNTAX		0x0003 +#define SDP_INVALID_PDU_SIZE		0x0004 +#define SDP_INVALID_CSTATE		0x0005 + +/* + * SDP PDU + */ +typedef struct { +	uint8_t  pdu_id; +	uint16_t tid; +	uint16_t plen; +} __attribute__ ((packed)) sdp_pdu_hdr_t; + +/* + * Common definitions for attributes in the SDP. + * Should the type of any of these change, you need only make a change here. + */ +typedef struct { +	uint8_t data[16]; +} uint128_t; + +typedef struct { +	uint8_t type; +	union { +		uint16_t  uuid16; +		uint32_t  uuid32; +		uint128_t uuid128; +	} value; +} uuid_t; + +#define SDP_IS_UUID(x) ((x) == SDP_UUID16 || (x) == SDP_UUID32 || (x) ==SDP_UUID128) + +typedef struct _sdp_list sdp_list_t; +struct _sdp_list { +	sdp_list_t *next; +	void *data; +}; + +/* + * User-visible strings can be in many languages + * in addition to the universal language. + * + * Language meta-data includes language code in ISO639 + * followed by the encoding format. The third field in this + * structure is the attribute offset for the language. + * User-visible strings in the specified language can be + * obtained at this offset. + */ +typedef struct { +	uint16_t code_ISO639; +	uint16_t encoding; +	uint16_t base_offset; +} sdp_lang_attr_t; + +/* + * Profile descriptor is the Bluetooth profile metadata. If a + * service conforms to a well-known profile, then its profile + * identifier (UUID) is an attribute of the service. In addition, + * if the profile has a version number it is specified here. + */ +typedef struct { +	uuid_t uuid; +	uint16_t version; +} sdp_profile_desc_t; + +typedef struct { +	uint8_t major; +	uint8_t minor; +} sdp_version_t; + +typedef struct { +	uint8_t *data; +	uint32_t data_size; +	uint32_t buf_size; +} sdp_buf_t; + +typedef struct { +	uint32_t handle; + +	/* Search pattern: a sequence of all UUIDs seen in this record */ +	sdp_list_t *pattern; +	sdp_list_t *attrlist; + +	/* Main service class for Extended Inquiry Response */ +	uuid_t svclass; +} sdp_record_t; + +typedef struct sdp_data_struct sdp_data_t; +struct sdp_data_struct { +	uint8_t dtd; +	uint16_t attrId; +	union { +		int8_t    int8; +		int16_t   int16; +		int32_t   int32; +		int64_t   int64; +		uint128_t int128; +		uint8_t   uint8; +		uint16_t  uint16; +		uint32_t  uint32; +		uint64_t  uint64; +		uint128_t uint128; +		uuid_t    uuid; +		char     *str; +		sdp_data_t *dataseq; +	} val; +	sdp_data_t *next; +	int unitSize; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __SDP_H */ diff --git a/include/sdp_lib.h b/include/sdp_lib.h new file mode 100644 index 00000000..143056f6 --- /dev/null +++ b/include/sdp_lib.h @@ -0,0 +1,619 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2001-2002  Nokia Corporation + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifndef __SDP_LIB_H +#define __SDP_LIB_H + +#include <sys/socket.h> +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SDP lists + */ +typedef void(*sdp_list_func_t)(void *, void *); +typedef void(*sdp_free_func_t)(void *); +typedef int (*sdp_comp_func_t)(const void *, const void *); + +sdp_list_t *sdp_list_append(sdp_list_t *list, void *d); +sdp_list_t *sdp_list_remove(sdp_list_t *list, void *d); +sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *data, sdp_comp_func_t f); +void        sdp_list_free(sdp_list_t *list, sdp_free_func_t f); + +static inline int sdp_list_len(const sdp_list_t *list)  +{ +	int n = 0; +	for (; list; list = list->next) +		n++; +	return n; +} + +static inline sdp_list_t *sdp_list_find(sdp_list_t *list, void *u, sdp_comp_func_t f) +{ +	for (; list; list = list->next) +		if (f(list->data, u) == 0) +			return list; +	return NULL; +} + +static inline void sdp_list_foreach(sdp_list_t *list, sdp_list_func_t f, void *u) +{ +	for (; list; list = list->next) +		f(list->data, u); +} + +/* + * Values of the flags parameter to sdp_record_register + */ +#define SDP_RECORD_PERSIST	0x01 +#define SDP_DEVICE_RECORD	0x02 + +/* + * Values of the flags parameter to sdp_connect + */ +#define SDP_RETRY_IF_BUSY	0x01 +#define SDP_WAIT_ON_CLOSE	0x02 +#define SDP_NON_BLOCKING	0x04 + +/* + * a session with an SDP server + */ +typedef struct { +	int sock; +	int state; +	int local; +	int flags; +	uint16_t tid;	// Current transaction ID +	void *priv; +} sdp_session_t; + +typedef enum { +	/* +	 *  Attributes are specified as individual elements +	 */ +	SDP_ATTR_REQ_INDIVIDUAL = 1, +	/* +	 *  Attributes are specified as a range +	 */ +	SDP_ATTR_REQ_RANGE +} sdp_attrreq_type_t; + +/* + * 	When the pdu_id(type) is a sdp error response, check the status value + * 	to figure out the error reason. For status values 0x0001-0x0006 check + * 	Bluetooth SPEC. If the status is 0xffff, call sdp_get_error function + * 	to get the real reason: + * 	    - wrong transaction ID(EPROTO) + * 	    - wrong PDU id or(EPROTO) + * 	    - I/O error + */ +typedef void sdp_callback_t(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *udata); + +/* + * create an L2CAP connection to a Bluetooth device + *  + * INPUT: + *   + *  bdaddr_t *src: + *	Address of the local device to use to make the connection + *	(or BDADDR_ANY) + * + *  bdaddr_t *dst: + *    Address of the SDP server device + */ +sdp_session_t *sdp_connect(const bdaddr_t *src, const bdaddr_t *dst, uint32_t flags); +int sdp_close(sdp_session_t *session); +int sdp_get_socket(const sdp_session_t *session); + +/* + * SDP transaction: functions for asynchronous search. + */ +sdp_session_t *sdp_create(int sk, uint32_t flags); +int sdp_get_error(sdp_session_t *session); +int sdp_process(sdp_session_t *session); +int sdp_set_notify(sdp_session_t *session, sdp_callback_t *func, void *udata); + +int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num); +int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list); +int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list); + +uint16_t sdp_gen_tid(sdp_session_t *session); + +/* + * find all devices in the piconet + */ +int sdp_general_inquiry(inquiry_info *ii, int dev_num, int duration, uint8_t *found); + +/* flexible extraction of basic attributes - Jean II */ +int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attr, int *value); +int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attr, char *value, int valuelen); + +/* + * Basic sdp data functions + */ +sdp_data_t *sdp_data_alloc(uint8_t dtd, const void *value); +sdp_data_t *sdp_data_alloc_with_length(uint8_t dtd, const void *value, uint32_t length); +void sdp_data_free(sdp_data_t *data); +sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attr_id); + +sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len); +sdp_data_t *sdp_seq_alloc_with_length(void **dtds, void **values, int *length, int len); +sdp_data_t *sdp_seq_append(sdp_data_t *seq, sdp_data_t *data); + +int sdp_attr_add(sdp_record_t *rec, uint16_t attr, sdp_data_t *data); +void sdp_attr_remove(sdp_record_t *rec, uint16_t attr); +void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *data); +int sdp_set_uuidseq_attr(sdp_record_t *rec, uint16_t attr, sdp_list_t *seq); +int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr, sdp_list_t **seqp); + +/* + * NOTE that none of the functions below will update the SDP server,  + * unless the {register, update}sdp_record_t() function is invoked. + * All functions which return an integer value, return 0 on success  + * or -1 on failure. + */ + +/* + * Create an attribute and add it to the service record's attribute list. + * This consists of the data type descriptor of the attribute,  + * the value of the attribute and the attribute identifier. + */ +int sdp_attr_add_new(sdp_record_t *rec, uint16_t attr, uint8_t dtd, const void *p); + +/* + * Set the information attributes of the service record. + * The set of attributes comprises service name, description  + * and provider name + */ +void sdp_set_info_attr(sdp_record_t *rec, const char *name, const char *prov, const char *desc); + +/* + * Set the ServiceClassID attribute to the sequence specified by seq. + * Note that the identifiers need to be in sorted order from the most  + * specific to the most generic service class that this service + * conforms to. + */ +static inline int sdp_set_service_classes(sdp_record_t *rec, sdp_list_t *seq) +{ +	return sdp_set_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seq); +} + +/* + * Get the service classes to which the service conforms. + *  + * When set, the list contains elements of ServiceClassIdentifer(uint16_t)  + * ordered from most specific to most generic + */ +static inline int sdp_get_service_classes(const sdp_record_t *rec, sdp_list_t **seqp) +{ +	return sdp_get_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seqp); +} + +/* + * Set the BrowseGroupList attribute to the list specified by seq. + *  + * A service can belong to one or more service groups  + * and the list comprises such group identifiers (UUIDs) + */ +static inline int sdp_set_browse_groups(sdp_record_t *rec, sdp_list_t *seq) +{ +	return sdp_set_uuidseq_attr(rec, SDP_ATTR_BROWSE_GRP_LIST, seq); +} + +/* + * Set the access protocols of the record to those specified in proto + */ +int sdp_set_access_protos(sdp_record_t *rec, const sdp_list_t *proto); + +/* + * Set the additional access protocols of the record to those specified in proto + */ +int sdp_set_add_access_protos(sdp_record_t *rec, const sdp_list_t *proto); + +/* + * Get protocol port (i.e. PSM for L2CAP, Channel for RFCOMM)  + */ +int sdp_get_proto_port(const sdp_list_t *list, int proto); + +/* + * Get protocol descriptor.  + */ +sdp_data_t *sdp_get_proto_desc(sdp_list_t *list, int proto); + +/* + * Set the LanguageBase attributes to the values specified in list  + * (a linked list of sdp_lang_attr_t objects, one for each language in  + * which user-visible attributes are present). + */ +int sdp_set_lang_attr(sdp_record_t *rec, const sdp_list_t *list); + +/* + * Set the ServiceInfoTimeToLive attribute of the service.   + * This is the number of seconds that this record is guaranteed + * not to change after being obtained by a client. + */ +static inline int sdp_set_service_ttl(sdp_record_t *rec, uint32_t ttl) +{ +	return sdp_attr_add_new(rec, SDP_ATTR_SVCINFO_TTL, SDP_UINT32, &ttl); +} + +/* + * Set the ServiceRecordState attribute of a service. This is + * guaranteed to change if there is any kind of modification to  + * the record.  + */ +static inline int sdp_set_record_state(sdp_record_t *rec, uint32_t state) +{ +	return sdp_attr_add_new(rec, SDP_ATTR_RECORD_STATE, SDP_UINT32, &state); +} + +/* + * Set the ServiceID attribute of a service.  + */ +void sdp_set_service_id(sdp_record_t *rec, uuid_t uuid); + +/* + * Set the GroupID attribute of a service + */ +void sdp_set_group_id(sdp_record_t *rec, uuid_t grouuuid); + +/* + * Set the ServiceAvailability attribute of a service. + *  + * Note that this represents the relative availability + * of the service: 0x00 means completely unavailable; + * 0xFF means maximum availability. + */ +static inline int sdp_set_service_avail(sdp_record_t *rec, uint8_t avail) +{ +	return sdp_attr_add_new(rec, SDP_ATTR_SERVICE_AVAILABILITY, SDP_UINT8, &avail); +} + +/* + * Set the profile descriptor list attribute of a record. + *  + * Each element in the list is an object of type + * sdp_profile_desc_t which is a definition of the + * Bluetooth profile that this service conforms to. + */ +int sdp_set_profile_descs(sdp_record_t *rec, const sdp_list_t *desc); + +/* + * Set URL attributes of a record. + *  + * ClientExecutableURL: a URL to a client's platform specific (WinCE,  + * PalmOS) executable code that can be used to access this service. + *  + * DocumentationURL: a URL pointing to service documentation + *  + * IconURL: a URL to an icon that can be used to represent this service. + *  + * Note: pass NULL for any URLs that you don't want to set or remove + */ +void sdp_set_url_attr(sdp_record_t *rec, const char *clientExecURL, const char *docURL, const char *iconURL); + +/* + * a service search request.  + *  + *  INPUT : + *  + *    sdp_list_t *search + *      list containing elements of the search + *      pattern. Each entry in the list is a UUID + *      of the service to be searched + *  + *    uint16_t max_rec_num + *       An integer specifying the maximum number of + *       entries that the client can handle in the response. + *  + *  OUTPUT : + *  + *    int return value + *      0  + *        The request completed successfully. This does not + *        mean the requested services were found + *      -1 + *        The request completed unsuccessfully + *  + *    sdp_list_t *rsp_list + *      This variable is set on a successful return if there are + *      non-zero service handles. It is a singly linked list of + *      service record handles (uint16_t) + */ +int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num, sdp_list_t **rsp_list); + +/* + *  a service attribute request.  + *  + *  INPUT : + *  + *    uint32_t handle + *      The handle of the service for which the attribute(s) are + *      requested + *  + *    sdp_attrreq_type_t reqtype + *      Attribute identifiers are 16 bit unsigned integers specified + *      in one of 2 ways described below : + *      SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers + *         They are the actual attribute identifiers in ascending order + *  + *      SDP_ATTR_REQ_RANGE - 32bit identifier range + *         The high-order 16bits is the start of range + *         the low-order 16bits are the end of range + *         0x0000 to 0xFFFF gets all attributes + *  + *    sdp_list_t *attrid_list + *      Singly linked list containing attribute identifiers desired. + *      Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)   + *      or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE) + *  + *  OUTPUT : + *    int return value + *      0  + *        The request completed successfully. This does not + *        mean the requested services were found + *      -1 + *        The request completed unsuccessfully due to a timeout + */ +sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list); + +/* + *  This is a service search request combined with the service + *  attribute request. First a service class match is done and + *  for matching service, requested attributes are extracted + *  + *  INPUT : + *  + *    sdp_list_t *search + *      Singly linked list containing elements of the search + *      pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16) + *      of the service to be searched + *  + *    AttributeSpecification attrSpec + *      Attribute identifiers are 16 bit unsigned integers specified + *      in one of 2 ways described below : + *      SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers + *         They are the actual attribute identifiers in ascending order + *  + *      SDP_ATTR_REQ_RANGE - 32bit identifier range + *         The high-order 16bits is the start of range + *         the low-order 16bits are the end of range + *         0x0000 to 0xFFFF gets all attributes + *  + *    sdp_list_t *attrid_list + *      Singly linked list containing attribute identifiers desired. + *      Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)   + *      or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE) + *  + *  OUTPUT : + *    int return value + *      0  + *        The request completed successfully. This does not + *        mean the requested services were found + *      -1 + *        The request completed unsuccessfully due to a timeout + *  + *    sdp_list_t *rsp_list + *      This variable is set on a successful return to point to + *      service(s) found. Each element of this list is of type + *      sdp_record_t *. + */ +int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list, sdp_list_t **rsp_list); + +/* + * Allocate/free a service record and its attributes + */ +sdp_record_t *sdp_record_alloc(void); +void sdp_record_free(sdp_record_t *rec); + +/* + * Register a service record.  + *  + * Note: It is the responsbility of the Service Provider to create the  + * record first and set its attributes using setXXX() methods. + *  + * The service provider must then call sdp_record_register() to make  + * the service record visible to SDP clients.  This function returns 0 + * on success or -1 on failure (and sets errno). + */ +int sdp_device_record_register_binary(sdp_session_t *session, bdaddr_t *device, uint8_t *data, uint32_t size, uint8_t flags, uint32_t *handle); +int sdp_device_record_register(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec, uint8_t flags); +int sdp_record_register(sdp_session_t *session, sdp_record_t *rec, uint8_t flags); + +/* + * Unregister a service record. + */ +int sdp_device_record_unregister_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle); +int sdp_device_record_unregister(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec); +int sdp_record_unregister(sdp_session_t *session, sdp_record_t *rec); + +/* + * Update an existing service record.  (Calling this function + * before a previous call to sdp_record_register() will result + * in an error.) + */ +int sdp_device_record_update_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle, uint8_t *data, uint32_t size); +int sdp_device_record_update(sdp_session_t *session, bdaddr_t *device, const sdp_record_t *rec); +int sdp_record_update(sdp_session_t *sess, const sdp_record_t *rec); + +void sdp_record_print(const sdp_record_t *rec); + +/* + * UUID functions + */ +uuid_t *sdp_uuid16_create(uuid_t *uuid, uint16_t data); +uuid_t *sdp_uuid32_create(uuid_t *uuid, uint32_t data); +uuid_t *sdp_uuid128_create(uuid_t *uuid, const void *data); +int sdp_uuid16_cmp(const void *p1, const void *p2); +int sdp_uuid128_cmp(const void *p1, const void *p2); +uuid_t *sdp_uuid_to_uuid128(uuid_t *uuid); +void sdp_uuid16_to_uuid128(uuid_t *uuid128, uuid_t *uuid16); +void sdp_uuid32_to_uuid128(uuid_t *uuid128, uuid_t *uuid32); +int sdp_uuid128_to_uuid(uuid_t *uuid); +int sdp_uuid_to_proto(uuid_t *uuid); +int sdp_uuid_extract(const uint8_t *buffer, uuid_t *uuid, int *scanned); +int sdp_uuid_extract_safe(const uint8_t *buffer, int bufsize, uuid_t *uuid, int *scanned); +void sdp_uuid_print(const uuid_t *uuid); + +#define MAX_LEN_UUID_STR 37 +#define MAX_LEN_PROTOCOL_UUID_STR 8 +#define MAX_LEN_SERVICECLASS_UUID_STR 28 +#define MAX_LEN_PROFILEDESCRIPTOR_UUID_STR 28 + +int sdp_uuid2strn(const uuid_t *uuid, char *str, size_t n); +int sdp_proto_uuid2strn(const uuid_t *uuid, char *str, size_t n); +int sdp_svclass_uuid2strn(const uuid_t *uuid, char *str, size_t n); +int sdp_profile_uuid2strn(const uuid_t *uuid, char *str, size_t n); + +/* + * In all the sdp_get_XXX(handle, XXX *xxx) functions below,  + * the XXX * is set to point to the value, should it exist + * and 0 is returned. If the value does not exist, -1 is + * returned and errno set to ENODATA. + * + * In all the methods below, the memory management rules are + * simple. Don't free anything! The pointer returned, in the + * case of constructed types, is a pointer to the contents  + * of the sdp_record_t. + */ + +/* + * Get the access protocols from the service record + */ +int sdp_get_access_protos(const sdp_record_t *rec, sdp_list_t **protos); + +/* + * Get the additional access protocols from the service record + */ +int sdp_get_add_access_protos(const sdp_record_t *rec, sdp_list_t **protos); + +/* + * Extract the list of browse groups to which the service belongs. + * When set, seqp contains elements of GroupID (uint16_t)  + */ +static inline int sdp_get_browse_groups(const sdp_record_t *rec, sdp_list_t **seqp) +{ +	return sdp_get_uuidseq_attr(rec, SDP_ATTR_BROWSE_GRP_LIST, seqp); +} + +/* + * Extract language attribute meta-data of the service record.  + * For each language in the service record, LangSeq has a struct of type + * sdp_lang_attr_t.  + */ +int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq); + +/* + * Extract the Bluetooth profile descriptor sequence from a record. + * Each element in the list is of type sdp_profile_desc_t + * which contains the UUID of the profile and its version number + * (encoded as major and minor in the high-order 8bits + * and low-order 8bits respectively of the uint16_t) + */ +int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDesc); + +/* + * Extract SDP server version numbers  + *  + * Note: that this is an attribute of the SDP server only and + * contains a list of uint16_t each of which represent the + * major and minor SDP version numbers supported by this server + */ +int sdp_get_server_ver(const sdp_record_t *rec, sdp_list_t **pVnumList); + +int sdp_get_service_id(const sdp_record_t *rec, uuid_t *uuid); +int sdp_get_group_id(const sdp_record_t *rec, uuid_t *uuid); +int sdp_get_record_state(const sdp_record_t *rec, uint32_t *svcRecState); +int sdp_get_service_avail(const sdp_record_t *rec, uint8_t *svcAvail); +int sdp_get_service_ttl(const sdp_record_t *rec, uint32_t *svcTTLInfo); +int sdp_get_database_state(const sdp_record_t *rec, uint32_t *svcDBState); + +static inline int sdp_get_service_name(const sdp_record_t *rec, char *str, int len) +{ +	return sdp_get_string_attr(rec, SDP_ATTR_SVCNAME_PRIMARY, str, len); +} + +static inline int sdp_get_service_desc(const sdp_record_t *rec, char *str, int len) +{ +	return sdp_get_string_attr(rec, SDP_ATTR_SVCDESC_PRIMARY, str, len); +} + +static inline int sdp_get_provider_name(const sdp_record_t *rec, char *str, int len) +{ +	return sdp_get_string_attr(rec, SDP_ATTR_PROVNAME_PRIMARY, str, len); +} + +static inline int sdp_get_doc_url(const sdp_record_t *rec, char *str, int len) +{ +	return sdp_get_string_attr(rec, SDP_ATTR_DOC_URL, str, len); +} + +static inline int sdp_get_clnt_exec_url(const sdp_record_t *rec, char *str, int len) +{ +	return sdp_get_string_attr(rec, SDP_ATTR_CLNT_EXEC_URL, str, len); +} + +static inline int sdp_get_icon_url(const sdp_record_t *rec, char *str, int len) +{ +	return sdp_get_string_attr(rec, SDP_ATTR_ICON_URL, str, len); +} + +sdp_record_t *sdp_extract_pdu(const uint8_t *pdata, int *scanned); +sdp_record_t *sdp_extract_pdu_safe(const uint8_t *pdata, int bufsize, int *scanned); + +void sdp_data_print(sdp_data_t *data); +void sdp_print_service_attr(sdp_list_t *alist); + +int sdp_attrid_comp_func(const void *key1, const void *key2); + +void sdp_set_seq_len(uint8_t *ptr, uint32_t length); +void sdp_set_attrid(sdp_buf_t *pdu, uint16_t id); +void sdp_append_to_pdu(sdp_buf_t *dst, sdp_data_t *d); +void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len); + +int sdp_gen_pdu(sdp_buf_t *pdu, sdp_data_t *data); +int sdp_gen_record_pdu(const sdp_record_t *rec, sdp_buf_t *pdu); + +int sdp_extract_seqtype(const uint8_t *buf, uint8_t *dtdp, int *seqlen); +int sdp_extract_seqtype_safe(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size); + +sdp_data_t *sdp_extract_attr(const uint8_t *pdata, int *extractedLength, sdp_record_t *rec); +sdp_data_t *sdp_extract_attr_safe(const uint8_t *pdata, int bufsize, int *extractedLength, sdp_record_t *rec); + +void sdp_pattern_add_uuid(sdp_record_t *rec, uuid_t *uuid); +void sdp_pattern_add_uuidseq(sdp_record_t *rec, sdp_list_t *seq); + +int sdp_send_req_w4_rsp(sdp_session_t *session, uint8_t *req, uint8_t *rsp, uint32_t reqsize, uint32_t *rspsize); + +#ifdef __cplusplus +} +#endif + +#endif /* __SDP_LIB_H */ diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..065bbe60 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,9 @@ + +lib_LTLIBRARIES = libbluetooth.la + +libbluetooth_la_SOURCES = bluetooth.c hci.c sdp.c +libbluetooth_la_LDFLAGS = -version-info 13:2:11 + +INCLUDES = -I$(top_builddir)/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/bluetooth.c b/src/bluetooth.c new file mode 100644 index 00000000..f7a46bcf --- /dev/null +++ b/src/bluetooth.c @@ -0,0 +1,448 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2000-2001  Qualcomm Incorporated + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> + +void baswap(bdaddr_t *dst, const bdaddr_t *src) +{ +	register unsigned char *d = (unsigned char *) dst; +	register const unsigned char *s = (const unsigned char *) src; +	register int i; +	for (i = 0; i < 6; i++) +		d[i] = s[5-i]; +} + +char *batostr(const bdaddr_t *ba) +{ +	char *str = bt_malloc(18); +	if (!str) +		return NULL; + +	sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", +		ba->b[0], ba->b[1], ba->b[2],  +		ba->b[3], ba->b[4], ba->b[5]); +	return str; +} + +bdaddr_t *strtoba(const char *str) +{ +	const char *ptr = str; +	int i; + +	uint8_t *ba = bt_malloc(sizeof(bdaddr_t)); +	if (!ba) +		return NULL; + +	for(i = 0; i < 6; i++) { +		ba[i] = (uint8_t) strtol(ptr, NULL, 16); +		if (i != 5 && !(ptr = strchr(ptr,':'))) +			ptr = ":00:00:00:00:00"; +		ptr++; +	} +	return (bdaddr_t *) ba; +} + +int ba2str(const bdaddr_t *ba, char *str) +{ +	uint8_t b[6]; + +	baswap((bdaddr_t *) b, ba); +	return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", +		b[0], b[1], b[2], b[3], b[4], b[5]); +} + +int str2ba(const char *str, bdaddr_t *ba) +{ +	uint8_t b[6]; +	const char *ptr = str; +	int i; + +	for (i = 0; i < 6; i++) { +		b[i] = (uint8_t) strtol(ptr, NULL, 16); +		if (i != 5 && !(ptr = strchr(ptr, ':'))) +			ptr = ":00:00:00:00:00"; +		ptr++; +	} +	baswap(ba, (bdaddr_t *) b); +	return 0; +} + +int ba2oui(const bdaddr_t *ba, char *str) +{ +	uint8_t b[6]; + +	baswap((bdaddr_t *) b, ba); +	return sprintf(str, "%2.2X-%2.2X-%2.2X", b[0], b[1], b[2]); +} + +int bachk(const char *str) +{ +	char tmp[18], *ptr = tmp; + +	if (!str) +		return -1; + +	if (strlen(str) != 17) +		return -1; + +	memcpy(tmp, str, 18); + +	while (*ptr) { +		*ptr = toupper(*ptr); +		if (*ptr < '0'|| (*ptr > '9' && *ptr < 'A') || *ptr > 'F') +			return -1; +		ptr++; + +		*ptr = toupper(*ptr); +		if (*ptr < '0'|| (*ptr > '9' && *ptr < 'A') || *ptr > 'F') +			return -1; +		ptr++; + +		*ptr = toupper(*ptr); +		if (*ptr == 0) +			break; +		if (*ptr != ':') +			return -1; +		ptr++; +	} + +	return 0; +} + +int baprintf(const char *format, ...) +{ +	va_list ap; +	int len; + +	va_start(ap, format); +	len = vprintf(format, ap); +	va_end(ap); + +	return len; +} + +int bafprintf(FILE *stream, const char *format, ...) +{ +	va_list ap; +	int len; + +	va_start(ap, format); +	len = vfprintf(stream, format, ap); +	va_end(ap); + +	return len; +} + +int basprintf(char *str, const char *format, ...) +{ +	va_list ap; +	int len; + +	va_start(ap, format); +	len = vsnprintf(str, (~0U) >> 1, format, ap); +	va_end(ap); + +	return len; +} + +int basnprintf(char *str, size_t size, const char *format, ...) +{ +	va_list ap; +	int len; + +	va_start(ap, format); +	len = vsnprintf(str, size, format, ap); +	va_end(ap); + +	return len; +} + +void *bt_malloc(size_t size) +{ +	return malloc(size); +} + +void bt_free(void *ptr) +{ +	free(ptr); +} + +/* Bluetooth error codes to Unix errno mapping */ +int bt_error(uint16_t code) +{ +	switch (code) { +	case 0: +		return 0; +	case HCI_UNKNOWN_COMMAND: +		return EBADRQC; +	case HCI_NO_CONNECTION: +		return ENOTCONN; +	case HCI_HARDWARE_FAILURE: +		return EIO; +	case HCI_PAGE_TIMEOUT: +		return EHOSTDOWN; +	case HCI_AUTHENTICATION_FAILURE: +		return EACCES; +	case HCI_PIN_OR_KEY_MISSING: +		return EINVAL; +	case HCI_MEMORY_FULL: +		return ENOMEM; +	case HCI_CONNECTION_TIMEOUT: +		return ETIMEDOUT; +	case HCI_MAX_NUMBER_OF_CONNECTIONS: +	case HCI_MAX_NUMBER_OF_SCO_CONNECTIONS: +		return EMLINK; +	case HCI_ACL_CONNECTION_EXISTS: +		return EALREADY; +	case HCI_COMMAND_DISALLOWED: +	case HCI_TRANSACTION_COLLISION: +	case HCI_ROLE_SWITCH_PENDING: +		return EBUSY; +	case HCI_REJECTED_LIMITED_RESOURCES: +	case HCI_REJECTED_PERSONAL: +	case HCI_QOS_REJECTED: +		return ECONNREFUSED; +	case HCI_HOST_TIMEOUT: +		return ETIMEDOUT; +	case HCI_UNSUPPORTED_FEATURE: +	case HCI_QOS_NOT_SUPPORTED: +	case HCI_PAIRING_NOT_SUPPORTED: +	case HCI_CLASSIFICATION_NOT_SUPPORTED: +	case HCI_UNSUPPORTED_LMP_PARAMETER_VALUE: +	case HCI_PARAMETER_OUT_OF_RANGE: +	case HCI_QOS_UNACCEPTABLE_PARAMETER: +		return EOPNOTSUPP; +	case HCI_INVALID_PARAMETERS: +	case HCI_SLOT_VIOLATION: +		return EINVAL; +	case HCI_OE_USER_ENDED_CONNECTION: +	case HCI_OE_LOW_RESOURCES: +	case HCI_OE_POWER_OFF: +		return ECONNRESET; +	case HCI_CONNECTION_TERMINATED: +		return ECONNABORTED; +	case HCI_REPEATED_ATTEMPTS: +		return ELOOP; +	case HCI_REJECTED_SECURITY: +	case HCI_PAIRING_NOT_ALLOWED: +	case HCI_INSUFFICIENT_SECURITY: +		return EACCES; +	case HCI_UNSUPPORTED_REMOTE_FEATURE: +		return EPROTONOSUPPORT; +	case HCI_SCO_OFFSET_REJECTED: +		return ECONNREFUSED; +	case HCI_UNKNOWN_LMP_PDU: +	case HCI_INVALID_LMP_PARAMETERS: +	case HCI_LMP_ERROR_TRANSACTION_COLLISION: +	case HCI_LMP_PDU_NOT_ALLOWED: +	case HCI_ENCRYPTION_MODE_NOT_ACCEPTED: +		return EPROTO; +	default: +		return ENOSYS; +	} +} + +char *bt_compidtostr(int compid) +{ +	switch (compid) { +	case 0: +		return "Ericsson Technology Licensing"; +	case 1: +		return "Nokia Mobile Phones"; +	case 2: +		return "Intel Corp."; +	case 3: +		return "IBM Corp."; +	case 4: +		return "Toshiba Corp."; +	case 5: +		return "3Com"; +	case 6: +		return "Microsoft"; +	case 7: +		return "Lucent"; +	case 8: +		return "Motorola"; +	case 9: +		return "Infineon Technologies AG"; +	case 10: +		return "Cambridge Silicon Radio"; +	case 11: +		return "Silicon Wave"; +	case 12: +		return "Digianswer A/S"; +	case 13: +		return "Texas Instruments Inc."; +	case 14: +		return "Parthus Technologies Inc."; +	case 15: +		return "Broadcom Corporation"; +	case 16: +		return "Mitel Semiconductor"; +	case 17: +		return "Widcomm, Inc."; +	case 18: +		return "Zeevo, Inc."; +	case 19: +		return "Atmel Corporation"; +	case 20: +		return "Mitsubishi Electric Corporation"; +	case 21: +		return "RTX Telecom A/S"; +	case 22: +		return "KC Technology Inc."; +	case 23: +		return "Newlogic"; +	case 24: +		return "Transilica, Inc."; +	case 25: +		return "Rohde & Schwartz GmbH & Co. KG"; +	case 26: +		return "TTPCom Limited"; +	case 27: +		return "Signia Technologies, Inc."; +	case 28: +		return "Conexant Systems Inc."; +	case 29: +		return "Qualcomm"; +	case 30: +		return "Inventel"; +	case 31: +		return "AVM Berlin"; +	case 32: +		return "BandSpeed, Inc."; +	case 33: +		return "Mansella Ltd"; +	case 34: +		return "NEC Corporation"; +	case 35: +		return "WavePlus Technology Co., Ltd."; +	case 36: +		return "Alcatel"; +	case 37: +		return "Philips Semiconductors"; +	case 38: +		return "C Technologies"; +	case 39: +		return "Open Interface"; +	case 40: +		return "R F Micro Devices"; +	case 41: +		return "Hitachi Ltd"; +	case 42: +		return "Symbol Technologies, Inc."; +	case 43: +		return "Tenovis"; +	case 44: +		return "Macronix International Co. Ltd."; +	case 45: +		return "GCT Semiconductor"; +	case 46: +		return "Norwood Systems"; +	case 47: +		return "MewTel Technology Inc."; +	case 48: +		return "ST Microelectronics"; +	case 49: +		return "Synopsys"; +	case 50: +		return "Red-M (Communications) Ltd"; +	case 51: +		return "Commil Ltd"; +	case 52: +		return "Computer Access Technology Corporation (CATC)"; +	case 53: +		return "Eclipse (HQ Espana) S.L."; +	case 54: +		return "Renesas Technology Corp."; +	case 55: +		return "Mobilian Corporation"; +	case 56: +		return "Terax"; +	case 57: +		return "Integrated System Solution Corp."; +	case 58: +		return "Matsushita Electric Industrial Co., Ltd."; +	case 59: +		return "Gennum Corporation"; +	case 60: +		return "Research In Motion"; +	case 61: +		return "IPextreme, Inc."; +	case 62: +		return "Systems and Chips, Inc"; +	case 63: +		return "Bluetooth SIG, Inc"; +	case 64: +		return "Seiko Epson Corporation"; +	case 65: +		return "Integrated Silicon Solution Taiwain, Inc."; +	case 66: +		return "CONWISE Technology Corporation Ltd"; +	case 67: +		return "PARROT SA"; +	case 68: +		return "Socket Communications"; +	case 69: +		return "Atheros Communications, Inc."; +	case 70: +		return "MediaTek, Inc."; +	case 71: +		return "Bluegiga";	/* (tentative) */ +	case 72: +		return "Marvell Technology Group Ltd."; +	case 73: +		return "3DSP Corporation"; +	case 74: +		return "Accel Semiconductor Ltd."; +	case 75: +		return "Continental Automotive Systems"; +	case 76: +		return "Apple, Inc."; +	case 77: +		return "Staccato Communications, Inc."; +	case 78: +		return "Avago Technologies"; +	case 79: +		return "APT Ltd."; +	case 65535: +		return "internal use"; +	default: +		return "not assigned"; +	} +} diff --git a/src/hci.c b/src/hci.c new file mode 100644 index 00000000..a72b0355 --- /dev/null +++ b/src/hci.c @@ -0,0 +1,2489 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2000-2001  Qualcomm Incorporated + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/param.h> +#include <sys/uio.h> +#include <sys/poll.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif + +typedef struct { +	char *str; +	unsigned int val; +} hci_map; + +static char *hci_bit2str(hci_map *m, unsigned int val)  +{ +	char *str = malloc(120); +	char *ptr = str; + +	if (!str) +		return NULL; + +	*ptr = 0; +	while (m->str) { +		if ((unsigned int) m->val & val) +			ptr += sprintf(ptr, "%s ", m->str); +		m++; +	} +	return str; +} + +static int hci_str2bit(hci_map *map, char *str, unsigned int *val) +{ +	char *t, *ptr; +	hci_map *m; +	int set; + +	if (!str || !(str = ptr = strdup(str))) +		return 0; + +	*val = set = 0; + +	while ((t = strsep(&ptr, ","))) { +		for (m = map; m->str; m++) { +			if (!strcasecmp(m->str, t)) { +				*val |= (unsigned int) m->val; +				set = 1; +			} +		} +	} +	free(str); + +	return set; +} + +static char *hci_uint2str(hci_map *m, unsigned int val)  +{ +	char *str = malloc(50); +	char *ptr = str; + +	if (!str) +		return NULL; + +	*ptr = 0; +	while (m->str) { +		if ((unsigned int) m->val == val) { +			ptr += sprintf(ptr, "%s", m->str); +			break; +		} +		m++; +	} +	return str; +} + +static int hci_str2uint(hci_map *map, char *str, unsigned int *val) +{ +	char *t, *ptr; +	hci_map *m; +	int set = 0; + +	if (!str) +		return 0; + +	str = ptr = strdup(str); + +	while ((t = strsep(&ptr, ","))) { +		for (m = map; m->str; m++) { +			if (!strcasecmp(m->str,t)) { +				*val = (unsigned int) m->val; set = 1; +				break; +			} +		} +	} +	free(str); + +	return set; +} + +char *hci_dtypetostr(int type) +{ +	switch (type) { +	case HCI_VIRTUAL: +		return "VIRTUAL"; +	case HCI_USB: +		return "USB"; +	case HCI_PCCARD: +		return "PCCARD"; +	case HCI_UART: +		return "UART"; +	case HCI_RS232: +		return "RS232"; +	case HCI_PCI: +		return "PCI"; +	case HCI_SDIO: +		return "SDIO"; +	default: +		return "UNKNOWN"; +	} +} + +/* HCI dev flags mapping */ +static hci_map dev_flags_map[] = { +	{ "UP",      HCI_UP      }, +	{ "INIT",    HCI_INIT    }, +	{ "RUNNING", HCI_RUNNING }, +	{ "RAW",     HCI_RAW     }, +	{ "PSCAN",   HCI_PSCAN   }, +	{ "ISCAN",   HCI_ISCAN   }, +	{ "INQUIRY", HCI_INQUIRY }, +	{ "AUTH",    HCI_AUTH    }, +	{ "ENCRYPT", HCI_ENCRYPT }, +	{ "SECMGR",  HCI_SECMGR  }, +	{ NULL } +}; + +char *hci_dflagstostr(uint32_t flags) +{ +	char *str = bt_malloc(50); +	char *ptr = str; +	hci_map *m = dev_flags_map; + +	if (!str) +		return NULL; + +	*ptr = 0; + +	if (!hci_test_bit(HCI_UP, &flags)) +		ptr += sprintf(ptr, "DOWN "); + +	while (m->str) { +		if (hci_test_bit(m->val, &flags)) +			ptr += sprintf(ptr, "%s ", m->str); +		m++; +	} 	 +	return str; +} + +/* HCI packet type mapping */ +static hci_map pkt_type_map[] = { +	{ "DM1",   HCI_DM1  }, +	{ "DM3",   HCI_DM3  }, +	{ "DM5",   HCI_DM5  }, +	{ "DH1",   HCI_DH1  }, +	{ "DH3",   HCI_DH3  }, +	{ "DH5",   HCI_DH5  }, +	{ "HV1",   HCI_HV1  }, +	{ "HV2",   HCI_HV2  }, +	{ "HV3",   HCI_HV3  }, +	{ "2-DH1", HCI_2DH1 }, +	{ "2-DH3", HCI_2DH3 }, +	{ "2-DH5", HCI_2DH5 }, +	{ "3-DH1", HCI_3DH1 }, +	{ "3-DH3", HCI_3DH3 }, +	{ "3-DH5", HCI_3DH5 }, +	{ NULL } +}; + +static hci_map sco_ptype_map[] = { +	{ "HV1",   0x0001   }, +	{ "HV2",   0x0002   }, +	{ "HV3",   0x0004   }, +	{ "EV3",   HCI_EV3  }, +	{ "EV4",   HCI_EV4  }, +	{ "EV5",   HCI_EV5  }, +	{ "2-EV3", HCI_2EV3 }, +	{ "2-EV5", HCI_2EV5 }, +	{ "3-EV3", HCI_3EV3 }, +	{ "3-EV5", HCI_3EV5 }, +	{ NULL } +}; + +char *hci_ptypetostr(unsigned int ptype) +{ +	return hci_bit2str(pkt_type_map, ptype); +} + +int hci_strtoptype(char *str, unsigned int *val) +{ +	return hci_str2bit(pkt_type_map, str, val); +} + +char *hci_scoptypetostr(unsigned int ptype) +{ +	return hci_bit2str(sco_ptype_map, ptype); +} + +int hci_strtoscoptype(char *str, unsigned int *val) +{ +	return hci_str2bit(sco_ptype_map, str, val); +} + +/* Link policy mapping */ +static hci_map link_policy_map[] = { +	{ "NONE",	0		}, +	{ "RSWITCH",	HCI_LP_RSWITCH	}, +	{ "HOLD",	HCI_LP_HOLD	}, +	{ "SNIFF",	HCI_LP_SNIFF	}, +	{ "PARK",	HCI_LP_PARK	}, +	{ NULL } +}; + +char *hci_lptostr(unsigned int lp) +{ +	return hci_bit2str(link_policy_map, lp); +} + +int hci_strtolp(char *str, unsigned int *val) +{ +	return hci_str2bit(link_policy_map, str, val); +} + +/* Link mode mapping */ +static hci_map link_mode_map[] = { +	{ "NONE",	0		}, +	{ "ACCEPT",	HCI_LM_ACCEPT	}, +	{ "MASTER",	HCI_LM_MASTER	}, +	{ "AUTH",	HCI_LM_AUTH	}, +	{ "ENCRYPT",	HCI_LM_ENCRYPT	}, +	{ "TRUSTED",	HCI_LM_TRUSTED	}, +	{ "RELIABLE",	HCI_LM_RELIABLE	}, +	{ "SECURE",	HCI_LM_SECURE	}, +	{ NULL } +}; + +char *hci_lmtostr(unsigned int lm) +{ +	char *s, *str = bt_malloc(50); +	if (!str) +		return NULL; + +	*str = 0; +	if (!(lm & HCI_LM_MASTER)) +		strcpy(str, "SLAVE "); + +	s = hci_bit2str(link_mode_map, lm); +	if (!s) { +		bt_free(str); +		return NULL; +	} + +	strcat(str, s); +	free(s); +	return str; +} + +int hci_strtolm(char *str, unsigned int *val) +{ +	return hci_str2bit(link_mode_map, str, val); +} + +/* Command mapping */ +static hci_map commands_map[] = { +	{ "Inquiry",					0   }, +	{ "Inquiry Cancel",				1   }, +	{ "Periodic Inquiry Mode",			2   }, +	{ "Exit Periodic Inquiry Mode",			3   }, +	{ "Create Connection",				4   }, +	{ "Disconnect",					5   }, +	{ "Add SCO Connection",				6   }, +	{ "Cancel Create Connection",			7   }, + +	{ "Accept Connection Request",			8   }, +	{ "Reject Connection Request",			9   }, +	{ "Link Key Request Reply",			10  }, +	{ "Link Key Request Negative Reply",		11  }, +	{ "PIN Code Request Reply",			12  }, +	{ "PIN Code Request Negative Reply",		13  }, +	{ "Change Connection Packet Type",		14  }, +	{ "Authentication Requested",			15  }, + +	{ "Set Connection Encryption",			16  }, +	{ "Change Connection Link Key",			17  }, +	{ "Master Link Key",				18  }, +	{ "Remote Name Request",			19  }, +	{ "Cancel Remote Name Request",			20  }, +	{ "Read Remote Supported Features",		21  }, +	{ "Read Remote Extended Features",		22  }, +	{ "Read Remote Version Information",		23  }, + +	{ "Read Clock Offset",				24  }, +	{ "Read LMP Handle",				25  }, +	{ "Reserved",					26  }, +	{ "Reserved",					27  }, +	{ "Reserved",					28  }, +	{ "Reserved",					29  }, +	{ "Reserved",					30  }, +	{ "Reserved",					31  }, + +	{ "Reserved",					32  }, +	{ "Hold Mode",					33  }, +	{ "Sniff Mode",					34  }, +	{ "Exit Sniff Mode",				35  }, +	{ "Park State",					36  }, +	{ "Exit Park State",				37  }, +	{ "QoS Setup",					38  }, +	{ "Role Discovery",				39  }, + +	{ "Switch Role",				40  }, +	{ "Read Link Policy Settings",			41  }, +	{ "Write Link Policy Settings",			42  }, +	{ "Read Default Link Policy Settings",		43  }, +	{ "Write Default Link Policy Settings",		44  }, +	{ "Flow Specification",				45  }, +	{ "Set Event Mask",				46  }, +	{ "Reset",					47  }, + +	{ "Set Event Filter",				48  }, +	{ "Flush",					49  }, +	{ "Read PIN Type",				50  }, +	{ "Write PIN Type",				51  }, +	{ "Create New Unit Key",			52  }, +	{ "Read Stored Link Key",			53  }, +	{ "Write Stored Link Key",			54  }, +	{ "Delete Stored Link Key",			55  }, + +	{ "Write Local Name",				56  }, +	{ "Read Local Name",				57  }, +	{ "Read Connection Accept Timeout",		58  }, +	{ "Write Connection Accept Timeout",		59  }, +	{ "Read Page Timeout",				60  }, +	{ "Write Page Timeout",				61  }, +	{ "Read Scan Enable",				62  }, +	{ "Write Scan Enable",				63  }, + +	{ "Read Page Scan Activity",			64  }, +	{ "Write Page Scan Activity",			65  }, +	{ "Read Inquiry Scan Activity",			66  }, +	{ "Write Inquiry Scan Activity",		67  }, +	{ "Read Authentication Enable",			68  }, +	{ "Write Authentication Enable",		69  }, +	{ "Read Encryption Mode",			70  }, +	{ "Write Encryption Mode",			71  }, + +	{ "Read Class Of Device",			72  }, +	{ "Write Class Of Device",			73  }, +	{ "Read Voice Setting",				74  }, +	{ "Write Voice Setting",			75  }, +	{ "Read Automatic Flush Timeout",		76  }, +	{ "Write Automatic Flush Timeout",		77  }, +	{ "Read Num Broadcast Retransmissions",		78  }, +	{ "Write Num Broadcast Retransmissions",	79  }, + +	{ "Read Hold Mode Activity",			80  }, +	{ "Write Hold Mode Activity",			81  }, +	{ "Read Transmit Power Level",			82  }, +	{ "Read Synchronous Flow Control Enable",	83  }, +	{ "Write Synchronous Flow Control Enable",	84  }, +	{ "Set Host Controller To Host Flow Control",	85  }, +	{ "Host Buffer Size",				86  }, +	{ "Host Number Of Completed Packets",		87  }, + +	{ "Read Link Supervision Timeout",		88  }, +	{ "Write Link Supervision Timeout",		89  }, +	{ "Read Number of Supported IAC",		90  }, +	{ "Read Current IAC LAP",			91  }, +	{ "Write Current IAC LAP",			92  }, +	{ "Read Page Scan Period Mode",			93  }, +	{ "Write Page Scan Period Mode",		94  }, +	{ "Read Page Scan Mode",			95  }, + +	{ "Write Page Scan Mode",			96  }, +	{ "Set AFH Channel Classification",		97  }, +	{ "Reserved",					98  }, +	{ "Reserved",					99  }, +	{ "Read Inquiry Scan Type",			100 }, +	{ "Write Inquiry Scan Type",			101 }, +	{ "Read Inquiry Mode",				102 }, +	{ "Write Inquiry Mode",				103 }, + +	{ "Read Page Scan Type",			104 }, +	{ "Write Page Scan Type",			105 }, +	{ "Read AFH Channel Assessment Mode",		106 }, +	{ "Write AFH Channel Assessment Mode",		107 }, +	{ "Reserved",					108 }, +	{ "Reserved",					109 }, +	{ "Reserved",					110 }, +	{ "Reserved",					111 }, + +	{ "Reserved",					112 }, +	{ "Reserved",					113 }, +	{ "Reserved",					114 }, +	{ "Read Local Version Information",		115 }, +	{ "Read Local Supported Commands",		116 }, +	{ "Read Local Supported Features",		117 }, +	{ "Read Local Extended Features",		118 }, +	{ "Read Buffer Size",				119 }, + +	{ "Read Country Code",				120 }, +	{ "Read BD ADDR",				121 }, +	{ "Read Failed Contact Counter",		122 }, +	{ "Reset Failed Contact Counter",		123 }, +	{ "Get Link Quality",				124 }, +	{ "Read RSSI",					125 }, +	{ "Read AFH Channel Map",			126 }, +	{ "Read BD Clock",				127 }, + +	{ "Read Loopback Mode",				128 }, +	{ "Write Loopback Mode",			129 }, +	{ "Enable Device Under Test Mode",		130 }, +	{ "Setup Synchronous Connection",		131 }, +	{ "Accept Synchronous Connection",		132 }, +	{ "Reject Synchronous Connection",		133 }, +	{ "Reserved",					134 }, +	{ "Reserved",					135 }, + +	{ "Read Extended Inquiry Response",		136 }, +	{ "Write Extended Inquiry Response",		137 }, +	{ "Refresh Encryption Key",			138 }, +	{ "Reserved",					139 }, +	{ "Sniff Subrating",				140 }, +	{ "Read Simple Pairing Mode",			141 }, +	{ "Write Simple Pairing Mode",			142 }, +	{ "Read Local OOB Data",			143 }, + +	{ "Read Inquiry Transmit Power Level",		144 }, +	{ "Write Inquiry Transmit Power Level",		145 }, +	{ "Read Default Erroneous Data Reporting",	146 }, +	{ "Write Default Erroneous Data Reporting",	147 }, +	{ "Reserved",					148 }, +	{ "Reserved",					149 }, +	{ "Reserved",					150 }, +	{ "IO Capability Request Reply",		151 }, + +	{ "User Confirmation Request Reply",		152 }, +	{ "User Confirmation Request Negative Reply",	153 }, +	{ "User Passkey Request Reply",			154 }, +	{ "User Passkey Request Negative Reply",	155 }, +	{ "Remote OOB Data Request Reply",		156 }, +	{ "Write Simple Pairing Debug Mode",		157 }, +	{ "Enhanced Flush",				158 }, +	{ "Remote OOB Data Request Negative Reply",	159 }, + +	{ "Reserved",					160 }, +	{ "Reserved",					161 }, +	{ "Send Keypress Notification",			162 }, +	{ "IO Capabilities Response Negative Reply",	163 }, +	{ "Reserved",					164 }, +	{ "Reserved",					165 }, +	{ "Reserved",					166 }, +	{ "Reserved",					167 }, + +	{ NULL } +}; + +char *hci_cmdtostr(unsigned int cmd) +{ +	return hci_uint2str(commands_map, cmd); +} + +char *hci_commandstostr(uint8_t *commands, char *pref, int width) +{ +	hci_map *m; +	char *off, *ptr, *str; +	int size = 10; + +	m = commands_map; + +	while (m->str) { +		if (commands[m->val / 8] & (1 << (m->val % 8))) +			size += strlen(m->str) + (pref ? strlen(pref) : 0) + 3; +		m++; +	} + +	str = bt_malloc(size); +	if (!str) +		return NULL; + +	ptr = str; *ptr = '\0'; + +	if (pref) +		ptr += sprintf(ptr, "%s", pref); + +	off = ptr; + +	m = commands_map; + +	while (m->str) { +		if (commands[m->val / 8] & (1 << (m->val % 8))) { +			if (strlen(off) + strlen(m->str) > width - 3) { +				ptr += sprintf(ptr, "\n%s", pref ? pref : ""); +				off = ptr; +			} +			ptr += sprintf(ptr, "'%s' ", m->str); +		} +		m++; +	} + +	return str; +} + +/* Version mapping */ +static hci_map ver_map[] = { +	{ "1.0b",	0x00 }, +	{ "1.1",	0x01 }, +	{ "1.2",	0x02 }, +	{ "2.0",	0x03 }, +	{ "2.1",	0x04 }, +	{ NULL } +}; + +char *hci_vertostr(unsigned int ver) +{ +	return hci_uint2str(ver_map, ver); +} + +int hci_strtover(char *str, unsigned int *ver) +{ +	return hci_str2uint(ver_map, str, ver); +} + +char *lmp_vertostr(unsigned int ver) +{ +	return hci_uint2str(ver_map, ver); +} + +int lmp_strtover(char *str, unsigned int *ver) +{ +	return hci_str2uint(ver_map, str, ver); +} + +/* LMP features mapping */ +static hci_map lmp_features_map[8][9] = { +	{	/* Byte 0 */ +		{ "<3-slot packets>",	LMP_3SLOT	},	/* Bit 0 */ +		{ "<5-slot packets>",	LMP_5SLOT	},	/* Bit 1 */ +		{ "<encryption>",	LMP_ENCRYPT	},	/* Bit 2 */ +		{ "<slot offset>",	LMP_SOFFSET	},	/* Bit 3 */ +		{ "<timing accuracy>",	LMP_TACCURACY	},	/* Bit 4 */ +		{ "<role switch>",	LMP_RSWITCH	},	/* Bit 5 */ +		{ "<hold mode>",	LMP_HOLD	},	/* Bit 6 */ +		{ "<sniff mode>",	LMP_SNIFF	},	/* Bit 7 */ +		{ NULL } +	}, +	{	/* Byte 1 */ +		{ "<park state>",	LMP_PARK	},	/* Bit 0 */ +		{ "<RSSI>",		LMP_RSSI	},	/* Bit 1 */ +		{ "<channel quality>",	LMP_QUALITY	},	/* Bit 2 */ +		{ "<SCO link>",		LMP_SCO		},	/* Bit 3 */ +		{ "<HV2 packets>",	LMP_HV2		},	/* Bit 4 */ +		{ "<HV3 packets>",	LMP_HV3		},	/* Bit 5 */ +		{ "<u-law log>",	LMP_ULAW	},	/* Bit 6 */ +		{ "<A-law log>",	LMP_ALAW	},	/* Bit 7 */ +		{ NULL } +	}, +	{	/* Byte 2 */ +		{ "<CVSD>",		LMP_CVSD	},	/* Bit 0 */ +		{ "<paging scheme>",	LMP_PSCHEME	},	/* Bit 1 */ +		{ "<power control>",	LMP_PCONTROL	},	/* Bit 2 */ +		{ "<transparent SCO>",	LMP_TRSP_SCO	},	/* Bit 3 */ +		{ "<broadcast encrypt>",LMP_BCAST_ENC	},	/* Bit 7 */ +		{ NULL } +	}, +	{	/* Byte 3 */ +		{ "<no. 24>",		0x01		},	/* Bit 0 */ +		{ "<EDR ACL 2 Mbps>",	LMP_EDR_ACL_2M	},	/* Bit 1 */ +		{ "<EDR ACL 3 Mbps>",	LMP_EDR_ACL_3M	},	/* Bit 2 */ +		{ "<enhanced iscan>",	LMP_ENH_ISCAN	},	/* Bit 3 */ +		{ "<interlaced iscan>",	LMP_ILACE_ISCAN	},	/* Bit 4 */ +		{ "<interlaced pscan>",	LMP_ILACE_PSCAN	},	/* Bit 5 */ +		{ "<inquiry with RSSI>",LMP_RSSI_INQ	},	/* Bit 6 */ +		{ "<extended SCO>",	LMP_ESCO	},	/* Bit 7 */ +		{ NULL } +	}, +	{	/* Byte 4 */ +		{ "<EV4 packets>",	LMP_EV4		},	/* Bit 0 */ +		{ "<EV5 packets>",	LMP_EV5		},	/* Bit 1 */ +		{ "<no. 34>",		0x04		},	/* Bit 2 */ +		{ "<AFH cap. slave>",	LMP_AFH_CAP_SLV	},	/* Bit 3 */ +		{ "<AFH class. slave>",	LMP_AFH_CLS_SLV	},	/* Bit 4 */ +		{ "<no. 37>",		0x20		},	/* Bit 5 */ +		{ "<no. 38>",		0x40		},	/* Bit 6 */ +		{ "<3-slot EDR ACL>",	LMP_EDR_3SLOT	},	/* Bit 7 */ +		{ NULL } +	}, +	{	/* Byte 5 */ +		{ "<5-slot EDR ACL>",	LMP_EDR_5SLOT	},	/* Bit 0 */ +		{ "<sniff subrating>",	LMP_SNIFF_SUBR	},	/* Bit 1 */ +		{ "<pause encryption>",	LMP_PAUSE_ENC	},	/* Bit 2 */ +		{ "<AFH cap. master>",	LMP_AFH_CAP_MST	},	/* Bit 3 */ +		{ "<AFH class. master>",LMP_AFH_CLS_MST	},	/* Bit 4 */ +		{ "<EDR eSCO 2 Mbps>",	LMP_EDR_ESCO_2M	},	/* Bit 5 */ +		{ "<EDR eSCO 3 Mbps>",	LMP_EDR_ESCO_3M	},	/* Bit 6 */ +		{ "<3-slot EDR eSCO>",	LMP_EDR_3S_ESCO	},	/* Bit 7 */ +		{ NULL } +	}, +	{	/* Byte 6 */ +		{ "<extended inquiry>",	LMP_EXT_INQ	},	/* Bit 0 */ +		{ "<no. 49>",		0x02		},	/* Bit 1 */ +		{ "<no. 50>",		0x04		},	/* Bit 2 */ +		{ "<simple pairing>",	LMP_SIMPLE_PAIR	},	/* Bit 3 */ +		{ "<encapsulated PDU>",	LMP_ENCAPS_PDU	},	/* Bit 4 */ +		{ "<err. data report>",	LMP_ERR_DAT_REP	},	/* Bit 5 */ +		{ "<non-flush flag>",	LMP_NFLUSH_PKTS	},	/* Bit 6 */ +		{ "<no. 55>",		0x80		},	/* Bit 7 */ +		{ NULL } +	}, +	{	/* Byte 7 */ +		{ "<LSTO>",		LMP_LSTO	},	/* Bit 1 */ +		{ "<inquiry TX power>",	LMP_INQ_TX_PWR	},	/* Bit 1 */ +		{ "<no. 58>",		0x04		},	/* Bit 2 */ +		{ "<no. 59>",		0x08		},	/* Bit 3 */ +		{ "<no. 60>",		0x10		},	/* Bit 4 */ +		{ "<no. 61>",		0x20		},	/* Bit 5 */ +		{ "<no. 62>",		0x40		},	/* Bit 6 */ +		{ "<extended features>",LMP_EXT_FEAT	},	/* Bit 7 */ +		{ NULL } +	}, +}; + +char *lmp_featurestostr(uint8_t *features, char *pref, int width) +{ +	char *off, *ptr, *str; +	int i, size = 10; + +	for (i = 0; i < 8; i++) { +		hci_map *m = lmp_features_map[i]; + +		while (m->str) { +			if (m->val & features[i]) +				size += strlen(m->str) + (pref ? strlen(pref) : 0) + 1; +			m++; +		} +	} + +	str = bt_malloc(size); +	if (!str) +		return NULL; + +	ptr = str; *ptr = '\0'; + +	if (pref) +		ptr += sprintf(ptr, "%s", pref); + +	off = ptr; + +	for (i = 0; i < 8; i++) { +		hci_map *m = lmp_features_map[i]; + +		while (m->str) { +			if (m->val & features[i]) { +				if (strlen(off) + strlen(m->str) > width - 1) { +					ptr += sprintf(ptr, "\n%s", pref ? pref : ""); +					off = ptr; +				} +				ptr += sprintf(ptr, "%s ", m->str); +			} +			m++; +		} +	} + +	return str; +} + +/* HCI functions that do not require open device */ + +int hci_for_each_dev(int flag, int (*func)(int dd, int dev_id, long arg), long arg) +{ +	struct hci_dev_list_req *dl; +	struct hci_dev_req *dr; +	int dev_id = -1; +	int i, sk, err = 0; + +	sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); +	if (sk < 0) +		return -1; + +	dl = malloc(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl)); +	if (!dl) { +		err = errno; +		goto done; +	} + +	memset(dl, 0, HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl)); + +	dl->dev_num = HCI_MAX_DEV; +	dr = dl->dev_req; + +	if (ioctl(sk, HCIGETDEVLIST, (void *) dl) < 0) { +		err = errno; +		goto free; +	} + +	for (i = 0; i < dl->dev_num; i++, dr++) { +		if (hci_test_bit(flag, &dr->dev_opt)) +			if (!func || func(sk, dr->dev_id, arg)) { +				dev_id = dr->dev_id; +				break; +			} +	} + +	if (dev_id < 0) +		err = ENODEV; + +free: +	free(dl); + +done: +	close(sk); +	errno = err; + +	return dev_id; +} + +static int __other_bdaddr(int dd, int dev_id, long arg) +{ +	struct hci_dev_info di = { dev_id: dev_id }; + +	if (ioctl(dd, HCIGETDEVINFO, (void *) &di)) +		return 0; + +	if (hci_test_bit(HCI_RAW, &di.flags)) +		return 0; + +	return bacmp((bdaddr_t *) arg, &di.bdaddr); +} + +static int __same_bdaddr(int dd, int dev_id, long arg) +{ +	struct hci_dev_info di = { dev_id: dev_id }; + +	if (ioctl(dd, HCIGETDEVINFO, (void *) &di)) +		return 0; + +	return !bacmp((bdaddr_t *) arg, &di.bdaddr); +} + +int hci_get_route(bdaddr_t *bdaddr) +{ +	return hci_for_each_dev(HCI_UP, __other_bdaddr, +				(long) (bdaddr ? bdaddr : BDADDR_ANY)); +} + +int hci_devid(const char *str) +{ +	bdaddr_t ba; +	int id = -1; + +	if (!strncmp(str, "hci", 3) && strlen(str) >= 4) { +		id = atoi(str + 3); +		if (hci_devba(id, &ba) < 0) +			return -1; +	} else { +		errno = ENODEV; +		str2ba(str, &ba); +		id = hci_for_each_dev(HCI_UP, __same_bdaddr, (long) &ba); +	} + +	return id; +} + +int hci_devinfo(int dev_id, struct hci_dev_info *di) +{ +	int dd, err, ret; + +	dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); +	if (dd < 0) +		return dd; + +	memset(di, 0, sizeof(struct hci_dev_info)); + +	di->dev_id = dev_id; +	ret = ioctl(dd, HCIGETDEVINFO, (void *) di); + +	err = errno; +	close(dd); +	errno = err; + +	return ret; +} + +int hci_devba(int dev_id, bdaddr_t *bdaddr) +{ +	struct hci_dev_info di; + +	memset(&di, 0, sizeof(di)); + +	if (hci_devinfo(dev_id, &di)) +		return -1; + +	if (!hci_test_bit(HCI_UP, &di.flags)) { +		errno = ENETDOWN; +		return -1; +	} + +	bacpy(bdaddr, &di.bdaddr); + +	return 0; +} + +int hci_inquiry(int dev_id, int len, int nrsp, const uint8_t *lap, inquiry_info **ii, long flags) +{ +	struct hci_inquiry_req *ir; +	uint8_t num_rsp = nrsp; +	void *buf; +	int dd, size, err, ret = -1; + +	if (nrsp <= 0) { +		num_rsp = 0; +		nrsp = 255; +	} + +	if (dev_id < 0) { +		dev_id = hci_get_route(NULL); +		if (dev_id < 0) { +			errno = ENODEV; +			return -1; +		} +	}	 + +	dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); +	if (dd < 0) +		return dd; + +	buf = malloc(sizeof(*ir) + (sizeof(inquiry_info) * (nrsp))); +	if (!buf) +		goto done; + +	ir = buf; +	ir->dev_id  = dev_id; +	ir->num_rsp = num_rsp; +	ir->length  = len; +	ir->flags   = flags; + +	if (lap) { +		memcpy(ir->lap, lap, 3); +	} else { +		ir->lap[0] = 0x33; +		ir->lap[1] = 0x8b; +		ir->lap[2] = 0x9e; +	} + +	ret = ioctl(dd, HCIINQUIRY, (unsigned long) buf); +	if (ret < 0) +		goto free; + +	size = sizeof(inquiry_info) * ir->num_rsp; + +	if (!*ii) +		*ii = malloc(size); + +	if (*ii) { +		memcpy((void *) *ii, buf + sizeof(*ir), size); +		ret = ir->num_rsp; +	} else +		ret = -1; + +free: +	free(buf); + +done: +	err = errno; +	close(dd); +	errno = err; + +	return ret; +} + +/* Open HCI device.  + * Returns device descriptor (dd). */ +int hci_open_dev(int dev_id) +{ +	struct sockaddr_hci a; +	int dd, err; + +	/* Create HCI socket */ +	dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); +	if (dd < 0) +		return dd; + +	/* Bind socket to the HCI device */ +	memset(&a, 0, sizeof(a)); +	a.hci_family = AF_BLUETOOTH; +	a.hci_dev = dev_id; +	if (bind(dd, (struct sockaddr *) &a, sizeof(a)) < 0) +		goto failed; + +	return dd; + +failed: +	err = errno; +	close(dd); +	errno = err; + +	return -1; +} + +int hci_close_dev(int dd) +{ +	return close(dd); +} + +/* HCI functions that require open device + * dd - Device descriptor returned by hci_open_dev. */ + +int hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param) +{ +	uint8_t type = HCI_COMMAND_PKT; +	hci_command_hdr hc; +	struct iovec iv[3]; +	int ivn; + +	hc.opcode = htobs(cmd_opcode_pack(ogf, ocf)); +	hc.plen= plen; + +	iv[0].iov_base = &type; +	iv[0].iov_len  = 1; +	iv[1].iov_base = &hc; +	iv[1].iov_len  = HCI_COMMAND_HDR_SIZE; +	ivn = 2; + +	if (plen) { +		iv[2].iov_base = param; +		iv[2].iov_len  = plen; +		ivn = 3; +	} + +	while (writev(dd, iv, ivn) < 0) { +		if (errno == EAGAIN || errno == EINTR) +			continue; +		return -1; +	} +	return 0; +} + +int hci_send_req(int dd, struct hci_request *r, int to) +{ +	unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr; +	uint16_t opcode = htobs(cmd_opcode_pack(r->ogf, r->ocf)); +	struct hci_filter nf, of; +	socklen_t len; +	hci_event_hdr *hdr; +	int err, try; + +	len = sizeof(of); +	if (getsockopt(dd, SOL_HCI, HCI_FILTER, &of, &len) < 0) +		return -1; + +	hci_filter_clear(&nf); +	hci_filter_set_ptype(HCI_EVENT_PKT,  &nf); +	hci_filter_set_event(EVT_CMD_STATUS, &nf); +	hci_filter_set_event(EVT_CMD_COMPLETE, &nf); +	hci_filter_set_event(r->event, &nf); +	hci_filter_set_opcode(opcode, &nf); +	if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) +		return -1; + +	if (hci_send_cmd(dd, r->ogf, r->ocf, r->clen, r->cparam) < 0) +		goto failed; + +	try = 10; +	while (try--) { +		evt_cmd_complete *cc; +		evt_cmd_status *cs; +		evt_remote_name_req_complete *rn; +		remote_name_req_cp *cp; + +		if (to) { +			struct pollfd p; +			int n; + +			p.fd = dd; p.events = POLLIN; +			while ((n = poll(&p, 1, to)) < 0) { +				if (errno == EAGAIN || errno == EINTR) +					continue; +				goto failed; +			} + +			if (!n) { +				errno = ETIMEDOUT; +				goto failed; +			} + +			to -= 10; +			if (to < 0) to = 0; + +		} + +		while ((len = read(dd, buf, sizeof(buf))) < 0) { +			if (errno == EAGAIN || errno == EINTR) +				continue; +			goto failed; +		} + +		hdr = (void *) (buf + 1); +		ptr = buf + (1 + HCI_EVENT_HDR_SIZE); +		len -= (1 + HCI_EVENT_HDR_SIZE); + +		switch (hdr->evt) { +		case EVT_CMD_STATUS: +			cs = (void *) ptr; + +			if (cs->opcode != opcode) +				continue; + +			if (r->event != EVT_CMD_STATUS) { +				if (cs->status) { +					errno = EIO; +					goto failed; +				} +				break; +			} + +			r->rlen = MIN(len, r->rlen); +			memcpy(r->rparam, ptr, r->rlen); +			goto done; + +		case EVT_CMD_COMPLETE: +			cc = (void *) ptr; + +			if (cc->opcode != opcode) +				continue; + +			ptr += EVT_CMD_COMPLETE_SIZE; +			len -= EVT_CMD_COMPLETE_SIZE; + +			r->rlen = MIN(len, r->rlen); +			memcpy(r->rparam, ptr, r->rlen); +			goto done; + +		case EVT_REMOTE_NAME_REQ_COMPLETE: +			if (hdr->evt != r->event) +				break; + +			rn = (void *) ptr; +			cp = r->cparam; + +			if (bacmp(&rn->bdaddr, &cp->bdaddr)) +				continue; + +			r->rlen = MIN(len, r->rlen); +			memcpy(r->rparam, ptr, r->rlen); +			goto done; + +		default: +			if (hdr->evt != r->event) +				break; + +			r->rlen = MIN(len, r->rlen); +			memcpy(r->rparam, ptr, r->rlen); +			goto done; +		} +	} +	errno = ETIMEDOUT; + +failed: +	err = errno; +	setsockopt(dd, SOL_HCI, HCI_FILTER, &of, sizeof(of)); +	errno = err; +	return -1; + +done: +	setsockopt(dd, SOL_HCI, HCI_FILTER, &of, sizeof(of)); +	return 0; +} + +int hci_create_connection(int dd, const bdaddr_t *bdaddr, uint16_t ptype, uint16_t clkoffset, uint8_t rswitch, uint16_t *handle, int to) +{ +	evt_conn_complete rp; +	create_conn_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	bacpy(&cp.bdaddr, bdaddr); +	cp.pkt_type       = ptype; +	cp.pscan_rep_mode = 0x02; +	cp.clock_offset   = clkoffset; +	cp.role_switch    = rswitch; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_CREATE_CONN; +	rq.event  = EVT_CONN_COMPLETE; +	rq.cparam = &cp; +	rq.clen   = CREATE_CONN_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_CONN_COMPLETE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*handle = rp.handle; +	return 0; +} + +int hci_disconnect(int dd, uint16_t handle, uint8_t reason, int to) +{ +	evt_disconn_complete rp; +	disconnect_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.handle = handle; +	cp.reason = reason; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_DISCONNECT; +	rq.event  = EVT_DISCONN_COMPLETE; +	rq.cparam = &cp; +	rq.clen   = DISCONNECT_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_DISCONN_COMPLETE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} +	return 0; +} + +int hci_read_local_name(int dd, int len, char *name, int to) +{ +	read_local_name_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_LOCAL_NAME; +	rq.rparam = &rp; +	rq.rlen   = READ_LOCAL_NAME_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	rp.name[247] = '\0'; +	strncpy(name, (char *) rp.name, len); +	return 0; +} + +int hci_write_local_name(int dd, const char *name, int to) +{ +	change_local_name_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	strncpy((char *) cp.name, name, sizeof(cp.name)); + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_CHANGE_LOCAL_NAME; +	rq.cparam = &cp; +	rq.clen   = CHANGE_LOCAL_NAME_CP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	return 0; +} + +int hci_read_remote_name_with_clock_offset(int dd, const bdaddr_t *bdaddr, uint8_t pscan_rep_mode, uint16_t clkoffset, int len, char *name, int to) +{ +	evt_remote_name_req_complete rn; +	remote_name_req_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	bacpy(&cp.bdaddr, bdaddr); +	cp.pscan_rep_mode = pscan_rep_mode; +	cp.clock_offset   = clkoffset; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_REMOTE_NAME_REQ; +	rq.cparam = &cp; +	rq.clen   = REMOTE_NAME_REQ_CP_SIZE; +	rq.event  = EVT_REMOTE_NAME_REQ_COMPLETE; +	rq.rparam = &rn; +	rq.rlen   = EVT_REMOTE_NAME_REQ_COMPLETE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rn.status) { +		errno = EIO; +		return -1; +	} + +	rn.name[247] = '\0'; +	strncpy(name, (char *) rn.name, len); +	return 0; +} + +int hci_read_remote_name(int dd, const bdaddr_t *bdaddr, int len, char *name, int to) +{ +	return hci_read_remote_name_with_clock_offset(dd, bdaddr, 0x02, 0x0000, len, name, to); +} + +int hci_read_remote_name_cancel(int dd, const bdaddr_t *bdaddr, int to) +{ +	remote_name_req_cancel_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	bacpy(&cp.bdaddr, bdaddr); + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_REMOTE_NAME_REQ_CANCEL; +	rq.cparam = &cp; +	rq.clen   = REMOTE_NAME_REQ_CANCEL_CP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	return 0; +} + +int hci_read_remote_version(int dd, uint16_t handle, struct hci_version *ver, int to) +{ +	evt_read_remote_version_complete rp; +	read_remote_version_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.handle = handle; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_READ_REMOTE_VERSION; +	rq.event  = EVT_READ_REMOTE_VERSION_COMPLETE; +	rq.cparam = &cp; +	rq.clen   = READ_REMOTE_VERSION_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_READ_REMOTE_VERSION_COMPLETE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	ver->manufacturer = btohs(rp.manufacturer); +	ver->lmp_ver      = rp.lmp_ver; +	ver->lmp_subver   = btohs(rp.lmp_subver); +	return 0; +} + +int hci_read_remote_features(int dd, uint16_t handle, uint8_t *features, int to) +{ +	evt_read_remote_features_complete rp; +	read_remote_features_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.handle = handle; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_READ_REMOTE_FEATURES; +	rq.event  = EVT_READ_REMOTE_FEATURES_COMPLETE; +	rq.cparam = &cp; +	rq.clen   = READ_REMOTE_FEATURES_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	memcpy(features, rp.features, 8); +	return 0; +} + +int hci_read_remote_ext_features(int dd, uint16_t handle, uint8_t page, uint8_t *max_page, uint8_t *features, int to) +{ +	evt_read_remote_ext_features_complete rp; +	read_remote_ext_features_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.handle   = handle; +	cp.page_num = page; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_READ_REMOTE_EXT_FEATURES; +	rq.event  = EVT_READ_REMOTE_EXT_FEATURES_COMPLETE; +	rq.cparam = &cp; +	rq.clen   = READ_REMOTE_EXT_FEATURES_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*max_page = rp.max_page_num; +	memcpy(features, rp.features, 8); +	return 0; +} + +int hci_read_clock_offset(int dd, uint16_t handle, uint16_t *clkoffset, int to) +{ +	evt_read_clock_offset_complete rp; +	read_clock_offset_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.handle = handle; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_READ_CLOCK_OFFSET; +	rq.event  = EVT_READ_CLOCK_OFFSET_COMPLETE; +	rq.cparam = &cp; +	rq.clen   = READ_CLOCK_OFFSET_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*clkoffset = rp.clock_offset; +	return 0; +} + +int hci_read_local_version(int dd, struct hci_version *ver, int to) +{ +	read_local_version_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_INFO_PARAM; +	rq.ocf    = OCF_READ_LOCAL_VERSION; +	rq.rparam = &rp; +	rq.rlen   = READ_LOCAL_VERSION_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	ver->manufacturer = btohs(rp.manufacturer); +	ver->hci_ver      = rp.hci_ver; +	ver->hci_rev      = btohs(rp.hci_rev); +	ver->lmp_ver      = rp.lmp_ver; +	ver->lmp_subver   = btohs(rp.lmp_subver); +	return 0; +} + +int hci_read_local_commands(int dd, uint8_t *commands, int to) +{ +	read_local_commands_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_INFO_PARAM; +	rq.ocf    = OCF_READ_LOCAL_COMMANDS; +	rq.rparam = &rp; +	rq.rlen   = READ_LOCAL_COMMANDS_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	memcpy(commands, rp.commands, 64); +	return 0; +} + +int hci_read_local_features(int dd, uint8_t *features, int to) +{ +	read_local_features_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_INFO_PARAM; +	rq.ocf    = OCF_READ_LOCAL_FEATURES; +	rq.rparam = &rp; +	rq.rlen   = READ_LOCAL_FEATURES_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	memcpy(features, rp.features, 8); +	return 0; +} + +int hci_read_local_ext_features(int dd, uint8_t page, uint8_t *max_page, uint8_t *features, int to) +{ +	read_local_ext_features_cp cp; +	read_local_ext_features_rp rp; +	struct hci_request rq; + +	cp.page_num = page; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_INFO_PARAM; +	rq.ocf    = OCF_READ_LOCAL_EXT_FEATURES; +	rq.cparam = &cp; +	rq.clen   = READ_LOCAL_EXT_FEATURES_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = READ_LOCAL_EXT_FEATURES_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*max_page = rp.max_page_num; +	memcpy(features, rp.features, 8); +	return 0; +} + +int hci_read_bd_addr(int dd, bdaddr_t *bdaddr, int to) +{ +	read_bd_addr_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_INFO_PARAM; +	rq.ocf    = OCF_READ_BD_ADDR; +	rq.rparam = &rp; +	rq.rlen   = READ_BD_ADDR_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	bacpy(bdaddr, &rp.bdaddr); +	return 0; +} + +int hci_read_class_of_dev(int dd, uint8_t *cls, int to) +{ +	read_class_of_dev_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_CLASS_OF_DEV; +	rq.rparam = &rp; +	rq.rlen   = READ_CLASS_OF_DEV_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	memcpy(cls, rp.dev_class, 3); +	return 0; +} + +int hci_write_class_of_dev(int dd, uint32_t cls, int to) +{ +	write_class_of_dev_cp cp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	cp.dev_class[0] = cls & 0xff; +	cp.dev_class[1] = (cls >> 8) & 0xff; +	cp.dev_class[2] = (cls >> 16) & 0xff; +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_CLASS_OF_DEV; +	rq.cparam = &cp; +	rq.clen   = WRITE_CLASS_OF_DEV_CP_SIZE; +	return hci_send_req(dd, &rq, to); +} + +int hci_read_voice_setting(int dd, uint16_t *vs, int to) +{ +	read_voice_setting_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_VOICE_SETTING; +	rq.rparam = &rp; +	rq.rlen   = READ_VOICE_SETTING_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*vs = rp.voice_setting; +	return 0; +} + +int hci_write_voice_setting(int dd, uint16_t vs, int to) +{ +	write_voice_setting_cp cp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	cp.voice_setting = vs; +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_VOICE_SETTING; +	rq.cparam = &cp; +	rq.clen   = WRITE_VOICE_SETTING_CP_SIZE; + +	return hci_send_req(dd, &rq, to); +} + +int hci_read_current_iac_lap(int dd, uint8_t *num_iac, uint8_t *lap, int to) +{ +	read_current_iac_lap_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_CURRENT_IAC_LAP; +	rq.rparam = &rp; +	rq.rlen   = READ_CURRENT_IAC_LAP_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*num_iac = rp.num_current_iac; +	memcpy(lap, rp.lap, rp.num_current_iac * 3); +	return 0; +} + +int hci_write_current_iac_lap(int dd, uint8_t num_iac, uint8_t *lap, int to) +{ +	write_current_iac_lap_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.num_current_iac = num_iac; +	memcpy(&cp.lap, lap, num_iac * 3); + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_CURRENT_IAC_LAP; +	rq.cparam = &cp; +	rq.clen   = num_iac * 3 + 1; + +	return hci_send_req(dd, &rq, to); +} + +int hci_read_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to) +{ +	read_stored_link_key_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	bacpy(&cp.bdaddr, bdaddr); +	cp.read_all = all; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_STORED_LINK_KEY; +	rq.cparam = &cp; +	rq.clen   = READ_STORED_LINK_KEY_CP_SIZE; + +	return hci_send_req(dd, &rq, to); +} + +int hci_write_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t *key, int to) +{ +	unsigned char cp[WRITE_STORED_LINK_KEY_CP_SIZE + 6 + 16]; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp[0] = 1; +	bacpy((bdaddr_t *) (cp + 1), bdaddr); +	memcpy(cp + 7, key, 16); + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_STORED_LINK_KEY; +	rq.cparam = &cp; +	rq.clen   = WRITE_STORED_LINK_KEY_CP_SIZE + 6 + 16; + +	return hci_send_req(dd, &rq, to); +} + +int hci_delete_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to) +{ +	delete_stored_link_key_cp cp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	bacpy(&cp.bdaddr, bdaddr); +	cp.delete_all = all; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_DELETE_STORED_LINK_KEY; +	rq.cparam = &cp; +	rq.clen   = DELETE_STORED_LINK_KEY_CP_SIZE; + +	return hci_send_req(dd, &rq, to); +} + +int hci_authenticate_link(int dd, uint16_t handle, int to) +{ +	auth_requested_cp cp; +	evt_auth_complete rp; +	struct hci_request rq; + +	cp.handle = handle; + +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_AUTH_REQUESTED; +	rq.event  = EVT_AUTH_COMPLETE; +	rq.cparam = &cp; +	rq.clen   = AUTH_REQUESTED_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_AUTH_COMPLETE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_encrypt_link(int dd, uint16_t handle, uint8_t encrypt, int to) +{ +	set_conn_encrypt_cp cp; +	evt_encrypt_change rp; +	struct hci_request rq; + +	cp.handle  = handle; +	cp.encrypt = encrypt; + +	rq.ogf     = OGF_LINK_CTL; +	rq.ocf     = OCF_SET_CONN_ENCRYPT; +	rq.event   = EVT_ENCRYPT_CHANGE; +	rq.cparam  = &cp; +	rq.clen    = SET_CONN_ENCRYPT_CP_SIZE; +	rq.rparam  = &rp; +	rq.rlen    = EVT_ENCRYPT_CHANGE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_change_link_key(int dd, uint16_t handle, int to) +{ +	change_conn_link_key_cp cp; +	evt_change_conn_link_key_complete rp; +	struct hci_request rq; + +	cp.handle = handle; + +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_CHANGE_CONN_LINK_KEY; +	rq.event  = EVT_CHANGE_CONN_LINK_KEY_COMPLETE; +	rq.cparam = &cp; +	rq.clen   = CHANGE_CONN_LINK_KEY_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_CHANGE_CONN_LINK_KEY_COMPLETE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_switch_role(int dd, bdaddr_t *bdaddr, uint8_t role, int to) +{ +	switch_role_cp cp; +	evt_role_change rp; +	struct hci_request rq; + +	bacpy(&cp.bdaddr, bdaddr); +	cp.role   = role; +	rq.ogf    = OGF_LINK_POLICY; +	rq.ocf    = OCF_SWITCH_ROLE; +	rq.cparam = &cp; +	rq.clen   = SWITCH_ROLE_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_ROLE_CHANGE_SIZE; +	rq.event  = EVT_ROLE_CHANGE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_park_mode(int dd, uint16_t handle, uint16_t max_interval, uint16_t min_interval, int to) +{ +	park_mode_cp cp; +	evt_mode_change rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof (cp)); +	cp.handle       = handle; +	cp.max_interval = max_interval; +	cp.min_interval = min_interval; + +	memset(&rq, 0, sizeof (rq)); +	rq.ogf    = OGF_LINK_POLICY; +	rq.ocf    = OCF_PARK_MODE; +	rq.event  = EVT_MODE_CHANGE; +	rq.cparam = &cp; +	rq.clen   = PARK_MODE_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_MODE_CHANGE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_exit_park_mode(int dd, uint16_t handle, int to) +{ +	exit_park_mode_cp cp; +	evt_mode_change rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof (cp)); +	cp.handle = handle; + +	memset (&rq, 0, sizeof (rq)); +	rq.ogf    = OGF_LINK_POLICY; +	rq.ocf    = OCF_EXIT_PARK_MODE; +	rq.event  = EVT_MODE_CHANGE; +	rq.cparam = &cp; +	rq.clen   = EXIT_PARK_MODE_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_MODE_CHANGE_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_read_inquiry_scan_type(int dd, uint8_t *type, int to) +{ +	read_inquiry_scan_type_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_INQUIRY_SCAN_TYPE; +	rq.rparam = &rp; +	rq.rlen   = READ_INQUIRY_SCAN_TYPE_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*type = rp.type; +	return 0; +} + +int hci_write_inquiry_scan_type(int dd, uint8_t type, int to) +{ +	write_inquiry_scan_type_cp cp; +	write_inquiry_scan_type_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.type = type; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_INQUIRY_SCAN_TYPE; +	rq.cparam = &cp; +	rq.clen   = WRITE_INQUIRY_SCAN_TYPE_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = WRITE_INQUIRY_SCAN_TYPE_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_read_inquiry_mode(int dd, uint8_t *mode, int to) +{ +	read_inquiry_mode_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_INQUIRY_MODE; +	rq.rparam = &rp; +	rq.rlen   = READ_INQUIRY_MODE_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*mode = rp.mode; +	return 0; +} + +int hci_write_inquiry_mode(int dd, uint8_t mode, int to) +{ +	write_inquiry_mode_cp cp; +	write_inquiry_mode_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.mode = mode; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_INQUIRY_MODE; +	rq.cparam = &cp; +	rq.clen   = WRITE_INQUIRY_MODE_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = WRITE_INQUIRY_MODE_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_read_afh_mode(int dd, uint8_t *mode, int to) +{ +	read_afh_mode_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_AFH_MODE; +	rq.rparam = &rp; +	rq.rlen   = READ_AFH_MODE_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*mode = rp.mode; +	return 0; +} + +int hci_write_afh_mode(int dd, uint8_t mode, int to) +{ +	write_afh_mode_cp cp; +	write_afh_mode_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.mode = mode; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_AFH_MODE; +	rq.cparam = &cp; +	rq.clen   = WRITE_AFH_MODE_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = WRITE_AFH_MODE_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_read_ext_inquiry_response(int dd, uint8_t *fec, uint8_t *data, int to) +{ +	read_ext_inquiry_response_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_EXT_INQUIRY_RESPONSE; +	rq.rparam = &rp; +	rq.rlen   = READ_EXT_INQUIRY_RESPONSE_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*fec = rp.fec; +	memcpy(data, rp.data, 240); + +	return 0; +} + +int hci_write_ext_inquiry_response(int dd, uint8_t fec, uint8_t *data, int to) +{ +	write_ext_inquiry_response_cp cp; +	write_ext_inquiry_response_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.fec = fec; +	memcpy(cp.data, data, 240); + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_EXT_INQUIRY_RESPONSE; +	rq.cparam = &cp; +	rq.clen   = WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = WRITE_EXT_INQUIRY_RESPONSE_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_read_simple_pairing_mode(int dd, uint8_t *mode, int to) +{ +	read_simple_pairing_mode_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_SIMPLE_PAIRING_MODE; +	rq.rparam = &rp; +	rq.rlen   = READ_SIMPLE_PAIRING_MODE_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*mode = rp.mode; +	return 0; +} + +int hci_write_simple_pairing_mode(int dd, uint8_t mode, int to) +{ +	write_simple_pairing_mode_cp cp; +	write_simple_pairing_mode_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.mode = mode; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_SIMPLE_PAIRING_MODE; +	rq.cparam = &cp; +	rq.clen   = WRITE_SIMPLE_PAIRING_MODE_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = WRITE_SIMPLE_PAIRING_MODE_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_read_local_oob_data(int dd, uint8_t *hash, uint8_t *randomizer, int to) +{ +	read_local_oob_data_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_LOCAL_OOB_DATA; +	rq.rparam = &rp; +	rq.rlen   = READ_LOCAL_OOB_DATA_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	memcpy(hash, rp.hash, 16); +	memcpy(randomizer, rp.randomizer, 16); +	return 0; +} + +int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to) +{ +	read_inquiry_transmit_power_level_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_INQUIRY_TRANSMIT_POWER_LEVEL; +	rq.rparam = &rp; +	rq.rlen   = READ_INQUIRY_TRANSMIT_POWER_LEVEL_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*level = rp.level; +	return 0; +} + +int hci_write_inquiry_transmit_power_level(int dd, int8_t level, int to) +{ +	write_inquiry_transmit_power_level_cp cp; +	write_inquiry_transmit_power_level_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.level = level; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL; +	rq.cparam = &cp; +	rq.clen   = WRITE_INQUIRY_TRANSMIT_POWER_LEVEL_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = WRITE_INQUIRY_TRANSMIT_POWER_LEVEL_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_read_transmit_power_level(int dd, uint16_t handle, uint8_t type, int8_t *level, int to) +{ +	read_transmit_power_level_cp cp; +	read_transmit_power_level_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.handle = handle; +	cp.type   = type; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_TRANSMIT_POWER_LEVEL; +	rq.cparam = &cp; +	rq.clen   = READ_TRANSMIT_POWER_LEVEL_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = READ_TRANSMIT_POWER_LEVEL_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*level = rp.level; +	return 0; +} + +int hci_read_link_policy(int dd, uint16_t handle, uint16_t *policy, int to) +{ +	read_link_policy_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_POLICY; +	rq.ocf    = OCF_READ_LINK_POLICY; +	rq.cparam = &handle; +	rq.clen   = 2; +	rq.rparam = &rp; +	rq.rlen   = READ_LINK_POLICY_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*policy = rp.policy; +	return 0; +} + +int hci_write_link_policy(int dd, uint16_t handle, uint16_t policy, int to) +{ +	write_link_policy_cp cp; +	write_link_policy_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.handle = handle; +	cp.policy = policy; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_POLICY; +	rq.ocf    = OCF_WRITE_LINK_POLICY; +	rq.cparam = &cp; +	rq.clen   = WRITE_LINK_POLICY_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = WRITE_LINK_POLICY_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_read_link_supervision_timeout(int dd, uint16_t handle, uint16_t *timeout, int to) +{ +	read_link_supervision_timeout_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_READ_LINK_SUPERVISION_TIMEOUT; +	rq.cparam = &handle; +	rq.clen   = 2; +	rq.rparam = &rp; +	rq.rlen   = READ_LINK_SUPERVISION_TIMEOUT_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*timeout = rp.timeout; +	return 0; +} + +int hci_write_link_supervision_timeout(int dd, uint16_t handle, uint16_t timeout, int to) +{ +	write_link_supervision_timeout_cp cp; +	write_link_supervision_timeout_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.handle  = handle; +	cp.timeout = timeout; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_WRITE_LINK_SUPERVISION_TIMEOUT; +	rq.cparam = &cp; +	rq.clen   = WRITE_LINK_SUPERVISION_TIMEOUT_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = WRITE_LINK_SUPERVISION_TIMEOUT_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_set_afh_classification(int dd, uint8_t *map, int to) +{ +	set_afh_classification_cp cp; +	set_afh_classification_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	memcpy(cp.map, map, 10); + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_HOST_CTL; +	rq.ocf    = OCF_SET_AFH_CLASSIFICATION; +	rq.cparam = &cp; +	rq.clen   = SET_AFH_CLASSIFICATION_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = SET_AFH_CLASSIFICATION_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +int hci_read_link_quality(int dd, uint16_t handle, uint8_t *link_quality, int to) +{ +	read_link_quality_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_STATUS_PARAM; +	rq.ocf    = OCF_READ_LINK_QUALITY; +	rq.cparam = &handle; +	rq.clen   = 2; +	rq.rparam = &rp; +	rq.rlen   = READ_LINK_QUALITY_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*link_quality = rp.link_quality; +	return 0; +} + +int hci_read_rssi(int dd, uint16_t handle, int8_t *rssi, int to) +{ +	read_rssi_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_STATUS_PARAM; +	rq.ocf    = OCF_READ_RSSI; +	rq.cparam = &handle; +	rq.clen   = 2; +	rq.rparam = &rp; +	rq.rlen   = READ_RSSI_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*rssi = rp.rssi; +	return 0; +} + +int hci_read_afh_map(int dd, uint16_t handle, uint8_t *mode, uint8_t *map, int to) +{ +	read_afh_map_rp rp; +	struct hci_request rq; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_STATUS_PARAM; +	rq.ocf    = OCF_READ_AFH_MAP; +	rq.cparam = &handle; +	rq.clen   = 2; +	rq.rparam = &rp; +	rq.rlen   = READ_AFH_MAP_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*mode = rp.mode; +	memcpy(map, rp.map, 10); +	return 0; +} + +int hci_read_clock(int dd, uint16_t handle, uint8_t which, uint32_t *clock, uint16_t *accuracy, int to) +{ +	read_clock_cp cp; +	read_clock_rp rp; +	struct hci_request rq; + +	memset(&cp, 0, sizeof(cp)); +	cp.handle      = handle; +	cp.which_clock = which; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_STATUS_PARAM; +	rq.ocf    = OCF_READ_CLOCK; +	rq.cparam = &cp; +	rq.clen   = READ_CLOCK_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = READ_CLOCK_RP_SIZE; + +	if (hci_send_req(dd, &rq, to) < 0) +		return -1; + +	if (rp.status) { +		errno = EIO; +		return -1; +	} + +	*clock    = rp.clock; +	*accuracy = rp.accuracy; +	return 0; +} + +int hci_local_name(int dd, int len, char *name, int to) +{ +	return hci_read_local_name(dd, len, name, to); +} + +int hci_remote_name(int dd, const bdaddr_t *bdaddr, int len, char *name, int to) +{ +	return hci_read_remote_name(dd, bdaddr, len, name, to); +} diff --git a/src/sdp.c b/src/sdp.c new file mode 100644 index 00000000..3149c0f1 --- /dev/null +++ b/src/sdp.c @@ -0,0 +1,4421 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2001-2002  Nokia Corporation + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> + *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org> + *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <syslog.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> +#include <bluetooth/l2cap.h> +#include <bluetooth/sdp.h> +#include <bluetooth/sdp_lib.h> + +#include <netinet/in.h> + +#define SDPINF(fmt, arg...) syslog(LOG_INFO, fmt "\n", ## arg) +#define SDPERR(fmt, arg...) syslog(LOG_ERR, "%s: " fmt "\n", __func__ , ## arg) + +#ifdef SDP_DEBUG +#define SDPDBG(fmt, arg...) syslog(LOG_DEBUG, "%s: " fmt "\n", __func__ , ## arg) +#else +#define SDPDBG(fmt...) +#endif + +#if __BYTE_ORDER == __BIG_ENDIAN +#define ntoh64(x) (x) +static inline void ntoh128(uint128_t *src, uint128_t *dst) +{ +	int i; +	for (i = 0; i < 16; i++) +		dst->data[i] = src->data[i]; +} +#else +static inline uint64_t ntoh64(uint64_t n) +{ +	uint64_t h; +	uint64_t tmp = ntohl(n & 0x00000000ffffffff); +	h = ntohl(n >> 32); +	h |= tmp << 32; +	return h; +} +static inline void ntoh128(uint128_t *src, uint128_t *dst) +{ +	int i; +	for (i = 0; i < 16; i++) +		dst->data[15 - i] = src->data[i]; +} +#endif + +#define hton64(x)     ntoh64(x) +#define hton128(x, y) ntoh128(x, y) + +#define BASE_UUID "00000000-0000-1000-8000-00805F9B34FB" + +static uint128_t bluetooth_base_uuid = { +	.data = {	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, +			0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB } +}; + +#define SDP_MAX_ATTR_LEN 65535 + +/* Message structure. */ +struct tupla { +	int index; +	char *str; +}; + +static struct tupla Protocol[] = { +	{ SDP_UUID,		"SDP"		}, +	{ UDP_UUID,		"UDP"		}, +	{ RFCOMM_UUID,		"RFCOMM"	}, +	{ TCP_UUID,		"TCP"		}, +	{ TCS_BIN_UUID,		"TCS-BIN"	}, +	{ TCS_AT_UUID,		"TCS-AT"	}, +	{ OBEX_UUID,		"OBEX"		}, +	{ IP_UUID,		"IP"		}, +	{ FTP_UUID,		"FTP"		}, +	{ HTTP_UUID,		"HTTP"		}, +	{ WSP_UUID,		"WSP"		}, +	{ BNEP_UUID,		"BNEP"		}, +	{ UPNP_UUID,		"UPNP"		}, +	{ HIDP_UUID,		"HIDP"		}, +	{ HCRP_CTRL_UUID,	"HCRP-Ctrl"	}, +	{ HCRP_DATA_UUID,	"HCRP-Data"	}, +	{ HCRP_NOTE_UUID,	"HCRP-Notify"	}, +	{ AVCTP_UUID,		"AVCTP"		}, +	{ AVDTP_UUID,		"AVDTP"		}, +	{ CMTP_UUID,		"CMTP"		}, +	{ UDI_UUID,		"UDI"		}, +	{ MCAP_CTRL_UUID,	"MCAP-Ctrl"	}, +	{ MCAP_DATA_UUID,	"MCAP-Data"	}, +	{ L2CAP_UUID,		"L2CAP"		}, +	{ 0 } +}; + +static struct tupla ServiceClass[] = { +	{ SDP_SERVER_SVCLASS_ID,		"SDP Server"			}, +	{ BROWSE_GRP_DESC_SVCLASS_ID,		"Browse Group Descriptor"	}, +	{ PUBLIC_BROWSE_GROUP,			"Public Browse Group"		}, +	{ SERIAL_PORT_SVCLASS_ID,		"Serial Port"			}, +	{ LAN_ACCESS_SVCLASS_ID,		"LAN Access Using PPP"		}, +	{ DIALUP_NET_SVCLASS_ID,		"Dialup Networking"		}, +	{ IRMC_SYNC_SVCLASS_ID,			"IrMC Sync"			}, +	{ OBEX_OBJPUSH_SVCLASS_ID,		"OBEX Object Push"		}, +	{ OBEX_FILETRANS_SVCLASS_ID,		"OBEX File Transfer"		}, +	{ IRMC_SYNC_CMD_SVCLASS_ID,		"IrMC Sync Command"		}, +	{ HEADSET_SVCLASS_ID,			"Headset"			}, +	{ CORDLESS_TELEPHONY_SVCLASS_ID,	"Cordless Telephony"		}, +	{ AUDIO_SOURCE_SVCLASS_ID,		"Audio Source"			}, +	{ AUDIO_SINK_SVCLASS_ID,		"Audio Sink"			}, +	{ AV_REMOTE_TARGET_SVCLASS_ID,		"AV Remote Target"		}, +	{ ADVANCED_AUDIO_SVCLASS_ID,		"Advanced Audio"		}, +	{ AV_REMOTE_SVCLASS_ID,			"AV Remote"			}, +	{ VIDEO_CONF_SVCLASS_ID,		"Video Conferencing"		}, +	{ INTERCOM_SVCLASS_ID,			"Intercom"			}, +	{ FAX_SVCLASS_ID,			"Fax"				}, +	{ HEADSET_AGW_SVCLASS_ID,		"Headset Audio Gateway"		}, +	{ WAP_SVCLASS_ID,			"WAP"				}, +	{ WAP_CLIENT_SVCLASS_ID,		"WAP Client"			}, +	{ PANU_SVCLASS_ID,			"PAN User"			}, +	{ NAP_SVCLASS_ID,			"Network Access Point"		}, +	{ GN_SVCLASS_ID,			"PAN Group Network"		}, +	{ DIRECT_PRINTING_SVCLASS_ID,		"Direct Printing"		}, +	{ REFERENCE_PRINTING_SVCLASS_ID,	"Reference Printing"		}, +	{ IMAGING_SVCLASS_ID,			"Imaging"			}, +	{ IMAGING_RESPONDER_SVCLASS_ID,		"Imaging Responder"		}, +	{ IMAGING_ARCHIVE_SVCLASS_ID,		"Imaging Automatic Archive"	}, +	{ IMAGING_REFOBJS_SVCLASS_ID,		"Imaging Referenced Objects"	}, +	{ HANDSFREE_SVCLASS_ID,			"Handsfree"			}, +	{ HANDSFREE_AGW_SVCLASS_ID,		"Handsfree Audio Gateway"	}, +	{ DIRECT_PRT_REFOBJS_SVCLASS_ID,	"Direct Printing Ref. Objects"	}, +	{ REFLECTED_UI_SVCLASS_ID,		"Reflected UI"			}, +	{ BASIC_PRINTING_SVCLASS_ID,		"Basic Printing"		}, +	{ PRINTING_STATUS_SVCLASS_ID,		"Printing Status"		}, +	{ HID_SVCLASS_ID,			"Human Interface Device"	}, +	{ HCR_SVCLASS_ID,			"Hardcopy Cable Replacement"	}, +	{ HCR_PRINT_SVCLASS_ID,			"HCR Print"			}, +	{ HCR_SCAN_SVCLASS_ID,			"HCR Scan"			}, +	{ CIP_SVCLASS_ID,			"Common ISDN Access"		}, +	{ VIDEO_CONF_GW_SVCLASS_ID,		"Video Conferencing Gateway"	}, +	{ UDI_MT_SVCLASS_ID,			"UDI MT"			}, +	{ UDI_TA_SVCLASS_ID,			"UDI TA"			}, +	{ AV_SVCLASS_ID,			"Audio/Video"			}, +	{ SAP_SVCLASS_ID,			"SIM Access"			}, +	{ PBAP_PCE_SVCLASS_ID,			"Phonebook Access - PCE"	}, +	{ PBAP_PSE_SVCLASS_ID,			"Phonebook Access - PSE"	}, +	{ PBAP_SVCLASS_ID,			"Phonebook Access"		}, +	{ PNP_INFO_SVCLASS_ID,			"PnP Information"		}, +	{ GENERIC_NETWORKING_SVCLASS_ID,	"Generic Networking"		}, +	{ GENERIC_FILETRANS_SVCLASS_ID,		"Generic File Transfer"		}, +	{ GENERIC_AUDIO_SVCLASS_ID,		"Generic Audio"			}, +	{ GENERIC_TELEPHONY_SVCLASS_ID,		"Generic Telephony"		}, +	{ UPNP_SVCLASS_ID,			"UPnP"				}, +	{ UPNP_IP_SVCLASS_ID,			"UPnP IP"			}, +	{ UPNP_PAN_SVCLASS_ID,			"UPnP PAN"			}, +	{ UPNP_LAP_SVCLASS_ID,			"UPnP LAP"			}, +	{ UPNP_L2CAP_SVCLASS_ID,		"UPnP L2CAP"			}, +	{ VIDEO_SOURCE_SVCLASS_ID,		"Video Source"			}, +	{ VIDEO_SINK_SVCLASS_ID,		"Video Sink"			}, +	{ VIDEO_DISTRIBUTION_SVCLASS_ID,	"Video Distribution"		}, +	{ MDP_SVCLASS_ID,			"MDP"				}, +	{ MDP_SOURCE_SVCLASS_ID,		"MDP Source"			}, +	{ MDP_SINK_SVCLASS_ID,			"MDP Sink"			}, +	{ APPLE_AGENT_SVCLASS_ID,		"Apple Agent"			}, +	{ 0 } +}; + +#define Profile ServiceClass + +static char *string_lookup(struct tupla *pt0, int index) +{ +	struct tupla *pt; + +	for (pt = pt0; pt->index; pt++) +		if (pt->index == index) +			return pt->str; + +	return ""; +} + +static char *string_lookup_uuid(struct tupla *pt0, const uuid_t* uuid) +{ +	uuid_t tmp_uuid; + +	memcpy(&tmp_uuid, uuid, sizeof(tmp_uuid)); + +	if (sdp_uuid128_to_uuid(&tmp_uuid)) { +		switch (tmp_uuid.type) { +		case SDP_UUID16: +			return string_lookup(pt0, tmp_uuid.value.uuid16); +		case SDP_UUID32: +			return string_lookup(pt0, tmp_uuid.value.uuid32); +		} +	} + +	return ""; +} + +/* + * Prints into a string the Protocol UUID + * coping a maximum of n characters. + */ +static int uuid2str(struct tupla *message, const uuid_t *uuid, char *str, size_t n)  +{ +	char *str2; + +	if (!uuid) { +		snprintf(str, n, "NULL"); +		return -2; +	} + +	switch (uuid->type) { +	case SDP_UUID16: +		str2 = string_lookup(message, uuid->value.uuid16); +		snprintf(str, n, str2); +		break; +	case SDP_UUID32: +		str2 = string_lookup(message, uuid->value.uuid32); +		snprintf(str, n, str2); +		break; +	case SDP_UUID128: +		str2 = string_lookup_uuid(message, uuid); +		snprintf(str, n, str2); +		break; +	default: +		snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type); +		return -1; +	} + +	return 0; +} + +int sdp_proto_uuid2strn(const uuid_t *uuid, char *str, size_t n) +{ +	return uuid2str(Protocol, uuid, str, n); +} + +int sdp_svclass_uuid2strn(const uuid_t *uuid, char *str, size_t n) +{ +	return uuid2str(ServiceClass, uuid, str, n); +} + +int sdp_profile_uuid2strn(const uuid_t *uuid, char *str, size_t n) +{ +	return uuid2str(Profile, uuid, str, n); +} + +/* + * convert the UUID to string, copying a maximum of n characters. + */ +int sdp_uuid2strn(const uuid_t *uuid, char *str, size_t n) +{ +	if (!uuid) { +		snprintf(str, n, "NULL"); +		return -2; +	} +	switch (uuid->type) { +	case SDP_UUID16: +		snprintf(str, n, "%.4x", uuid->value.uuid16); +		break; +	case SDP_UUID32: +		snprintf(str, n, "%.8x", uuid->value.uuid32); +		break; +	case SDP_UUID128:{ +		unsigned int   data0; +		unsigned short data1; +		unsigned short data2; +		unsigned short data3; +		unsigned int   data4; +		unsigned short data5; + +		memcpy(&data0, &uuid->value.uuid128.data[0], 4); +		memcpy(&data1, &uuid->value.uuid128.data[4], 2); +		memcpy(&data2, &uuid->value.uuid128.data[6], 2); +		memcpy(&data3, &uuid->value.uuid128.data[8], 2); +		memcpy(&data4, &uuid->value.uuid128.data[10], 4); +		memcpy(&data5, &uuid->value.uuid128.data[14], 2); + +		snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",  +				ntohl(data0), ntohs(data1),  +				ntohs(data2), ntohs(data3),  +				ntohl(data4), ntohs(data5)); +		} +		break; +	default: +		snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type); +		return -1;	// Enum type of UUID not set +	} +	return 0; +} + +#ifdef SDP_DEBUG +/* + * Function prints the UUID in hex as per defined syntax - + * + * 4bytes-2bytes-2bytes-2bytes-6bytes + * + * There is some ugly code, including hardcoding, but + * that is just the way it is converting 16 and 32 bit + * UUIDs to 128 bit as defined in the SDP doc + */ +void sdp_uuid_print(const uuid_t *uuid) +{ +	if (uuid == NULL) { +		SDPERR("Null passed to print UUID\n"); +		return; +	} +	if (uuid->type == SDP_UUID16) { +		SDPDBG("  uint16_t : 0x%.4x\n", uuid->value.uuid16); +	} else if (uuid->type == SDP_UUID32) { +		SDPDBG("  uint32_t : 0x%.8x\n", uuid->value.uuid32); +	} else if (uuid->type == SDP_UUID128) { +		unsigned int data0; +		unsigned short data1; +		unsigned short data2; +		unsigned short data3; +		unsigned int data4; +		unsigned short data5; + +		memcpy(&data0, &uuid->value.uuid128.data[0], 4); +		memcpy(&data1, &uuid->value.uuid128.data[4], 2); +		memcpy(&data2, &uuid->value.uuid128.data[6], 2); +		memcpy(&data3, &uuid->value.uuid128.data[8], 2); +		memcpy(&data4, &uuid->value.uuid128.data[10], 4); +		memcpy(&data5, &uuid->value.uuid128.data[14], 2); + +		SDPDBG("  uint128_t : 0x%.8x-", ntohl(data0)); +		SDPDBG("%.4x-", ntohs(data1)); +		SDPDBG("%.4x-", ntohs(data2)); +		SDPDBG("%.4x-", ntohs(data3)); +		SDPDBG("%.8x", ntohl(data4)); +		SDPDBG("%.4x\n", ntohs(data5)); +	} else +		SDPERR("Enum type of UUID not set\n"); +} +#endif + +sdp_data_t *sdp_data_alloc_with_length(uint8_t dtd, const void *value, uint32_t length) +{ +	sdp_data_t *seq; +	sdp_data_t *d = malloc(sizeof(sdp_data_t)); + +	if (!d) +		return NULL; + +	memset(d, 0, sizeof(sdp_data_t)); +	d->dtd = dtd; +	d->unitSize = sizeof(uint8_t); + +	switch (dtd) { +	case SDP_DATA_NIL: +		break; +	case SDP_UINT8: +		d->val.uint8 = *(uint8_t *) value; +		d->unitSize += sizeof(uint8_t); +		break; +	case SDP_INT8: +	case SDP_BOOL: +		d->val.int8 = *(int8_t *) value; +		d->unitSize += sizeof(int8_t); +		break; +	case SDP_UINT16: +		d->val.uint16 = bt_get_unaligned((uint16_t *) value); +		d->unitSize += sizeof(uint16_t); +		break; +	case SDP_INT16: +		d->val.int16 = bt_get_unaligned((int16_t *) value); +		d->unitSize += sizeof(int16_t); +		break; +	case SDP_UINT32: +		d->val.uint32 = bt_get_unaligned((uint32_t *) value); +		d->unitSize += sizeof(uint32_t); +		break; +	case SDP_INT32: +		d->val.int32 = bt_get_unaligned((int32_t *) value); +		d->unitSize += sizeof(int32_t); +		break; +	case SDP_INT64: +		d->val.int64 = bt_get_unaligned((int64_t *) value); +		d->unitSize += sizeof(int64_t); +		break; +	case SDP_UINT64: +		d->val.uint64 = bt_get_unaligned((uint64_t *) value); +		d->unitSize += sizeof(uint64_t); +		break; +	case SDP_UINT128: +		memcpy(&d->val.uint128.data, value, sizeof(uint128_t)); +		d->unitSize += sizeof(uint128_t); +		break; +	case SDP_INT128: +		memcpy(&d->val.int128.data, value, sizeof(uint128_t)); +		d->unitSize += sizeof(uint128_t); +		break; +	case SDP_UUID16: +		sdp_uuid16_create(&d->val.uuid, bt_get_unaligned((uint16_t *) value)); +		d->unitSize += sizeof(uint16_t); +		break; +	case SDP_UUID32: +		sdp_uuid32_create(&d->val.uuid, bt_get_unaligned((uint32_t *) value)); +		d->unitSize += sizeof(uint32_t); +		break; +	case SDP_UUID128: +		sdp_uuid128_create(&d->val.uuid, value); +		d->unitSize += sizeof(uint128_t); +		break; +	case SDP_URL_STR8: +	case SDP_URL_STR16: +	case SDP_TEXT_STR8: +	case SDP_TEXT_STR16: +		if (!value) { +			free(d); +			return NULL; +		} + +		d->unitSize += length; +		if (length <= USHRT_MAX) { +			d->val.str = malloc(length); +			if (!d->val.str) { +				free(d); +				return NULL; +			} + +			memcpy(d->val.str, value, length); +		} else { +			SDPERR("Strings of size > USHRT_MAX not supported\n"); +			free(d); +			d = NULL; +		} +		break; +	case SDP_URL_STR32: +	case SDP_TEXT_STR32: +		SDPERR("Strings of size > USHRT_MAX not supported\n"); +		break; +	case SDP_ALT8: +	case SDP_ALT16: +	case SDP_ALT32: +	case SDP_SEQ8: +	case SDP_SEQ16: +	case SDP_SEQ32: +		if (dtd == SDP_ALT8 || dtd == SDP_SEQ8) +			d->unitSize += sizeof(uint8_t); +		else if (dtd == SDP_ALT16 || dtd == SDP_SEQ16) +			d->unitSize += sizeof(uint16_t); +		else if (dtd == SDP_ALT32 || dtd == SDP_SEQ32) +			d->unitSize += sizeof(uint32_t); +		seq = (sdp_data_t *)value; +		d->val.dataseq = seq; +		for (; seq; seq = seq->next) +			d->unitSize += seq->unitSize; +		break; +	default: +		free(d); +		d = NULL; +	} + +	return d; +} + +sdp_data_t *sdp_data_alloc(uint8_t dtd, const void *value) +{ +	uint32_t length; + +	switch (dtd) { +	case SDP_URL_STR8: +	case SDP_URL_STR16: +	case SDP_TEXT_STR8: +	case SDP_TEXT_STR16: +		if (!value) +			return NULL; + +		length = strlen((char *) value); +		break; +	default: +		length = 0; +		break; +	} + +	return sdp_data_alloc_with_length(dtd, value, length); +} + +sdp_data_t *sdp_seq_append(sdp_data_t *seq, sdp_data_t *d) +{ +	if (seq) { +		sdp_data_t *p; +		for (p = seq; p->next; p = p->next); +		p->next = d; +	} else +		seq = d; +	d->next = NULL; +	return seq; +} + +sdp_data_t *sdp_seq_alloc_with_length(void **dtds, void **values, int *length, int len) +{ +	sdp_data_t *curr = NULL, *seq = NULL; +	int i; + +	for (i = 0; i < len; i++) { +		sdp_data_t *data; +		int8_t dtd = *(uint8_t *) dtds[i]; + +		if (dtd >= SDP_SEQ8 && dtd <= SDP_ALT32) +			data = (sdp_data_t *) values[i]; +		else +			data = sdp_data_alloc_with_length(dtd, values[i], length[i]); + +		if (!data) +			return NULL; + +		if (curr) +			curr->next = data; +		else +			seq = data; + +		curr = data; +	} + +	return sdp_data_alloc_with_length(SDP_SEQ8, seq, length[i]); +} + +sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len) +{ +	sdp_data_t *curr = NULL, *seq = NULL; +	int i; + +	for (i = 0; i < len; i++) { +		sdp_data_t *data; +		uint8_t dtd = *(uint8_t *) dtds[i]; + +		if (dtd >= SDP_SEQ8 && dtd <= SDP_ALT32) +			data = (sdp_data_t *) values[i]; +		else +			data = sdp_data_alloc(dtd, values[i]); + +		if (!data) +			return NULL; + +		if (curr) +			curr->next = data; +		else +			seq = data; + +		curr = data; +	} + +	return sdp_data_alloc(SDP_SEQ8, seq); +} + +static void extract_svclass_uuid(sdp_data_t *data, uuid_t *uuid) +{ +	sdp_data_t *d; + +	if (!data || data->dtd < SDP_SEQ8 || data->dtd > SDP_SEQ32) +		return; + +	d = data->val.dataseq; +	if (!d) +		return; + +	if (d->dtd < SDP_UUID16 || d->dtd > SDP_UUID128) +		return; + +	*uuid = d->val.uuid; +} + +int sdp_attr_add(sdp_record_t *rec, uint16_t attr, sdp_data_t *d) +{ +	sdp_data_t *p = sdp_data_get(rec, attr); + +	if (p) +		return -1; + +	d->attrId = attr; +	rec->attrlist = sdp_list_insert_sorted(rec->attrlist, d, sdp_attrid_comp_func); + +	if (attr == SDP_ATTR_SVCLASS_ID_LIST) +		extract_svclass_uuid(d, &rec->svclass); + +	return 0; +} + +void sdp_attr_remove(sdp_record_t *rec, uint16_t attr) +{ +	sdp_data_t *d = sdp_data_get(rec, attr); + +	if (d) +		rec->attrlist = sdp_list_remove(rec->attrlist, d); + +	if (attr == SDP_ATTR_SVCLASS_ID_LIST) +		memset(&rec->svclass, 0, sizeof(rec->svclass)); +} + +void sdp_set_seq_len(uint8_t *ptr, uint32_t length) +{ +	uint8_t dtd = *(uint8_t *) ptr++; + +	switch (dtd) { +	case SDP_SEQ8: +	case SDP_ALT8: +	case SDP_TEXT_STR8: +	case SDP_URL_STR8: +		*(uint8_t *)ptr = (uint8_t) length; +		break; +	case SDP_SEQ16: +	case SDP_ALT16: +	case SDP_TEXT_STR16: +	case SDP_URL_STR16: +		bt_put_unaligned(htons(length), (uint16_t *) ptr); +		break; +	case SDP_SEQ32: +	case SDP_ALT32: +	case SDP_TEXT_STR32: +	case SDP_URL_STR32: +		bt_put_unaligned(htonl(length), (uint32_t *) ptr); +		break; +	} +} + +int sdp_set_data_type(sdp_buf_t *buf, uint8_t dtd) +{ +	int orig = buf->data_size; +	uint8_t *p = buf->data + buf->data_size; + +	*p++ = dtd; +	buf->data_size += sizeof(uint8_t); + +	switch (dtd) { +	case SDP_SEQ8: +	case SDP_TEXT_STR8: +	case SDP_URL_STR8: +	case SDP_ALT8: +		buf->data_size += sizeof(uint8_t); +		break; +	case SDP_SEQ16: +	case SDP_TEXT_STR16: +	case SDP_URL_STR16: +	case SDP_ALT16: +		buf->data_size += sizeof(uint16_t); +		break; +	case SDP_SEQ32: +	case SDP_TEXT_STR32: +	case SDP_URL_STR32: +	case SDP_ALT32: +		buf->data_size += sizeof(uint32_t); +		break; +	} + +	return buf->data_size - orig; +} + +void sdp_set_attrid(sdp_buf_t *buf, uint16_t attr) +{ +	uint8_t *p = buf->data; + +	// data type for attr +	*p++ = SDP_UINT16; +	buf->data_size = sizeof(uint8_t); +	bt_put_unaligned(htons(attr), (uint16_t *) p); +	p += sizeof(uint16_t); +	buf->data_size += sizeof(uint16_t); +} + +static int get_data_size(sdp_buf_t *buf, sdp_data_t *sdpdata) +{ +	sdp_data_t *d; +	int n = 0; + +	for (d = sdpdata->val.dataseq; d; d = d->next) +		n += sdp_gen_pdu(buf, d); + +	return n; +} + +int sdp_gen_pdu(sdp_buf_t *buf, sdp_data_t *d) +{ +	uint32_t pdu_size = 0, data_size = 0; +	unsigned char *src = NULL, is_seq = 0, is_alt = 0; +	uint8_t dtd = d->dtd; +	uint16_t u16; +	uint32_t u32; +	uint64_t u64; +	uint128_t u128; +	uint8_t *seqp = buf->data + buf->data_size; + +	pdu_size = sdp_set_data_type(buf, dtd); + +	switch (dtd) { +	case SDP_DATA_NIL: +		break; +	case SDP_UINT8: +		src = &d->val.uint8; +		data_size = sizeof(uint8_t); +		break; +	case SDP_UINT16: +		u16 = htons(d->val.uint16); +		src = (unsigned char *) &u16; +		data_size = sizeof(uint16_t); +		break; +	case SDP_UINT32: +		u32 = htonl(d->val.uint32); +		src = (unsigned char *) &u32; +		data_size = sizeof(uint32_t); +		break; +	case SDP_UINT64: +		u64 = hton64(d->val.uint64); +		src = (unsigned char *) &u64; +		data_size = sizeof(uint64_t); +		break; +	case SDP_UINT128: +		hton128(&d->val.uint128, &u128); +		src = (unsigned char *) &u128; +		data_size = sizeof(uint128_t); +		break; +	case SDP_INT8: +	case SDP_BOOL: +		src = (unsigned char *) &d->val.int8; +		data_size = sizeof(int8_t); +		break; +	case SDP_INT16: +		u16 = htons(d->val.int16); +		src = (unsigned char *) &u16; +		data_size = sizeof(int16_t); +		break; +	case SDP_INT32: +		u32 = htonl(d->val.int32); +		src = (unsigned char *) &u32; +		data_size = sizeof(int32_t); +		break; +	case SDP_INT64: +		u64 = hton64(d->val.int64); +		src = (unsigned char *) &u64; +		data_size = sizeof(int64_t); +		break; +	case SDP_INT128: +		hton128(&d->val.int128, &u128); +		src = (unsigned char *) &u128; +		data_size = sizeof(uint128_t); +		break; +	case SDP_TEXT_STR8: +	case SDP_TEXT_STR16: +	case SDP_TEXT_STR32: +	case SDP_URL_STR8: +	case SDP_URL_STR16: +	case SDP_URL_STR32: +		src = (unsigned char *) d->val.str; +		data_size = d->unitSize - sizeof(uint8_t); +		sdp_set_seq_len(seqp, data_size); +		break; +	case SDP_SEQ8: +	case SDP_SEQ16: +	case SDP_SEQ32: +		is_seq = 1; +		data_size = get_data_size(buf, d); +		sdp_set_seq_len(seqp, data_size); +		break; +	case SDP_ALT8: +	case SDP_ALT16: +	case SDP_ALT32: +		is_alt = 1; +		data_size = get_data_size(buf, d); +		sdp_set_seq_len(seqp, data_size); +		break; +	case SDP_UUID16: +		u16 = htons(d->val.uuid.value.uuid16); +		src = (unsigned char *) &u16; +		data_size = sizeof(uint16_t); +		break; +	case SDP_UUID32: +		u32 = htonl(d->val.uuid.value.uuid32); +		src = (unsigned char *) &u32; +		data_size = sizeof(uint32_t); +		break; +	case SDP_UUID128: +		src = (unsigned char *) &d->val.uuid.value.uuid128; +		data_size = sizeof(uint128_t); +		break; +	default: +		break; +	} + +	if (!is_seq && !is_alt) { +		if (src && buf) { +			memcpy(buf->data + buf->data_size, src, data_size); +			buf->data_size += data_size; +		} else if (dtd != SDP_DATA_NIL) +			SDPDBG("Gen PDU : Cant copy from NULL source or dest\n"); +	} + +	pdu_size += data_size; + +	return pdu_size; +} + +static void sdp_attr_pdu(void *value, void *udata) +{ +	sdp_append_to_pdu((sdp_buf_t *)udata, (sdp_data_t *)value); +} + +int sdp_gen_record_pdu(const sdp_record_t *rec, sdp_buf_t *buf) +{ +	buf->data = malloc(SDP_PDU_CHUNK_SIZE); +	if (!buf->data) +		return -ENOMEM; + +	buf->buf_size = SDP_PDU_CHUNK_SIZE; +	buf->data_size = 0; +	memset(buf->data, 0, buf->buf_size); +	sdp_list_foreach(rec->attrlist, sdp_attr_pdu, buf); + +	return 0; +} + +void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *d) +{ +	sdp_data_t *p = sdp_data_get(rec, attr); + +	if (p) { +		rec->attrlist = sdp_list_remove(rec->attrlist, p); +		sdp_data_free(p); +	} + +	d->attrId = attr; +	rec->attrlist = sdp_list_insert_sorted(rec->attrlist, d, sdp_attrid_comp_func); + +	if (attr == SDP_ATTR_SVCLASS_ID_LIST) +		extract_svclass_uuid(d, &rec->svclass); +} + +int sdp_attrid_comp_func(const void *key1, const void *key2) +{ +	const sdp_data_t *d1 = (const sdp_data_t *)key1; +	const sdp_data_t *d2 = (const sdp_data_t *)key2; + +	if (d1 && d2) +		return d1->attrId - d2->attrId; +	return 0; +} + +static void data_seq_free(sdp_data_t *seq) +{ +	sdp_data_t *d = seq->val.dataseq; + +	while (d) { +		sdp_data_t *next = d->next; +		sdp_data_free(d); +		d = next; +	} +} + +void sdp_data_free(sdp_data_t *d) +{ +	switch (d->dtd) { +	case SDP_SEQ8: +	case SDP_SEQ16: +	case SDP_SEQ32: +		data_seq_free(d); +		break; +	case SDP_URL_STR8: +	case SDP_URL_STR16: +	case SDP_URL_STR32: +	case SDP_TEXT_STR8: +	case SDP_TEXT_STR16: +	case SDP_TEXT_STR32: +		free(d->val.str); +		break; +	} +	free(d); +} + +int sdp_uuid_extract_safe(const uint8_t *p, int bufsize, uuid_t *uuid, int *scanned) +{ +	uint8_t type; + +	if (bufsize < sizeof(uint8_t)) { +		SDPERR("Unexpected end of packet"); +		return -1; +	} + +	type = *(const uint8_t *) p; + +	if (!SDP_IS_UUID(type)) { +		SDPERR("Unknown data type : %d expecting a svc UUID\n", type); +		return -1; +	} +	p += sizeof(uint8_t); +	*scanned += sizeof(uint8_t); +	bufsize -= sizeof(uint8_t); +	if (type == SDP_UUID16) { +		if (bufsize < sizeof(uint16_t)) { +			SDPERR("Not enough room for 16-bit UUID"); +			return -1; +		} +		sdp_uuid16_create(uuid, ntohs(bt_get_unaligned((uint16_t *) p))); +		*scanned += sizeof(uint16_t); +		p += sizeof(uint16_t); +	} else if (type == SDP_UUID32) { +		if (bufsize < sizeof(uint32_t)) { +			SDPERR("Not enough room for 32-bit UUID"); +			return -1; +		} +		sdp_uuid32_create(uuid, ntohl(bt_get_unaligned((uint32_t *) p))); +		*scanned += sizeof(uint32_t); +		p += sizeof(uint32_t); +	} else { +		if (bufsize < sizeof(uint128_t)) { +			SDPERR("Not enough room for 128-bit UUID"); +			return -1; +		} +		sdp_uuid128_create(uuid, p); +		*scanned += sizeof(uint128_t); +		p += sizeof(uint128_t); +	} +	return 0; +} + +int sdp_uuid_extract(const uint8_t *p, uuid_t *uuid, int *scanned) +{ +	/* Assume p points to a buffer of size at least SDP_MAX_ATTR_LEN, +	   because we don't have any better information */ +	return sdp_uuid_extract_safe(p, SDP_MAX_ATTR_LEN, uuid, scanned); +} + +static sdp_data_t *extract_int(const void *p, int bufsize, int *len) +{ +	sdp_data_t *d; + +	if (bufsize < sizeof(uint8_t)) { +		SDPERR("Unexpected end of packet"); +		return NULL; +	} + +	d = malloc(sizeof(sdp_data_t)); + +	SDPDBG("Extracting integer\n"); +	memset(d, 0, sizeof(sdp_data_t)); +	d->dtd = *(uint8_t *) p; +	p += sizeof(uint8_t); +	*len += sizeof(uint8_t); +	bufsize -= sizeof(uint8_t); + +	switch (d->dtd) { +	case SDP_DATA_NIL: +		break; +	case SDP_BOOL: +	case SDP_INT8: +	case SDP_UINT8: +		if (bufsize < sizeof(uint8_t)) { +			SDPERR("Unexpected end of packet"); +			free(d); +			return NULL; +		} +		*len += sizeof(uint8_t); +		d->val.uint8 = *(uint8_t *) p; +		break; +	case SDP_INT16: +	case SDP_UINT16: +		if (bufsize < sizeof(uint16_t)) { +			SDPERR("Unexpected end of packet"); +			free(d); +			return NULL; +		} +		*len += sizeof(uint16_t); +		d->val.uint16 = ntohs(bt_get_unaligned((uint16_t *) p)); +		break; +	case SDP_INT32: +	case SDP_UINT32: +		if (bufsize < sizeof(uint32_t)) { +			SDPERR("Unexpected end of packet"); +			free(d); +			return NULL; +		} +		*len += sizeof(uint32_t); +		d->val.uint32 = ntohl(bt_get_unaligned((uint32_t *) p)); +		break; +	case SDP_INT64: +	case SDP_UINT64: +		if (bufsize < sizeof(uint64_t)) { +			SDPERR("Unexpected end of packet"); +			free(d); +			return NULL; +		} +		*len += sizeof(uint64_t); +		d->val.uint64 = ntoh64(bt_get_unaligned((uint64_t *) p)); +		break; +	case SDP_INT128: +	case SDP_UINT128: +		if (bufsize < sizeof(uint128_t)) { +			SDPERR("Unexpected end of packet"); +			free(d); +			return NULL; +		} +		*len += sizeof(uint128_t); +		ntoh128((uint128_t *) p, &d->val.uint128); +		break; +	default: +		free(d); +		d = NULL; +	} +	return d; +} + +static sdp_data_t *extract_uuid(const uint8_t *p, int bufsize, int *len, sdp_record_t *rec) +{ +	sdp_data_t *d = malloc(sizeof(sdp_data_t)); + +	SDPDBG("Extracting UUID"); +	memset(d, 0, sizeof(sdp_data_t)); +	if (sdp_uuid_extract_safe(p, bufsize, &d->val.uuid, len) < 0) { +		free(d); +		return NULL; +	} +	d->dtd = *(uint8_t *) p; +	if (rec) +		sdp_pattern_add_uuid(rec, &d->val.uuid); +	return d; +} + +/* + * Extract strings from the PDU (could be service description and similar info)  + */ +static sdp_data_t *extract_str(const void *p, int bufsize, int *len) +{ +	char *s; +	int n; +	sdp_data_t *d; + +	if (bufsize < sizeof(uint8_t)) { +		SDPERR("Unexpected end of packet"); +		return NULL; +	} + +	d = malloc(sizeof(sdp_data_t)); + +	memset(d, 0, sizeof(sdp_data_t)); +	d->dtd = *(uint8_t *) p; +	p += sizeof(uint8_t); +	*len += sizeof(uint8_t); +	bufsize -= sizeof(uint8_t); + +	switch (d->dtd) { +	case SDP_TEXT_STR8: +	case SDP_URL_STR8: +		if (bufsize < sizeof(uint8_t)) { +			SDPERR("Unexpected end of packet"); +			free(d); +			return NULL; +		} +		n = *(uint8_t *) p; +		p += sizeof(uint8_t); +		*len += sizeof(uint8_t); +		bufsize -= sizeof(uint8_t); +		break; +	case SDP_TEXT_STR16: +	case SDP_URL_STR16: +		if (bufsize < sizeof(uint16_t)) { +			SDPERR("Unexpected end of packet"); +			free(d); +			return NULL; +		} +		n = ntohs(bt_get_unaligned((uint16_t *) p)); +		p += sizeof(uint16_t); +		*len += sizeof(uint16_t) + n; +		bufsize -= sizeof(uint16_t); +		break; +	default: +		SDPERR("Sizeof text string > UINT16_MAX\n"); +		free(d); +		return 0; +	} + +	if (bufsize < n) { +		SDPERR("String too long to fit in packet"); +		free(d); +		return NULL; +	} + +	s = malloc(n + 1); +	if (!s) { +		SDPERR("Not enough memory for incoming string"); +		free(d); +		return NULL; +	} +	memset(s, 0, n + 1); +	memcpy(s, p, n); + +	*len += n; + +	SDPDBG("Len : %d\n", n); +	SDPDBG("Str : %s\n", s); + +	d->val.str = s; +	d->unitSize = n + sizeof(uint8_t); +	return d; +} + +/* + * Extract the sequence type and its length, and return offset into buf + * or 0 on failure. + */ +int sdp_extract_seqtype_safe(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size) +{ +	uint8_t dtd; +	int scanned = sizeof(uint8_t); + +	if (bufsize < sizeof(uint8_t)) { +		SDPERR("Unexpected end of packet"); +		return 0; +	} + +	dtd = *(uint8_t *) buf; +	buf += sizeof(uint8_t); +	bufsize -= sizeof(uint8_t); +	*dtdp = dtd; +	switch (dtd) { +	case SDP_SEQ8: +	case SDP_ALT8: +		if (bufsize < sizeof(uint8_t)) { +			SDPERR("Unexpected end of packet"); +			return 0; +		} +		*size = *(uint8_t *) buf; +		scanned += sizeof(uint8_t); +		break; +	case SDP_SEQ16: +	case SDP_ALT16: +		if (bufsize < sizeof(uint16_t)) { +			SDPERR("Unexpected end of packet"); +			return 0; +		} +		*size = ntohs(bt_get_unaligned((uint16_t *) buf)); +		scanned += sizeof(uint16_t); +		break; +	case SDP_SEQ32: +	case SDP_ALT32: +		if (bufsize < sizeof(uint32_t)) { +			SDPERR("Unexpected end of packet"); +			return 0; +		} +		*size = ntohl(bt_get_unaligned((uint32_t *) buf)); +		scanned += sizeof(uint32_t); +		break; +	default: +		SDPERR("Unknown sequence type, aborting\n"); +		return 0; +	} +	return scanned; +} + +int sdp_extract_seqtype(const uint8_t *buf, uint8_t *dtdp, int *size) +{ +	/* Assume buf points to a buffer of size at least SDP_MAX_ATTR_LEN, +	   because we don't have any better information */ +	return sdp_extract_seqtype_safe(buf, SDP_MAX_ATTR_LEN, dtdp, size); +} + +static sdp_data_t *extract_seq(const void *p, int bufsize, int *len, sdp_record_t *rec) +{ +	int seqlen, n = 0; +	sdp_data_t *curr, *prev; +	sdp_data_t *d = malloc(sizeof(sdp_data_t)); + +	SDPDBG("Extracting SEQ"); +	memset(d, 0, sizeof(sdp_data_t)); +	*len = sdp_extract_seqtype_safe(p, bufsize, &d->dtd, &seqlen); +	SDPDBG("Sequence Type : 0x%x length : 0x%x\n", d->dtd, seqlen); + +	if (*len == 0) +		return d; + +	if (*len > bufsize) { +		SDPERR("Packet not big enough to hold sequence."); +		free(d); +		return NULL; +	} + +	p += *len; +	bufsize -= *len; +	curr = prev = NULL; +	while (n < seqlen) { +		int attrlen = 0; +		curr = sdp_extract_attr_safe(p, bufsize, &attrlen, rec); +		if (curr == NULL) +			break; + +		if (prev) +			prev->next = curr; +		else +			d->val.dataseq = curr; +		prev = curr; +		p += attrlen; +		n += attrlen; +		bufsize -= attrlen; + +		SDPDBG("Extracted: %d SequenceLength: %d", n, seqlen); +	} + +	*len += n; +	return d; +} + +sdp_data_t *sdp_extract_attr_safe(const uint8_t *p, int bufsize, int *size, sdp_record_t *rec) +{ +	sdp_data_t *elem; +	int n = 0; +	uint8_t dtd; + +	if (bufsize < sizeof(uint8_t)) { +		SDPERR("Unexpected end of packet"); +		return NULL; +	} + +	dtd = *(const uint8_t *)p; + +	SDPDBG("extract_attr: dtd=0x%x", dtd); +	switch (dtd) { +	case SDP_DATA_NIL: +	case SDP_BOOL: +	case SDP_UINT8: +	case SDP_UINT16: +	case SDP_UINT32: +	case SDP_UINT64: +	case SDP_UINT128: +	case SDP_INT8: +	case SDP_INT16: +	case SDP_INT32: +	case SDP_INT64: +	case SDP_INT128: +		elem = extract_int(p, bufsize, &n); +		break; +	case SDP_UUID16: +	case SDP_UUID32: +	case SDP_UUID128: +		elem = extract_uuid(p, bufsize, &n, rec); +		break; +	case SDP_TEXT_STR8: +	case SDP_TEXT_STR16: +	case SDP_TEXT_STR32: +	case SDP_URL_STR8: +	case SDP_URL_STR16: +	case SDP_URL_STR32: +		elem = extract_str(p, bufsize, &n); +		break; +	case SDP_SEQ8: +	case SDP_SEQ16: +	case SDP_SEQ32: +	case SDP_ALT8: +	case SDP_ALT16: +	case SDP_ALT32: +		elem = extract_seq(p, bufsize, &n, rec); +		break; +	default: +		SDPERR("Unknown data descriptor : 0x%x terminating\n", dtd); +		return NULL; +	} +	*size += n; +	return elem; +} + +sdp_data_t *sdp_extract_attr(const uint8_t *p, int *size, sdp_record_t *rec) +{ +	/* Assume p points to a buffer of size at least SDP_MAX_ATTR_LEN, +	   because we don't have any better information */ +	return sdp_extract_attr_safe(p, SDP_MAX_ATTR_LEN, size, rec); +} + +#ifdef SDP_DEBUG +static void attr_print_func(void *value, void *userData) +{ +	sdp_data_t *d = (sdp_data_t *)value; + +	SDPDBG("=====================================\n"); +	SDPDBG("ATTRIBUTE IDENTIFIER : 0x%x\n",  d->attrId); +	SDPDBG("ATTRIBUTE VALUE PTR : 0x%x\n", (uint32_t)value); +	if (d) +		sdp_data_print(d); +	else +		SDPDBG("NULL value\n"); +	SDPDBG("=====================================\n"); +} + +void sdp_print_service_attr(sdp_list_t *svcAttrList) +{ +	SDPDBG("Printing service attr list %p\n", svcAttrList); +	sdp_list_foreach(svcAttrList, attr_print_func, NULL); +	SDPDBG("Printed service attr list %p\n", svcAttrList); +} +#endif + +sdp_record_t *sdp_extract_pdu_safe(const uint8_t *buf, int bufsize, int *scanned) +{ +	int extracted = 0, seqlen = 0; +	uint8_t dtd; +	uint16_t attr; +	sdp_record_t *rec = sdp_record_alloc(); +	const uint8_t *p = buf; + +	*scanned = sdp_extract_seqtype_safe(buf, bufsize, &dtd, &seqlen); +	p += *scanned; +	bufsize -= *scanned; +	rec->attrlist = NULL; + +	while (extracted < seqlen && bufsize > 0) { +		int n = sizeof(uint8_t), attrlen = 0; +		sdp_data_t *data = NULL; + +		SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d", +							seqlen, extracted); + +		if (bufsize < n + sizeof(uint16_t)) { +			SDPERR("Unexpected end of packet"); +			break; +		} + +		dtd = *(uint8_t *) p; +		attr = ntohs(bt_get_unaligned((uint16_t *) (p + n))); +		n += sizeof(uint16_t); + +		SDPDBG("DTD of attrId : %d Attr id : 0x%x \n", dtd, attr); + +		data = sdp_extract_attr_safe(p + n, bufsize - n, &attrlen, rec); + +		SDPDBG("Attr id : 0x%x attrValueLength : %d\n", attr, attrlen); + +		n += attrlen; +		if (data == NULL) { +			SDPDBG("Terminating extraction of attributes"); +			break; +		} + +		if (attr == SDP_ATTR_RECORD_HANDLE) +			rec->handle = data->val.uint32; + +		if (attr == SDP_ATTR_SVCLASS_ID_LIST) +			extract_svclass_uuid(data, &rec->svclass); + +		extracted += n; +		p += n; +		bufsize -= n; +		sdp_attr_replace(rec, attr, data); + +		SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d", +							seqlen, extracted); +	} +#ifdef SDP_DEBUG +	SDPDBG("Successful extracting of Svc Rec attributes\n"); +	sdp_print_service_attr(rec->attrlist); +#endif +	*scanned += seqlen; +	return rec; +} + +sdp_record_t *sdp_extract_pdu(const uint8_t *buf, int *scanned) +{ +	/* Assume buf points to a buffer of size at least SDP_MAX_ATTR_LEN, +	   because we don't have any better information */ +	return sdp_extract_pdu_safe(buf, SDP_MAX_ATTR_LEN, scanned); +} + +#ifdef SDP_DEBUG +static void print_dataseq(sdp_data_t *p) +{ +	sdp_data_t *d; + +	for (d = p; d; d = d->next) +		sdp_data_print(d); +} +#endif + +void sdp_record_print(const sdp_record_t *rec) +{ +	sdp_data_t *d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY); +	if (d) +		printf("Service Name: %.*s\n", d->unitSize, d->val.str); +	d = sdp_data_get(rec, SDP_ATTR_SVCDESC_PRIMARY); +	if (d) +		printf("Service Description: %.*s\n", d->unitSize, d->val.str); +	d = sdp_data_get(rec, SDP_ATTR_PROVNAME_PRIMARY); +	if (d) +		printf("Service Provider: %.*s\n", d->unitSize, d->val.str); +} + +#ifdef SDP_DEBUG +void sdp_data_print(sdp_data_t *d) +{ +	switch (d->dtd) { +	case SDP_DATA_NIL: +		SDPDBG("NIL\n"); +		break; +	case SDP_BOOL: +	case SDP_UINT8: +	case SDP_UINT16: +	case SDP_UINT32: +	case SDP_UINT64: +	case SDP_UINT128: +	case SDP_INT8: +	case SDP_INT16: +	case SDP_INT32: +	case SDP_INT64: +	case SDP_INT128: +		SDPDBG("Integer : 0x%x\n", d->val.uint32); +		break; +	case SDP_UUID16: +	case SDP_UUID32: +	case SDP_UUID128: +		SDPDBG("UUID\n"); +		sdp_uuid_print(&d->val.uuid); +		break; +	case SDP_TEXT_STR8: +	case SDP_TEXT_STR16: +	case SDP_TEXT_STR32: +		SDPDBG("Text : %s\n", d->val.str); +		break; +	case SDP_URL_STR8: +	case SDP_URL_STR16: +	case SDP_URL_STR32: +		SDPDBG("URL : %s\n", d->val.str); +		break; +	case SDP_SEQ8: +	case SDP_SEQ16: +	case SDP_SEQ32: +		print_dataseq(d->val.dataseq); +		break; +	case SDP_ALT8: +	case SDP_ALT16: +	case SDP_ALT32: +		SDPDBG("Data Sequence Alternates\n"); +		print_dataseq(d->val.dataseq); +		break; +	} +} +#endif + +sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attrId) +{ +	if (rec->attrlist) { +		sdp_data_t sdpTemplate; +		sdp_list_t *p; + +		sdpTemplate.attrId = attrId; +		p = sdp_list_find(rec->attrlist, &sdpTemplate, sdp_attrid_comp_func); +		if (p) +			return (sdp_data_t *)p->data; +	} +	return NULL; +} + +int sdp_send_req(sdp_session_t *session, uint8_t *buf, uint32_t size) +{ +	uint32_t sent = 0; + +	while (sent < size) { +		int n = send(session->sock, buf + sent, size - sent, 0); +		if (n < 0) +			return -1; +		sent += n; +	} +	return 0; +} + +int sdp_read_rsp(sdp_session_t *session, uint8_t *buf, uint32_t size) +{ +	fd_set readFds; +	struct timeval timeout = { SDP_RESPONSE_TIMEOUT, 0 }; + +	FD_ZERO(&readFds); +	FD_SET(session->sock, &readFds); +	SDPDBG("Waiting for response\n"); +	if (select(session->sock + 1, &readFds, NULL, NULL, &timeout) == 0) { +		SDPERR("Client timed out\n"); +		errno = ETIMEDOUT; +		return -1; +	} +	return recv(session->sock, buf, size, 0); +} + +/* + * generic send request, wait for response method. + */ +int sdp_send_req_w4_rsp(sdp_session_t *session, uint8_t *reqbuf, uint8_t *rspbuf, uint32_t reqsize, uint32_t *rspsize) +{ +	int n; +	sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)reqbuf; +	sdp_pdu_hdr_t *rsphdr = (sdp_pdu_hdr_t *)rspbuf; + +	SDPDBG(""); +	if (0 > sdp_send_req(session, reqbuf, reqsize)) { +		SDPERR("Error sending data:%s", strerror(errno)); +		return -1; +	} +	n = sdp_read_rsp(session, rspbuf, SDP_RSP_BUFFER_SIZE); +	if (0 > n) +		return -1; +	SDPDBG("Read : %d\n", n); +	if (n == 0 || reqhdr->tid != rsphdr->tid) { +		errno = EPROTO; +		return -1; +	} +	*rspsize = n; +	return 0; +} + +/* + * singly-linked lists (after openobex implementation) + */ +sdp_list_t *sdp_list_append(sdp_list_t *p, void *d) +{ +	sdp_list_t *q, *n = malloc(sizeof(sdp_list_t)); + +	if (!n) +		return 0; + +	n->data = d; +	n->next = 0; + +	if (!p) +		return n; + +	for (q = p; q->next; q = q->next); +	q->next = n; + +	return p; +} + +sdp_list_t *sdp_list_remove(sdp_list_t *list, void *d) +{ +	sdp_list_t *p, *q; + +	for (q = 0, p = list; p; q = p, p = p->next) +		if (p->data == d) { +			if (q) +				q->next = p->next; +			else +				list = p->next; +			free(p); +			break; +		} + +	return list; +} + +sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *d, sdp_comp_func_t f) +{ +	sdp_list_t *q, *p, *n; + +	n = malloc(sizeof(sdp_list_t)); +	if (!n) +		return 0; +	n->data = d; +	for (q = 0, p = list; p; q = p, p = p->next) +		if (f(p->data, d) >= 0) +			break;  +	// insert between q and p; if !q insert at head +	if (q) +		q->next = n; +	else +		list = n; +	n->next = p; +	return list; +} + +/* + * Every element of the list points to things which need  + * to be free()'d. This method frees the list's contents + */ +void sdp_list_free(sdp_list_t *list, sdp_free_func_t f) +{ +	sdp_list_t *next; +	while (list) { +		next = list->next; +		if (f) +			f(list->data); +		free(list); +		list = next; +	} +} + +static inline int __find_port(sdp_data_t *seq, int proto) +{ +	if (!seq || !seq->next) +		return 0; + +	if (SDP_IS_UUID(seq->dtd) && sdp_uuid_to_proto(&seq->val.uuid) == proto) { +		seq = seq->next; +		switch (seq->dtd) { +		case SDP_UINT8: +			return seq->val.uint8; +		case SDP_UINT16: +			return seq->val.uint16; +		} +	} +	return 0; +} + +int sdp_get_proto_port(const sdp_list_t *list, int proto) +{ +	if (proto != L2CAP_UUID && proto != RFCOMM_UUID) { +		errno = EINVAL; +		return -1; +	} + +	for (; list; list = list->next) { +		sdp_list_t *p; +		for (p = list->data; p; p = p->next) { +			sdp_data_t *seq = (sdp_data_t *) p->data; +			int port = __find_port(seq, proto); +			if (port) +				return port; +		} +	} +	return 0; +} + +sdp_data_t *sdp_get_proto_desc(sdp_list_t *list, int proto) +{ +	for (; list; list = list->next) { +		sdp_list_t *p; +		for (p = list->data; p; p = p->next) { +			sdp_data_t *seq = (sdp_data_t *) p->data; +			if (SDP_IS_UUID(seq->dtd) &&  +					sdp_uuid_to_proto(&seq->val.uuid) == proto) +				return seq->next; +		} +	} +	return NULL; +} + +int sdp_get_access_protos(const sdp_record_t *rec, sdp_list_t **pap) +{ +	sdp_data_t *pdlist, *curr; +	sdp_list_t *ap = 0; + +	pdlist = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST); +	if (pdlist == NULL) { +		errno = ENODATA; +		return -1; +	} +	SDPDBG("AP type : 0%x\n", pdlist->dtd); + +	for (; pdlist; pdlist = pdlist->next) { +		sdp_list_t *pds = 0; +		for (curr = pdlist->val.dataseq; curr; curr = curr->next) +			pds = sdp_list_append(pds, curr->val.dataseq); +		ap = sdp_list_append(ap, pds); +	} +	*pap = ap; +	return 0; +} + +int sdp_get_add_access_protos(const sdp_record_t *rec, sdp_list_t **pap) +{ +	sdp_data_t *pdlist, *curr; +	sdp_list_t *ap = 0; + +	pdlist = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST); +	if (pdlist == NULL) { +		errno = ENODATA; +		return -1; +	} +	SDPDBG("AP type : 0%x\n", pdlist->dtd); + +	pdlist = pdlist->val.dataseq; + +	for (; pdlist; pdlist = pdlist->next) { +		sdp_list_t *pds = 0; +		for (curr = pdlist->val.dataseq; curr; curr = curr->next) +			pds = sdp_list_append(pds, curr->val.dataseq); +		ap = sdp_list_append(ap, pds); +	} +	*pap = ap; +	return 0; +} + +int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr, sdp_list_t **seqp) +{ +	sdp_data_t *sdpdata = sdp_data_get(rec, attr); + +	*seqp = NULL; +	if (sdpdata && sdpdata->dtd >= SDP_SEQ8 && sdpdata->dtd <= SDP_SEQ32) { +		sdp_data_t *d; +		for (d = sdpdata->val.dataseq; d; d = d->next) { +			uuid_t *u; +			if (d->dtd < SDP_UUID16 || d->dtd > SDP_UUID128) +				goto fail; + +			u = malloc(sizeof(uuid_t)); +			memset(u, 0, sizeof(uuid_t)); +			*u = d->val.uuid; +			*seqp = sdp_list_append(*seqp, u); +		} +		return 0; +	} +fail: +	sdp_list_free(*seqp, free); +	errno = EINVAL; +	return -1; +} + +int sdp_set_uuidseq_attr(sdp_record_t *rec, uint16_t aid, sdp_list_t *seq) +{ +	int status = 0, i, len; +	void **dtds, **values; +	uint8_t uuid16 = SDP_UUID16; +	uint8_t uuid32 = SDP_UUID32; +	uint8_t uuid128 = SDP_UUID128; +	sdp_list_t *p; + +	len = sdp_list_len(seq); +	if (!seq || len == 0) +		return -1; +	dtds = (void **)malloc(len * sizeof(void *)); +	values = (void **)malloc(len * sizeof(void *)); +	for (p = seq, i = 0; i < len; i++, p = p->next) { +		uuid_t *uuid = (uuid_t *)p->data; +		if (uuid) +			switch (uuid->type) { +			case SDP_UUID16: +				dtds[i] = &uuid16; +				values[i] = &uuid->value.uuid16; +				break; +			case SDP_UUID32: +				dtds[i] = &uuid32; +				values[i] = &uuid->value.uuid32; +				break; +			case SDP_UUID128: +				dtds[i] = &uuid128; +				values[i] = &uuid->value.uuid128; +				break; +			default: +				status = -1; +				break; +			} +		else { +			status = -1; +			break; +		} +	} +	if (status == 0) { +		sdp_data_t *data = sdp_seq_alloc(dtds, values, len); +		sdp_attr_replace(rec, aid, data); +		sdp_pattern_add_uuidseq(rec, seq); +	} +	free(dtds); +	free(values); +	return status; +} + +int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq) +{ +	sdp_lang_attr_t *lang; +	sdp_data_t *sdpdata, *curr_data; + +	*langSeq = NULL; +	sdpdata = sdp_data_get(rec, SDP_ATTR_LANG_BASE_ATTR_ID_LIST); +	if (sdpdata == NULL) { +		errno = ENODATA; +		return -1; +	} +	curr_data = sdpdata->val.dataseq; +	while (curr_data) { +		sdp_data_t *pCode = curr_data; +		sdp_data_t *pEncoding = pCode->next; +		sdp_data_t *pOffset = pEncoding->next; +		if (pCode && pEncoding && pOffset) { +			lang = malloc(sizeof(sdp_lang_attr_t)); +			lang->code_ISO639 = pCode->val.uint16; +			lang->encoding = pEncoding->val.uint16; +			lang->base_offset = pOffset->val.uint16; +			SDPDBG("code_ISO639 :  0x%02x\n", lang->code_ISO639); +			SDPDBG("encoding :     0x%02x\n", lang->encoding); +			SDPDBG("base_offfset : 0x%02x\n", lang->base_offset); +			*langSeq = sdp_list_append(*langSeq, lang); +		} +		curr_data = pOffset->next; +	} +	return 0; +} + +int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDescSeq) +{ +	sdp_profile_desc_t *profDesc; +	sdp_data_t *sdpdata, *seq; + +	*profDescSeq = NULL; +	sdpdata = sdp_data_get(rec, SDP_ATTR_PFILE_DESC_LIST); +	if (!sdpdata || !sdpdata->val.dataseq) { +		errno = ENODATA; +		return -1; +	} +	for (seq = sdpdata->val.dataseq; seq && seq->val.dataseq; seq = seq->next) { +		uuid_t *uuid = NULL; +		uint16_t version = 0x100; + +		if (SDP_IS_UUID(seq->dtd)) { +			uuid = &seq->val.uuid; +		} else { +			sdp_data_t *puuid = seq->val.dataseq; +			sdp_data_t *pVnum = seq->val.dataseq->next; +			if (puuid && pVnum) { +				uuid = &puuid->val.uuid; +				version = pVnum->val.uint16; +			} +		} + +		if (uuid != NULL) { +			profDesc = malloc(sizeof(sdp_profile_desc_t)); +			profDesc->uuid = *uuid; +			profDesc->version = version; +#ifdef SDP_DEBUG +			sdp_uuid_print(&profDesc->uuid); +			SDPDBG("Vnum : 0x%04x\n", profDesc->version); +#endif +			*profDescSeq = sdp_list_append(*profDescSeq, profDesc); +		} +	} +	return 0; +} + +int sdp_get_server_ver(const sdp_record_t *rec, sdp_list_t **u16) +{ +	sdp_data_t *d, *curr; + +	*u16 = NULL; +	d = sdp_data_get(rec, SDP_ATTR_VERSION_NUM_LIST); +	if (d == NULL) { +		errno = ENODATA; +		return -1; +	} +	for (curr = d->val.dataseq; curr; curr = curr->next) +		*u16 = sdp_list_append(*u16, &curr->val.uint16); +	return 0; +} + +/* flexible extraction of basic attributes - Jean II */ +/* How do we expect caller to extract predefined data sequences? */ +int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attrid, int *value) +{ +	sdp_data_t *sdpdata = sdp_data_get(rec, attrid); + +	if (sdpdata) +		/* Verify that it is what the caller expects */ +		if (sdpdata->dtd == SDP_BOOL || sdpdata->dtd == SDP_UINT8 || +		sdpdata->dtd == SDP_UINT16 || sdpdata->dtd == SDP_UINT32 || +		sdpdata->dtd == SDP_INT8 || sdpdata->dtd == SDP_INT16 || +		sdpdata->dtd == SDP_INT32) { +			*value = sdpdata->val.uint32; +			return 0; +		} +	errno = EINVAL; +	return -1; +} + +int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attrid, char *value, int valuelen) +{ +	sdp_data_t *sdpdata = sdp_data_get(rec, attrid); +	if (sdpdata) +		/* Verify that it is what the caller expects */ +		if (sdpdata->dtd == SDP_TEXT_STR8 || sdpdata->dtd == SDP_TEXT_STR16 || sdpdata->dtd == SDP_TEXT_STR32) +			if (strlen(sdpdata->val.str) < valuelen) { +				strcpy(value, sdpdata->val.str); +				return 0; +			} +	errno = EINVAL; +	return -1; +} + +#define get_basic_attr(attrID, pAttrValue, fieldName)		\ +	sdp_data_t *data = sdp_data_get(rec, attrID);		\ +	if (data) {						\ +		*pAttrValue = data->val.fieldName;		\ +		return 0;					\ +	}							\ +	errno = EINVAL;						\ +	return -1; + +int sdp_get_service_id(const sdp_record_t *rec, uuid_t *uuid) +{ +	get_basic_attr(SDP_ATTR_SERVICE_ID, uuid, uuid); +} + +int sdp_get_group_id(const sdp_record_t *rec, uuid_t *uuid) +{ +	get_basic_attr(SDP_ATTR_GROUP_ID, uuid, uuid); +} + +int sdp_get_record_state(const sdp_record_t *rec, uint32_t *svcRecState) +{ +	get_basic_attr(SDP_ATTR_RECORD_STATE, svcRecState, uint32); +} + +int sdp_get_service_avail(const sdp_record_t *rec, uint8_t *svcAvail) +{ +	get_basic_attr(SDP_ATTR_SERVICE_AVAILABILITY, svcAvail, uint8); +} + +int sdp_get_service_ttl(const sdp_record_t *rec, uint32_t *svcTTLInfo) +{ +	get_basic_attr(SDP_ATTR_SVCINFO_TTL, svcTTLInfo, uint32); +} + +int sdp_get_database_state(const sdp_record_t *rec, uint32_t *svcDBState) +{ +	get_basic_attr(SDP_ATTR_SVCDB_STATE, svcDBState, uint32); +} + +/* + * NOTE that none of the setXXX() functions below will + * actually update the SDP server, unless the + * {register, update}sdp_record_t() function is invoked. + */ + +int sdp_attr_add_new(sdp_record_t *rec, uint16_t attr, uint8_t dtd, const void *value) +{ +	sdp_data_t *d = sdp_data_alloc(dtd, value); +	if (d) { +		sdp_attr_replace(rec, attr, d); +		return 0; +	} +	return -1; +} + +/* + * Set the information attributes of the service + * pointed to by rec. The attributes are + * service name, description and provider name + */ +void sdp_set_info_attr(sdp_record_t *rec, const char *name, const char *prov, const char *desc) +{ +	if (name) +		sdp_attr_add_new(rec, SDP_ATTR_SVCNAME_PRIMARY, SDP_TEXT_STR8, (void *)name); +	if (prov) +		sdp_attr_add_new(rec, SDP_ATTR_PROVNAME_PRIMARY, SDP_TEXT_STR8, (void *)prov); +	if (desc) +		sdp_attr_add_new(rec, SDP_ATTR_SVCDESC_PRIMARY, SDP_TEXT_STR8, (void *)desc); +} + +static sdp_data_t *access_proto_to_dataseq(sdp_record_t *rec, sdp_list_t *proto) +{ +	sdp_data_t *seq = NULL; +	void *dtds[10], *values[10]; +	void **seqDTDs, **seqs; +	int i, seqlen; +	sdp_list_t *p; + +	seqlen = sdp_list_len(proto); +	seqDTDs = (void **)malloc(seqlen * sizeof(void *)); +	seqs = (void **)malloc(seqlen * sizeof(void *)); +	for (i = 0, p = proto; p; p = p->next, i++) { +		sdp_list_t *elt = (sdp_list_t *)p->data; +		sdp_data_t *s; +		int pslen = 0; +		for (; elt && pslen < sizeof(dtds); elt = elt->next, pslen++) { +			sdp_data_t *d = (sdp_data_t *)elt->data; +			dtds[pslen] = &d->dtd; +			switch (d->dtd) { +			case SDP_UUID16: +				values[pslen] = &((uuid_t *)d)->value.uuid16; +				break; +			case SDP_UUID32: +				values[pslen] = &((uuid_t *)d)->value.uuid32; +				break; +			case SDP_UUID128: +				values[pslen] = &((uuid_t *)d)->value.uuid128; +				break; +			case SDP_UINT8: +				values[pslen] = &d->val.uint8; +				break; +			case SDP_UINT16: +				values[pslen] = &d->val.uint16; +				break; +			case SDP_SEQ8: +			case SDP_SEQ16: +			case SDP_SEQ32: +				values[pslen] = d; +				break; +			// FIXME: more +			} +		} +		s = sdp_seq_alloc(dtds, values, pslen); +		if (s) { +			seqDTDs[i] = &s->dtd; +			seqs[i] = s; +		} +	} +	seq = sdp_seq_alloc(seqDTDs, seqs, seqlen); +	free(seqDTDs); +	free(seqs); +	return seq; +} + +/* + * sets the access protocols of the service specified + * to the value specified in "access_proto" + * + * Note that if there are alternate mechanisms by  + * which the service is accessed, then they should  + * be specified as sequences  + * + * Using a value of NULL for accessProtocols has + * effect of removing this attribute (if previously set) + *  + * This function replaces the existing sdp_access_proto_t + * structure (if any) with the new one specified. + * + * returns 0 if successful or -1 if there is a failure. + */ +int sdp_set_access_protos(sdp_record_t *rec, const sdp_list_t *ap) +{ +	const sdp_list_t *p; +	sdp_data_t *protos = NULL; + +	for (p = ap; p; p = p->next) { +		sdp_data_t *seq = access_proto_to_dataseq(rec, (sdp_list_t *) p->data); +		protos = sdp_seq_append(protos, seq); +	} + +	sdp_attr_add(rec, SDP_ATTR_PROTO_DESC_LIST, protos); + +	return 0; +} + +int sdp_set_add_access_protos(sdp_record_t *rec, const sdp_list_t *ap) +{ +	const sdp_list_t *p; +	sdp_data_t *protos = NULL; + +	for (p = ap; p; p = p->next) { +		sdp_data_t *seq = access_proto_to_dataseq(rec, (sdp_list_t *) p->data); +		protos = sdp_seq_append(protos, seq); +	} + +	sdp_attr_add(rec, SDP_ATTR_ADD_PROTO_DESC_LIST, +			protos ? sdp_data_alloc(SDP_SEQ8, protos) : NULL); + +	return 0; +} + +/* + * set the "LanguageBase" attributes of the service record + * record to the value specified in "langAttrList". + * + * "langAttrList" is a linked list of "sdp_lang_attr_t" + * objects, one for each language in which user visible + * attributes are present in the service record. + * + * Using a value of NULL for langAttrList has + * effect of removing this attribute (if previously set) + *  + * This function replaces the exisiting sdp_lang_attr_t + * structure (if any) with the new one specified. + * + * returns 0 if successful or -1 if there is a failure. + */ +int sdp_set_lang_attr(sdp_record_t *rec, const sdp_list_t *seq) +{ +	uint8_t uint16 = SDP_UINT16; +	int status = 0, i = 0, seqlen = sdp_list_len(seq); +	void **dtds = (void **)malloc(3 * seqlen * sizeof(void *)); +	void **values = (void **)malloc(3 * seqlen * sizeof(void *)); +	const sdp_list_t *p; + +	for (p = seq; p; p = p->next) { +		sdp_lang_attr_t *lang = (sdp_lang_attr_t *)p->data; +		if (!lang) { +			status = -1; +			break; +		} +		dtds[i] = &uint16; +		values[i] = &lang->code_ISO639; +		i++; +		dtds[i] = &uint16; +		values[i] = &lang->encoding; +		i++; +		dtds[i] = &uint16; +		values[i] = &lang->base_offset; +		i++; +	} +	if (status == 0) { +		sdp_data_t *seq = sdp_seq_alloc(dtds, values, 3 * seqlen); +		sdp_attr_add(rec, SDP_ATTR_LANG_BASE_ATTR_ID_LIST, seq); +	} +	free(dtds); +	free(values); +	return status; +} + +/* + * set the "ServiceID" attribute of the service.  + *  + * This is the UUID of the service.  + *  + * returns 0 if successful or -1 if there is a failure. + */ +void sdp_set_service_id(sdp_record_t *rec, uuid_t uuid) +{ +	switch (uuid.type) { +	case SDP_UUID16: +		sdp_attr_add_new(rec, SDP_ATTR_SERVICE_ID, SDP_UUID16, &uuid.value.uuid16); +		break; +	case SDP_UUID32: +		sdp_attr_add_new(rec, SDP_ATTR_SERVICE_ID, SDP_UUID32, &uuid.value.uuid32); +		break; +	case SDP_UUID128: +		sdp_attr_add_new(rec, SDP_ATTR_SERVICE_ID, SDP_UUID128, &uuid.value.uuid128); +		break; +	} +	sdp_pattern_add_uuid(rec, &uuid); +} + +/* + * set the GroupID attribute of the service record defining a group.  + *  + * This is the UUID of the group.  + *  + * returns 0 if successful or -1 if there is a failure. + */ +void sdp_set_group_id(sdp_record_t *rec, uuid_t uuid) +{ +	switch (uuid.type) { +	case SDP_UUID16: +		sdp_attr_add_new(rec, SDP_ATTR_GROUP_ID, SDP_UUID16, &uuid.value.uuid16); +		break; +	case SDP_UUID32: +		sdp_attr_add_new(rec, SDP_ATTR_GROUP_ID, SDP_UUID32, &uuid.value.uuid32); +		break; +	case SDP_UUID128: +		sdp_attr_add_new(rec, SDP_ATTR_GROUP_ID, SDP_UUID128, &uuid.value.uuid128); +		break; +	} +	sdp_pattern_add_uuid(rec, &uuid); +} + +/* + * set the ProfileDescriptorList attribute of the service record + * pointed to by record to the value specified in "profileDesc". + * + * Each element in the list is an object of type + * sdp_profile_desc_t which is a definition of the + * Bluetooth profile that this service conforms to. + * + * Using a value of NULL for profileDesc has + * effect of removing this attribute (if previously set) + *  + * This function replaces the exisiting ProfileDescriptorList + * structure (if any) with the new one specified. + * + * returns 0 if successful or -1 if there is a failure. + */ +int sdp_set_profile_descs(sdp_record_t *rec, const sdp_list_t *profiles) +{ +	int status = 0; +	uint8_t uuid16 = SDP_UUID16; +	uint8_t uuid32 = SDP_UUID32; +	uint8_t uuid128 = SDP_UUID128; +	uint8_t uint16 = SDP_UINT16; +	int i = 0, seqlen = sdp_list_len(profiles); +	void **seqDTDs = (void **)malloc(seqlen * sizeof(void *)); +	void **seqs = (void **)malloc(seqlen * sizeof(void *)); +	const sdp_list_t *p; + +	for (p = profiles; p; p = p->next) { +		sdp_data_t *seq; +		void *dtds[2], *values[2]; +		sdp_profile_desc_t *profile = (sdp_profile_desc_t *)p->data; +		if (!profile) { +			status = -1; +			break; +		} +		switch (profile->uuid.type) { +		case SDP_UUID16: +			dtds[0] = &uuid16; +			values[0] = &profile->uuid.value.uuid16; +			break; +		case SDP_UUID32: +			dtds[0] = &uuid32; +			values[0] = &profile->uuid.value.uuid32; +			break; +		case SDP_UUID128: +			dtds[0] = &uuid128; +			values[0] = &profile->uuid.value.uuid128; +			break; +		default: +			status = -1; +			break; +		} +		dtds[1] = &uint16; +		values[1] = &profile->version; +		seq = sdp_seq_alloc(dtds, values, 2); +		if (seq) { +			seqDTDs[i] = &seq->dtd; +			seqs[i] = seq; +			sdp_pattern_add_uuid(rec, &profile->uuid); +		} +		i++; +	} +	if (status == 0) { +		sdp_data_t *pAPSeq = sdp_seq_alloc(seqDTDs, seqs, seqlen); +		sdp_attr_add(rec, SDP_ATTR_PFILE_DESC_LIST, pAPSeq); +	} +	free(seqDTDs); +	free(seqs); +	return status; +} + +/* + * sets various URL attributes of the service + * pointed to by record. The URL include + * + * client: a URL to the client's + *   platform specific (WinCE, PalmOS) executable + *   code that can be used to access this service. + * + * doc: a URL pointing to service documentation + * + * icon: a URL to an icon that can be used to represent + *   this service. + * + * Note that you need to pass NULL for any URLs + * that you don't want to set or remove + */ +void sdp_set_url_attr(sdp_record_t *rec, const char *client, const char *doc, const char *icon) +{ +	sdp_attr_add_new(rec, SDP_ATTR_CLNT_EXEC_URL, SDP_URL_STR8, client); +	sdp_attr_add_new(rec, SDP_ATTR_DOC_URL, SDP_URL_STR8, doc); +	sdp_attr_add_new(rec, SDP_ATTR_ICON_URL, SDP_URL_STR8, icon); +} + +/* + * The code in this function is executed only once per + * thread. We compute the actual bit value of the Bluetooth + * base UUID which is a string defined in bt_std_values.h  + * and is assumed to be of the standard form with "-" separators. + * + * The algorithm however converts the string to 4 unsigned longs + * using the strtoul() and assigns the values in sequence to + * the 128bit value + */ +uint128_t *sdp_create_base_uuid(void) +{ +	uint128_t *base_uuid; +	char baseStr[128]; +	int delim = '-'; +	unsigned long dataLongValue; +	char *delimPtr; +	char *dataPtr; +	char temp[10]; +	int toBeCopied; +	uint8_t *data; + +	strcpy(baseStr, BASE_UUID); +	base_uuid = malloc(sizeof(uint128_t)); +	if (!base_uuid) +		return NULL; + +	data = base_uuid->data; +	memset(data, '\0', sizeof(uint128_t)); +	memset(temp, '\0', 10); +	dataPtr = baseStr; +	delimPtr = NULL; +	delimPtr = strchr(dataPtr, delim); +	toBeCopied = delimPtr - dataPtr; +	if (toBeCopied != 8) { +		SDPDBG("To be copied(1) : %d\n", toBeCopied); +		free(base_uuid); +		return NULL; +	} +	strncpy(temp, dataPtr, toBeCopied); +	dataLongValue = htonl(strtoul(temp, NULL, 16)); +	memcpy(&data[0], &dataLongValue, 4); + +	/* +	 * Get the next 4 bytes (note that there is a "-" +	 * between them now) +	 */ +	memset(temp, '\0', 10); +	dataPtr = delimPtr + 1; +	delimPtr = strchr(dataPtr, delim); +	toBeCopied = delimPtr - dataPtr; +	if (toBeCopied != 4) { +		SDPDBG("To be copied(2) : %d\n", toBeCopied); +		free(base_uuid); +		return NULL; +	} +	strncpy(temp, dataPtr, toBeCopied); +	dataPtr = delimPtr + 1; +	delimPtr = strchr(dataPtr, delim); +	toBeCopied = delimPtr - dataPtr; +	if (toBeCopied != 4) { +		SDPDBG("To be copied(3) : %d\n", toBeCopied); +		free(base_uuid); +		return NULL; +	} +	strncat(temp, dataPtr, toBeCopied); +	dataLongValue = htonl(strtoul(temp, NULL, 16)); +	memcpy(&data[4], &dataLongValue, 4); + +	/* +	 * Get the last 4 bytes (note that there are 6 bytes +	 * after the last separator, which is truncated (2+4) +	 */ +	memset(temp, '\0', 10); +	dataPtr = delimPtr + 1; +	dataPtr = delimPtr + 1; +	delimPtr = strchr(dataPtr, delim); +	toBeCopied = delimPtr - dataPtr; +	if (toBeCopied != 4) { +		SDPDBG("To be copied(4) : %d\n", toBeCopied); +		free(base_uuid); +		return NULL; +	} +	strncpy(temp, dataPtr, toBeCopied); +	strncat(temp, (delimPtr + 1), 4); +	dataLongValue = htonl(strtoul(temp, NULL, 16)); +	memcpy(&data[8], &dataLongValue, 4); +	dataLongValue = htonl(strtoul(delimPtr + 5, NULL, 16)); +	memcpy(&data[12], &dataLongValue, 4); + +	return base_uuid; +} + +uuid_t *sdp_uuid16_create(uuid_t *u, uint16_t val) +{ +	memset(u, 0, sizeof(uuid_t)); +	u->type = SDP_UUID16; +	u->value.uuid16 = val; +	return u; +} + +uuid_t *sdp_uuid32_create(uuid_t *u, uint32_t val) +{ +	memset(u, 0, sizeof(uuid_t)); +	u->type = SDP_UUID32; +	u->value.uuid32 = val; +	return u; +} + +uuid_t *sdp_uuid128_create(uuid_t *u, const void *val) +{  +	memset(u, 0, sizeof(uuid_t)); +	u->type = SDP_UUID128; +	memcpy(&u->value.uuid128, val, sizeof(uint128_t)); +	return u; +} + +/* + * UUID comparison function + * returns 0 if uuidValue1 == uuidValue2 else -1 + */ +int sdp_uuid16_cmp(const void *p1, const void *p2) +{ +	const uuid_t *u1 = (const uuid_t *)p1; +	const uuid_t *u2 = (const uuid_t *)p2; +	return memcmp(&u1->value.uuid16, &u2->value.uuid16, sizeof(uint16_t)); +} + +/* + * UUID comparison function + * returns 0 if uuidValue1 == uuidValue2 else -1 + */ +int sdp_uuid128_cmp(const void *p1, const void *p2) +{ +	const uuid_t *u1 = (const uuid_t *)p1; +	const uuid_t *u2 = (const uuid_t *)p2; +	return memcmp(&u1->value.uuid128, &u2->value.uuid128, sizeof(uint128_t)); +} + +/* + * 128 to 16 bit and 32 to 16 bit UUID conversion functions + * yet to be implemented. Note that the input is in NBO in + * both 32 and 128 bit UUIDs and conversion is needed + */ +void sdp_uuid16_to_uuid128(uuid_t *uuid128, uuid_t *uuid16) +{ +	/* +	 * We have a 16 bit value, which needs to be added to +	 * bytes 3 and 4 (at indices 2 and 3) of the Bluetooth base +	 */ +	unsigned short data1; + +	// allocate a 128bit UUID and init to the Bluetooth base UUID +	uuid128->value.uuid128 = bluetooth_base_uuid; +	uuid128->type = SDP_UUID128; + +	// extract bytes 2 and 3 of 128bit BT base UUID +	memcpy(&data1, &bluetooth_base_uuid.data[2], 2); + +	// add the given UUID (16 bits) +	data1 += htons(uuid16->value.uuid16); + +	// set bytes 2 and 3 of the 128 bit value +	memcpy(&uuid128->value.uuid128.data[2], &data1, 2); +} + +void sdp_uuid32_to_uuid128(uuid_t *uuid128, uuid_t *uuid32) +{ +	/* +	 * We have a 32 bit value, which needs to be added to +	 * bytes 1->4 (at indices 0 thru 3) of the Bluetooth base +	 */ +	unsigned int data0; + +	// allocate a 128bit UUID and init to the Bluetooth base UUID +	uuid128->value.uuid128 = bluetooth_base_uuid; +	uuid128->type = SDP_UUID128; + +	// extract first 4 bytes +	memcpy(&data0, &bluetooth_base_uuid.data[0], 4); + +	// add the given UUID (32bits) +	data0 += htonl(uuid32->value.uuid32); + +	// set the 4 bytes of the 128 bit value +	memcpy(&uuid128->value.uuid128.data[0], &data0, 4); +} + +uuid_t *sdp_uuid_to_uuid128(uuid_t *uuid) +{ +	uuid_t *uuid128 = bt_malloc(sizeof(uuid_t)); +	memset(uuid128, 0, sizeof(uuid_t)); +	switch (uuid->type) { +	case SDP_UUID128: +		*uuid128 = *uuid; +		break; +	case SDP_UUID32: +		sdp_uuid32_to_uuid128(uuid128, uuid); +		break; +	case SDP_UUID16: +		sdp_uuid16_to_uuid128(uuid128, uuid); +		break; +	} +	return uuid128; +} + +/*  + * converts a 128-bit uuid to a 16/32-bit one if possible + * returns true if uuid contains a 16/32-bit UUID at exit + */ +int sdp_uuid128_to_uuid(uuid_t *uuid) +{ +	uint128_t *b = &bluetooth_base_uuid; +	uint128_t *u = &uuid->value.uuid128; +	uint32_t data; +	int i; + +	if (uuid->type != SDP_UUID128) +		return 1; + +	for (i = 4; i < sizeof(b->data); i++) +		if (b->data[i] != u->data[i]) +			return 0; + +	memcpy(&data, u->data, 4); +	data = htonl(data); +	if (data <= 0xffff) { +		uuid->type = SDP_UUID16; +		uuid->value.uuid16 = (uint16_t) data; +	} else { +		uuid->type = SDP_UUID32; +		uuid->value.uuid32 = data; +	} +	return 1; +} + +/* + * convert a UUID to the 16-bit short-form + */ +int sdp_uuid_to_proto(uuid_t *uuid) +{ +	uuid_t u = *uuid; +	if (sdp_uuid128_to_uuid(&u)) { +		switch (u.type) { +		case SDP_UUID16: +			return u.value.uuid16; +		case SDP_UUID32: +			return u.value.uuid32; +		} +	} +	return 0; +} + +/* + * This function appends data to the PDU buffer "dst" from source "src".  + * The data length is also computed and set. + * Should the PDU length exceed 2^8, then sequence type is + * set accordingly and the data is memmove()'d. + */ +void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len) +{ +	uint8_t *p = dst->data; +	uint8_t dtd = *(uint8_t *) p; + +	SDPDBG("Append src size: %d\n", len); +	SDPDBG("Append dst size: %d\n", dst->data_size); +	SDPDBG("Dst buffer size: %d\n", dst->buf_size); +	if (dst->data_size + len > dst->buf_size) { +		int need = SDP_PDU_CHUNK_SIZE * ((len / SDP_PDU_CHUNK_SIZE) + 1); +		dst->data = realloc(dst->data, dst->buf_size + need); + +		SDPDBG("Realloc'ing : %d\n", need); + +		if (dst->data == NULL) { +			SDPERR("Realloc fails \n"); +		} +		dst->buf_size += need; +	} +	if (dst->data_size == 0 && dtd == 0) { +		// create initial sequence +		*(uint8_t *)p = SDP_SEQ8; +		p += sizeof(uint8_t); +		dst->data_size += sizeof(uint8_t); +		// reserve space for sequence size +		p += sizeof(uint8_t); +		dst->data_size += sizeof(uint8_t); +	} + +	memcpy(dst->data + dst->data_size, data, len); +	dst->data_size += len; + +	dtd = *(uint8_t *)dst->data; +	if (dst->data_size > UCHAR_MAX && dtd == SDP_SEQ8) { +		short offset = sizeof(uint8_t) + sizeof(uint8_t); +		memmove(dst->data + offset + 1, dst->data + offset, dst->data_size - offset); +		p = dst->data; +		*(uint8_t *) p = SDP_SEQ16; +		p += sizeof(uint8_t); +		dst->data_size += 1; +	} +	p = dst->data; +	dtd = *(uint8_t *) p; +	p += sizeof(uint8_t); +	switch (dtd) { +	case SDP_SEQ8: +		*(uint8_t *) p = dst->data_size - sizeof(uint8_t) - sizeof(uint8_t); +		break; +	case SDP_SEQ16: +		bt_put_unaligned(htons(dst->data_size - sizeof(uint8_t) - sizeof(uint16_t)), (uint16_t *) p); +		break; +	case SDP_SEQ32: +		bt_put_unaligned(htonl(dst->data_size - sizeof(uint8_t) - sizeof(uint32_t)), (uint32_t *) p); +		break; +	} +} + +void sdp_append_to_pdu(sdp_buf_t *pdu, sdp_data_t *d) +{ +	uint8_t buf[256]; +	sdp_buf_t append; + +	memset(&append, 0, sizeof(sdp_buf_t)); +	append.data = buf; +	append.buf_size = sizeof(buf); +	append.data_size = 0; + +	sdp_set_attrid(&append, d->attrId); +	sdp_gen_pdu(&append, d); +	sdp_append_to_buf(pdu, append.data, append.data_size); +} + +/* + * Registers an sdp record. + * + * It is incorrect to call this method on a record that + * has been already registered with the server. + * + * Returns zero on success, otherwise -1 (and sets errno). + */ +int sdp_device_record_register_binary(sdp_session_t *session, bdaddr_t *device, uint8_t *data, uint32_t size, uint8_t flags, uint32_t *handle) +{ +	uint8_t *req, *rsp, *p; +	uint32_t reqsize, rspsize; +	sdp_pdu_hdr_t *reqhdr, *rsphdr; +	int status; + +	SDPDBG(""); + +	if (!session->local) { +		errno = EREMOTE; +		return -1; +	} +	req = malloc(SDP_REQ_BUFFER_SIZE); +	rsp = malloc(SDP_RSP_BUFFER_SIZE); +	if (req == NULL || rsp == NULL) { +		status = -1; +		errno = ENOMEM; +		goto end; +	} + +	reqhdr = (sdp_pdu_hdr_t *)req; +	reqhdr->pdu_id = SDP_SVC_REGISTER_REQ; +	reqhdr->tid    = htons(sdp_gen_tid(session)); +	reqsize = sizeof(sdp_pdu_hdr_t) + 1; +	p = req + sizeof(sdp_pdu_hdr_t); + +	if (bacmp(device, BDADDR_ANY)) { +		*p++ = flags | SDP_DEVICE_RECORD; +		bacpy((bdaddr_t *) p, device); +		p += sizeof(bdaddr_t); +		reqsize += sizeof(bdaddr_t); +	} else +		*p++ = flags; + +	memcpy(p, data, size); +	reqsize += size; +	reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t)); + +	status = sdp_send_req_w4_rsp(session, req, rsp, reqsize, &rspsize); +	if (status < 0) +		goto end; + +	if (rspsize < sizeof(sdp_pdu_hdr_t)) { +		SDPERR("Unexpected end of packet"); +		errno = EPROTO; +		status = -1; +		goto end; +	} + +	rsphdr = (sdp_pdu_hdr_t *) rsp; +	p = rsp + sizeof(sdp_pdu_hdr_t); + +	if (rsphdr->pdu_id == SDP_ERROR_RSP) { +		/* Invalid service record */ +		errno = EINVAL; +		status = -1; +	} else if (rsphdr->pdu_id != SDP_SVC_REGISTER_RSP) { +		errno = EPROTO; +		status = -1; +	} else { +		if (rspsize < sizeof(sdp_pdu_hdr_t) + sizeof(uint32_t)) { +			SDPERR("Unexpected end of packet"); +			errno = EPROTO; +			status = -1; +			goto end; +		} +		if (handle) +			*handle  = ntohl(bt_get_unaligned((uint32_t *) p)); +	} + +end: +	if (req) +		free(req); + +	if (rsp) +		free(rsp); + +	return status; +} + +int sdp_device_record_register(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec, uint8_t flags) +{ +	sdp_buf_t pdu; +	uint32_t handle; +	int err; + +	SDPDBG(""); + +	if (rec->handle && rec->handle != 0xffffffff) { +		uint32_t handle = rec->handle; +		sdp_data_t *data = sdp_data_alloc(SDP_UINT32, &handle); +		sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data); +	} + +	if (sdp_gen_record_pdu(rec, &pdu) < 0) { +		errno = ENOMEM; +		return -1; +	} + +	err = sdp_device_record_register_binary(session, device, +				pdu.data, pdu.data_size, flags, &handle); + +	free(pdu.data); + +	if (err == 0) { +		sdp_data_t *data = sdp_data_alloc(SDP_UINT32, &handle); +		rec->handle = handle; +		sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data); +	} + +	return err; +} + +int sdp_record_register(sdp_session_t *session, sdp_record_t *rec, uint8_t flags) +{ +	return sdp_device_record_register(session, BDADDR_ANY, rec, flags); +} + +/* + * unregister a service record + */ +int sdp_device_record_unregister_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle) +{ +	uint8_t *reqbuf, *rspbuf, *p; +	uint32_t reqsize = 0, rspsize = 0; +	sdp_pdu_hdr_t *reqhdr, *rsphdr; +	int status; + +	SDPDBG(""); + +	if (handle == SDP_SERVER_RECORD_HANDLE) { +		errno = EINVAL; +		return -1; +	} + +	if (!session->local) { +		errno = EREMOTE; +		return -1; +	} + +	reqbuf = malloc(SDP_REQ_BUFFER_SIZE); +	rspbuf = malloc(SDP_RSP_BUFFER_SIZE); +	if (!reqbuf || !rspbuf) { +		errno = ENOMEM; +		status = -1; +		goto end; +	} +	reqhdr = (sdp_pdu_hdr_t *) reqbuf; +	reqhdr->pdu_id = SDP_SVC_REMOVE_REQ; +	reqhdr->tid    = htons(sdp_gen_tid(session)); + +	p = reqbuf + sizeof(sdp_pdu_hdr_t); +	reqsize = sizeof(sdp_pdu_hdr_t); +	bt_put_unaligned(htonl(handle), (uint32_t *) p); +	reqsize += sizeof(uint32_t); + +	reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t)); +	status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize); +	if (status < 0) +		goto end; + +	if (rspsize < sizeof(sdp_pdu_hdr_t) + sizeof(uint16_t)) { +		SDPERR("Unexpected end of packet"); +		errno = EPROTO; +		status = -1; +		goto end; +	} + +	rsphdr = (sdp_pdu_hdr_t *) rspbuf; +	p = rspbuf + sizeof(sdp_pdu_hdr_t); +	status = bt_get_unaligned((uint16_t *) p); + +	if (rsphdr->pdu_id == SDP_ERROR_RSP) { +		/* For this case the status always is invalid record handle */ +		errno = EINVAL; +		status = -1; +	} else if (rsphdr->pdu_id != SDP_SVC_REMOVE_RSP) { +		errno = EPROTO; +		status = -1; +	} +end: +	if (reqbuf) +		free(reqbuf); + +	if (rspbuf) +		free(rspbuf); + +	return status; +} + +int sdp_device_record_unregister(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec) +{ +	int err; + +	err = sdp_device_record_unregister_binary(session, device, rec->handle); +	if (err == 0) +		sdp_record_free(rec); + +	return err; +} + +int sdp_record_unregister(sdp_session_t *session, sdp_record_t *rec) +{ +	return sdp_device_record_unregister(session, BDADDR_ANY, rec); +} + +/* + * modify an existing service record + */ +int sdp_device_record_update_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle, uint8_t *data, uint32_t size) +{ +	return -1; +} + +int sdp_device_record_update(sdp_session_t *session, bdaddr_t *device, const sdp_record_t *rec) +{ +	uint8_t *reqbuf, *rspbuf, *p; +	uint32_t reqsize, rspsize; +	sdp_pdu_hdr_t *reqhdr, *rsphdr; +	uint32_t handle; +	sdp_buf_t pdu; +	int status; + +	SDPDBG(""); + +	handle = rec->handle; + +	if (handle == SDP_SERVER_RECORD_HANDLE) { +		errno = EINVAL; +		return -1; +	} +	if (!session->local) { +		errno = EREMOTE; +		return -1; +	} +	reqbuf = malloc(SDP_REQ_BUFFER_SIZE); +	rspbuf = malloc(SDP_RSP_BUFFER_SIZE); +	if (!reqbuf || !rspbuf) { +		errno = ENOMEM; +		status = -1; +		goto end; +	} +	reqhdr = (sdp_pdu_hdr_t *) reqbuf; +	reqhdr->pdu_id = SDP_SVC_UPDATE_REQ; +	reqhdr->tid    = htons(sdp_gen_tid(session)); + +	p = reqbuf + sizeof(sdp_pdu_hdr_t); +	reqsize = sizeof(sdp_pdu_hdr_t); + +	bt_put_unaligned(htonl(handle), (uint32_t *) p); +	reqsize += sizeof(uint32_t); +	p += sizeof(uint32_t); + +	if (sdp_gen_record_pdu(rec, &pdu) < 0) { +		errno = ENOMEM; +		status = -1; +		goto end; +	} +	memcpy(p, pdu.data, pdu.data_size); +	reqsize += pdu.data_size; +	free(pdu.data); + +	reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t)); +	status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize); +	if (status < 0) +		goto end; + +	if (rspsize < sizeof(sdp_pdu_hdr_t) + sizeof(uint16_t)) { +		SDPERR("Unexpected end of packet"); +		errno = EPROTO; +		status = -1; +		goto end; +	} + +	SDPDBG("Send req status : %d\n", status); + +	rsphdr = (sdp_pdu_hdr_t *) rspbuf; +	p = rspbuf + sizeof(sdp_pdu_hdr_t); +	status = bt_get_unaligned((uint16_t *) p); + +	if (rsphdr->pdu_id == SDP_ERROR_RSP) { +		/* The status can be invalid sintax or invalid record handle */ +		errno = EINVAL; +		status = -1; +	} else if (rsphdr->pdu_id != SDP_SVC_UPDATE_RSP) { +		errno = EPROTO; +		status = -1; +	} +end: +	if (reqbuf) +		free(reqbuf); +	if (rspbuf) +		free(rspbuf); +	return status; +} + +int sdp_record_update(sdp_session_t *session, const sdp_record_t *rec) +{ +	return sdp_device_record_update(session, BDADDR_ANY, rec); +} + +sdp_record_t *sdp_record_alloc() +{ +	sdp_record_t *rec = malloc(sizeof(sdp_record_t)); +	memset((void *)rec, 0, sizeof(sdp_record_t)); +	rec->handle = 0xffffffff; +	return rec; +} + +/* + * Free the contents of a service record + */ +void sdp_record_free(sdp_record_t *rec) +{ +	sdp_list_free(rec->attrlist, (sdp_free_func_t)sdp_data_free); +	sdp_list_free(rec->pattern, free); +	free(rec); +} + +void sdp_pattern_add_uuid(sdp_record_t *rec, uuid_t *uuid) +{ +	uuid_t *uuid128 = sdp_uuid_to_uuid128(uuid); + +	SDPDBG("SvcRec : 0x%lx\n", (unsigned long)rec); +	SDPDBG("Elements in target pattern : %d\n", sdp_list_len(rec->pattern)); +	SDPDBG("Trying to add : 0x%lx\n", (unsigned long)uuid128); + +	if (sdp_list_find(rec->pattern, uuid128, sdp_uuid128_cmp) == NULL) +		rec->pattern = sdp_list_insert_sorted(rec->pattern, uuid128, sdp_uuid128_cmp); +	else +		bt_free(uuid128); + +	SDPDBG("Elements in target pattern : %d\n", sdp_list_len(rec->pattern)); +} + +void sdp_pattern_add_uuidseq(sdp_record_t *rec, sdp_list_t *seq) +{ +	for (; seq; seq = seq->next) { +		uuid_t *uuid = (uuid_t *)seq->data; +		sdp_pattern_add_uuid(rec, uuid); +	} +} + +/* + * Extract a sequence of service record handles from a PDU buffer + * and add the entries to a sdp_list_t. Note that the service record + * handles are not in "data element sequence" form, but just like + * an array of service handles + */ +static void extract_record_handle_seq(uint8_t *pdu, int bufsize, sdp_list_t **seq, int count, int *scanned) +{ +	sdp_list_t *pSeq = *seq; +	uint8_t *pdata = pdu; +	int n; + +	for (n = 0; n < count; n++) { +		if (bufsize < sizeof(uint32_t)) { +			SDPERR("Unexpected end of packet"); +			break; +		} +		uint32_t *pSvcRec = malloc(sizeof(uint32_t)); +		*pSvcRec = ntohl(bt_get_unaligned((uint32_t *) pdata)); +		pSeq = sdp_list_append(pSeq, pSvcRec); +		pdata += sizeof(uint32_t); +		*scanned += sizeof(uint32_t); +		bufsize -= sizeof(uint32_t); +	} +	*seq = pSeq; +} +/* + * Generate the attribute sequence pdu form + * from sdp_list_t elements. Return length of attr seq + */ +static int gen_dataseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dtd) +{ +	sdp_data_t *dataseq; +	void **types, **values; +	sdp_buf_t buf; +	int i, seqlen = sdp_list_len(seq); + +	// Fill up the value and the dtd arrays +	SDPDBG(""); + +	memset(&buf, 0, sizeof(sdp_buf_t)); +	buf.data = malloc(256); +	buf.buf_size = 256; + +	if (!buf.data) +		return -ENOMEM; + +	SDPDBG("Seq length : %d\n", seqlen); + +	types = malloc(seqlen * sizeof(void *)); +	values = malloc(seqlen * sizeof(void *)); +	for (i = 0; i < seqlen; i++) { +		void *data = seq->data; +		types[i] = &dtd; +		if (SDP_IS_UUID(dtd)) +			data = &((uuid_t *)data)->value; +		values[i] = data; +		seq = seq->next; +	} + +	dataseq = sdp_seq_alloc(types, values, seqlen); +	SDPDBG("Data Seq : 0x%p\n", seq); +	seqlen = sdp_gen_pdu(&buf, dataseq); +	SDPDBG("Copying : %d\n", buf.data_size); +	memcpy(dst, buf.data, buf.data_size); + +	sdp_data_free(dataseq); + +	free(types); +	free(values); +	free(buf.data); +	return seqlen; +} + +static int gen_searchseq_pdu(uint8_t *dst, const sdp_list_t *seq) +{ +	uuid_t *uuid = (uuid_t *) seq->data; +	return gen_dataseq_pdu(dst, seq, uuid->type); +} + +static int gen_attridseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dataType) +{ +	return gen_dataseq_pdu(dst, seq, dataType); +} + +typedef struct { +	uint8_t length; +	unsigned char data[16]; +} __attribute__ ((packed)) sdp_cstate_t; + +static int copy_cstate(uint8_t *pdata, int pdata_len, const sdp_cstate_t *cstate) +{ +	if (cstate) { +		uint8_t len = cstate->length; +		if (len >= pdata_len) { +			SDPERR("Continuation state size exceeds internal buffer"); +			len = pdata_len - 1; +		} +		*pdata++ = len; +		memcpy(pdata, cstate->data, len); +		return len + 1; +	} +	*pdata = 0; +	return 1; +} + +/* + * This is a service search request.  + * + * INPUT : + * + *   sdp_list_t *search + *     Singly linked list containing elements of the search + *     pattern. Each entry in the list is a UUID (DataTypeSDP_UUID16) + *     of the service to be searched + * + *   uint16_t max_rec_num + *      A 16 bit integer which tells the service, the maximum + *      entries that the client can handle in the response. The + *      server is obliged not to return > max_rec_num entries + * + * OUTPUT : + * + *   int return value + *     0: + *       The request completed successfully. This does not + *       mean the requested services were found + *     -1: + *       On any failure and sets errno + * + *   sdp_list_t **rsp_list + *     This variable is set on a successful return if there are + *     non-zero service handles. It is a singly linked list of + *     service record handles (uint16_t) + */ +int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search, +			uint16_t max_rec_num, sdp_list_t **rsp) +{ +	int status = 0; +	uint32_t reqsize = 0, _reqsize; +	uint32_t rspsize = 0, rsplen; +	int seqlen = 0; +	int scanned, total_rec_count, rec_count, pdata_len; +	uint8_t *pdata, *_pdata; +	uint8_t *reqbuf, *rspbuf; +	sdp_pdu_hdr_t *reqhdr, *rsphdr; +	sdp_cstate_t *cstate = NULL; + +	reqbuf = malloc(SDP_REQ_BUFFER_SIZE); +	rspbuf = malloc(SDP_RSP_BUFFER_SIZE); +	if (!reqbuf || !rspbuf) { +		errno = ENOMEM; +		status = -1; +		goto end; +	} +	reqhdr = (sdp_pdu_hdr_t *) reqbuf; +	reqhdr->pdu_id = SDP_SVC_SEARCH_REQ; +	pdata = reqbuf + sizeof(sdp_pdu_hdr_t); +	reqsize = sizeof(sdp_pdu_hdr_t); + +	// add service class IDs for search +	seqlen = gen_searchseq_pdu(pdata, search); + +	SDPDBG("Data seq added : %d\n", seqlen); + +	// set the length and increment the pointer +	reqsize += seqlen; +	pdata += seqlen; + +	// specify the maximum svc rec count that client expects +	bt_put_unaligned(htons(max_rec_num), (uint16_t *) pdata); +	reqsize += sizeof(uint16_t); +	pdata += sizeof(uint16_t); + +	_reqsize = reqsize; +	_pdata   = pdata; +	*rsp = NULL; + +	do { +		// Add continuation state or NULL (first time) +		reqsize = _reqsize + copy_cstate(_pdata, +					SDP_REQ_BUFFER_SIZE - _reqsize, cstate); + +		// Set the request header's param length +		reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t)); + +		reqhdr->tid  = htons(sdp_gen_tid(session)); +		/* +		 * Send the request, wait for response and if +		 * no error, set the appropriate values and return +		 */ +		status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize); +		if (status < 0) +			goto end; + +		if (rspsize < sizeof(sdp_pdu_hdr_t)) { +			SDPERR("Unexpected end of packet"); +			status = -1; +			goto end; +		} + +		rsphdr = (sdp_pdu_hdr_t *) rspbuf; +		rsplen = ntohs(rsphdr->plen); + +		if (rsphdr->pdu_id == SDP_ERROR_RSP) { +			SDPDBG("Status : 0x%x\n", rsphdr->pdu_id); +			status = -1; +			goto end; +		} +		scanned = 0; +		pdata = rspbuf + sizeof(sdp_pdu_hdr_t); +		pdata_len = rspsize - sizeof(sdp_pdu_hdr_t); + +		if (pdata_len < sizeof(uint16_t) + sizeof(uint16_t)) { +			SDPERR("Unexpected end of packet"); +			status = -1; +			goto end; +		} + +		// net service record match count +		total_rec_count = ntohs(bt_get_unaligned((uint16_t *) pdata)); +		pdata += sizeof(uint16_t); +		scanned += sizeof(uint16_t); +		pdata_len -= sizeof(uint16_t); +		rec_count = ntohs(bt_get_unaligned((uint16_t *) pdata)); +		pdata += sizeof(uint16_t); +		scanned += sizeof(uint16_t); +		pdata_len -= sizeof(uint16_t); + +		SDPDBG("Total svc count: %d\n", total_rec_count); +		SDPDBG("Current svc count: %d\n", rec_count); +		SDPDBG("ResponseLength: %d\n", rsplen); + +		if (!rec_count) { +			status = -1; +			goto end; +		} +		extract_record_handle_seq(pdata, pdata_len, rsp, rec_count, &scanned); +		SDPDBG("BytesScanned : %d\n", scanned); + +		if (rsplen > scanned) { +			uint8_t cstate_len; + +			if (rspsize < sizeof(sdp_pdu_hdr_t) + scanned + sizeof(uint8_t)) { +				SDPERR("Unexpected end of packet: continuation state data missing"); +				status = -1; +				goto end; +			} + +			pdata = rspbuf + sizeof(sdp_pdu_hdr_t) + scanned; +			cstate_len = *(uint8_t *) pdata; +			if (cstate_len > 0) { +				cstate = (sdp_cstate_t *)pdata; +				SDPDBG("Cont state length: %d\n", cstate_len); +			} else +				cstate = NULL; +		} +	} while (cstate); + +end: +	if (reqbuf) +		free(reqbuf); +	if (rspbuf) +		free(rspbuf); + +	return status; +} + +/* + * This is a service attribute request.  + * + * INPUT : + * + *   uint32_t handle + *     The handle of the service for which the attribute(s) are + *     requested + * + *   sdp_attrreq_type_t reqtype + *     Attribute identifiers are 16 bit unsigned integers specified + *     in one of 2 ways described below : + *     SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers + *        They are the actual attribute identifiers in ascending order + * + *     SDP_ATTR_REQ_RANGE - 32bit identifier range + *        The high-order 16bits is the start of range + *        the low-order 16bits are the end of range + *        0x0000 to 0xFFFF gets all attributes + * + *   sdp_list_t *attrid + *     Singly linked list containing attribute identifiers desired. + *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)   + *     or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE) + * + * OUTPUT : + *   return sdp_record_t * + *     0: + *       On any error and sets errno + *     !0: + *	 The service record + */ +sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,  +			sdp_attrreq_type_t reqtype, const sdp_list_t *attrids) +{ +	int status = 0; +	uint32_t reqsize = 0, _reqsize; +	uint32_t rspsize = 0, rsp_count; +	int attr_list_len = 0; +	int seqlen = 0, pdata_len; +	uint8_t *pdata, *_pdata; +	uint8_t *reqbuf, *rspbuf; +	sdp_pdu_hdr_t *reqhdr, *rsphdr; +	sdp_cstate_t *cstate = NULL; +	uint8_t cstate_len = 0; +	sdp_buf_t rsp_concat_buf; +	sdp_record_t *rec = 0; + +	if (reqtype != SDP_ATTR_REQ_INDIVIDUAL && reqtype != SDP_ATTR_REQ_RANGE) { +		errno = EINVAL; +		return 0; +	} + +	reqbuf = malloc(SDP_REQ_BUFFER_SIZE); +	rspbuf = malloc(SDP_RSP_BUFFER_SIZE); +	if (!reqbuf || !rspbuf) { +		errno = ENOMEM; +		status = -1; +		goto end; +	} +	memset((char *) &rsp_concat_buf, 0, sizeof(sdp_buf_t)); +	reqhdr = (sdp_pdu_hdr_t *) reqbuf; +	reqhdr->pdu_id = SDP_SVC_ATTR_REQ; + +	pdata = reqbuf + sizeof(sdp_pdu_hdr_t); +	reqsize = sizeof(sdp_pdu_hdr_t); + +	// add the service record handle +	bt_put_unaligned(htonl(handle), (uint32_t *) pdata); +	reqsize += sizeof(uint32_t); +	pdata += sizeof(uint32_t); + +	// specify the response limit +	bt_put_unaligned(htons(65535), (uint16_t *) pdata); +	reqsize += sizeof(uint16_t); +	pdata += sizeof(uint16_t); + +	// get attr seq PDU form +	seqlen = gen_attridseq_pdu(pdata, attrids,  +		reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32); +	if (seqlen == -1) { +		errno = EINVAL; +		status = -1; +		goto end; +	} +	pdata += seqlen; +	reqsize += seqlen; +	SDPDBG("Attr list length : %d\n", seqlen); + +	// save before Continuation State +	_pdata = pdata; +	_reqsize = reqsize; + +	do { +		// add NULL continuation state +		reqsize = _reqsize + copy_cstate(_pdata, +					SDP_REQ_BUFFER_SIZE - _reqsize, cstate); + +		// set the request header's param length +		reqhdr->tid  = htons(sdp_gen_tid(session)); +		reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t)); + +		status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize); +		if (status < 0) +			goto end; + +		if (rspsize < sizeof(sdp_pdu_hdr_t)) { +			SDPERR("Unexpected end of packet"); +			status = -1; +			goto end; +		} + +		rsp_count = 0; +		rsphdr = (sdp_pdu_hdr_t *) rspbuf; +		if (rsphdr->pdu_id == SDP_ERROR_RSP) { +			SDPDBG("PDU ID : 0x%x\n", rsphdr->pdu_id); +			status = -1; +			goto end; +		} +		pdata = rspbuf + sizeof(sdp_pdu_hdr_t); +		pdata_len = rspsize - sizeof(sdp_pdu_hdr_t); + +		if (pdata_len < sizeof(uint16_t)) { +			SDPERR("Unexpected end of packet"); +			status = -1; +			goto end; +		} + +		rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata)); +		attr_list_len += rsp_count; +		pdata += sizeof(uint16_t); +		pdata_len -= sizeof(uint16_t); + +		// if continuation state set need to re-issue request before parsing +		if (pdata_len < rsp_count + sizeof(uint8_t)) { +			SDPERR("Unexpected end of packet: continuation state data missing"); +			status = -1; +			goto end; +		} +		cstate_len = *(uint8_t *) (pdata + rsp_count); + +		SDPDBG("Response id : %d\n", rsphdr->pdu_id); +		SDPDBG("Attrlist byte count : %d\n", rsp_count); +		SDPDBG("sdp_cstate_t length : %d\n", cstate_len); + +		/* +		 * a split response: concatenate intermediate responses  +		 * and the last one (which has cstate_len == 0) +		 */ +		if (cstate_len > 0 || rsp_concat_buf.data_size != 0) { +			uint8_t *targetPtr = NULL; + +			cstate = cstate_len > 0 ? (sdp_cstate_t *) (pdata + rsp_count) : 0; + +			// build concatenated response buffer +			rsp_concat_buf.data = realloc(rsp_concat_buf.data, rsp_concat_buf.data_size + rsp_count); +			rsp_concat_buf.buf_size = rsp_concat_buf.data_size + rsp_count; +			targetPtr = rsp_concat_buf.data + rsp_concat_buf.data_size; +			memcpy(targetPtr, pdata, rsp_count); +			rsp_concat_buf.data_size += rsp_count; +		} +	} while (cstate); + +	if (attr_list_len > 0) { +		int scanned = 0; +		if (rsp_concat_buf.data_size != 0) { +			pdata = rsp_concat_buf.data; +			pdata_len = rsp_concat_buf.data_size; +		} +		rec = sdp_extract_pdu_safe(pdata, pdata_len, &scanned); + +		if (!rec) +			status = -1; +	} +	 +end: +	if (reqbuf) +		free(reqbuf); +	if (rsp_concat_buf.data) +		free(rsp_concat_buf.data); +	if (rspbuf) +		free(rspbuf); +	return rec; +} + +/* + * SDP transaction structure for asynchronous search + */ +struct sdp_transaction { +	sdp_callback_t *cb;	/* called when the transaction finishes */ +	void *udata;		/* client user data */ +	uint8_t *reqbuf;	/* pointer to request PDU */ +	sdp_buf_t rsp_concat_buf; +	uint32_t reqsize;	/* without cstate */ +	int err;		/* ZERO if success or the errno if failed */ +}; + +/* + * Creates a new sdp session for asynchronous search + * INPUT: + *  int sk + *     non-blocking L2CAP socket + * + * RETURN: + *  sdp_session_t * + *  NULL - On memory allocation failure + */ +sdp_session_t *sdp_create(int sk, uint32_t flags) +{ +	sdp_session_t *session; +	struct sdp_transaction *t; + +	session = malloc(sizeof(sdp_session_t)); +	if (!session) { +		errno = ENOMEM; +		return NULL; +	} +	memset(session, 0, sizeof(*session)); + +	session->flags = flags; +	session->sock = sk; + +	t = malloc(sizeof(struct sdp_transaction)); +	if (!t) { +		errno = ENOMEM; +		free(session); +		return NULL; +	} +	memset(t, 0, sizeof(*t)); + +	session->priv = t; + +	return session; +} + +/* + * Sets the callback function/user data used to notify the application + * that the asynchronous transaction finished. This function must be + * called before request an asynchronous search. + * + * INPUT: + *  sdp_session_t *session + *	Current sdp session to be handled + *  sdp_callback_t *cb + *      callback to be called when the transaction finishes + *  void *udata + *      user data passed to callback + * RETURN: + * 	 0 - Success + * 	-1 - Failure + */ +int sdp_set_notify(sdp_session_t *session, sdp_callback_t *func, void *udata) +{ +	struct sdp_transaction *t; + +	if (!session || !session->priv) +		return -1; + +	t = session->priv; +	t->cb = func; +	t->udata = udata; + +	return 0; +} + +/* + * This function starts an asynchronous service search request. + * The incomming and outgoing data are stored in the transaction structure  + * buffers. When there is incomming data the sdp_process function must be + * called to get the data and handle the continuation state. + * + * INPUT : + *  sdp_session_t *session + *     Current sdp session to be handled + * + *   sdp_list_t *search + *     Singly linked list containing elements of the search + *     pattern. Each entry in the list is a UUID (DataTypeSDP_UUID16) + *     of the service to be searched + * + *   uint16_t max_rec_num + *      A 16 bit integer which tells the service, the maximum + *      entries that the client can handle in the response. The + *      server is obliged not to return > max_rec_num entries + * + * OUTPUT : + * + *   int return value + * 	0  - if the request has been sent properly + * 	-1 - On any failure and sets errno + */ + +int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num) +{ +	struct sdp_transaction *t; +	sdp_pdu_hdr_t *reqhdr; +	uint8_t *pdata; +	int cstate_len, seqlen = 0; + +	if (!session || !session->priv) +		return -1; + +	t = session->priv; + +	/* check if the buffer is already allocated */ +	if (t->rsp_concat_buf.data) +		free(t->rsp_concat_buf.data); +	memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t)); + +	if (!t->reqbuf) { +		t->reqbuf = malloc(SDP_REQ_BUFFER_SIZE); +		if (!t->reqbuf) { +			t->err = ENOMEM; +			goto end; +		} +	} +	memset(t->reqbuf, 0, SDP_REQ_BUFFER_SIZE); + +	reqhdr = (sdp_pdu_hdr_t *) t->reqbuf; +	reqhdr->tid = htons(sdp_gen_tid(session)); +	reqhdr->pdu_id = SDP_SVC_SEARCH_REQ; + +	// generate PDU +	pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t); +	t->reqsize = sizeof(sdp_pdu_hdr_t); + +	// add service class IDs for search +	seqlen = gen_searchseq_pdu(pdata, search); + +	SDPDBG("Data seq added : %d\n", seqlen); + +	// now set the length and increment the pointer +	t->reqsize += seqlen; +	pdata += seqlen; + +	bt_put_unaligned(htons(max_rec_num), (uint16_t *) pdata); +	t->reqsize += sizeof(uint16_t); +	pdata += sizeof(uint16_t); + +	// set the request header's param length +	cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL); +	reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t)); + +	if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) { +		SDPERR("Error sendind data:%s", strerror(errno)); +		t->err = errno; +		goto end; +	} + +	return 0; +end: + +	if (t->reqbuf) { +		free(t->reqbuf); +		t->reqbuf = NULL; +	} + +	return -1; +} + +/* + * This function starts an asynchronous service attribute request. + * The incomming and outgoing data are stored in the transaction structure  + * buffers. When there is incomming data the sdp_process function must be + * called to get the data and handle the continuation state. + * + * INPUT : + *  sdp_session_t *session + *	Current sdp session to be handled + * + *   uint32_t handle + *     The handle of the service for which the attribute(s) are + *     requested + * + *   sdp_attrreq_type_t reqtype + *     Attribute identifiers are 16 bit unsigned integers specified + *     in one of 2 ways described below : + *     SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers + *        They are the actual attribute identifiers in ascending order + * + *     SDP_ATTR_REQ_RANGE - 32bit identifier range + *        The high-order 16bits is the start of range + *        the low-order 16bits are the end of range + *        0x0000 to 0xFFFF gets all attributes + * + *   sdp_list_t *attrid_list + *     Singly linked list containing attribute identifiers desired. + *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)   + *     or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE) + * + * OUTPUT : + *   int return value + * 	 0 - if the request has been sent properly + * 	-1 - On any failure and sets errno + */ + +int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list) +{ +	struct sdp_transaction *t; +	sdp_pdu_hdr_t *reqhdr; +	uint8_t *pdata; +	int cstate_len, seqlen = 0; + +	if (!session || !session->priv) +		return -1; + +	t = session->priv; + +	/* check if the buffer is already allocated */ +	if (t->rsp_concat_buf.data) +		free(t->rsp_concat_buf.data); +	memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t)); + +	if (!t->reqbuf) { +		t->reqbuf = malloc(SDP_REQ_BUFFER_SIZE); +		if (!t->reqbuf) { +			t->err = ENOMEM; +			goto end; +		} +	} +	memset(t->reqbuf, 0, SDP_REQ_BUFFER_SIZE); + +	reqhdr = (sdp_pdu_hdr_t *) t->reqbuf; +	reqhdr->tid = htons(sdp_gen_tid(session)); +	reqhdr->pdu_id = SDP_SVC_ATTR_REQ; + +	// generate PDU +	pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t); +	t->reqsize = sizeof(sdp_pdu_hdr_t); + +	// add the service record handle +	bt_put_unaligned(htonl(handle), (uint32_t *) pdata); +	t->reqsize += sizeof(uint32_t); +	pdata += sizeof(uint32_t); + +	// specify the response limit +	bt_put_unaligned(htons(65535), (uint16_t *) pdata); +	t->reqsize += sizeof(uint16_t); +	pdata += sizeof(uint16_t); + +	// get attr seq PDU form +	seqlen = gen_attridseq_pdu(pdata, attrid_list, +			reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32); +	if (seqlen == -1) { +		t->err = EINVAL; +		goto end; +	} + +	// now set the length and increment the pointer +	t->reqsize += seqlen; +	pdata += seqlen; +	SDPDBG("Attr list length : %d\n", seqlen); + +	// set the request header's param length +	cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL); +	reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t)); + +	if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) { +		SDPERR("Error sendind data:%s", strerror(errno)); +		t->err = errno; +		goto end; +	} + +	return 0; +end: + +	if (t->reqbuf) { +		free(t->reqbuf); +		t->reqbuf = NULL; +	} + +	return -1; +} + +/* + * This function starts an asynchronous service search attributes. + * It is a service search request combined with attribute request. The incomming + * and outgoing data are stored in the transaction structure buffers. When there + * is incomming data the sdp_process function must be called to get the data + * and handle the continuation state. + * + * INPUT: + *  sdp_session_t *session + *	Current sdp session to be handled + * + *   sdp_list_t *search + *     Singly linked list containing elements of the search + *     pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16) + *     of the service to be searched + * + *   AttributeSpecification attrSpec + *     Attribute identifiers are 16 bit unsigned integers specified + *     in one of 2 ways described below : + *     SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers + *        They are the actual attribute identifiers in ascending order + * + *     SDP_ATTR_REQ_RANGE - 32bit identifier range + *        The high-order 16bits is the start of range + *        the low-order 16bits are the end of range + *        0x0000 to 0xFFFF gets all attributes + * + *   sdp_list_t *attrid_list + *     Singly linked list containing attribute identifiers desired. + *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)   + *     or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE) + * + + * RETURN: + * 	 0 - if the request has been sent properly + * 	-1 - On any failure + */ +int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list) +{ +	struct sdp_transaction *t; +	sdp_pdu_hdr_t *reqhdr; +	uint8_t *pdata; +	int cstate_len, seqlen = 0; + +	if (!session || !session->priv) +		return -1; + +	t = session->priv; + +	/* check if the buffer is already allocated */ +	if (t->rsp_concat_buf.data) +		free(t->rsp_concat_buf.data); +	memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t)); + +	if (!t->reqbuf) { +		t->reqbuf = malloc(SDP_REQ_BUFFER_SIZE); +		if (!t->reqbuf) { +			t->err = ENOMEM; +			goto end; +		} +	} +	memset(t->reqbuf, 0, SDP_REQ_BUFFER_SIZE); + +	reqhdr = (sdp_pdu_hdr_t *) t->reqbuf; +	reqhdr->tid = htons(sdp_gen_tid(session)); +	reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ; + +	// generate PDU +	pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t); +	t->reqsize = sizeof(sdp_pdu_hdr_t); + +	// add service class IDs for search +	seqlen = gen_searchseq_pdu(pdata, search); + +	SDPDBG("Data seq added : %d\n", seqlen); + +	// now set the length and increment the pointer +	t->reqsize += seqlen; +	pdata += seqlen; + +	bt_put_unaligned(htons(SDP_MAX_ATTR_LEN), (uint16_t *) pdata); +	t->reqsize += sizeof(uint16_t); +	pdata += sizeof(uint16_t); + +	SDPDBG("Max attr byte count : %d\n", SDP_MAX_ATTR_LEN); + +	// get attr seq PDU form +	seqlen = gen_attridseq_pdu(pdata, attrid_list, +			reqtype == SDP_ATTR_REQ_INDIVIDUAL ? SDP_UINT16 : SDP_UINT32); +	if (seqlen == -1) { +		t->err = EINVAL; +		goto end; +	} + +	pdata += seqlen; +	SDPDBG("Attr list length : %d\n", seqlen); +	t->reqsize += seqlen; + +	// set the request header's param length +	cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL); +	reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t)); + +	if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) { +		SDPERR("Error sendind data:%s", strerror(errno)); +		t->err = errno; +		goto end; +	} + +	return 0; +end: + +	if (t->reqbuf) { +		free(t->reqbuf); +		t->reqbuf = NULL; +	} + +	return -1; +} + +/* + * Function used to get the error reason after sdp_callback_t function has been called + * and the status is 0xffff or if sdp_service_{search, attr, search_attr}_async returns -1. + * It indicates that an error NOT related to SDP_ErrorResponse happened. Get errno directly + * is not safe because multiple transactions can be triggered. + * This function must be used with asynchronous sdp functions only. + * + * INPUT: + *  sdp_session_t *session + *	Current sdp session to be handled + * RETURN: + * 	 0 = No error in the current transaction + * 	-1 - if the session is invalid + * 	positive value - the errno value + * + */ +int sdp_get_error(sdp_session_t *session) +{ +	struct sdp_transaction *t; + +	if (!session || !session->priv) { +		SDPERR("Invalid session"); +		return -1; +	} + +	t = session->priv; + +	return t->err; +} + +/* + * Receive the incomming SDP PDU. This function must be called when there is data + * available to be read. On continuation state, the original request (with a new + * transaction ID) and the continuation state data will be appended in the initial PDU. + * If an error happens or the transaction finishes the callback function will be called. + * + * INPUT: + *  sdp_session_t *session + *	Current sdp session to be handled + * RETURN: + * 	0  - if the transaction is on continuation state + * 	-1 - On any failure or the transaction finished + */ +int sdp_process(sdp_session_t *session) +{ +	struct sdp_transaction *t; +	sdp_pdu_hdr_t *reqhdr, *rsphdr; +	sdp_cstate_t *pcstate; +	uint8_t *pdata, *rspbuf, *targetPtr; +	int rsp_count, err = -1; +	size_t size = 0; +	int n, plen; +	uint16_t status = 0xffff; +	uint8_t pdu_id = 0x00; + +	if (!session || !session->priv) { +		SDPERR("Invalid session"); +		return -1; +	} + +	rspbuf = malloc(SDP_RSP_BUFFER_SIZE); +	if (!rspbuf) { +		SDPERR("Response buffer alloc failure:%s (%d)", +				strerror(errno), errno); +		return -1; +	} + +	memset(rspbuf, 0, SDP_RSP_BUFFER_SIZE); + +	t = session->priv; +	reqhdr = (sdp_pdu_hdr_t *)t->reqbuf; +	rsphdr = (sdp_pdu_hdr_t *)rspbuf; + +	pdata = rspbuf + sizeof(sdp_pdu_hdr_t); + +	n = sdp_read_rsp(session, rspbuf, SDP_RSP_BUFFER_SIZE); +	if (n < 0) { +		SDPERR("Read response:%s (%d)", strerror(errno), errno); +		t->err = errno; +		goto end; +	} + +	if (n == 0 || reqhdr->tid != rsphdr->tid || +		(n != (ntohs(rsphdr->plen) + sizeof(sdp_pdu_hdr_t)))) { +		t->err = EPROTO; +		SDPERR("Protocol error."); +		goto end; +	} + +	pdu_id = rsphdr->pdu_id; +	switch (rsphdr->pdu_id) { +	uint8_t *ssr_pdata; +	uint16_t tsrc, csrc; +	case SDP_SVC_SEARCH_RSP: +		/* +		 * TSRC: Total Service Record Count (2 bytes) +		 * CSRC: Current Service Record Count (2 bytes) +		 */ +		ssr_pdata = pdata; +		tsrc = ntohs(bt_get_unaligned((uint16_t *) ssr_pdata)); +		ssr_pdata += sizeof(uint16_t); +		csrc = ntohs(bt_get_unaligned((uint16_t *) ssr_pdata)); + +		/* csrc should never be larger than tsrc */ +		if (csrc > tsrc) { +			t->err = EPROTO; +			SDPERR("Protocol error: wrong current service record count value."); +			goto end; +		} + +		SDPDBG("Total svc count: %d\n", tsrc); +		SDPDBG("Current svc count: %d\n", csrc); + +		/* parameter length without continuation state */ +		plen = sizeof(tsrc) + sizeof(csrc) + csrc * 4; + +		if (t->rsp_concat_buf.data_size == 0) { +			/* first fragment */ +			rsp_count = sizeof(tsrc) + sizeof(csrc) + csrc * 4; +		} else { +			/* point to the first csrc */ +			uint16_t *pcsrc = (uint16_t *) (t->rsp_concat_buf.data + 2); + +			/* FIXME: update the interface later. csrc doesn't need be passed to clients */ + +			pdata += sizeof(uint16_t); /* point to csrc */ + +			/* the first csrc contains the sum of partial csrc responses */ +			*pcsrc += bt_get_unaligned((uint16_t *) pdata);  + +			pdata += sizeof(uint16_t); /* point to the first handle */ +			rsp_count = csrc * 4; +		} +		status = 0x0000; +		break; +	case SDP_SVC_ATTR_RSP: +	case SDP_SVC_SEARCH_ATTR_RSP: +		rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata)); +		SDPDBG("Attrlist byte count : %d\n", rsp_count); +	 +		/*  +		 * Number of bytes in the AttributeLists parameter(without +		 * continuation state) + AttributeListsByteCount field size. +		 */ +		plen = sizeof(uint16_t) + rsp_count; + +		pdata += sizeof(uint16_t); // points to attribute list +		status = 0x0000; +		break; +	case SDP_ERROR_RSP: +		status = ntohs(bt_get_unaligned((uint16_t *) pdata)); +		size = ntohs(rsphdr->plen); + +		/* error code + error info */ +		plen = size; +		goto end; +	default: +		t->err = EPROTO; +		SDPERR("Illegal PDU ID: 0x%x", rsphdr->pdu_id); +		goto end; +	} + +	pcstate = (sdp_cstate_t *) (pdata + rsp_count); + +	SDPDBG("Cstate length : %d\n", pcstate->length); + +	/*  +	 * Check out of bound. Continuation state must have at least +	 * 1 byte: ZERO to indicate that it is not a partial response. +	 */ +	if ((n - sizeof(sdp_pdu_hdr_t))  != (plen + pcstate->length + 1)) { +		t->err = EPROTO; +		SDPERR("Protocol error: wrong PDU size."); +		status = 0xffff; +		goto end; +	} + +	/* +	 * This is a split response, need to concatenate intermediate +	 * responses and the last one which will have cstate length == 0 +	 */ +	t->rsp_concat_buf.data = realloc(t->rsp_concat_buf.data, t->rsp_concat_buf.data_size + rsp_count); +	targetPtr = t->rsp_concat_buf.data + t->rsp_concat_buf.data_size; +	t->rsp_concat_buf.buf_size = t->rsp_concat_buf.data_size + rsp_count; +	memcpy(targetPtr, pdata, rsp_count); +	t->rsp_concat_buf.data_size += rsp_count; + +	if (pcstate->length > 0) { +		int reqsize, cstate_len; + +		reqhdr->tid = htons(sdp_gen_tid(session)); + +		// add continuation state +		cstate_len = copy_cstate(t->reqbuf + t->reqsize, +				SDP_REQ_BUFFER_SIZE - t->reqsize, pcstate); + +		reqsize = t->reqsize + cstate_len; + +		// set the request header's param length +		reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t)); +	 +		if (sdp_send_req(session, t->reqbuf, reqsize) < 0) { +			SDPERR("Error sendind data:%s(%d)", strerror(errno), errno); +			status = 0xffff; +			t->err = errno; +			goto end; +		} +		err = 0; +	} + +end: +	if (err) { +		if (t->rsp_concat_buf.data_size != 0) { +			pdata = t->rsp_concat_buf.data; +			size = t->rsp_concat_buf.data_size; +		} +		if (t->cb) +			t->cb(pdu_id, status, pdata, size, t->udata); +	} + +	if (rspbuf) +		free(rspbuf); + +	return err; +} + +/* + * This is a service search request combined with the service + * attribute request. First a service class match is done and + * for matching service, requested attributes are extracted + * + * INPUT : + * + *   sdp_list_t *search + *     Singly linked list containing elements of the search + *     pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16) + *     of the service to be searched + * + *   AttributeSpecification attrSpec + *     Attribute identifiers are 16 bit unsigned integers specified + *     in one of 2 ways described below : + *     SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers + *        They are the actual attribute identifiers in ascending order + * + *     SDP_ATTR_REQ_RANGE - 32bit identifier range + *        The high-order 16bits is the start of range + *        the low-order 16bits are the end of range + *        0x0000 to 0xFFFF gets all attributes + * + *   sdp_list_t *attrids + *     Singly linked list containing attribute identifiers desired. + *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)   + *     or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE) + * + * OUTPUT : + *   int return value + *     0: + *       The request completed successfully. This does not + *       mean the requested services were found + *     -1: + *       On any error and sets errno + * + *   sdp_list_t **rsp + *     This variable is set on a successful return to point to + *     service(s) found. Each element of this list is of type + *     sdp_record_t* (of the services which matched the search list) + */ +int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrids, sdp_list_t **rsp) +{ +	int status = 0; +	uint32_t reqsize = 0, _reqsize; +	uint32_t rspsize = 0; +	int seqlen = 0, attr_list_len = 0; +	int rsp_count = 0, cstate_len = 0, pdata_len; +	uint8_t *pdata, *_pdata; +	uint8_t *reqbuf, *rspbuf; +	sdp_pdu_hdr_t *reqhdr, *rsphdr; +	uint8_t dataType; +	sdp_list_t *rec_list = NULL; +	sdp_buf_t rsp_concat_buf; +	sdp_cstate_t *cstate = NULL; + +	if (reqtype != SDP_ATTR_REQ_INDIVIDUAL && reqtype != SDP_ATTR_REQ_RANGE) { +		errno = EINVAL; +		return -1; +	} +	reqbuf = malloc(SDP_REQ_BUFFER_SIZE); +	rspbuf = malloc(SDP_RSP_BUFFER_SIZE); +	if (!reqbuf || !rspbuf) { +		errno = ENOMEM; +		status = -1; +		goto end; +	} + +	memset((char *)&rsp_concat_buf, 0, sizeof(sdp_buf_t)); +	reqhdr = (sdp_pdu_hdr_t *) reqbuf; +	reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ; + +	// generate PDU +	pdata = reqbuf + sizeof(sdp_pdu_hdr_t); +	reqsize = sizeof(sdp_pdu_hdr_t); + +	// add service class IDs for search +	seqlen = gen_searchseq_pdu(pdata, search); + +	SDPDBG("Data seq added : %d\n", seqlen); + +	// now set the length and increment the pointer +	reqsize += seqlen; +	pdata += seqlen; + +	bt_put_unaligned(htons(SDP_MAX_ATTR_LEN), (uint16_t *) pdata); +	reqsize += sizeof(uint16_t); +	pdata += sizeof(uint16_t); + +	SDPDBG("Max attr byte count : %d\n", SDP_MAX_ATTR_LEN); + +	// get attr seq PDU form  +	seqlen = gen_attridseq_pdu(pdata, attrids, +		reqtype == SDP_ATTR_REQ_INDIVIDUAL ? SDP_UINT16 : SDP_UINT32); +	if (seqlen == -1) { +		status = EINVAL; +		goto end; +	} +	pdata += seqlen; +	SDPDBG("Attr list length : %d\n", seqlen); +	reqsize += seqlen; +	*rsp = 0; + +	// save before Continuation State +	_pdata = pdata; +	_reqsize = reqsize; + +	do { +		reqhdr->tid = htons(sdp_gen_tid(session)); + +		// add continuation state (can be null) +		reqsize = _reqsize + copy_cstate(_pdata, +					SDP_REQ_BUFFER_SIZE - _reqsize, cstate); + +		// set the request header's param length +		reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t)); +		rsphdr = (sdp_pdu_hdr_t *) rspbuf; +		status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize); +		if (rspsize < sizeof(sdp_pdu_hdr_t)) { +			SDPERR("Unexpected end of packet"); +			status = -1; +			goto end; +		} + +		if (status < 0) { +			SDPDBG("Status : 0x%x\n", rsphdr->pdu_id); +			goto end; +		} +	   +		if (rsphdr->pdu_id == SDP_ERROR_RSP) { +			status = -1; +			goto end; +		} +	   +		pdata = rspbuf + sizeof(sdp_pdu_hdr_t); +		pdata_len = rspsize - sizeof(sdp_pdu_hdr_t); + +		if (pdata_len < sizeof(uint16_t)) { +			SDPERR("Unexpected end of packet"); +			status = -1; +			goto end; +		} + +		rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata)); +		attr_list_len += rsp_count; +		pdata += sizeof(uint16_t);	// pdata points to attribute list +		pdata_len -= sizeof(uint16_t); + +		if (pdata_len < rsp_count + sizeof(uint8_t)) { +			SDPERR("Unexpected end of packet: continuation state data missing"); +			status = -1; +			goto end; +		} + +		cstate_len = *(uint8_t *) (pdata + rsp_count); + +		SDPDBG("Attrlist byte count : %d\n", attr_list_len); +		SDPDBG("Response byte count : %d\n", rsp_count); +		SDPDBG("Cstate length : %d\n", cstate_len); +		/* +		 * This is a split response, need to concatenate intermediate +		 * responses and the last one which will have cstate_len == 0 +		 */ +		if (cstate_len > 0 || rsp_concat_buf.data_size != 0) { +			uint8_t *targetPtr = NULL; + +			cstate = cstate_len > 0 ? (sdp_cstate_t *) (pdata + rsp_count) : 0; + +			// build concatenated response buffer +			rsp_concat_buf.data = realloc(rsp_concat_buf.data, rsp_concat_buf.data_size + rsp_count); +			targetPtr = rsp_concat_buf.data + rsp_concat_buf.data_size; +			rsp_concat_buf.buf_size = rsp_concat_buf.data_size + rsp_count; +			memcpy(targetPtr, pdata, rsp_count); +			rsp_concat_buf.data_size += rsp_count; +		} +	} while (cstate); + +	if (attr_list_len > 0) { +		int scanned = 0; + +		if (rsp_concat_buf.data_size != 0) { +			pdata = rsp_concat_buf.data; +			pdata_len = rsp_concat_buf.data_size; +		} + +		/* +		 * Response is a sequence of sequence(s) for one or +		 * more data element sequence(s) representing services +		 * for which attributes are returned +		 */ +		scanned = sdp_extract_seqtype_safe(pdata, pdata_len, &dataType, &seqlen); + +		SDPDBG("Bytes scanned : %d\n", scanned); +		SDPDBG("Seq length : %d\n", seqlen); + +		if (scanned && seqlen) { +			pdata += scanned; +			pdata_len -= scanned; +			do { +				int recsize = 0; +				sdp_record_t *rec = sdp_extract_pdu_safe(pdata, pdata_len, &recsize); +				if (rec == NULL) { +					SDPERR("SVC REC is null\n"); +					status = -1; +					goto end; +				} +				if (!recsize) { +					sdp_record_free(rec); +					break; +				} +				scanned += recsize; +				pdata += recsize; +				pdata_len -= recsize; + +				SDPDBG("Loc seq length : %d\n", recsize); +				SDPDBG("Svc Rec Handle : 0x%x\n", rec->handle); +				SDPDBG("Bytes scanned : %d\n", scanned); +				SDPDBG("Attrlist byte count : %d\n", attr_list_len); +				rec_list = sdp_list_append(rec_list, rec); +			} while (scanned < attr_list_len && pdata_len > 0); + +			SDPDBG("Successful scan of service attr lists\n"); +			*rsp = rec_list; +		} +	} +  end: +	if (rsp_concat_buf.data) +		free(rsp_concat_buf.data); +	if (reqbuf) +		free(reqbuf); +	if (rspbuf) +		free(rspbuf); +	return status; +} + +/* + * Find devices in the piconet. + */ +int sdp_general_inquiry(inquiry_info *ii, int num_dev, int duration, uint8_t *found) +{ +	int n = hci_inquiry(-1, 10, num_dev, NULL, &ii, 0); +	if (n < 0) { +		SDPERR("Inquiry failed:%s", strerror(errno)); +		return -1; +	} +	*found = n; +	return 0; +} + +int sdp_close(sdp_session_t *session) +{ +	struct sdp_transaction *t; +	int ret; +	 +	if (!session) +		return -1; + +	ret = close(session->sock); + +	t = session->priv; + +	if (t) { +		if (t->reqbuf) +			free(t->reqbuf); + +		if (t->rsp_concat_buf.data) +			free(t->rsp_concat_buf.data); + +		free(t); +	} +	free(session); +	return ret; +} + +static inline int sdp_is_local(const bdaddr_t *device) +{ +	return memcmp(device, BDADDR_LOCAL, sizeof(bdaddr_t)) == 0; +} + +static int sdp_connect_local(sdp_session_t *session) +{ +	struct sockaddr_un sa; + +	session->sock = socket(PF_UNIX, SOCK_STREAM, 0); +	if (session->sock < 0) +		return -1; +	session->local = 1; + +	sa.sun_family = AF_UNIX; +	strcpy(sa.sun_path, SDP_UNIX_PATH); + +	return connect(session->sock, (struct sockaddr *)&sa, sizeof(sa)); +} + +static int sdp_connect_l2cap(const bdaddr_t *src, +			     const bdaddr_t *dst, sdp_session_t *session) +{ +	uint32_t flags = session->flags; +	struct sockaddr_l2 sa; +	int sk; + +	session->sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); +	if (session->sock < 0) +		return -1; +	session->local = 0; + +	sk = session->sock; + +	if (flags & SDP_NON_BLOCKING) { +		long arg = fcntl(sk, F_GETFL, 0); +		fcntl(sk, F_SETFL, arg | O_NONBLOCK); +	} + +	sa.l2_family = AF_BLUETOOTH; +	sa.l2_psm = 0; + +	if (bacmp(src, BDADDR_ANY)) { +		sa.l2_bdaddr = *src; +		if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) +			return -1; +	} + +	if (flags & SDP_WAIT_ON_CLOSE) { +		struct linger l = { .l_onoff = 1, .l_linger = 1 }; +		setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)); +	} + +	sa.l2_psm = htobs(SDP_PSM); +	sa.l2_bdaddr = *dst; + +	do { +		int ret = connect(sk, (struct sockaddr *) &sa, sizeof(sa)); +		if (!ret) +			return 0; +		if (ret < 0 && (flags & SDP_NON_BLOCKING) && +		    (errno == EAGAIN || errno == EINPROGRESS)) +			return 0; +	} while (errno == EBUSY && (flags & SDP_RETRY_IF_BUSY)); + +	return -1; +} + +sdp_session_t *sdp_connect(const bdaddr_t *src, +			   const bdaddr_t *dst, uint32_t flags) +{ +	sdp_session_t *session; +	int err; + +	if ((flags & SDP_RETRY_IF_BUSY) && (flags & SDP_NON_BLOCKING)) { +		errno = EINVAL; +		return NULL; +	} + +	session = sdp_create(-1, flags); +	if (!session) +		return NULL; + +	if (sdp_is_local(dst)) { +		if (sdp_connect_local(session) < 0) +			goto fail; +	} else { +		if (sdp_connect_l2cap(src, dst, session) < 0) +			goto fail; +	} + +	return session; + +fail: +	err = errno; +	if (session->sock >= 0) +		close(session->sock); +	if (session->priv) +		free(session->priv); +	free(session); +	errno = err; + +	return NULL; +} + +int sdp_get_socket(const sdp_session_t *session) +{ +	return session->sock; +} + +uint16_t sdp_gen_tid(sdp_session_t *session) +{ +	return session->tid++; +} | 
