summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am10
-rw-r--r--src/Makefile.in353
-rw-r--r--src/bluetooth.c164
-rw-r--r--src/hci.c624
4 files changed, 1151 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 00000000..cc7b582b
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,10 @@
+#
+# $Id$
+#
+
+lib_LTLIBRARIES = libbluetooth.la
+
+libbluetooth_la_SOURCES = bluetooth.c hci.c
+libbluetooth_la_LDFLAGS = -version-info 1:0:0
+
+CFLAGS += -I../include
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 00000000..6da2db02
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,353 @@
+# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#
+# $Id$
+#
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AR = @AR@
+AS = @AS@
+CC = @CC@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+lib_LTLIBRARIES = libbluetooth.la
+
+libbluetooth_la_SOURCES = bluetooth.c hci.c
+libbluetooth_la_LDFLAGS = -version-info 1:0:0
+
+CFLAGS = -I../include
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(lib_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libbluetooth_la_LIBADD =
+libbluetooth_la_OBJECTS = bluetooth.lo hci.lo
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+DEP_FILES = .deps/bluetooth.P .deps/hci.P
+SOURCES = $(libbluetooth_la_SOURCES)
+OBJECTS = $(libbluetooth_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .lo .o .obj .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-libLTLIBRARIES:
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+
+distclean-libLTLIBRARIES:
+
+maintainer-clean-libLTLIBRARIES:
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(libdir)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo "$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p"; \
+ $(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \
+ done
+
+# FIXME: We should only use cygpath when building on Windows,
+# and only if it is available.
+.c.obj:
+ $(COMPILE) -c `cygpath -w $<`
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+ -rm -f *.$(OBJEXT)
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libbluetooth.la: $(libbluetooth_la_OBJECTS) $(libbluetooth_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(libbluetooth_la_LDFLAGS) $(libbluetooth_la_OBJECTS) $(libbluetooth_la_LIBADD) $(LIBS)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = src
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-libLTLIBRARIES
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-libLTLIBRARIES
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(libdir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-libLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-libLTLIBRARIES clean-compile clean-libtool clean-tags \
+ clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-libLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-libLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \
+clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \
+uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \
+distclean-compile clean-compile maintainer-clean-compile \
+mostlyclean-libtool distclean-libtool clean-libtool \
+maintainer-clean-libtool tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir mostlyclean-depend \
+distclean-depend clean-depend maintainer-clean-depend info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/bluetooth.c b/src/bluetooth.c
new file mode 100644
index 00000000..6dfccf44
--- /dev/null
+++ b/src/bluetooth.c
@@ -0,0 +1,164 @@
+/*
+ BlueZ - Bluetooth protocol stack for Linux
+ Copyright (C) 2000-2001 Qualcomm Incorporated
+
+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation;
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
+ SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+
+#include <bluetooth.h>
+#include <hci.h>
+
+void baswap(bdaddr_t *dst, bdaddr_t *src)
+{
+ register unsigned char * d = (unsigned char *)dst;
+ register unsigned char * s = (unsigned char *)src;
+ register int i;
+ for(i=0; i<6; i++)
+ d[i] = s[5-i];
+}
+
+char * batostr(bdaddr_t *ba)
+{
+ static char str[2][18];
+ static int i = 1;
+
+ i ^= 1;
+ sprintf(str[i], "%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[i];
+}
+
+bdaddr_t * strtoba(char *str)
+{
+ static unsigned char ba[2][sizeof(bdaddr_t)];
+ static int i = 1;
+ register char *ptr = str;
+ register int x;
+
+ i ^= 1;
+ for(x=0; x<6; x++){
+ ba[i][x] = (uint8_t) strtol(ptr, NULL, 16);
+ if( x!=5 && !(ptr=strchr(ptr,':')) )
+ ptr = ":00:00:00:00:00";
+ ptr++;
+ }
+ return (bdaddr_t *) ba[i];
+}
+
+int ba2str(bdaddr_t *ba, char *str)
+{
+ return 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]);
+}
+
+int str2ba(char *str, bdaddr_t *ba)
+{
+ unsigned char *b = (void *) ba;
+ char *ptr = str;
+ register int x;
+
+ for (x=0; x < 6; x++) {
+ b[x] = (uint8_t) strtol(ptr, NULL, 16);
+ if (x!=5 && !(ptr=strchr(ptr, ':')))
+ ptr = ":00:00:00:00:00";
+ ptr++;
+ }
+ return 0;
+}
+
+/* Bluetooth error codes to Unix errno mapping */
+int bterr(uint16_t code)
+{
+ switch(code) {
+ case 0:
+ return 0;
+ case 0x01:
+ return EBADRQC;
+ case 0x02:
+ return ENOTCONN;
+ case 0x03:
+ return EIO;
+ case 0x04:
+ return EHOSTDOWN;
+ case 0x05:
+ return EACCES;
+ case 0x06:
+ return EINVAL;
+ case 0x07:
+ return ENOMEM;
+ case 0x08:
+ return ETIMEDOUT;
+ case 0x09:
+ return EMLINK;
+ case 0x0a:
+ return EMLINK;
+ case 0x0b:
+ return EALREADY;
+ case 0x0c:
+ return EBUSY;
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ return ECONNREFUSED;
+ case 0x10:
+ return ETIMEDOUT;
+ case 0x11:
+ case 0x27:
+ case 0x29:
+ case 0x20:
+ return EOPNOTSUPP;
+ case 0x12:
+ return EINVAL;
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ return ECONNRESET;
+ case 0x16:
+ return ECONNABORTED;
+ case 0x17:
+ return ELOOP;
+ case 0x18:
+ return EACCES;
+ case 0x1a:
+ return EPROTONOSUPPORT;
+ case 0x1b:
+ return ECONNREFUSED;
+ case 0x19:
+ case 0x1e:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ return EPROTO;
+ default:
+ return ENOSYS;
+ }
+}
diff --git a/src/hci.c b/src/hci.c
new file mode 100644
index 00000000..e9693d3e
--- /dev/null
+++ b/src/hci.c
@@ -0,0 +1,624 @@
+/*
+ BlueZ - Bluetooth protocol stack for Linux
+ Copyright (C) 2000-2001 Qualcomm Incorporated
+
+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation;
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
+ SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id$
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#include <termios.h>
+#include <fcntl.h>
+
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <asm/types.h>
+
+#include <bluetooth.h>
+#include <hci.h>
+#include <hci_lib.h>
+
+typedef struct {
+ char *str; unsigned int val;
+} hci_map;
+
+static char * hci_uint2str(hci_map *m, unsigned int val)
+{
+ static char str[50];
+ char *ptr = str;
+
+ *ptr = 0;
+ while (m->str) {
+ if ((unsigned int) m->val & val)
+ ptr += sprintf(ptr, "%s ", m->str);
+ m++;
+ }
+ return str;
+}
+
+int hci_str2uint(hci_map *map, char *str, unsigned int *val)
+{
+ char *t, *ptr;
+ hci_map *m;
+ int set;
+
+ if (!str)
+ return 0;
+
+ str = ptr = strdup(str);
+ *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;
+}
+
+char *hci_dtypetostr(int type)
+{
+ switch (type) {
+ case HCI_VHCI:
+ return "VHCI";
+ case HCI_USB:
+ return "USB ";
+ case HCI_PCCARD:
+ return "PCCARD";
+ case HCI_UART:
+ return "UART";
+ default:
+ return "UKNW";
+ }
+}
+
+/* HCI dev flags mapping */
+hci_map dev_flags_map[] = {
+ { "UP", HCI_UP },
+ { "INIT", HCI_INIT },
+ { "RUNNING", HCI_RUNNING },
+ { "RAW", HCI_RAW },
+ { "PSCAN", HCI_PSCAN },
+ { "ISCAN", HCI_ISCAN },
+ { "IQUIRY", HCI_INQUIRY },
+ { "AUTH", HCI_AUTH },
+ { "ENCRYPT", HCI_ENCRYPT },
+ { NULL }
+};
+char *hci_dflagstostr(uint32_t flags)
+{
+ static char str[50];
+ char *ptr = str;
+ hci_map *m = dev_flags_map;
+
+ *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 */
+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 },
+ { NULL }
+};
+char *hci_ptypetostr(unsigned int ptype)
+{
+ return hci_uint2str(pkt_type_map, ptype);
+}
+int hci_strtoptype(char *str, unsigned int *val)
+{
+ return hci_str2uint(pkt_type_map, str, val);
+}
+
+/* Link policy mapping */
+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_uint2str(link_policy_map, lp);
+}
+int hci_strtolp(char *str, unsigned int *val)
+{
+ return hci_str2uint(link_policy_map, str, val);
+}
+
+/* Link mode mapping */
+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},
+ { NULL }
+};
+char *hci_lmtostr(unsigned int lm)
+{
+ static char str[50];
+
+ str[0] = 0;
+ if (!(lm & HCI_LM_MASTER))
+ strcpy(str, "SLAVE ");
+
+ strcat(str, hci_uint2str(link_mode_map, lm));
+ return str;
+}
+int hci_strtolm(char *str, unsigned int *val)
+{
+ return hci_str2uint(link_mode_map, str, val);
+}
+
+/* HCI functions that do not require open device */
+
+int hci_devinfo(int dev_id, struct hci_dev_info *di)
+{
+ int s, err;
+
+ s = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (s < 0)
+ return s;
+
+ di->dev_id = dev_id;
+ err = ioctl(s, HCIGETDEVINFO, (void *) di);
+ close(s);
+
+ return err;
+}
+
+inquiry_info *hci_inquiry(int dev_id, int len, int *num_rsp, uint8_t *lap, long flags)
+{
+ struct hci_inquiry_req *ir;
+ char *buf, *ptr;
+ int s, err, size;
+
+ if (!*num_rsp)
+ *num_rsp = 200; // enough ?
+
+ size = sizeof(*ir) + (sizeof(inquiry_info) * (*num_rsp));
+ if (!(buf = malloc(size)))
+ return NULL;
+
+ ir = (void *)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;
+ }
+
+ if ((s = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
+ goto failed;
+ if (ioctl(s, HCIINQUIRY, (unsigned long)buf) < 0)
+ goto failed;
+
+ size = sizeof(inquiry_info) * ir->num_rsp;
+ if (!(ptr = malloc(size)))
+ goto failed;
+
+ memcpy(ptr, buf + sizeof(*ir), size);
+ *num_rsp = ir->num_rsp;
+
+ free(buf);
+ close(s);
+ return (void *) ptr;
+
+failed:
+ err = errno;
+ free(buf);
+ close(s);
+ errno = err;
+ return NULL;
+}
+
+/* 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 */
+ 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_dev_open. */
+
+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;
+ hci_event_hdr *hdr;
+ int err, len, 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;
+
+ 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 (cs->status) {
+ errno = EIO;
+ goto failed;
+ }
+ break;
+
+ 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;
+
+ 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, bdaddr_t *ba, int ptype, int rswitch, int to)
+{
+ evt_conn_complete rp;
+ create_conn_cp cp;
+ struct hci_request rq;
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, ba);
+ cp.pkt_type = ptype;
+ cp.role_switch = rswitch;
+
+ 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;
+ }
+
+ return rp.handle;
+}
+
+int hci_disconnect(int dd, int hndl, int res, int to)
+{
+ evt_disconn_complete rp;
+ disconnect_cp cp;
+ struct hci_request rq;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.handle = hndl;
+ cp.reason = res;
+
+ 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_remote_name(int dd, bdaddr_t *ba, 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, ba);
+
+ 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, rn.name, len);
+ return 0;
+}
+
+int hci_read_remote_features(int dd, int hndl, 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 = hndl;
+
+ 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_version(int dd, int hndl, 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 = hndl;
+
+ 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_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.cparam = NULL;
+ rq.clen = 0;
+ rq.rparam = &rp;
+ rq.rlen = READ_LOCAL_VERSION_RP_SIZE;
+
+ if (hci_send_req(dd, &rq, 1000) < 0)
+ return -1;
+
+ if (rp.status) {
+ errno = EIO;
+ return -1;
+ }
+
+ ver->manufacturer = btohs(rp.manufacturer);
+ ver->hci_ver = rp.lmp_ver;
+ ver->hci_rev = btohs(rp.hci_rev);
+ ver->lmp_ver = rp.lmp_ver;
+ ver->lmp_subver = btohs(rp.lmp_subver);
+
+ return 0;
+}