xref: /freebsd/libexec/rc/rc.d/bluetooth (revision 78807c196c9481cdd88b5ce611b488903f52fbd0)
1#!/bin/sh
2#
3# Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27
28# PROVIDE: bluetooth
29# REQUIRE: DAEMON
30# KEYWORD: nojail nostart
31
32. /etc/rc.subr
33
34name="bluetooth"
35desc="Bluetooth setup script"
36rcvar=
37start_cmd="bluetooth_start"
38stop_cmd="bluetooth_stop"
39required_modules="ng_bluetooth ng_hci ng_l2cap ng_btsocket"
40
41##############################################################################
42# Read and parse Bluetooth device configuration file
43##############################################################################
44
45bluetooth_read_conf()
46{
47	local _err _file _line _namespace
48
49	_file=$1
50	_namespace=$2
51	_err=0
52
53	if [ ! -e $_file ]; then
54		return 0
55	fi
56
57	if [ ! -f $_file -o ! -r $_file ]; then
58		err 1 "Bluetooth configuration file $_file is not a file or not readable"
59	fi
60
61	while read _line
62	do
63		case "$_line" in
64		\#*)
65			continue
66			;;
67
68		*)
69			if [ -z "$_line" ]; then
70				continue;
71			fi
72
73
74			if expr "$_line" : "[a-zA-Z0-9_]*=" > /dev/null 2>&1; then
75				eval "${_namespace}${_line}"
76			else
77				warn "Unable to parse line \"$_line\" in $_file"
78				_err=1
79			fi
80			;;
81		esac
82	done < $_file
83
84	return $_err
85}
86
87##############################################################################
88# Setup Bluetooth stack. Create and connect nodes
89##############################################################################
90
91bluetooth_setup_stack()
92{
93	dev=$1
94	shift
95	hook=$1
96	shift
97
98	# Setup HCI
99	ngctl mkpeer ${dev}: hci ${hook} drv \
100		> /dev/null 2>&1 || return 1
101
102	ngctl name ${dev}:${hook} ${dev}hci \
103		> /dev/null 2>&1 || return 1
104
105	ngctl msg ${dev}hci: set_debug ${bluetooth_device_hci_debug_level} \
106		> /dev/null 2>&1 || return 1
107
108	# Setup L2CAP
109	ngctl mkpeer ${dev}hci: l2cap acl hci \
110		> /dev/null 2>&1 || return 1
111
112	ngctl name ${dev}hci:acl ${dev}l2cap \
113		> /dev/null 2>&1 || return 1
114
115	ngctl msg ${dev}l2cap: set_debug ${bluetooth_device_l2cap_debug_level} \
116		> /dev/null 2>&1 || return 1
117
118	# Connect HCI node to the Bluetooth sockets layer
119	ngctl connect ${dev}hci: btsock_hci_raw: raw ${dev}raw \
120		> /dev/null 2>&1 || return 1
121
122	# Connect L2CAP node to Bluetooth sockets layer
123	ngctl connect ${dev}l2cap: btsock_l2c_raw: ctl ${dev}ctl \
124		> /dev/null 2>&1 || return 1
125
126	ngctl connect ${dev}l2cap: btsock_l2c: l2c ${dev}l2c \
127		> /dev/null 2>&1 || return 1
128
129	# Initilalize HCI node
130	for loop in 1 2 3
131	do
132		${hccontrol} -n ${dev}hci reset \
133			> /dev/null 2>&1 && break
134		if [ ${loop} -eq 3 ]
135		then
136			warn Reset failed three times, giving up.
137			return 1
138		fi
139		warn Reset failed, retrying.
140	done
141
142	${hccontrol} -n ${dev}hci read_bd_addr \
143		> /dev/null 2>&1 || return 1
144
145	${hccontrol} -n ${dev}hci read_local_supported_features \
146		> /dev/null 2>&1 || return 1
147
148	${hccontrol} -n ${dev}hci read_buffer_size \
149		> /dev/null 2>&1 || return 1
150
151	if checkyesno bluetooth_device_discoverable; then
152		if checkyesno bluetooth_device_connectable; then
153			${hccontrol} -n ${dev}hci write_scan_enable 3 \
154				> /dev/null 2>&1 || return 1
155		else
156			${hccontrol} -n ${dev}hci write_scan_enable 1 \
157				> /dev/null 2>&1 || return 1
158		fi
159	else
160		if checkyesno bluetooth_device_connectable; then
161			${hccontrol} -n ${dev}hci write_scan_enable 2 \
162				> /dev/null 2>&1 || return 1
163		else
164			${hccontrol} -n ${dev}hci write_scan_enable 0 \
165				> /dev/null 2>&1 || return 1
166		fi
167	fi
168
169
170	${hccontrol} -n ${dev}hci write_class_of_device ${bluetooth_device_class} \
171		> /dev/null 2>&1 || return 1
172
173	if checkyesno bluetooth_device_authentication_enable; then
174		${hccontrol} -n ${dev}hci write_authentication_enable 1 \
175			> /dev/null 2>&1 || return 1
176	else
177		${hccontrol} -n ${dev}hci write_authentication_enable 0 \
178			> /dev/null 2>&1 || return 1
179	fi
180
181	case "${bluetooth_device_encryption_mode}" in
182	[Nn][Oo][Nn][Ee]|0)
183		${hccontrol} -n ${dev}hci write_encryption_mode 0 \
184			> /dev/null 2>&1 || return 1
185		;;
186
187	[Pp][2][Pp]|1)
188		${hccontrol} -n ${dev}hci write_encryption_mode 1 \
189			> /dev/null 2>&1 || return 1
190		;;
191
192	[Al][Ll][Ll]|2)
193		${hccontrol} -n ${dev}hci write_encryption_mode 2 \
194			> /dev/null 2>&1 || return 1
195		;;
196
197	*)
198		warn "Unsupported encryption mode ${bluetooth_device_encryption_mode} for device ${dev}"
199		return 1
200		;;
201	esac
202
203	if checkyesno bluetooth_device_role_switch; then
204		${hccontrol} -n ${dev}hci write_node_role_switch 1 \
205			> /dev/null 2>&1 || return 1
206	else
207		${hccontrol} -n ${dev}hci write_node_role_switch 0 \
208			> /dev/null 2>&1 || return 1
209	fi
210
211	${hccontrol} -n ${dev}hci change_local_name "${bluetooth_device_local_name}" \
212		> /dev/null 2>&1 || return 1
213
214	${hccontrol} -n ${dev}hci initialize \
215		> /dev/null 2>&1 || return 1
216
217	return 0
218}
219
220##############################################################################
221# Shutdown Bluetooth stack. Destroy all nodes
222##############################################################################
223
224bluetooth_shutdown_stack()
225{
226	dev=$1
227
228	ngctl shutdown ${dev}hci: > /dev/null 2>&1
229	ngctl shutdown ${dev}l2cap: > /dev/null 2>&1
230
231	return 0
232}
233
234##############################################################################
235# bluetooth_start()
236##############################################################################
237
238bluetooth_start()
239{
240	local _file
241
242	dev=$1
243
244	# Try to figure out device type by looking at device name
245	case "${dev}" in
246	# USB Bluetooth adapters
247	ubt*)
248		hook="hook"
249
250		# Obtain unit number from device.
251		unit=`expr ${dev} : 'ubt\([0-9]\{1,\}\)'`
252		if [ -z "${unit}" ]; then
253			err 1 "Unable to get ubt unit number: ${dev}"
254		fi
255		;;
256
257	# Unknown
258	*)
259		err 1 "Unsupported device: ${dev}"
260		;;
261	esac
262
263	# Be backward compatible and setup reasonable defaults
264	bluetooth_device_authentication_enable="0"
265	bluetooth_device_class="ff:01:0c"
266	bluetooth_device_connectable="1"
267	bluetooth_device_discoverable="0"
268	bluetooth_device_encryption_mode="0"
269	bluetooth_device_hci_debug_level="3"
270	bluetooth_device_l2cap_debug_level="3"
271	bluetooth_device_local_name="`/usr/bin/uname -n` (${dev})"
272	bluetooth_device_role_switch="1"
273
274	# Load default device configuration parameters
275	_file="/etc/defaults/bluetooth.device.conf"
276
277	if ! bluetooth_read_conf $_file bluetooth_device_ ; then
278		err 1 "Unable to read default Bluetooth configuration from $_file"
279	fi
280
281	# Load device specific overrides
282	_file="/etc/bluetooth/$dev.conf"
283
284	if ! bluetooth_read_conf $_file bluetooth_device_ ; then
285		err 1 "Unable to read Bluetooth device configuration from $_file"
286	fi
287
288	# Setup stack
289	if ! bluetooth_setup_stack ${dev} ${hook} ; then
290		bluetooth_shutdown_stack $dev
291		err 1 "Unable to setup Bluetooth stack for device ${dev}"
292	fi
293
294	return 0
295}
296
297##############################################################################
298# bluetooth_stop()
299##############################################################################
300
301bluetooth_stop()
302{
303	dev=$1
304
305	# Try to figure out device type by looking at device name
306	case "${dev}" in
307	# USB Bluetooth adapters
308	ubt*)
309		;;
310
311	# Unknown
312	*)
313		err 1 "Unsupported device: ${dev}"
314		;;
315	esac
316
317	bluetooth_shutdown_stack ${dev}
318
319	return 0
320}
321
322##############################################################################
323# Start here
324##############################################################################
325
326load_rc_config $name
327hccontrol="${bluetooth_hccontrol:-/usr/sbin/hccontrol}"
328
329# doesn't make sense to run in a svcj: nojail keyword
330bluetooth_svcj="NO"
331
332run_rc_command $*
333
334