Add bluetooth-config script to simplify setting up bluetooth connections to

devices like mice, keyboards, bt-audio, ...

This script currently allows scanning for nearby devices, adds one to
/etc/bluetooth/hosts, adds an entry to hcsecd's conf and if it is a HID, add an
entry to bthidd's configs, as well.

Submitted by:	erdgeist <erdgeist@erdgeist.org>
Approved by:	bapt
MFC after:	2 weeks
Differential Revision:	D3778
Reviewers:	bapt, emax
This commit is contained in:
Lars Engels 2019-01-11 15:52:09 +00:00
parent 7d9545fcc0
commit 0fc0faf846
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=342945
5 changed files with 506 additions and 0 deletions

View File

@ -504,6 +504,7 @@ OLD_FILES+=usr/lib32/libsdp_p.a
.endif
OLD_FILES+=usr/sbin/ath3kfw
OLD_FILES+=usr/sbin/bcmfw
OLD_FILES+=usr/sbin/bluetooth-config
OLD_FILES+=usr/sbin/bt3cfw
OLD_FILES+=usr/sbin/bthidcontrol
OLD_FILES+=usr/sbin/bthidd
@ -580,6 +581,7 @@ OLD_FILES+=usr/share/man/man5/bluetooth.protocols.5.gz
OLD_FILES+=usr/share/man/man5/hcsecd.conf.5.gz
OLD_FILES+=usr/share/man/man8/ath3kfw.8.gz
OLD_FILES+=usr/share/man/man8/bcmfw.8.gz
OLD_FILES+=usr/share/man/man8/bluetooth-config.8.gz
OLD_FILES+=usr/share/man/man8/bt3cfw.8.gz
OLD_FILES+=usr/share/man/man8/bthidcontrol.8.gz
OLD_FILES+=usr/share/man/man8/bthidd.8.gz

View File

@ -4,6 +4,7 @@
.include <src.opts.mk>
SUBDIR= \
bluetooth-config \
bt3cfw \
btpand \
hccontrol \

View File

@ -0,0 +1,6 @@
# $FreeBSD$
SCRIPTS=bluetooth-config.sh
MAN= bluetooth-config.8
.include <bsd.prog.mk>

View File

@ -0,0 +1,222 @@
.\" Copyright (c) 2019 Dirk Engling
.\" 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.
.\"
.\" $FreeBSD$
.\"
.Dd January 7, 2019
.Dt BLUETOOTH-CONFIG 8
.Os
.Sh NAME
.Nm bluetooth-config
.Nd a script to manage config files for the bluetooth sub system
.Sh SYNOPSIS
.Nm
.Ar scan
.Op Fl d Ar device
.Op Fl n Ar node
.Sh DESCRIPTION
The
.Nm
utility is an interactive script to provide a frontend to the complex bluetooth sub system daemons.
.Pp
The following options are available:
.Bl -tag -width indent+
.It Fl d
Scan for a specific bluetooth device address.
.It Fl n
Limit scan to a specific host controller. Hint: List all netgraph nodes with
.Ql /usr/sbin/ngctl list .
.El
.Pp
.Nm
will help finding and setting up bluetooth controllers, scan for nearby bluetooth devices in
pairing mode, lookup their names, allow mapping to friendly names in
.Pa /etc/bluetooth/hosts ,
ask for the paring PIN, instrument
.Xr hcsecd 8
to securely pair with new devices and, if the device offers HID endpoints such as mice or
keyboards, configure and restart
.Xr bthidd 8 .
.Pp
.Nm
can bring up any interface and daemon necessary for operation and, if a node is provided on
command line, will do so automatically for that interface.
.Sh CAVEATS
.Nm
can not parse entries in
.Xr hcsecd 8
config file and thus will ask the user to manually modify existing pairing PIN entries.
.Sh FILES
.Bl -tag -width ".Pa /etc/bluetooth/hosts" -compact
.It Pa /etc/bluetooth/hosts
.It Pa sysrc -n bthidd_config
.It Pa sysrc -n hcsecd_config
.El
.Sh EXAMPLES
.Nm
scan -n ubt0 -a 00:26:bb:7a:58:95
.Bd -ragged -offset indent
This will scan the bluetooth controller ubt0hci for a bluetooth device with the address
00:26:bb:7a:58:95, set up ubt0 if necessary and enter an interactive dialog to pair the
new device. Since in this example a mouse is paired,
.Nm
will interact with
.Xr bthidd 8 ,
enabling it if necessary and then write an HID descriptor to its config.
.Ed
.Pp
.Nm
scan
.Bd -ragged -offset indent
This will scan all bluetooth controllers on the systems for bluetooth devices, prompting
to bring up controllers or daemons along the way.
.Ed
.Sh SEE ALSO
.Xr bthidcontrol 8 ,
.Xr bthidd 8 ,
.Xr bthost 1 ,
.Xr hccontrol 8 ,
.Xr hcsecd 8 ,
.Xr sdpcontrol 8 ,
.Xr sysrc 8
.Sh HISTORY
A
.Nm
utility first appeared in
.Fx 12.1 .
.Sh AUTHORS
.An Dirk Engling Aq Mt erdgeist@erdgeist.org
.Sh THANKS TO
Lars Engels and Warren Block for suggestions, help, and testing.
.\" Copyright (c) 2019 Dirk Engling
.\" 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.
.\"
.\" $FreeBSD$
.\"
.Dd January 7, 2019
.Dt BLUETOOTH-CONFIG 8
.Os
.Sh NAME
.Nm bluetooth-config
.Nd a script to manage config files for the bluetooth sub system
.Sh SYNOPSIS
.Nm
.Ar scan
.Op Fl d Ar device
.Op Fl n Ar node
.Sh DESCRIPTION
The
.Nm
utility is an interactive script to provide a frontend to the complex bluetooth sub system daemons.
.Pp
The following options are available:
.Bl -tag -width indent+
.It Fl d
Scan for a specific bluetooth device address.
.It Fl n
Limit scan to a specific host controller. Hint: List all netgraph nodes with
.Ql /usr/sbin/ngctl list .
.El
.Pp
.Nm
will help finding and setting up bluetooth controllers, scan for nearby bluetooth devices in
pairing mode, lookup their names, allow mapping to friendly names in
.Pa /etc/bluetooth/hosts ,
ask for the paring PIN, instrument
.Xr hcsecd 8
to securely pair with new devices and, if the device offers HID endpoints such as mice or
keyboards, configure and restart
.Xr bthidd 8 .
.Pp
.Nm
can bring up any interface and daemon necessary for operation and, if a node is provided on
command line, will do so automatically for that interface.
.Sh CAVEATS
.Nm
can not parse entries in
.Xr hcsecd 8
config file and thus will ask the user to manually modify existing pairing PIN entries.
.Sh FILES
.Bl -tag -width ".Pa /etc/bluetooth/hosts" -compact
.It Pa /etc/bluetooth/hosts
.It Pa sysrc -n bthidd_config
.It Pa sysrc -n hcsecd_config
.El
.Sh EXAMPLES
.Nm
scan -n ubt0 -a 00:26:bb:7a:58:95
.Bd -ragged -offset indent
This will scan the bluetooth controller ubt0hci for a bluetooth device with the address
00:26:bb:7a:58:95, set up ubt0 if necessary and enter an interactive dialog to pair the
new device. Since in this example a mouse is paired,
.Nm
will interact with
.Xr bthidd 8 ,
enabling it if necessary and then write an HID descriptor to its config.
.Ed
.Pp
.Nm
scan
.Bd -ragged -offset indent
This will scan all bluetooth controllers on the systems for bluetooth devices, prompting
to bring up controllers or daemons along the way.
.Ed
.Sh SEE ALSO
.Xr bthidcontrol 8 ,
.Xr bthidd 8 ,
.Xr bthost 1 ,
.Xr hccontrol 8 ,
.Xr hcsecd 8 ,
.Xr sdpcontrol 8 ,
.Xr sysrc 8
.Sh HISTORY
A
.Nm
utility first appeared in
.Fx 12.1 .
.Sh AUTHORS
.An Dirk Engling Aq Mt erdgeist@erdgeist.org
.Sh THANKS TO
Lars Engels and Warren Block for suggestions, help, and testing.

View File

@ -0,0 +1,275 @@
#!/bin/sh
#-
# Copyleft 2019 Dirk Engling
#
# This script is released under the beerware license.
#
# $FreeBSD$
#
# define our bail out shortcut
exerr () { echo -e "Error: $*" >&2 ; exit 1; }
print_syntax () { echo -e "Syntax: $0 scan [-d device] [-n node]"; exit 1; }
# Assuming we are called to do the pair-new-device subcommand first
main() {
unset node device started bdaddresses retry
# Only one command at the moment is scan (+ add)
[ "$#" -eq 1 -a "$1" = "scan" ] || print_syntax
shift
# Get command line options
while getopts :d:n: arg; do
case ${arg} in
d) device="$OPTARG";;
n) node="$OPTARG";;
?) print_syntax;;
esac
done
# No use running without super user rights
[ $( id -u ) -eq 0 ] || exerr "$0 must modify files that belong to root. Re-run as root."
known_nodes=$(/usr/sbin/hccontrol read_node_list 2>/dev/null | \
/usr/bin/tail -n +2 | /usr/bin/cut -d ' ' -f 1)
# Check if netgraph knows about any HCI nodes
if ! [ "${known_nodes}" ]; then
ng_nodes=$(/usr/sbin/ngctl list 2>/dev/null | \
/usr/bin/grep -o "Name: .* Type: ubt" | /usr/bin/cut -d ' ' -f 2)
[ "${ng_nodes}" ] || exerr "No Bluetooth host controllers found."
unset found
for n in ${ng_nodes}; do
if [ "${n}" = "${node%hci}" ]; then
# If we found the node but its stack is not set up, do it now
/usr/sbin/service bluetooth start ${node%hci} || exit 1
found="YES"
fi
done
# If we have Bluetooth controller nodes without a set up stack,
# ask the user if we shall start it up
if ! [ "${found}" ]; then
printf "No usable Bluetooth host controllers were found.\n"
printf "These host controllers exist in the system:\n %s" " ${ng_nodes}"
read -p "Choose a host controller to set up: [${ng_nodes%% *}]" node
: ${node:="${ng_nodes%% *}"}
/usr/sbin/service bluetooth start ${node} || exit 1
fi
# Re-read known nodes
known_nodes=$(/usr/sbin/hccontrol read_node_list 2>/dev/null | \
/usr/bin/tail -n +2 | /usr/bin/cut -d ' ' -f 1)
# check if we succeeded in bringing it up
[ "${known_nodes}" ] || exerr "Failed to set up Bluetooth stack"
fi
# if a node was requested on command line, check if it is there
if [ "${node}" ]; then
unset found
for n in ${known_nodes}; do
[ "${n}" = "${node}" ] && found="YES"
[ "${n}" = "${node}hci" ] && node="${node}hci" && found="YES"
done
[ "${found}" ] || exerr "Node ${node} not found"
fi
[ "${node}" ] && node="-n ${node}"
while ! [ "${bdaddresses}" ]; do
retry=X${retry}
printf "Scanning for new Bluetooth devices (Attempt %d of 5) ... " ${#retry}
bdaddresses=$( /usr/sbin/hccontrol -N ${node} inquiry 2>/dev/null | \
/usr/bin/grep -o "BD_ADDR: .*" | /usr/bin/cut -d ' ' -f 2 )
# Count entries and, if a device was requested on command line,
# try to find it
unset found count
for bdaddress in ${bdaddresses}; do
count=X${count}
if [ "${bdaddress}" = "${device}" ]; then
found=YES
bdaddresses="${device}"
count=X
break
fi
done
# If device was requested on command line but is not found,
# or no devices found at all, rescan until retry is exhausted
if ! [ "${found}" -o "${count}" -a -z "${device}" ]; then
printf "failed.\n"
if [ "${#retry}" -eq 5 ]; then
[ "${device}" ] && exerr "Device ${device} not found"
exerr "No new Bluetooth devices found"
fi
unset bdaddresses
sleep 2
continue
fi
[ ${#count} -gt 1 ] && plural=s || plural=''
printf "done.\nFound %d new bluetooth device%s (scanning for names):\n" ${#count} ${plural}
# Looping again for the faster feedback
unset count
for bdaddress in ${bdaddresses}; do
count=X${count}
bdname=$( /usr/bin/bthost -b "${bdaddress}" 2>/dev/null )
friendlyname=$( /usr/sbin/hccontrol Remote_Name_Request ${bdaddress} 2> /dev/null | \
/usr/bin/grep -o "Name: .*" | /usr/bin/cut -d ' ' -f 2- )
# sdpcontrol should be able to pull vendor and product id via sdp
printf "[%2d] %s\t\"%s\" (%s)\n" ${#count} "${bdaddress}" "${friendlyname}" "${bdname}"
eval bdaddress_${#count}=\${bdaddress}
eval bdname_${#count}=\${bdname}
eval friendlyname_${#count}=\${friendlyname}
done
# If a device was pre-selected, do not query the user
[ "${device}" ] && topair=1 || unset topair
# Even if only one device was found, user may chose 0 to rescan
while ! [ "${topair}" ]; do
if [ ${#count} -eq 1 ]; then
read -p "Select device to pair with [1, or 0 to rescan]: " topair
else
read -p "Select device to pair with [1-${#count}, or 0 to rescan]: " topair
fi
if ! [ "${topair}" -ge 0 -a "${topair}" -le "${#count}" ] 2>/dev/null ; then
printf "Value out of range: %s.\n" {topair}
unset topair
fi
done
[ "${topair}" -eq "0" ] && unset bdaddresses retry
done
eval bdaddress=\${bdaddress_${topair}}
eval bdname=\${bdname_${topair}}
eval friendlyname=\${friendlyname_${topair}}
# Do we need to add an entry to /etc/bluetooth/hosts?
if ! [ "${bdname}" ]; then
printf "\nAdding device ${bdaddress} to /etc/bluetooth/hosts.\n"
while ! [ "${bdname}" ]; do
read -p "Enter friendly name. [${friendlyname}]: " REPLY
: ${REPLY:="${friendlyname}"}
if [ "${REPLY}" ]; then
# Remove white space and non-friendly characters
bdname=$( printf "%s" "${REPLY}" | tr -c '[:alnum:]-,.' _ )
[ "${REPLY}" != "${bdname}" ] && printf "Notice: Using sanitized name \"%s\" in /etc/bluetooth/hosts.\n" "${bdname}"
fi
done
printf "%s\t%s\n" "${bdaddress}" "${bdname}" >> /etc/bluetooth/hosts
fi
# If scanning for the name did not succeed, resort to bdname
: ${friendlyname:="${bdname}"}
# now over to hcsecd
# Since hcsecd does not allow querying for known devices, we need to
# check for bdaddr entries manually.
#
# Also we cannot really modify the PIN in an existing entry. So we
# need to prompt the user to manually do it and restart this script
if ! /usr/sbin/service hcsecd enabled; then
printf "\nWarning: hcsecd is not enabled.\nThis daemon manages pairing requests.\n"
read -p "Enable hcsecd? [yes]: " REPLY
case "${REPLY}" in no|n|NO|N|No|nO) ;; *) /usr/sbin/sysrc hcsecd_enable="YES";; esac
fi
secd_config=$( /usr/sbin/sysrc -n hcsecd_config )
secd_entries=$( /usr/bin/grep -Eo "bdaddr[[:space:]]+(${bdaddress}|${bdname})" ${secd_config} | awk '{ print $2; }' )
if [ "${secd_entries}" ]; then
printf "\nWarning: An entry for device %s is already present in %s.\n" ${secd_entries} ${secd_config}
printf "To modify pairing information, edit this file and run\n service hcsecd restart\n"
read -p "Continue? [yes]: " REPLY
case "${REPLY}" in no|n|NO|N|No|nO) exit;; esac
else
printf "\nWriting pairing information description block to %s.\n" ${secd_config}
printf "(To get PIN, put device in pairing mode first.)\n"
read -p "Enter PIN [nopin]: " pin
[ "${pin}" ] && pin=\""${pin}"\" || pin="nopin"
# Write out new hcsecd config block
printf "\ndevice {\n\tbdaddr\t%s;\n\tname\t\"%s\";\n\tkey\tnokey\;\n\tpin\t%s\;\n}\n" \
"${bdaddress}" "${friendlyname}" "${pin}" >> ${secd_config}
# ... and make daemon reload config, TODO: hcsecd should provide a reload hook
/usr/sbin/service hcsecd restart
# TODO: we should check if hcsecd succeeded pairing and revert to an old version
# of hcsecd.conf so we can undo adding the block above and retry with a new PIN
# also, if there's a way to force devices to re-pair, try this
fi
# now check for specific services to be provided by the device
# first up: HID
if /usr/sbin/sdpcontrol -a "${bdaddress}" search HID | \
/usr/bin/grep -q "^Record Handle: "; then
printf "\nThis device provides human interface device services.\n"
read -p "Set it up? [yes]: " REPLY
case "${REPLY}" in no|n|NO|N|No|nO) ;;
*)
if ! /usr/sbin/service bthidd enabled; then
printf "\nWarning: bthidd is not enabled."
printf "\nThis daemon manages Bluetooth HID devices.\n"
read -p "Enable bthidd? [yes]: " REPLY
case "${REPLY}" in no|n|NO|N|No|nO) ;; *) /usr/sbin/sysrc bthidd_enable="YES";; esac
fi
# Check if bthidd already knows about this device
bthidd_known=$( /usr/sbin/bthidcontrol -a "${bdaddress}" known | \
/usr/bin/grep "${bdaddress}" )
if [ "${bthidd_known}" ]; then
printf "Notice: Device %s already known to bthidd.\n" "${bdaddress}"
else
bthidd_config=$( /usr/sbin/sysrc -n bthidd_config )
printf "Writing HID descriptor block to %s ... " "${bthidd_config}"
/usr/sbin/bthidcontrol -a "${bdaddress}" query >> "${bthidd_config}"
# Re-read config to see if we succeeded adding the device
bthidd_known=$( /usr/sbin/bthidcontrol -a "${bdaddress}" known | \
grep "${bdaddress}" )
if ! [ "${bthidd_known}" ]; then
printf "failed.\n"
else
printf "success.\nTo re-read its config, bthidd must be restarted.\n"
printf "Warning: If a Bluetooth keyboard is being used, the connection might be lost.\n"
printf "It can be manually restarted later with\n service bthidd restart\n"
read -p "Restart bthidd now? [yes]: " REPLY
case "${REPLY}" in no|n|NO|N|No|nO) ;; *) /usr/sbin/service bthidd restart;; esac
fi
fi
;;
esac
fi
}
# After function definitions, main() can use them
main "$@"
exit
# TODO
# * If device is a keyboard, offer a text entry test field and if it does
# not succeed, leave some clues for debugging (i.e. if the node responds
# to pings, maybe switch keyboard on/off, etc)
# * Same if device is a mouse, i.e. hexdump /dev/sysmouse.
# * If device offers DUN profiles, ask the user if an entry in
# /etc/ppp/ppp.conf should be created
# * If OPUSH or SPP is offered, refer to the respective man pages to give
# some clues how to continue