3e42392551
Introduce /etc/rc.d/bluetooth script to start/stop Bluetooth devices. It will be called from devd(8) in response to device arrival/departure events. It is also possible to call it by hand to start/stop particular device without unplugging it. Introduce generic way to set configuration parameters for Bluetooth devices. By default /etc/rc.d/bluetooth script has hardwired defaults compatible with old rc.bluetooth from /usr/share/netgraph/bluetooth/examples. These can be overridden using /etc/defaults/bluetooth.device.conf file (system wide defaults). Finally, there could be another device specific override file located in /etc/bluetooth/$device.conf (where $device is ubt0, btccc0 etc.) The list of configuration parameters and their meaning described in the /etc/defaults/bluetooth.device.conf file. Even though Bluetooth device configuration files are not shell scripts, they must follow basic sh(1) syntax. The bluetooth.device.conf(5) and handbook update will follow shortly. Inspired by: Panagiotis Astithas ( past at ebs dot gr ) Reviewed by: brooks, yar MFC after: 1 week
367 lines
9.2 KiB
Bash
367 lines
9.2 KiB
Bash
#!/bin/sh
|
|
#
|
|
# Copyright (c) 2005 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.
|
|
#
|
|
# $FreeBSD$
|
|
|
|
# PROVIDE: bluetooth
|
|
# REQUIRE: DAEMON
|
|
# KEYWORD: nojail nostart
|
|
|
|
. /etc/rc.subr
|
|
|
|
name="bluetooth"
|
|
rcvar=
|
|
start_cmd="bluetooth_start"
|
|
stop_cmd="bluetooth_stop"
|
|
|
|
##############################################################################
|
|
# Read and parse Bluetooth device configuration file
|
|
##############################################################################
|
|
|
|
bluetooth_read_conf()
|
|
{
|
|
_file=$1
|
|
_namespace=$2
|
|
_err=0
|
|
|
|
if [ ! -e $_file ]; then
|
|
return 0
|
|
fi
|
|
|
|
if [ ! -f $_file -o ! -r $_file ]; then
|
|
err 1 "Bluetooth configuration file $_file is not a file or not readable"
|
|
fi
|
|
|
|
while read _line
|
|
do
|
|
case "$_line" in
|
|
\#*)
|
|
continue
|
|
;;
|
|
|
|
*)
|
|
if [ -z "$_line" ]; then
|
|
continue;
|
|
fi
|
|
|
|
|
|
if expr "$_line" : "[a-zA-Z0-9_]*=" > /dev/null 2>&1; then
|
|
eval "${_namespace}${_line}"
|
|
else
|
|
warn "Unable to parse line \"$_line\" in $_file"
|
|
_err=1
|
|
fi
|
|
;;
|
|
esac
|
|
done < $_file
|
|
|
|
return $_err
|
|
}
|
|
|
|
##############################################################################
|
|
# Setup Bluetooth stack. Create and connect nodes
|
|
##############################################################################
|
|
|
|
bluetooth_setup_stack()
|
|
{
|
|
dev=$1
|
|
shift
|
|
hook=$1
|
|
shift
|
|
|
|
# Setup HCI
|
|
ngctl mkpeer ${dev}: hci ${hook} drv \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
ngctl name ${dev}:${hook} ${dev}hci \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
ngctl msg ${dev}hci: set_debug ${bluetooth_device_hci_debug_level} \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
# Setup L2CAP
|
|
ngctl mkpeer ${dev}hci: l2cap acl hci \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
ngctl name ${dev}hci:acl ${dev}l2cap \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
ngctl msg ${dev}l2cap: set_debug ${bluetooth_device_l2cap_debug_level} \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
# Connect HCI node to the Bluetooth sockets layer
|
|
ngctl connect ${dev}hci: btsock_hci_raw: raw ${dev}raw \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
# Connect L2CAP node to Bluetooth sockets layer
|
|
ngctl connect ${dev}l2cap: btsock_l2c_raw: ctl ${dev}ctl \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
ngctl connect ${dev}l2cap: btsock_l2c: l2c ${dev}l2c \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
# Initilalize HCI node
|
|
${hccontrol} -n ${dev}hci reset \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
${hccontrol} -n ${dev}hci read_bd_addr \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
${hccontrol} -n ${dev}hci read_local_supported_features \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
${hccontrol} -n ${dev}hci read_buffer_size \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
if checkyesno bluetooth_device_discoverable; then
|
|
if checkyesno bluetooth_device_connectable; then
|
|
${hccontrol} -n ${dev}hci write_scan_enable 3 \
|
|
> /dev/null 2>&1 || return 1
|
|
else
|
|
${hccontrol} -n ${dev}hci write_scan_enable 1 \
|
|
> /dev/null 2>&1 || return 1
|
|
fi
|
|
else
|
|
if checkyesno bluetooth_device_connectable; then
|
|
${hccontrol} -n ${dev}hci write_scan_enable 2 \
|
|
> /dev/null 2>&1 || return 1
|
|
else
|
|
${hccontrol} -n ${dev}hci write_scan_enable 0 \
|
|
> /dev/null 2>&1 || return 1
|
|
fi
|
|
fi
|
|
|
|
|
|
${hccontrol} -n ${dev}hci write_class_of_device ${bluetooth_device_class} \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
if checkyesno bluetooth_device_authentication_enable; then
|
|
${hccontrol} -n ${dev}hci write_authentication_enable 1 \
|
|
> /dev/null 2>&1 || return 1
|
|
else
|
|
${hccontrol} -n ${dev}hci write_authentication_enable 0 \
|
|
> /dev/null 2>&1 || return 1
|
|
fi
|
|
|
|
case "${bluetooth_device_encryption_mode}" in
|
|
[Nn][Oo][Nn][Ee]|0)
|
|
${hccontrol} -n ${dev}hci write_encryption_mode 0 \
|
|
> /dev/null 2>&1 || return 1
|
|
;;
|
|
|
|
[Pp][2][Pp]|1)
|
|
${hccontrol} -n ${dev}hci write_encryption_mode 1 \
|
|
> /dev/null 2>&1 || return 1
|
|
;;
|
|
|
|
[Al][Ll][Ll]|2)
|
|
${hccontrol} -n ${dev}hci write_encryption_mode 2 \
|
|
> /dev/null 2>&1 || return 1
|
|
;;
|
|
|
|
*)
|
|
warn "Unsupported encryption mode ${bluetooth_device_encryption_mode} for device ${dev}"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
if checkyesno bluetooth_device_role_switch; then
|
|
${hccontrol} -n ${dev}hci write_node_role_switch 1 \
|
|
> /dev/null 2>&1 || return 1
|
|
else
|
|
${hccontrol} -n ${dev}hci write_node_role_switch 0 \
|
|
> /dev/null 2>&1 || return 1
|
|
fi
|
|
|
|
${hccontrol} -n ${dev}hci change_local_name "${bluetooth_device_local_name}" \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
${hccontrol} -n ${dev}hci initialize \
|
|
> /dev/null 2>&1 || return 1
|
|
|
|
return 0
|
|
}
|
|
|
|
##############################################################################
|
|
# Shutdown Bluetooth stack. Destroy all nodes
|
|
##############################################################################
|
|
|
|
bluetooth_shutdown_stack()
|
|
{
|
|
dev=$1
|
|
|
|
ngctl shutdown ${dev}hci: > /dev/null 2>&1
|
|
ngctl shutdown ${dev}l2cap: > /dev/null 2>&1
|
|
|
|
return 0
|
|
}
|
|
|
|
##############################################################################
|
|
# bluetooth_start()
|
|
##############################################################################
|
|
|
|
bluetooth_start()
|
|
{
|
|
dev=$1
|
|
|
|
# Automatically load modules
|
|
kldload ng_bluetooth > /dev/null 2>&1
|
|
kldload ng_hci > /dev/null 2>&1
|
|
kldload ng_l2cap > /dev/null 2>&1
|
|
kldload ng_btsocket > /dev/null 2>&1
|
|
|
|
# Try to figure out device type by looking at device name
|
|
case "${dev}" in
|
|
# sioX - serial/UART Bluetooth device
|
|
sio*)
|
|
kldload ng_h4 > /dev/null 2>&1
|
|
|
|
hook="hook"
|
|
|
|
# Obtain unit number from device.
|
|
unit=`expr ${dev} : 'sio\([0-9]\{1,\}\)'`
|
|
if [ -z "${unit}" ]; then
|
|
err 1 "Unable to get sio unit number: ${dev}"
|
|
fi
|
|
|
|
${hcseriald} -f /dev/cuad${unit} -n ${dev}
|
|
sleep 1 # wait a little bit
|
|
|
|
if [ ! -f "/var/run/hcseriald.${dev}.pid" ]; then
|
|
err 1 "Unable to start hcseriald on ${dev}"
|
|
fi
|
|
;;
|
|
|
|
# 3Com Bluetooth Adapter 3CRWB60-A
|
|
btccc*)
|
|
hook="hook"
|
|
|
|
# Obtain unit number from device.
|
|
unit=`expr ${dev} : 'btccc\([0-9]\{1,\}\)'`
|
|
if [ -z "${unit}" ]; then
|
|
err 1 "Unable to get bt3c unit number: ${dev}"
|
|
fi
|
|
;;
|
|
|
|
# USB Bluetooth adapters
|
|
ubt*)
|
|
hook="hook"
|
|
|
|
# Obtain unit number from device.
|
|
unit=`expr ${dev} : 'ubt\([0-9]\{1,\}\)'`
|
|
if [ -z "${unit}" ]; then
|
|
err 1 "Unable to get ubt unit number: ${dev}"
|
|
fi
|
|
;;
|
|
|
|
# Unknown
|
|
*)
|
|
err 1 "Unsupported device: ${dev}"
|
|
;;
|
|
esac
|
|
|
|
# Be backward compatible and setup reasonable defaults
|
|
bluetooth_device_authentication_enable="0"
|
|
bluetooth_device_class="ff:01:0c"
|
|
bluetooth_device_connectable="1"
|
|
bluetooth_device_discoverable="1"
|
|
bluetooth_device_encryption_mode="0"
|
|
bluetooth_device_hci_debug_level="3"
|
|
bluetooth_device_l2cap_debug_level="3"
|
|
bluetooth_device_local_name="`/usr/bin/uname -n` (${dev})"
|
|
bluetooth_device_role_switch="1"
|
|
|
|
# Load default device configuration parameters
|
|
_file="/etc/defaults/bluetooth.device.conf"
|
|
|
|
if ! bluetooth_read_conf $_file bluetooth_device_ ; then
|
|
err 1 "Unable to read default Bluetooth configuration from $_file"
|
|
fi
|
|
|
|
# Load device specific overrides
|
|
_file="/etc/bluetooth/$dev.conf"
|
|
|
|
if ! bluetooth_read_conf $_file bluetooth_device_ ; then
|
|
err 1 "Unable to read Bluetooth device configuration from $_file"
|
|
fi
|
|
|
|
# Setup stack
|
|
if ! bluetooth_setup_stack ${dev} ${hook} ; then
|
|
bluetooth_shutdown_stack $dev
|
|
err 1 "Unable to setup Bluetooth stack for device ${dev}"
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
##############################################################################
|
|
# bluetooth_stop()
|
|
##############################################################################
|
|
|
|
bluetooth_stop()
|
|
{
|
|
dev=$1
|
|
|
|
# Try to figure out device type by looking at device name
|
|
case "${dev}" in
|
|
# sioX - serial/UART Bluetooth device
|
|
sio*)
|
|
if [ -f "/var/run/hcseriald.${dev}.pid" ]; then
|
|
kill `cat /var/run/hcseriald.${dev}.pid`
|
|
sleep 1 # wait a little bit
|
|
fi
|
|
;;
|
|
|
|
# 3Com Bluetooth Adapter 3CRWB60-A
|
|
btccc*)
|
|
;;
|
|
|
|
# USB Bluetooth adapters
|
|
ubt*)
|
|
;;
|
|
|
|
# Unknown
|
|
*)
|
|
err 1 "Unsupported device: ${dev}"
|
|
;;
|
|
esac
|
|
|
|
bluetooth_shutdown_stack ${dev}
|
|
|
|
return 0
|
|
}
|
|
|
|
##############################################################################
|
|
# Start here
|
|
##############################################################################
|
|
|
|
load_rc_config $name
|
|
hccontrol="${bluetooth_hccontrol:-/usr/sbin/hccontrol}"
|
|
hcseriald="${bluetooth_hcseriald:-/usr/sbin/hcseriald}"
|
|
|
|
run_rc_command $*
|
|
|