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# $FreeBSD$
28
29# PROVIDE: bluetooth
30# REQUIRE: DAEMON
31# KEYWORD: nojail nostart
32
33. /etc/rc.subr
34
35name="bluetooth"
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	${hccontrol} -n ${dev}hci reset \
131		> /dev/null 2>&1 || return 1
132
133	${hccontrol} -n ${dev}hci read_bd_addr \
134		> /dev/null 2>&1 || return 1
135
136	${hccontrol} -n ${dev}hci read_local_supported_features \
137		> /dev/null 2>&1 || return 1
138
139	${hccontrol} -n ${dev}hci read_buffer_size \
140		> /dev/null 2>&1 || return 1
141
142	if checkyesno bluetooth_device_discoverable; then
143		if checkyesno bluetooth_device_connectable; then
144			${hccontrol} -n ${dev}hci write_scan_enable 3 \
145				> /dev/null 2>&1 || return 1
146		else
147			${hccontrol} -n ${dev}hci write_scan_enable 1 \
148				> /dev/null 2>&1 || return 1
149		fi
150	else
151		if checkyesno bluetooth_device_connectable; then
152			${hccontrol} -n ${dev}hci write_scan_enable 2 \
153				> /dev/null 2>&1 || return 1
154		else
155			${hccontrol} -n ${dev}hci write_scan_enable 0 \
156				> /dev/null 2>&1 || return 1
157		fi
158	fi
159
160
161	${hccontrol} -n ${dev}hci write_class_of_device ${bluetooth_device_class} \
162		> /dev/null 2>&1 || return 1
163
164	if checkyesno bluetooth_device_authentication_enable; then
165		${hccontrol} -n ${dev}hci write_authentication_enable 1 \
166			> /dev/null 2>&1 || return 1
167	else
168		${hccontrol} -n ${dev}hci write_authentication_enable 0 \
169			> /dev/null 2>&1 || return 1
170	fi
171
172	case "${bluetooth_device_encryption_mode}" in
173	[Nn][Oo][Nn][Ee]|0)
174		${hccontrol} -n ${dev}hci write_encryption_mode 0 \
175			> /dev/null 2>&1 || return 1
176		;;
177
178	[Pp][2][Pp]|1)
179		${hccontrol} -n ${dev}hci write_encryption_mode 1 \
180			> /dev/null 2>&1 || return 1
181		;;
182
183	[Al][Ll][Ll]|2)
184		${hccontrol} -n ${dev}hci write_encryption_mode 2 \
185			> /dev/null 2>&1 || return 1
186		;;
187
188	*)
189		warn "Unsupported encryption mode ${bluetooth_device_encryption_mode} for device ${dev}"
190		return 1
191		;;
192	esac
193
194	if checkyesno bluetooth_device_role_switch; then
195		${hccontrol} -n ${dev}hci write_node_role_switch 1 \
196			> /dev/null 2>&1 || return 1
197	else
198		${hccontrol} -n ${dev}hci write_node_role_switch 0 \
199			> /dev/null 2>&1 || return 1
200	fi
201
202	${hccontrol} -n ${dev}hci change_local_name "${bluetooth_device_local_name}" \
203		> /dev/null 2>&1 || return 1
204
205	${hccontrol} -n ${dev}hci initialize \
206		> /dev/null 2>&1 || return 1
207
208	return 0
209}
210
211##############################################################################
212# Shutdown Bluetooth stack. Destroy all nodes
213##############################################################################
214
215bluetooth_shutdown_stack()
216{
217	dev=$1
218
219	ngctl shutdown ${dev}hci: > /dev/null 2>&1
220	ngctl shutdown ${dev}l2cap: > /dev/null 2>&1
221
222	return 0
223}
224
225##############################################################################
226# bluetooth_start()
227##############################################################################
228
229bluetooth_start()
230{
231	local _file
232
233	dev=$1
234
235	# Try to figure out device type by looking at device name
236	case "${dev}" in
237	# uartX - serial/UART Bluetooth device
238	uart*)
239		load_kld ng_h4 || return 1
240
241		hook="hook"
242
243		# Obtain unit number from device.
244		unit=`expr ${dev} : 'uart\([0-9]\{1,\}\)'`
245		if [ -z "${unit}" ]; then
246			err 1 "Unable to get uart unit number: ${dev}"
247		fi
248
249		${hcseriald} -f /dev/cuau${unit} -n ${dev}
250		sleep 1 # wait a little bit
251
252		if [ ! -f "/var/run/hcseriald.${dev}.pid" ]; then
253			err 1 "Unable to start hcseriald on ${dev}"
254		fi
255		;;
256
257	# 3Com Bluetooth Adapter 3CRWB60-A
258	btccc*)
259		hook="hook"
260
261		# Obtain unit number from device.
262		unit=`expr ${dev} : 'btccc\([0-9]\{1,\}\)'`
263		if [ -z "${unit}" ]; then
264			err 1 "Unable to get bt3c unit number: ${dev}"
265		fi
266		;;
267
268	# USB Bluetooth adapters
269	ubt*)
270		hook="hook"
271
272		# Obtain unit number from device.
273		unit=`expr ${dev} : 'ubt\([0-9]\{1,\}\)'`
274		if [ -z "${unit}" ]; then
275			err 1 "Unable to get ubt unit number: ${dev}"
276		fi
277		;;
278
279	# Unknown
280	*)
281		err 1 "Unsupported device: ${dev}"
282		;;
283	esac
284
285	# Be backward compatible and setup reasonable defaults
286	bluetooth_device_authentication_enable="0"
287	bluetooth_device_class="ff:01:0c"
288	bluetooth_device_connectable="1"
289	bluetooth_device_discoverable="1"
290	bluetooth_device_encryption_mode="0"
291	bluetooth_device_hci_debug_level="3"
292	bluetooth_device_l2cap_debug_level="3"
293	bluetooth_device_local_name="`/usr/bin/uname -n` (${dev})"
294	bluetooth_device_role_switch="1"
295
296	# Load default device configuration parameters
297	_file="/etc/defaults/bluetooth.device.conf"
298
299	if ! bluetooth_read_conf $_file bluetooth_device_ ; then
300		err 1 "Unable to read default Bluetooth configuration from $_file"
301	fi
302
303	# Load device specific overrides
304	_file="/etc/bluetooth/$dev.conf"
305
306	if ! bluetooth_read_conf $_file bluetooth_device_ ; then
307		err 1 "Unable to read Bluetooth device configuration from $_file"
308	fi
309
310	# Setup stack
311	if ! bluetooth_setup_stack ${dev} ${hook} ; then
312		bluetooth_shutdown_stack $dev
313		err 1 "Unable to setup Bluetooth stack for device ${dev}"
314	fi
315
316	return 0
317}
318
319##############################################################################
320# bluetooth_stop()
321##############################################################################
322
323bluetooth_stop()
324{
325	dev=$1
326
327	# Try to figure out device type by looking at device name
328	case "${dev}" in
329	# uartX - serial/UART Bluetooth device
330	uart*)
331		if [ -f "/var/run/hcseriald.${dev}.pid" ]; then
332			kill `cat /var/run/hcseriald.${dev}.pid`
333			sleep 1 # wait a little bit
334		fi
335		;;
336
337	# 3Com Bluetooth Adapter 3CRWB60-A
338	btccc*)
339		;;
340
341	# USB Bluetooth adapters
342	ubt*)
343		;;
344
345	# Unknown
346	*)
347		err 1 "Unsupported device: ${dev}"
348		;;
349	esac
350
351	bluetooth_shutdown_stack ${dev}
352
353	return 0
354}
355
356##############################################################################
357# Start here
358##############################################################################
359
360load_rc_config $name
361hccontrol="${bluetooth_hccontrol:-/usr/sbin/hccontrol}"
362hcseriald="${bluetooth_hcseriald:-/usr/sbin/hcseriald}"
363
364run_rc_command $*
365
366