#!/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. # # PROVIDE: bluetooth # REQUIRE: DAEMON # KEYWORD: nojail nostart . /etc/rc.subr name="bluetooth" desc="Bluetooth setup script" rcvar= start_cmd="bluetooth_start" stop_cmd="bluetooth_stop" required_modules="ng_bluetooth ng_hci ng_l2cap ng_btsocket" ############################################################################## # Read and parse Bluetooth device configuration file ############################################################################## bluetooth_read_conf() { local _err _file _line _namespace _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() { local _file dev=$1 # Try to figure out device type by looking at device name case "${dev}" in # 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="0" 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 # 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}" run_rc_command $*