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"
36desc="Bluetooth setup script"
37rcvar=
38start_cmd="bluetooth_start"
39stop_cmd="bluetooth_stop"
40required_modules="ng_bluetooth ng_hci ng_l2cap ng_btsocket"
41
42##############################################################################
43# Read and parse Bluetooth device configuration file
44##############################################################################
45
46bluetooth_read_conf()
47{
48	local _err _file _line _namespace
49
50	_file=$1
51	_namespace=$2
52	_err=0
53
54	if [ ! -e $_file ]; then
55		return 0
56	fi
57
58	if [ ! -f $_file -o ! -r $_file ]; then
59		err 1 "Bluetooth configuration file $_file is not a file or not readable"
60	fi
61
62	while read _line
63	do
64		case "$_line" in
65		\#*)
66			continue
67			;;
68
69		*)
70			if [ -z "$_line" ]; then
71				continue;
72			fi
73
74
75			if expr "$_line" : "[a-zA-Z0-9_]*=" > /dev/null 2>&1; then
76				eval "${_namespace}${_line}"
77			else
78				warn "Unable to parse line \"$_line\" in $_file"
79				_err=1
80			fi
81			;;
82		esac
83	done < $_file
84
85	return $_err
86}
87
88##############################################################################
89# Setup Bluetooth stack. Create and connect nodes
90##############################################################################
91
92bluetooth_setup_stack()
93{
94	dev=$1
95	shift
96	hook=$1
97	shift
98
99	# Setup HCI
100	ngctl mkpeer ${dev}: hci ${hook} drv \
101		> /dev/null 2>&1 || return 1
102
103	ngctl name ${dev}:${hook} ${dev}hci \
104		> /dev/null 2>&1 || return 1
105
106	ngctl msg ${dev}hci: set_debug ${bluetooth_device_hci_debug_level} \
107		> /dev/null 2>&1 || return 1
108
109	# Setup L2CAP
110	ngctl mkpeer ${dev}hci: l2cap acl hci \
111		> /dev/null 2>&1 || return 1
112
113	ngctl name ${dev}hci:acl ${dev}l2cap \
114		> /dev/null 2>&1 || return 1
115
116	ngctl msg ${dev}l2cap: set_debug ${bluetooth_device_l2cap_debug_level} \
117		> /dev/null 2>&1 || return 1
118
119	# Connect HCI node to the Bluetooth sockets layer
120	ngctl connect ${dev}hci: btsock_hci_raw: raw ${dev}raw \
121		> /dev/null 2>&1 || return 1
122
123	# Connect L2CAP node to Bluetooth sockets layer
124	ngctl connect ${dev}l2cap: btsock_l2c_raw: ctl ${dev}ctl \
125		> /dev/null 2>&1 || return 1
126
127	ngctl connect ${dev}l2cap: btsock_l2c: l2c ${dev}l2c \
128		> /dev/null 2>&1 || return 1
129
130	# Initilalize HCI node
131	${hccontrol} -n ${dev}hci reset \
132		> /dev/null 2>&1 || return 1
133
134	${hccontrol} -n ${dev}hci read_bd_addr \
135		> /dev/null 2>&1 || return 1
136
137	${hccontrol} -n ${dev}hci read_local_supported_features \
138		> /dev/null 2>&1 || return 1
139
140	${hccontrol} -n ${dev}hci read_buffer_size \
141		> /dev/null 2>&1 || return 1
142
143	if checkyesno bluetooth_device_discoverable; then
144		if checkyesno bluetooth_device_connectable; then
145			${hccontrol} -n ${dev}hci write_scan_enable 3 \
146				> /dev/null 2>&1 || return 1
147		else
148			${hccontrol} -n ${dev}hci write_scan_enable 1 \
149				> /dev/null 2>&1 || return 1
150		fi
151	else
152		if checkyesno bluetooth_device_connectable; then
153			${hccontrol} -n ${dev}hci write_scan_enable 2 \
154				> /dev/null 2>&1 || return 1
155		else
156			${hccontrol} -n ${dev}hci write_scan_enable 0 \
157				> /dev/null 2>&1 || return 1
158		fi
159	fi
160
161
162	${hccontrol} -n ${dev}hci write_class_of_device ${bluetooth_device_class} \
163		> /dev/null 2>&1 || return 1
164
165	if checkyesno bluetooth_device_authentication_enable; then
166		${hccontrol} -n ${dev}hci write_authentication_enable 1 \
167			> /dev/null 2>&1 || return 1
168	else
169		${hccontrol} -n ${dev}hci write_authentication_enable 0 \
170			> /dev/null 2>&1 || return 1
171	fi
172
173	case "${bluetooth_device_encryption_mode}" in
174	[Nn][Oo][Nn][Ee]|0)
175		${hccontrol} -n ${dev}hci write_encryption_mode 0 \
176			> /dev/null 2>&1 || return 1
177		;;
178
179	[Pp][2][Pp]|1)
180		${hccontrol} -n ${dev}hci write_encryption_mode 1 \
181			> /dev/null 2>&1 || return 1
182		;;
183
184	[Al][Ll][Ll]|2)
185		${hccontrol} -n ${dev}hci write_encryption_mode 2 \
186			> /dev/null 2>&1 || return 1
187		;;
188
189	*)
190		warn "Unsupported encryption mode ${bluetooth_device_encryption_mode} for device ${dev}"
191		return 1
192		;;
193	esac
194
195	if checkyesno bluetooth_device_role_switch; then
196		${hccontrol} -n ${dev}hci write_node_role_switch 1 \
197			> /dev/null 2>&1 || return 1
198	else
199		${hccontrol} -n ${dev}hci write_node_role_switch 0 \
200			> /dev/null 2>&1 || return 1
201	fi
202
203	${hccontrol} -n ${dev}hci change_local_name "${bluetooth_device_local_name}" \
204		> /dev/null 2>&1 || return 1
205
206	${hccontrol} -n ${dev}hci initialize \
207		> /dev/null 2>&1 || return 1
208
209	return 0
210}
211
212##############################################################################
213# Shutdown Bluetooth stack. Destroy all nodes
214##############################################################################
215
216bluetooth_shutdown_stack()
217{
218	dev=$1
219
220	ngctl shutdown ${dev}hci: > /dev/null 2>&1
221	ngctl shutdown ${dev}l2cap: > /dev/null 2>&1
222
223	return 0
224}
225
226##############################################################################
227# bluetooth_start()
228##############################################################################
229
230bluetooth_start()
231{
232	local _file
233
234	dev=$1
235
236	# Try to figure out device type by looking at device name
237	case "${dev}" in
238	# uartX - serial/UART Bluetooth device
239	uart*)
240		load_kld ng_h4 || return 1
241
242		hook="hook"
243
244		# Obtain unit number from device.
245		unit=`expr ${dev} : 'uart\([0-9]\{1,\}\)'`
246		if [ -z "${unit}" ]; then
247			err 1 "Unable to get uart unit number: ${dev}"
248		fi
249
250		${hcseriald} -f /dev/cuau${unit} -n ${dev}
251		sleep 1 # wait a little bit
252
253		if [ ! -f "/var/run/hcseriald.${dev}.pid" ]; then
254			err 1 "Unable to start hcseriald on ${dev}"
255		fi
256		;;
257
258	# 3Com Bluetooth Adapter 3CRWB60-A
259	btccc*)
260		hook="hook"
261
262		# Obtain unit number from device.
263		unit=`expr ${dev} : 'btccc\([0-9]\{1,\}\)'`
264		if [ -z "${unit}" ]; then
265			err 1 "Unable to get bt3c unit number: ${dev}"
266		fi
267		;;
268
269	# USB Bluetooth adapters
270	ubt*)
271		hook="hook"
272
273		# Obtain unit number from device.
274		unit=`expr ${dev} : 'ubt\([0-9]\{1,\}\)'`
275		if [ -z "${unit}" ]; then
276			err 1 "Unable to get ubt unit number: ${dev}"
277		fi
278		;;
279
280	# Unknown
281	*)
282		err 1 "Unsupported device: ${dev}"
283		;;
284	esac
285
286	# Be backward compatible and setup reasonable defaults
287	bluetooth_device_authentication_enable="0"
288	bluetooth_device_class="ff:01:0c"
289	bluetooth_device_connectable="1"
290	bluetooth_device_discoverable="1"
291	bluetooth_device_encryption_mode="0"
292	bluetooth_device_hci_debug_level="3"
293	bluetooth_device_l2cap_debug_level="3"
294	bluetooth_device_local_name="`/usr/bin/uname -n` (${dev})"
295	bluetooth_device_role_switch="1"
296
297	# Load default device configuration parameters
298	_file="/etc/defaults/bluetooth.device.conf"
299
300	if ! bluetooth_read_conf $_file bluetooth_device_ ; then
301		err 1 "Unable to read default Bluetooth configuration from $_file"
302	fi
303
304	# Load device specific overrides
305	_file="/etc/bluetooth/$dev.conf"
306
307	if ! bluetooth_read_conf $_file bluetooth_device_ ; then
308		err 1 "Unable to read Bluetooth device configuration from $_file"
309	fi
310
311	# Setup stack
312	if ! bluetooth_setup_stack ${dev} ${hook} ; then
313		bluetooth_shutdown_stack $dev
314		err 1 "Unable to setup Bluetooth stack for device ${dev}"
315	fi
316
317	return 0
318}
319
320##############################################################################
321# bluetooth_stop()
322##############################################################################
323
324bluetooth_stop()
325{
326	dev=$1
327
328	# Try to figure out device type by looking at device name
329	case "${dev}" in
330	# uartX - serial/UART Bluetooth device
331	uart*)
332		if [ -f "/var/run/hcseriald.${dev}.pid" ]; then
333			kill `cat /var/run/hcseriald.${dev}.pid`
334			sleep 1 # wait a little bit
335		fi
336		;;
337
338	# 3Com Bluetooth Adapter 3CRWB60-A
339	btccc*)
340		;;
341
342	# USB Bluetooth adapters
343	ubt*)
344		;;
345
346	# Unknown
347	*)
348		err 1 "Unsupported device: ${dev}"
349		;;
350	esac
351
352	bluetooth_shutdown_stack ${dev}
353
354	return 0
355}
356
357##############################################################################
358# Start here
359##############################################################################
360
361load_rc_config $name
362hccontrol="${bluetooth_hccontrol:-/usr/sbin/hccontrol}"
363hcseriald="${bluetooth_hcseriald:-/usr/sbin/hcseriald}"
364
365run_rc_command $*
366
367