Add bt_dev(3), an platform neutral API for accessing (locally configured)
Bluetooth devices, and bump libbluetooth minor version. This is a reimplementation of an API largely developed by Maksim Yevmenkin on FreeBSD to make it easier to port BlueZ/Linux programs which depend on something similar. Alas, the BlueZ/Linux API is incompatible and unportable as it depends on a 'device' being referenced by an int, but this will hopefully make it easier to port software using that. (bump libbluetooth minor version)
This commit is contained in:
parent
d90603b573
commit
bd42c2e8d0
@ -1,4 +1,4 @@
|
||||
# $NetBSD: md.amd64,v 1.61 2009/07/21 00:49:30 mrg Exp $
|
||||
# $NetBSD: md.amd64,v 1.62 2009/08/03 15:59:41 plunky Exp $
|
||||
./dev/lms0 base-obsolete obsolete
|
||||
./dev/mms0 base-obsolete obsolete
|
||||
./libexec/ld.elf_so-i386 base-sys-shlib compat,pic
|
||||
@ -58,7 +58,7 @@
|
||||
./usr/lib/i386/libbind9.so.4 base-compat-shlib compat,pic
|
||||
./usr/lib/i386/libbind9.so.4.0 base-compat-shlib compat,pic
|
||||
./usr/lib/i386/libbluetooth.so.4 base-compat-shlib compat,pic
|
||||
./usr/lib/i386/libbluetooth.so.4.1 base-compat-shlib compat,pic
|
||||
./usr/lib/i386/libbluetooth.so.4.2 base-compat-shlib compat,pic
|
||||
./usr/lib/i386/libbsdmalloc.so.0 base-compat-shlib compat,pic
|
||||
./usr/lib/i386/libbsdmalloc.so.0.0 base-compat-shlib compat,pic
|
||||
./usr/lib/i386/libbz2.so.1 base-compat-shlib compat,pic
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: md.sparc64,v 1.55 2009/07/21 00:49:30 mrg Exp $
|
||||
# $NetBSD: md.sparc64,v 1.56 2009/08/03 15:59:41 plunky Exp $
|
||||
./libexec/ld.elf_so-sparc base-sysutil-bin compat,pic
|
||||
./sbin/edlabel base-sysutil-root
|
||||
./usr/bin/fdformat base-util-bin
|
||||
@ -57,7 +57,7 @@
|
||||
./usr/lib/sparc/libbind9.so.4 base-compat-shlib compat,pic
|
||||
./usr/lib/sparc/libbind9.so.4.0 base-compat-shlib compat,pic
|
||||
./usr/lib/sparc/libbluetooth.so.4 base-compat-shlib compat,pic
|
||||
./usr/lib/sparc/libbluetooth.so.4.1 base-compat-shlib compat,pic
|
||||
./usr/lib/sparc/libbluetooth.so.4.2 base-compat-shlib compat,pic
|
||||
./usr/lib/sparc/libbsdmalloc.so.0 base-compat-shlib compat,pic
|
||||
./usr/lib/sparc/libbsdmalloc.so.0.0 base-compat-shlib compat,pic
|
||||
./usr/lib/sparc/libbz2.so.1 base-compat-shlib compat,pic
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: shl.mi,v 1.483 2009/07/21 00:49:13 mrg Exp $
|
||||
# $NetBSD: shl.mi,v 1.484 2009/08/03 15:59:41 plunky Exp $
|
||||
#
|
||||
# Note: Don't delete entries from here - mark them as "obsolete" instead,
|
||||
# unless otherwise stated below.
|
||||
@ -57,7 +57,7 @@
|
||||
./usr/lib/libasn1.so.8.0 base-krb5-shlib kerberos
|
||||
./usr/lib/libbfd.so.10.0 base-sys-shlib bfd
|
||||
./usr/lib/libbind9.so.4.0 base-bind-shlib
|
||||
./usr/lib/libbluetooth.so.4.1 base-sys-shlib
|
||||
./usr/lib/libbluetooth.so.4.2 base-sys-shlib
|
||||
./usr/lib/libbsdmalloc.so.0.0 base-sys-shlib
|
||||
./usr/lib/libbz2.so.1.1 base-sys-shlib
|
||||
./usr/lib/libc.so.12.169 base-sys-shlib
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: mi,v 1.1287 2009/07/21 14:55:32 joerg Exp $
|
||||
# $NetBSD: mi,v 1.1288 2009/08/03 15:59:41 plunky Exp $
|
||||
#
|
||||
# Note: don't delete entries from here - mark them as "obsolete" instead.
|
||||
#
|
||||
@ -4908,8 +4908,23 @@
|
||||
./usr/share/man/cat3/bswap64.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_aton.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_closeconfig.0 comp-obsolete obsolete
|
||||
./usr/share/man/cat3/bt_dev.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devaddr.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devenum.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devfilter.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devfilter_pkt_clr.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devfilter_pkt_set.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devfilter_pkt_tst.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devfilter_evt_clr.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devfilter_evt_set.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devfilter_evt_tst.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devinfo.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devname.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devopen.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devrecv.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devreq.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devsend.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_devinquiry.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_eachconfig.0 comp-obsolete obsolete
|
||||
./usr/share/man/cat3/bt_endhostent.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/bt_endprotoent.0 comp-c-catman .cat
|
||||
@ -10463,8 +10478,23 @@
|
||||
./usr/share/man/html3/bswap32.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bswap64.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_aton.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_dev.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devaddr.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devenum.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devfilter.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devfilter_pkt_clr.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devfilter_pkt_set.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devfilter_pkt_tst.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devfilter_evt_clr.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devfilter_evt_set.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devfilter_evt_tst.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devinfo.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devname.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devopen.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devrecv.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devreq.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devsend.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_devinquiry.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_endhostent.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_endprotoent.html comp-c-htmlman html
|
||||
./usr/share/man/html3/bt_gethostbyaddr.html comp-c-htmlman html
|
||||
@ -15826,8 +15856,23 @@
|
||||
./usr/share/man/man3/bswap64.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_aton.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_closeconfig.3 comp-obsolete obsolete
|
||||
./usr/share/man/man3/bt_dev.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devaddr.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devenum.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devfilter.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devfilter_pkt_clr.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devfilter_pkt_set.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devfilter_pkt_tst.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devfilter_evt_clr.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devfilter_evt_set.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devfilter_evt_tst.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devinfo.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devname.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devopen.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devrecv.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devreq.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devsend.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_devinquiry.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_eachconfig.3 comp-obsolete obsolete
|
||||
./usr/share/man/man3/bt_endhostent.3 comp-c-man .man
|
||||
./usr/share/man/man3/bt_endprotoent.3 comp-c-man .man
|
||||
|
@ -1,13 +1,13 @@
|
||||
# $NetBSD: Makefile,v 1.4 2009/05/12 10:05:06 plunky Exp $
|
||||
# $NetBSD: Makefile,v 1.5 2009/08/03 15:59:42 plunky Exp $
|
||||
|
||||
USE_FORT?= yes # network protocol library
|
||||
|
||||
LIB= bluetooth
|
||||
|
||||
SRCS= bluetooth.c devaddr.c \
|
||||
SRCS= bluetooth.c bt_dev.c \
|
||||
sdp_data.c sdp_get.c sdp_match.c sdp_put.c sdp_record.c \
|
||||
sdp_set.c sdp_uuid.c sdp_service.c sdp_session.c
|
||||
MAN= bluetooth.3 sdp.3 sdp_data.3
|
||||
MAN= bluetooth.3 bt_dev.3 sdp.3 sdp_data.3
|
||||
|
||||
CPPFLAGS+= -I${.CURDIR}
|
||||
|
||||
@ -33,8 +33,22 @@ MLINKS+= bluetooth.3 bt_endprotoent.3
|
||||
MLINKS+= bluetooth.3 bt_ntoa.3
|
||||
MLINKS+= bluetooth.3 bt_aton.3
|
||||
|
||||
MLINKS+= bluetooth.3 bt_devaddr.3
|
||||
MLINKS+= bluetooth.3 bt_devname.3
|
||||
MLINKS+= bt_dev.3 bt_devaddr.3
|
||||
MLINKS+= bt_dev.3 bt_devname.3
|
||||
MLINKS+= bt_dev.3 bt_devenum.3
|
||||
MLINKS+= bt_dev.3 bt_devinfo.3
|
||||
MLINKS+= bt_dev.3 bt_devopen.3
|
||||
MLINKS+= bt_dev.3 bt_devsend.3
|
||||
MLINKS+= bt_dev.3 bt_devrecv.3
|
||||
MLINKS+= bt_dev.3 bt_devreq.3
|
||||
MLINKS+= bt_dev.3 bt_devfilter.3
|
||||
MLINKS+= bt_dev.3 bt_devfilter_pkt_set.3
|
||||
MLINKS+= bt_dev.3 bt_devfilter_pkt_clr.3
|
||||
MLINKS+= bt_dev.3 bt_devfilter_pkt_tst.3
|
||||
MLINKS+= bt_dev.3 bt_devfilter_evt_set.3
|
||||
MLINKS+= bt_dev.3 bt_devfilter_evt_clr.3
|
||||
MLINKS+= bt_dev.3 bt_devfilter_evt_tst.3
|
||||
MLINKS+= bt_dev.3 bt_devinquiry.3
|
||||
|
||||
MLINKS+= sdp.3 sdp_open.3
|
||||
MLINKS+= sdp.3 sdp_open_local.3
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: bluetooth.3,v 1.3 2006/07/30 00:15:54 wiz Exp $
|
||||
.\" $NetBSD: bluetooth.3,v 1.4 2009/08/03 15:59:42 plunky Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
|
||||
.\" All rights reserved.
|
||||
@ -24,10 +24,9 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: bluetooth.3,v 1.3 2006/07/30 00:15:54 wiz Exp $
|
||||
.\" $FreeBSD: src/lib/libbluetooth/bluetooth.3,v 1.7 2005/01/21 10:26:11 ru Exp $
|
||||
.\"
|
||||
.Dd July 26, 2006
|
||||
.Dd August 3, 2009
|
||||
.Dt BLUETOOTH 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -43,9 +42,7 @@
|
||||
.Nm bt_endprotoent ,
|
||||
.Nm bt_aton ,
|
||||
.Nm bt_ntoa ,
|
||||
.Nm bt_devaddr ,
|
||||
.Nm bt_devname ,
|
||||
.Nd Bluetooth routines
|
||||
.Nd Bluetooth host lookup routines
|
||||
.Sh LIBRARY
|
||||
.Lb libbluetooth
|
||||
.Sh SYNOPSIS
|
||||
@ -74,10 +71,6 @@
|
||||
.Fn bt_aton "const char *str" "bdaddr_t *ba"
|
||||
.Ft const char *
|
||||
.Fn bt_ntoa "const bdaddr_t *ba" "char *str"
|
||||
.Ft int
|
||||
.Fn bt_devaddr "const char *name" "bdaddr_t *addr"
|
||||
.Ft int
|
||||
.Fn bt_devname "char *name" "const bdaddr_t *addr"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn bt_gethostent ,
|
||||
@ -194,18 +187,6 @@ takes a Bluetooth address and places an
|
||||
string representing the address into the buffer provided.
|
||||
It is up to the caller to ensure that provided buffer has enough space.
|
||||
If no buffer was provided then an internal static buffer will be used.
|
||||
.Pp
|
||||
The
|
||||
.Fn bt_devaddr
|
||||
function interprets the specified character string as the
|
||||
address or device name of a Bluetooth device on the local system, and
|
||||
places the device address in the structure provided, if any.
|
||||
It returns 1 if the string was successfully interpreted,
|
||||
or 0 if the string did not match any local device. The
|
||||
.Fn bt_devname
|
||||
function takes a Bluetooth device address and copies the local device
|
||||
name associated with that address into the buffer provided, if any.
|
||||
It returns 1 when the device was found, otherwise 0.
|
||||
.Sh FILES
|
||||
.Bl -tag -width ".Pa /etc/bluetooth/hosts" -compact
|
||||
.It Pa /etc/bluetooth/hosts
|
||||
|
@ -1,9 +1,7 @@
|
||||
/* $NetBSD: bluetooth.h,v 1.3 2006/09/26 19:18:19 plunky Exp $ */
|
||||
/* $NetBSD: bluetooth.h,v 1.4 2009/08/03 15:59:42 plunky Exp $ */
|
||||
|
||||
/*
|
||||
* bluetooth.h
|
||||
*
|
||||
* Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
|
||||
/*-
|
||||
* Copyright (c) 2001-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -27,8 +25,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: bluetooth.h,v 1.3 2006/09/26 19:18:19 plunky Exp $
|
||||
* $FreeBSD: src/lib/libbluetooth/bluetooth.h,v 1.2 2005/03/17 21:39:44 emax Exp $
|
||||
* $FreeBSD: src/lib/libbluetooth/bluetooth.h,v 1.5 2009/04/22 15:50:03 emax Exp $
|
||||
*/
|
||||
|
||||
#ifndef _BLUETOOTH_H_
|
||||
@ -37,11 +34,14 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <netbt/bluetooth.h>
|
||||
#include <netbt/hci.h>
|
||||
#include <netbt/l2cap.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
@ -64,8 +64,92 @@ void bt_endprotoent (void);
|
||||
char const * bt_ntoa (bdaddr_t const *, char *);
|
||||
int bt_aton (char const *, bdaddr_t *);
|
||||
|
||||
int bt_devaddr (const char *, bdaddr_t *);
|
||||
int bt_devname (char *, const bdaddr_t *);
|
||||
/*
|
||||
* Bluetooth device access API
|
||||
*/
|
||||
|
||||
struct bt_devinfo {
|
||||
char devname[HCI_DEVNAME_SIZE];
|
||||
int enabled; /* device is enabled */
|
||||
|
||||
/* device information */
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t features[HCI_FEATURES_SIZE];
|
||||
uint16_t acl_size; /* max ACL data size */
|
||||
uint16_t acl_pkts; /* total ACL packet buffers */
|
||||
uint16_t sco_size; /* max SCO data size */
|
||||
uint16_t sco_pkts; /* total SCO packet buffers */
|
||||
|
||||
/* flow control */
|
||||
uint16_t cmd_free; /* available CMD packet buffers */
|
||||
uint16_t acl_free; /* available ACL packet buffers */
|
||||
uint16_t sco_free; /* available SCO packet buffers */
|
||||
|
||||
/* statistics */
|
||||
uint32_t cmd_sent;
|
||||
uint32_t evnt_recv;
|
||||
uint32_t acl_recv;
|
||||
uint32_t acl_sent;
|
||||
uint32_t sco_recv;
|
||||
uint32_t sco_sent;
|
||||
uint32_t bytes_recv;
|
||||
uint32_t bytes_sent;
|
||||
|
||||
/* device settings */
|
||||
uint16_t link_policy_info;
|
||||
uint16_t packet_type_info;
|
||||
uint16_t role_switch_info;
|
||||
};
|
||||
|
||||
struct bt_devreq {
|
||||
uint16_t opcode;
|
||||
uint8_t event;
|
||||
void *cparam;
|
||||
size_t clen;
|
||||
void *rparam;
|
||||
size_t rlen;
|
||||
};
|
||||
|
||||
struct bt_devfilter {
|
||||
struct hci_filter packet_mask;
|
||||
struct hci_filter event_mask;
|
||||
};
|
||||
|
||||
struct bt_devinquiry {
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t pscan_rep_mode;
|
||||
uint8_t pscan_period_mode;
|
||||
uint8_t dev_class[3];
|
||||
uint16_t clock_offset;
|
||||
int8_t rssi;
|
||||
uint8_t data[240];
|
||||
};
|
||||
|
||||
/* bt_devopen() flags */
|
||||
#define BTOPT_DIRECTION (1 << 0)
|
||||
#define BTOPT_TIMESTAMP (1 << 1)
|
||||
|
||||
/* compatibility */
|
||||
#define bt_devclose(s) close(s)
|
||||
|
||||
typedef int (bt_devenum_cb_t)(int, const struct bt_devinfo *, void *);
|
||||
|
||||
int bt_devaddr(const char *, bdaddr_t *);
|
||||
int bt_devname(char *, const bdaddr_t *);
|
||||
int bt_devopen(const char *, int);
|
||||
ssize_t bt_devsend(int, uint16_t, void *, size_t);
|
||||
ssize_t bt_devrecv(int, void *, size_t, time_t);
|
||||
int bt_devreq(int, struct bt_devreq *, time_t);
|
||||
int bt_devfilter(int, const struct bt_devfilter *, struct bt_devfilter *);
|
||||
void bt_devfilter_pkt_set(struct bt_devfilter *, uint8_t);
|
||||
void bt_devfilter_pkt_clr(struct bt_devfilter *, uint8_t);
|
||||
int bt_devfilter_pkt_tst(const struct bt_devfilter *, uint8_t);
|
||||
void bt_devfilter_evt_set(struct bt_devfilter *, uint8_t);
|
||||
void bt_devfilter_evt_clr(struct bt_devfilter *, uint8_t);
|
||||
int bt_devfilter_evt_tst(const struct bt_devfilter *, uint8_t);
|
||||
int bt_devinquiry(const char *, time_t, int, struct bt_devinquiry **);
|
||||
int bt_devinfo(const char *, struct bt_devinfo *);
|
||||
int bt_devenum(bt_devenum_cb_t *, void *);
|
||||
|
||||
/*
|
||||
* bthcid(8) PIN Client API
|
||||
|
371
lib/libbluetooth/bt_dev.3
Normal file
371
lib/libbluetooth/bt_dev.3
Normal file
@ -0,0 +1,371 @@
|
||||
.\" $NetBSD: bt_dev.3,v 1.1 2009/08/03 15:59:42 plunky Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd August 3, 2009
|
||||
.Dt BT_DEV 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm bt_devaddr,
|
||||
.Nm bt_devname,
|
||||
.Nm bt_devenum ,
|
||||
.Nm bt_devinfo ,
|
||||
.Nm bt_devopen ,
|
||||
.Nm bt_devsend ,
|
||||
.Nm bt_devrecv ,
|
||||
.Nm bt_devreq ,
|
||||
.Nm bt_devfilter ,
|
||||
.Nm bt_devfilter_pkt_set ,
|
||||
.Nm bt_devfilter_pkt_clr ,
|
||||
.Nm bt_devfilter_pkt_tst ,
|
||||
.Nm bt_devfilter_evt_set ,
|
||||
.Nm bt_devfilter_evt_clr ,
|
||||
.Nm bt_devfilter_evt_tst ,
|
||||
.Nm bt_devinquiry ,
|
||||
.Nd Bluetooth device access routines
|
||||
.Sh LIBRARY
|
||||
.Lb libbluetooth
|
||||
.Sh SYNOPSIS
|
||||
.In bluetooth.h
|
||||
.Ft int
|
||||
.Fn bt_devaddr "const char *name" "bdaddr_t *bdaddr"
|
||||
.Ft int
|
||||
.Fn bt_devname "char *name" "const bdaddr_t *bdaddr"
|
||||
.Ft int
|
||||
.Fn bt_devenum "int (*cb)(int, const struct bt_devinfo *, void *)" "void *arg"
|
||||
.Ft int
|
||||
.Fn bt_devinfo "const char *name" "struct bt_devinfo *info"
|
||||
.Ft int
|
||||
.Fn bt_devopen "const char *name" "int flags"
|
||||
.Ft ssize_t
|
||||
.Fn bt_devsend "int s" "uint16_t opcode" "void *param" "size_t plen"
|
||||
.Ft ssize_t
|
||||
.Fn bt_devrecv "int s" "void *buf" "size_t size" "time_t timeout"
|
||||
.Ft int
|
||||
.Fn bt_devreq "int s" "struct bt_devreq *req" "time_t timeout"
|
||||
.Ft int
|
||||
.Fn bt_devfilter "int s" "const struct bt_devfilter *new" "struct bt_devfilter *old"
|
||||
.Ft void
|
||||
.Fn bt_devfilter_pkt_set "struct bt_devfilter *filter" "uint8_t type"
|
||||
.Ft void
|
||||
.Fn bt_devfilter_pkt_clr "struct bt_devfilter *filter" "uint8_t type"
|
||||
.Ft int
|
||||
.Fn bt_devfilter_pkt_tst "const struct bt_devfilter *filter" "uint8_t type"
|
||||
.Ft void
|
||||
.Fn bt_devfilter_evt_set "struct bt_devfilter *filter" "uint8_t event"
|
||||
.Ft void
|
||||
.Fn bt_devfilter_evt_clr "struct bt_devfilter *filter" "uint8_t event"
|
||||
.Ft int
|
||||
.Fn bt_devfilter_evt_tst "const struct bt_devfilter *filter" "uint8_t event"
|
||||
.Ft int
|
||||
.Fn bt_devinquiry "const char *name" "time_t timeout" "int max_rsp" "struct bt_devinquiry **iip"
|
||||
.Sh DESCRIPTION
|
||||
These routines are designed to provide access to locally configured Bluetooth
|
||||
devices in an operating system independent manner via a socket providing access
|
||||
to Bluetooth HCI packets.
|
||||
.Sh FUNCTIONS
|
||||
.Bl -tag -width 4n
|
||||
.It Fn bt_devaddr "name" "bdaddr"
|
||||
Return a Bluetooth device address.
|
||||
.Fn bt_devaddr
|
||||
will return 1 if the NUL-terminated
|
||||
.Fa name
|
||||
string refers to a Bluetooth device present in the system, otherwise 0.
|
||||
The name may be given as a device name
|
||||
.Pq eg Qo ubt0 Qc
|
||||
or Bluetooth device address
|
||||
.Pq eg Qo 00:11:22:33:44:55 Qc
|
||||
and the actual device address will be written to
|
||||
.Fa bdaddr
|
||||
if not
|
||||
.Dv NULL .
|
||||
.It Fn bt_devname "name" "bdaddr"
|
||||
Return a Bluetooth device name.
|
||||
.Fn bt_devname
|
||||
returns 1 if the
|
||||
.Fa bdaddr
|
||||
refers to a Bluetooth device present in the system, otherwise 0.
|
||||
The
|
||||
.Fa name
|
||||
buffer, if given, should have space for at least
|
||||
.Dv HCI_DEVNAME_SIZE
|
||||
bytes and the string will be NUL-terminated.
|
||||
.It Fn bt_devenum "cb" "arg"
|
||||
Enumerate Bluetooth devices present in the system.
|
||||
For each device found, the
|
||||
.Fa cb
|
||||
function
|
||||
.Pq if not Dv NULL
|
||||
will be called with the
|
||||
.Fa arg
|
||||
argument provided, a fully populated
|
||||
.Ft bt_devinfo
|
||||
structure and, where the device is enabled, a socket handle as returned by
|
||||
.Fn bt_devopen .
|
||||
The callback function can halt the enumeration by returning a
|
||||
non-zero value, and
|
||||
.Fn bt_devenum
|
||||
returns the number of successfully enumerated devices.
|
||||
.It Fn bt_devinfo "name" "info"
|
||||
Obtain information from a Bluetooth device present in the system.
|
||||
The
|
||||
.Fa info
|
||||
argument is a pointer to a
|
||||
.Ft bt_devinfo
|
||||
structure into which information about device
|
||||
.Fa name
|
||||
is placed.
|
||||
The
|
||||
.Ft bt_devinfo
|
||||
structure contains at least the following members:
|
||||
.Bd -literal
|
||||
char devname[HCI_DEVNAME_SIZE];
|
||||
int enabled; /* device is enabled */
|
||||
|
||||
/* device information */
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t features[HCI_FEATURES_SIZE];
|
||||
uint16_t acl_size; /* max ACL data size */
|
||||
uint16_t acl_pkts; /* total ACL packet buffers */
|
||||
uint16_t sco_size; /* max SCO data size */
|
||||
uint16_t sco_pkts; /* total SCO packet buffers */
|
||||
|
||||
/* flow control */
|
||||
uint16_t cmd_free; /* available CMD packet buffers */
|
||||
uint16_t acl_free; /* available ACL packet buffers */
|
||||
uint16_t sco_free; /* available ACL packet buffers */
|
||||
|
||||
/* statistics */
|
||||
uint32_t cmd_sent;
|
||||
uint32_t evnt_recv;
|
||||
uint32_t acl_recv;
|
||||
uint32_t acl_sent;
|
||||
uint32_t sco_recv;
|
||||
uint32_t sco_sent;
|
||||
uint32_t bytes_recv;
|
||||
uint32_t bytes_sent;
|
||||
|
||||
/* device settings */
|
||||
uint16_t link_policy_info;
|
||||
uint16_t packet_type_info;
|
||||
uint16_t role_switch_info;
|
||||
.Ed
|
||||
.Lp
|
||||
Because a Bluetooth device must be enabled in order to retrieve
|
||||
information, the
|
||||
.Fa enabled
|
||||
flag should be tested to be non-zero before relying on further data.
|
||||
.It Fn bt_devopen "name" "flags"
|
||||
Return a Bluetooth HCI socket handle bound and connected to the
|
||||
named Bluetooth device or, if
|
||||
.Fa name
|
||||
is
|
||||
.Dv NULL ,
|
||||
enabled to receive packets from any device.
|
||||
The socket should be closed using
|
||||
.Xr close 2
|
||||
after use.
|
||||
Any combination of the following
|
||||
.Fa flags
|
||||
may be used to pre-set the socket options:
|
||||
.Bl -tag -width ".Dv BTOPT_DIRECTION"
|
||||
.It Dv BTOPT_DIRECTION
|
||||
Enable control messages on each packet indicating the direction of travel.
|
||||
.It Dv BTOPT_TIMESTAMP
|
||||
Enable control messages providing packet timestamps.
|
||||
.El
|
||||
.Lp
|
||||
The default filter on the socket will only allow the HCI Event packets
|
||||
.Qq Command Status
|
||||
and
|
||||
.Qq Command Complete
|
||||
to be received.
|
||||
.It Fn bt_devsend "s" "opcode" "param" "plen"
|
||||
Send an HCI command packet on the socket
|
||||
.Fa s .
|
||||
The
|
||||
.Fa opcode
|
||||
should be in host byte order and the
|
||||
.Fa param
|
||||
and
|
||||
.Fa plen
|
||||
arguments can be used to provide command parameter data.
|
||||
.Fn bt_devsend
|
||||
will return the number of bytes successfully written.
|
||||
.It Fn bt_devrecv "s" "buf" "size" "timeout"
|
||||
Receive a single HCI packet on the socket
|
||||
.Fa s .
|
||||
.Fn bt_devrecv
|
||||
will return the number of bytes successfully received unless the
|
||||
provided buffer could not contain the entire packet, or if a timeout was
|
||||
requested with a non-negative
|
||||
.Fa timeout
|
||||
value.
|
||||
.It Fn bt_devreq "s" "req" "timeout"
|
||||
Make an HCI request on the socket
|
||||
.Fa s .
|
||||
The
|
||||
.Fa req
|
||||
argument is a pointer to a
|
||||
.Ft bt_devreq
|
||||
structure, defined as:
|
||||
.Bd -literal -offset indent
|
||||
struct bt_devreq {
|
||||
uint16_t opcode;
|
||||
uint8_t event;
|
||||
void *cparam;
|
||||
size_t clen;
|
||||
void *rparam;
|
||||
size_t rlen;
|
||||
};
|
||||
.Ed
|
||||
.Lp
|
||||
.Fn bt_devreq
|
||||
sends an HCI command packet with the given
|
||||
.Fa opcode
|
||||
and command parameters of
|
||||
.Fa clen
|
||||
bytes at
|
||||
.Fa cparam
|
||||
then waits up to
|
||||
.Fa timeout
|
||||
seconds for the command to return a
|
||||
.Qq Command Complete
|
||||
event.
|
||||
In the case where the command returns
|
||||
.Qq Command Status
|
||||
and an additional event, and where the status indicates
|
||||
that the command is in progress,
|
||||
.Fn bt_devreq
|
||||
will wait for the additional
|
||||
.Fa event
|
||||
specified in the request.
|
||||
If required, any response will be copied into the buffer of
|
||||
.Fa rlen
|
||||
bytes at
|
||||
.Fa rparam ,
|
||||
and
|
||||
.Fa rlen
|
||||
will be adjusted to indicate the number of bytes stored.
|
||||
.Fn bt_devreq
|
||||
temporarily modifies the socket filter.
|
||||
.It Fn bt_devfilter "s" "new" "old"
|
||||
Update or extract the packet filter on HCI socket
|
||||
.Fa s .
|
||||
Filters can be set to indicate packet types
|
||||
.Pq Commands, Events, ACL and SCO data ,
|
||||
and individual event IDs.
|
||||
Where
|
||||
.Fa old
|
||||
is given, the currently set filter will be extracted first, then if
|
||||
.Fa new
|
||||
is given, the filter will be updated.
|
||||
.It Fn bt_devfilter_pkt_set "filter" "type"
|
||||
Set packet
|
||||
.Fa type
|
||||
in
|
||||
.Fa filter .
|
||||
.It Fn bt_devfilter_pkt_clr "filter" "type"
|
||||
Clear packet
|
||||
.Fa type
|
||||
from
|
||||
.Fa filter .
|
||||
.It Fn bt_devfilter_pkt_tst "filter" "type"
|
||||
Test if
|
||||
.Fa filter
|
||||
has packet
|
||||
.Fa type
|
||||
set.
|
||||
.It Fn bt_devfilter_evt_set "filter" "event"
|
||||
Set
|
||||
.Fa event
|
||||
ID in
|
||||
.Fa filter .
|
||||
.It Fn bt_devfilter_evt_clr "filter" "event"
|
||||
Clear
|
||||
.Fa event
|
||||
ID from
|
||||
.Fa filter .
|
||||
.It Fn bt_devfilter_evt_tst "filter" "event"
|
||||
Test if
|
||||
.Fa filter
|
||||
has
|
||||
.Fa event
|
||||
ID set.
|
||||
.It Fn bt_devinquiry "name" "timeout" "max_rsp" "iip"
|
||||
Perform a Bluetooth Inquiry using the device
|
||||
.Fa name ,
|
||||
or the first available device if NULL is passed.
|
||||
The inquiry length will be
|
||||
.Fa timeout
|
||||
seconds, and the number of responses
|
||||
.Pq up to a limit of Fa max_rsp
|
||||
will be returned.
|
||||
A pointer to an array of
|
||||
.Ft bt_devinquiry
|
||||
structures, defined as:
|
||||
.Bd -literal -offset indent
|
||||
struct bt_devinquiry {
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t pscan_rep_mode;
|
||||
uint8_t pscan_period_mode;
|
||||
uint8_t dev_class[3];
|
||||
uint16_t clock_offset;
|
||||
int8_t rssi;
|
||||
uint8_t data[240];
|
||||
};
|
||||
.Ed
|
||||
.Lp
|
||||
will be stored in the location given by
|
||||
.Fa iip
|
||||
and this should be released after use with
|
||||
.Xr free 3 .
|
||||
.El
|
||||
.Sh RETURN VALUES
|
||||
These Bluetooth device access routines return -1 on failure, and
|
||||
.Va errno
|
||||
will be set to indicate the error.
|
||||
.Sh ERRORS
|
||||
In addition to errors returned by the standard C library IO functions,
|
||||
the following errors may be indicated by device access routines.
|
||||
.Bl -tag -offset indent -width ".Bq Er ETIMEDOUT"
|
||||
.It Bq Er EINVAL
|
||||
A provided function argument was not valid.
|
||||
.It Bq Er EIO
|
||||
A device response was not properly understood.
|
||||
.It Bq Er ETIMEDOUT
|
||||
An operation exceeded the given time limit.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr bluetooth 3
|
||||
.Sh HISTORY
|
||||
The Bluetooth device access API was created by
|
||||
.An Maksim Yevmenkin
|
||||
and first appeared in
|
||||
.Fx .
|
||||
This implementation written for
|
||||
.Nx
|
||||
by
|
||||
.An Iain Hibbert .
|
915
lib/libbluetooth/bt_dev.c
Normal file
915
lib/libbluetooth/bt_dev.c
Normal file
@ -0,0 +1,915 @@
|
||||
/* $NetBSD: bt_dev.c,v 1.1 2009/08/03 15:59:42 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009 Iain Hibbert
|
||||
* Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Written by Iain Hibbert for Itronix Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of Itronix Inc. may not be used to endorse
|
||||
* or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: bt_dev.c,v 1.1 2009/08/03 15:59:42 plunky Exp $");
|
||||
|
||||
#include <sys/event.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
bt_devaddr(const char *name, bdaddr_t *addr)
|
||||
{
|
||||
struct btreq btr;
|
||||
bdaddr_t bdaddr;
|
||||
int s, rv;
|
||||
|
||||
if (name == NULL) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
addr = &bdaddr;
|
||||
|
||||
if (bt_aton(name, addr))
|
||||
return bt_devname(NULL, addr);
|
||||
|
||||
memset(&btr, 0, sizeof(btr));
|
||||
strncpy(btr.btr_name, name, HCI_DEVNAME_SIZE);
|
||||
|
||||
s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
||||
if (s == -1)
|
||||
return 0;
|
||||
|
||||
rv = ioctl(s, SIOCGBTINFO, &btr);
|
||||
close(s);
|
||||
|
||||
if (rv == -1)
|
||||
return 0;
|
||||
|
||||
if ((btr.btr_flags & BTF_UP) == 0) {
|
||||
errno = ENXIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bdaddr_copy(addr, &btr.btr_bdaddr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
bt_devname(char *name, const bdaddr_t *bdaddr)
|
||||
{
|
||||
struct btreq btr;
|
||||
int s, rv;
|
||||
|
||||
if (bdaddr == NULL) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&btr, 0, sizeof(btr));
|
||||
bdaddr_copy(&btr.btr_bdaddr, bdaddr);
|
||||
|
||||
s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
||||
if (s == -1)
|
||||
return 0;
|
||||
|
||||
rv = ioctl(s, SIOCGBTINFOA, &btr);
|
||||
close(s);
|
||||
|
||||
if (rv == -1)
|
||||
return 0;
|
||||
|
||||
if ((btr.btr_flags & BTF_UP) == 0) {
|
||||
errno = ENXIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (name != NULL)
|
||||
strlcpy(name, btr.btr_name, HCI_DEVNAME_SIZE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
bt_devopen(const char *name, int options)
|
||||
{
|
||||
struct sockaddr_bt sa;
|
||||
int opt, s;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.bt_len = sizeof(sa);
|
||||
sa.bt_family = AF_BLUETOOTH;
|
||||
|
||||
if (name != NULL && !bt_devaddr(name, &sa.bt_bdaddr))
|
||||
return -1;
|
||||
|
||||
s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
||||
if (s == -1)
|
||||
return -1;
|
||||
|
||||
opt = 1;
|
||||
|
||||
if ((options & BTOPT_DIRECTION) && setsockopt(s, BTPROTO_HCI,
|
||||
SO_HCI_DIRECTION, &opt, sizeof(opt)) == -1) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((options & BTOPT_TIMESTAMP) && setsockopt(s, SOL_SOCKET,
|
||||
SO_TIMESTAMP, &opt, sizeof(opt)) == -1) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (name != NULL
|
||||
&& connect(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
bt_devsend(int s, uint16_t opcode, void *param, size_t plen)
|
||||
{
|
||||
hci_cmd_hdr_t hdr;
|
||||
struct iovec iov[2];
|
||||
ssize_t n;
|
||||
|
||||
if (plen > UINT8_MAX
|
||||
|| (plen == 0 && param != NULL)
|
||||
|| (plen != 0 && param == NULL)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr.type = HCI_CMD_PKT;
|
||||
hdr.opcode = htole16(opcode);
|
||||
hdr.length = (uint8_t)plen;
|
||||
|
||||
iov[0].iov_base = &hdr;
|
||||
iov[0].iov_len = sizeof(hdr);
|
||||
|
||||
iov[1].iov_base = param;
|
||||
iov[1].iov_len = plen;
|
||||
|
||||
while ((n = writev(s, iov, __arraycount(iov))) == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
bt_devrecv(int s, void *buf, size_t size, time_t to)
|
||||
{
|
||||
struct kevent ev;
|
||||
struct timespec ts;
|
||||
uint8_t *p;
|
||||
ssize_t n;
|
||||
int kq;
|
||||
|
||||
if (buf == NULL || size == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (to >= 0) { /* timeout is optional */
|
||||
kq = kqueue();
|
||||
if (kq == -1)
|
||||
return -1;
|
||||
|
||||
EV_SET(&ev, s, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
|
||||
ts.tv_sec = to;
|
||||
ts.tv_nsec = 0;
|
||||
|
||||
while (kevent(kq, &ev, 1, &ev, 1, &ts) == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
close(kq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(kq);
|
||||
|
||||
if (ev.data == 0) {
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
while ((n = recv(s, buf, size, 0)) == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
p = buf;
|
||||
switch (p[0]) { /* validate that they get complete packets */
|
||||
case HCI_CMD_PKT:
|
||||
if (sizeof(hci_cmd_hdr_t) > (size_t)n
|
||||
|| sizeof(hci_cmd_hdr_t) + p[3] != (size_t)n)
|
||||
break;
|
||||
|
||||
return n;
|
||||
|
||||
case HCI_ACL_DATA_PKT:
|
||||
if (sizeof(hci_acldata_hdr_t) > (size_t)n
|
||||
|| sizeof(hci_acldata_hdr_t) + le16dec(p + 3) != (size_t)n)
|
||||
break;
|
||||
|
||||
return n;
|
||||
|
||||
case HCI_SCO_DATA_PKT:
|
||||
if (sizeof(hci_scodata_hdr_t) > (size_t)n
|
||||
|| sizeof(hci_scodata_hdr_t) + p[3] != (size_t)n)
|
||||
break;
|
||||
|
||||
return n;
|
||||
|
||||
case HCI_EVENT_PKT:
|
||||
if (sizeof(hci_event_hdr_t) > (size_t)n
|
||||
|| sizeof(hci_event_hdr_t) + p[2] != (size_t)n)
|
||||
break;
|
||||
|
||||
return n;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal handler for bt_devreq(), do the actual request.
|
||||
*/
|
||||
static int
|
||||
bt__devreq(int s, struct bt_devreq *req, time_t t_end)
|
||||
{
|
||||
uint8_t buf[HCI_EVENT_PKT_SIZE], *p;
|
||||
hci_event_hdr_t ev;
|
||||
hci_command_status_ep cs;
|
||||
hci_command_compl_ep cc;
|
||||
time_t to;
|
||||
ssize_t n;
|
||||
|
||||
n = bt_devsend(s, req->opcode, req->cparam, req->clen);
|
||||
if (n == -1)
|
||||
return errno;
|
||||
|
||||
for (;;) {
|
||||
to = t_end - time(NULL);
|
||||
if (to < 0)
|
||||
return ETIMEDOUT;
|
||||
|
||||
p = buf;
|
||||
n = bt_devrecv(s, buf, sizeof(buf), to);
|
||||
if (n == -1)
|
||||
return errno;
|
||||
|
||||
if (sizeof(ev) > (size_t)n || p[0] != HCI_EVENT_PKT)
|
||||
return EIO;
|
||||
|
||||
memcpy(&ev, p, sizeof(ev));
|
||||
p += sizeof(ev);
|
||||
n -= sizeof(ev);
|
||||
|
||||
if (ev.event == req->event)
|
||||
break;
|
||||
|
||||
if (ev.event == HCI_EVENT_COMMAND_STATUS) {
|
||||
if (sizeof(cs) > (size_t)n)
|
||||
return EIO;
|
||||
|
||||
memcpy(&cs, p, sizeof(cs));
|
||||
p += sizeof(cs);
|
||||
n -= sizeof(cs);
|
||||
|
||||
if (le16toh(cs.opcode) == req->opcode) {
|
||||
if (cs.status != 0)
|
||||
return EIO;
|
||||
|
||||
if (req->event == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev.event == HCI_EVENT_COMMAND_COMPL) {
|
||||
if (sizeof(cc) > (size_t)n)
|
||||
return EIO;
|
||||
|
||||
memcpy(&cc, p, sizeof(cc));
|
||||
p += sizeof(cc);
|
||||
n -= sizeof(cc);
|
||||
|
||||
if (le16toh(cc.opcode) == req->opcode)
|
||||
break;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy out response data */
|
||||
if (req->rlen >= (size_t)n) {
|
||||
req->rlen = n;
|
||||
memcpy(req->rparam, p, req->rlen);
|
||||
} else if (req->rlen > 0)
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bt_devreq(int s, struct bt_devreq *req, time_t to)
|
||||
{
|
||||
struct bt_devfilter new, old;
|
||||
int error;
|
||||
|
||||
if (req == NULL || to < 0
|
||||
|| (req->rlen == 0 && req->rparam != NULL)
|
||||
|| (req->rlen != 0 && req->rparam == NULL)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&new, 0, sizeof(new));
|
||||
bt_devfilter_pkt_set(&new, HCI_EVENT_PKT);
|
||||
bt_devfilter_evt_set(&new, HCI_EVENT_COMMAND_COMPL);
|
||||
bt_devfilter_evt_set(&new, HCI_EVENT_COMMAND_STATUS);
|
||||
|
||||
if (req->event != 0)
|
||||
bt_devfilter_evt_set(&new, req->event);
|
||||
|
||||
if (bt_devfilter(s, &new, &old) == -1)
|
||||
return -1;
|
||||
|
||||
error = bt__devreq(s, req, to + time(NULL));
|
||||
|
||||
(void)bt_devfilter(s, &old, NULL);
|
||||
|
||||
if (error != 0) {
|
||||
errno = error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bt_devfilter(int s, const struct bt_devfilter *new, struct bt_devfilter *old)
|
||||
{
|
||||
socklen_t len;
|
||||
|
||||
if (new == NULL && old == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = sizeof(struct hci_filter);
|
||||
|
||||
if (old != NULL) {
|
||||
if (getsockopt(s, BTPROTO_HCI,
|
||||
SO_HCI_PKT_FILTER, &old->packet_mask, &len) == -1
|
||||
|| len != sizeof(struct hci_filter))
|
||||
return -1;
|
||||
|
||||
if (getsockopt(s, BTPROTO_HCI,
|
||||
SO_HCI_EVT_FILTER, &old->event_mask, &len) == -1
|
||||
|| len != sizeof(struct hci_filter))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (new != NULL) {
|
||||
if (setsockopt(s, BTPROTO_HCI,
|
||||
SO_HCI_PKT_FILTER, &new->packet_mask, len) == -1)
|
||||
return -1;
|
||||
|
||||
if (setsockopt(s, BTPROTO_HCI,
|
||||
SO_HCI_EVT_FILTER, &new->event_mask, len) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
bt_devfilter_pkt_set(struct bt_devfilter *filter, uint8_t type)
|
||||
{
|
||||
|
||||
hci_filter_set(type, &filter->packet_mask);
|
||||
}
|
||||
|
||||
void
|
||||
bt_devfilter_pkt_clr(struct bt_devfilter *filter, uint8_t type)
|
||||
{
|
||||
|
||||
hci_filter_clr(type, &filter->packet_mask);
|
||||
}
|
||||
|
||||
int
|
||||
bt_devfilter_pkt_tst(const struct bt_devfilter *filter, uint8_t type)
|
||||
{
|
||||
|
||||
return hci_filter_test(type, &filter->packet_mask);
|
||||
}
|
||||
|
||||
void
|
||||
bt_devfilter_evt_set(struct bt_devfilter *filter, uint8_t event)
|
||||
{
|
||||
|
||||
hci_filter_set(event, &filter->event_mask);
|
||||
}
|
||||
|
||||
void
|
||||
bt_devfilter_evt_clr(struct bt_devfilter *filter, uint8_t event)
|
||||
{
|
||||
|
||||
hci_filter_clr(event, &filter->event_mask);
|
||||
}
|
||||
|
||||
int
|
||||
bt_devfilter_evt_tst(const struct bt_devfilter *filter, uint8_t event)
|
||||
{
|
||||
|
||||
return hci_filter_test(event, &filter->event_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal function used by bt_devinquiry to find the first
|
||||
* active device.
|
||||
*/
|
||||
static int
|
||||
bt__devany_cb(int s, const struct bt_devinfo *info, void *arg)
|
||||
{
|
||||
|
||||
if ((info->enabled)) {
|
||||
strlcpy(arg, info->devname, HCI_DEVNAME_SIZE + 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal function used by bt_devinquiry to insert inquiry
|
||||
* results to an array. Make sure that a bdaddr only appears
|
||||
* once in the list and always use the latest result.
|
||||
*/
|
||||
static void
|
||||
bt__devresult(struct bt_devinquiry *ii, int *count, int max_count,
|
||||
bdaddr_t *ba, uint8_t psrm, uint8_t pspm, uint8_t *cl, uint16_t co,
|
||||
int8_t rssi, uint8_t *data)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; ; n++, ii++) {
|
||||
if (n == *count) {
|
||||
if (*count == max_count)
|
||||
return;
|
||||
|
||||
(*count)++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bdaddr_same(&ii->bdaddr, ba))
|
||||
break;
|
||||
}
|
||||
|
||||
bdaddr_copy(&ii->bdaddr, ba);
|
||||
ii->pscan_rep_mode = psrm;
|
||||
ii->pscan_period_mode = pspm;
|
||||
ii->clock_offset = le16toh(co);
|
||||
ii->rssi = rssi;
|
||||
|
||||
if (cl != NULL)
|
||||
memcpy(ii->dev_class, cl, HCI_CLASS_SIZE);
|
||||
|
||||
if (data != NULL)
|
||||
memcpy(ii->data, data, 240);
|
||||
}
|
||||
|
||||
int
|
||||
bt_devinquiry(const char *name, time_t to, int max_rsp,
|
||||
struct bt_devinquiry **iip)
|
||||
{
|
||||
uint8_t buf[HCI_EVENT_PKT_SIZE], *p;
|
||||
struct bt_devfilter f;
|
||||
hci_event_hdr_t ev;
|
||||
hci_command_status_ep sp;
|
||||
hci_inquiry_cp cp;
|
||||
hci_inquiry_result_ep ip;
|
||||
hci_inquiry_response ir;
|
||||
hci_rssi_result_ep rp;
|
||||
hci_rssi_response rr;
|
||||
hci_extended_result_ep ep;
|
||||
struct bt_devinquiry *ii;
|
||||
int count, i, s;
|
||||
time_t t_end;
|
||||
ssize_t n;
|
||||
|
||||
if (iip == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (name == NULL) {
|
||||
if (bt_devenum(bt__devany_cb, buf) == -1)
|
||||
return -1;
|
||||
|
||||
name = (const char *)buf;
|
||||
}
|
||||
|
||||
s = bt_devopen(name, 0);
|
||||
if (s == -1)
|
||||
return -1;
|
||||
|
||||
memset(&f, 0, sizeof(f));
|
||||
bt_devfilter_pkt_set(&f, HCI_EVENT_PKT);
|
||||
bt_devfilter_evt_set(&f, HCI_EVENT_COMMAND_STATUS);
|
||||
bt_devfilter_evt_set(&f, HCI_EVENT_INQUIRY_COMPL);
|
||||
bt_devfilter_evt_set(&f, HCI_EVENT_INQUIRY_RESULT);
|
||||
bt_devfilter_evt_set(&f, HCI_EVENT_RSSI_RESULT);
|
||||
bt_devfilter_evt_set(&f, HCI_EVENT_EXTENDED_RESULT);
|
||||
if (bt_devfilter(s, &f, NULL) == -1) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* silently adjust number of reponses to fit in uint8_t
|
||||
*/
|
||||
if (max_rsp < 1)
|
||||
max_rsp = 8;
|
||||
else if (max_rsp > UINT8_MAX)
|
||||
max_rsp = UINT8_MAX;
|
||||
|
||||
ii = calloc((size_t)max_rsp, sizeof(struct bt_devinquiry));
|
||||
if (ii == NULL) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* silently adjust timeout value so that inquiry_length
|
||||
* falls into the range 0x01->0x30 (unit is 1.28 seconds)
|
||||
*/
|
||||
if (to < 1)
|
||||
to = 5;
|
||||
else if (to == 1)
|
||||
to = 2;
|
||||
else if (to > 62)
|
||||
to = 62;
|
||||
|
||||
/* General Inquiry LAP is 0x9e8b33 */
|
||||
cp.lap[0] = 0x33;
|
||||
cp.lap[1] = 0x8b;
|
||||
cp.lap[2] = 0x9e;
|
||||
cp.inquiry_length = (uint8_t)(to * 100 / 128);
|
||||
cp.num_responses = (uint8_t)max_rsp;
|
||||
|
||||
if (bt_devsend(s, HCI_CMD_INQUIRY, &cp, sizeof(cp)) == -1)
|
||||
goto fail;
|
||||
|
||||
count = 0;
|
||||
|
||||
for (t_end = time(NULL) + to + 1; to > 0; to = t_end - time(NULL)) {
|
||||
p = buf;
|
||||
n = bt_devrecv(s, buf, sizeof(buf), to);
|
||||
if (n == -1)
|
||||
goto fail;
|
||||
|
||||
if (sizeof(ev) > (size_t)n) {
|
||||
errno = EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(&ev, p, sizeof(ev));
|
||||
p += sizeof(ev);
|
||||
n -= sizeof(ev);
|
||||
|
||||
switch (ev.event) {
|
||||
case HCI_EVENT_COMMAND_STATUS:
|
||||
if (sizeof(sp) > (size_t)n)
|
||||
break;
|
||||
|
||||
memcpy(&sp, p, sizeof(sp));
|
||||
|
||||
if (le16toh(sp.opcode) != HCI_CMD_INQUIRY
|
||||
|| sp.status == 0)
|
||||
break;
|
||||
|
||||
errno = EIO;
|
||||
goto fail;
|
||||
|
||||
case HCI_EVENT_INQUIRY_COMPL:
|
||||
close(s);
|
||||
*iip = ii;
|
||||
return count;
|
||||
|
||||
case HCI_EVENT_INQUIRY_RESULT:
|
||||
if (sizeof(ip) > (size_t)n)
|
||||
break;
|
||||
|
||||
memcpy(&ip, p, sizeof(ip));
|
||||
p += sizeof(ip);
|
||||
n -= sizeof(ip);
|
||||
|
||||
if (sizeof(ir) * ip.num_responses != (size_t)n)
|
||||
break;
|
||||
|
||||
for (i = 0; i < ip.num_responses; i++) {
|
||||
memcpy(&ir, p, sizeof(ir));
|
||||
p += sizeof(ir);
|
||||
|
||||
bt__devresult(ii, &count, max_rsp,
|
||||
&ir.bdaddr,
|
||||
ir.page_scan_rep_mode,
|
||||
ir.page_scan_period_mode,
|
||||
ir.uclass,
|
||||
ir.clock_offset,
|
||||
0, /* rssi */
|
||||
NULL); /* extended data */
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case HCI_EVENT_RSSI_RESULT:
|
||||
if (sizeof(rp) > (size_t)n)
|
||||
break;
|
||||
|
||||
memcpy(&rp, p, sizeof(rp));
|
||||
p += sizeof(rp);
|
||||
n -= sizeof(rp);
|
||||
|
||||
if (sizeof(rr) * rp.num_responses != (size_t)n)
|
||||
break;
|
||||
|
||||
for (i = 0; i < rp.num_responses; i++) {
|
||||
memcpy(&rr, p, sizeof(rr));
|
||||
p += sizeof(rr);
|
||||
|
||||
bt__devresult(ii, &count, max_rsp,
|
||||
&rr.bdaddr,
|
||||
rr.page_scan_rep_mode,
|
||||
0, /* page scan period mode */
|
||||
rr.uclass,
|
||||
rr.clock_offset,
|
||||
rr.rssi,
|
||||
NULL); /* extended data */
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case HCI_EVENT_EXTENDED_RESULT:
|
||||
if (sizeof(ep) != (size_t)n)
|
||||
break;
|
||||
|
||||
memcpy(&ep, p, sizeof(ep));
|
||||
|
||||
if (ep.num_responses != 1)
|
||||
break;
|
||||
|
||||
bt__devresult(ii, &count, max_rsp,
|
||||
&ep.bdaddr,
|
||||
ep.page_scan_rep_mode,
|
||||
0, /* page scan period mode */
|
||||
ep.uclass,
|
||||
ep.clock_offset,
|
||||
ep.rssi,
|
||||
ep.response);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
errno = ETIMEDOUT;
|
||||
|
||||
fail:
|
||||
free(ii);
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal version of bt_devinfo. Fill in the devinfo structure
|
||||
* with the socket handle provided. If the device is present and
|
||||
* active, the socket will be left connected to the device.
|
||||
*/
|
||||
static int
|
||||
bt__devinfo(int s, const char *name, struct bt_devinfo *info)
|
||||
{
|
||||
struct sockaddr_bt sa;
|
||||
struct bt_devreq req;
|
||||
struct btreq btr;
|
||||
hci_read_buffer_size_rp bp;
|
||||
hci_read_local_features_rp fp;
|
||||
|
||||
memset(&btr, 0, sizeof(btr));
|
||||
strncpy(btr.btr_name, name, HCI_DEVNAME_SIZE);
|
||||
|
||||
if (ioctl(s, SIOCGBTINFO, &btr) == -1)
|
||||
return -1;
|
||||
|
||||
memset(info, 0, sizeof(struct bt_devinfo));
|
||||
memcpy(info->devname, btr.btr_name, HCI_DEVNAME_SIZE);
|
||||
bdaddr_copy(&info->bdaddr, &btr.btr_bdaddr);
|
||||
info->enabled = ((btr.btr_flags & BTF_UP) ? 1 : 0);
|
||||
|
||||
info->sco_size = btr.btr_sco_mtu;
|
||||
info->acl_size = btr.btr_acl_mtu;
|
||||
info->cmd_free = btr.btr_num_cmd;
|
||||
info->sco_free = btr.btr_num_sco;
|
||||
info->acl_free = btr.btr_num_acl;
|
||||
|
||||
info->link_policy_info = btr.btr_link_policy;
|
||||
info->packet_type_info = btr.btr_packet_type;
|
||||
|
||||
if (ioctl(s, SIOCGBTSTATS, &btr) == -1)
|
||||
return -1;
|
||||
|
||||
info->cmd_sent = btr.btr_stats.cmd_tx;
|
||||
info->evnt_recv = btr.btr_stats.evt_rx;
|
||||
info->acl_recv = btr.btr_stats.acl_rx;
|
||||
info->acl_sent = btr.btr_stats.acl_tx;
|
||||
info->sco_recv = btr.btr_stats.sco_rx;
|
||||
info->sco_sent = btr.btr_stats.sco_tx;
|
||||
info->bytes_recv = btr.btr_stats.byte_rx;
|
||||
info->bytes_sent = btr.btr_stats.byte_tx;
|
||||
|
||||
/* can only get the rest from enabled devices */
|
||||
if ((info->enabled) == 0)
|
||||
return 0;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.bt_len = sizeof(sa);
|
||||
sa.bt_family = AF_BLUETOOTH;
|
||||
bdaddr_copy(&sa.bt_bdaddr, &info->bdaddr);
|
||||
|
||||
if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1
|
||||
|| connect(s, (struct sockaddr *)&sa, sizeof(sa)) == -1)
|
||||
return -1;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.opcode = HCI_CMD_READ_BUFFER_SIZE;
|
||||
req.rparam = &bp;
|
||||
req.rlen = sizeof(bp);
|
||||
|
||||
if (bt_devreq(s, &req, 5) == -1)
|
||||
return -1;
|
||||
|
||||
info->acl_pkts = bp.max_acl_size;
|
||||
info->sco_pkts = bp.max_sco_size;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.opcode = HCI_CMD_READ_LOCAL_FEATURES;
|
||||
req.rparam = &fp;
|
||||
req.rlen = sizeof(fp);
|
||||
|
||||
if (bt_devreq(s, &req, 5) == -1)
|
||||
return -1;
|
||||
|
||||
memcpy(info->features, fp.features, HCI_FEATURES_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bt_devinfo(const char *name, struct bt_devinfo *info)
|
||||
{
|
||||
int rv, s;
|
||||
|
||||
if (name == NULL || info == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
||||
if (s == -1)
|
||||
return -1;
|
||||
|
||||
rv = bt__devinfo(s, name, info);
|
||||
close(s);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
bt_devenum(bt_devenum_cb_t cb, void *arg)
|
||||
{
|
||||
struct btreq btr;
|
||||
struct bt_devinfo info;
|
||||
int count, fd, rv, s;
|
||||
|
||||
s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
||||
if (s == -1)
|
||||
return -1;
|
||||
|
||||
memset(&btr, 0, sizeof(btr));
|
||||
count = 0;
|
||||
|
||||
while (ioctl(s, SIOCNBTINFO, &btr) != -1) {
|
||||
count++;
|
||||
|
||||
if (cb == NULL)
|
||||
continue;
|
||||
|
||||
fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
||||
if (fd == -1) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bt__devinfo(fd, btr.btr_name, &info) == -1) {
|
||||
close(fd);
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = (*cb)(fd, &info, arg);
|
||||
close(fd);
|
||||
if (rv != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
close(s);
|
||||
return count;
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
/* $NetBSD: devaddr.c,v 1.2 2006/08/28 08:24:39 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Written by Iain Hibbert for Itronix Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of Itronix Inc. may not be used to endorse
|
||||
* or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: devaddr.c,v 1.2 2006/08/28 08:24:39 plunky Exp $");
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <bluetooth.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
bt_devaddr(const char *name, bdaddr_t *addr)
|
||||
{
|
||||
struct btreq btr;
|
||||
bdaddr_t bdaddr;
|
||||
int s, rv;
|
||||
|
||||
if (name == NULL) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
addr = &bdaddr;
|
||||
|
||||
if (bt_aton(name, addr))
|
||||
return bt_devname(NULL, addr);
|
||||
|
||||
memset(&btr, 0, sizeof(btr));
|
||||
strlcpy(btr.btr_name, name, HCI_DEVNAME_SIZE);
|
||||
|
||||
s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
||||
if (s == -1)
|
||||
return 0;
|
||||
|
||||
rv = ioctl(s, SIOCGBTINFO, &btr);
|
||||
close(s);
|
||||
|
||||
if (rv == -1)
|
||||
return 0;
|
||||
|
||||
if ((btr.btr_flags & BTF_UP) == 0) {
|
||||
errno = ENXIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bdaddr_copy(addr, &btr.btr_bdaddr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
bt_devname(char *name, const bdaddr_t *addr)
|
||||
{
|
||||
struct btreq btr;
|
||||
int s, rv;
|
||||
|
||||
if (addr == NULL) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&btr, 0, sizeof(btr));
|
||||
bdaddr_copy(&btr.btr_bdaddr, addr);
|
||||
|
||||
s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
||||
if (s == -1)
|
||||
return 0;
|
||||
|
||||
rv = ioctl(s, SIOCGBTINFOA, &btr);
|
||||
close(s);
|
||||
|
||||
if (rv == -1)
|
||||
return 0;
|
||||
|
||||
if ((btr.btr_flags & BTF_UP) == 0) {
|
||||
errno = ENXIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (name != NULL)
|
||||
strlcpy(name, btr.btr_name, HCI_DEVNAME_SIZE);
|
||||
|
||||
return 1;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
# $NetBSD: shlib_version,v 1.4 2009/05/12 10:05:06 plunky Exp $
|
||||
# $NetBSD: shlib_version,v 1.5 2009/08/03 15:59:42 plunky Exp $
|
||||
# Remember to update distrib/sets/lists/base/shl.* when changing
|
||||
#
|
||||
major=4
|
||||
minor=1
|
||||
minor=2
|
||||
|
Loading…
Reference in New Issue
Block a user