Wed Nov 3 08:27:27 2010 UTC ()
In server mode, relax the requirement to specify a channel number. If
one is not given, attempt to allocate the first unused one.


(plunky)
diff -r1.8 -r1.9 src/usr.bin/rfcomm_sppd/rfcomm_sppd.1
diff -r1.12 -r1.13 src/usr.bin/rfcomm_sppd/rfcomm_sppd.c

cvs diff -r1.8 -r1.9 src/usr.bin/rfcomm_sppd/rfcomm_sppd.1 (switch to unified diff)

--- src/usr.bin/rfcomm_sppd/rfcomm_sppd.1 2010/11/02 19:44:09 1.8
+++ src/usr.bin/rfcomm_sppd/rfcomm_sppd.1 2010/11/03 08:27:27 1.9
@@ -1,226 +1,226 @@ @@ -1,226 +1,226 @@
1.\" $NetBSD: rfcomm_sppd.1,v 1.8 2010/11/02 19:44:09 plunky Exp $ 1.\" $NetBSD: rfcomm_sppd.1,v 1.9 2010/11/03 08:27:27 plunky Exp $
2.\" 2.\"
3.\" Copyright (c) 2006 Itronix Inc. 3.\" Copyright (c) 2006 Itronix Inc.
4.\" All rights reserved. 4.\" All rights reserved.
5.\" 5.\"
6.\" Redistribution and use in source and binary forms, with or without 6.\" Redistribution and use in source and binary forms, with or without
7.\" modification, are permitted provided that the following conditions 7.\" modification, are permitted provided that the following conditions
8.\" are met: 8.\" are met:
9.\" 1. Redistributions of source code must retain the above copyright 9.\" 1. Redistributions of source code must retain the above copyright
10.\" notice, this list of conditions and the following disclaimer. 10.\" notice, this list of conditions and the following disclaimer.
11.\" 2. Redistributions in binary form must reproduce the above copyright 11.\" 2. Redistributions in binary form must reproduce the above copyright
12.\" notice, this list of conditions and the following disclaimer in the 12.\" notice, this list of conditions and the following disclaimer in the
13.\" documentation and/or other materials provided with the distribution. 13.\" documentation and/or other materials provided with the distribution.
14.\" 3. The name of Itronix Inc. may not be used to endorse 14.\" 3. The name of Itronix Inc. may not be used to endorse
15.\" or promote products derived from this software without specific 15.\" or promote products derived from this software without specific
16.\" prior written permission. 16.\" prior written permission.
17.\" 17.\"
18.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 18.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
19.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 21.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
22.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25.\" ON ANY THEORY OF LIABILITY, WHETHER IN 25.\" ON ANY THEORY OF LIABILITY, WHETHER IN
26.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28.\" POSSIBILITY OF SUCH DAMAGE. 28.\" POSSIBILITY OF SUCH DAMAGE.
29.\" 29.\"
30.\" 30.\"
31.\" Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 31.\" Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
32.\" All rights reserved. 32.\" All rights reserved.
33.\" 33.\"
34.\" Redistribution and use in source and binary forms, with or without 34.\" Redistribution and use in source and binary forms, with or without
35.\" modification, are permitted provided that the following conditions 35.\" modification, are permitted provided that the following conditions
36.\" are met: 36.\" are met:
37.\" 1. Redistributions of source code must retain the above copyright 37.\" 1. Redistributions of source code must retain the above copyright
38.\" notice, this list of conditions and the following disclaimer. 38.\" notice, this list of conditions and the following disclaimer.
39.\" 2. Redistributions in binary form must reproduce the above copyright 39.\" 2. Redistributions in binary form must reproduce the above copyright
40.\" notice, this list of conditions and the following disclaimer in the 40.\" notice, this list of conditions and the following disclaimer in the
41.\" documentation and/or other materials provided with the distribution. 41.\" documentation and/or other materials provided with the distribution.
42.\" 42.\"
43.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 43.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
44.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 46.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
47.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53.\" SUCH DAMAGE. 53.\" SUCH DAMAGE.
54.\" 54.\"
55.Dd November 2, 2010 55.Dd November 2, 2010
56.Dt RFCOMM_SPPD 1 56.Dt RFCOMM_SPPD 1
57.Os 57.Os
58.Sh NAME 58.Sh NAME
59.Nm rfcomm_sppd 59.Nm rfcomm_sppd
60.Nd RFCOMM Serial Port Profile daemon 60.Nd RFCOMM Serial Port Profile daemon
61.Sh SYNOPSIS 61.Sh SYNOPSIS
62.Nm 62.Nm
63.Op Fl d Ar device 63.Op Fl d Ar device
64.Op Fl m Ar mode 64.Op Fl m Ar mode
65.Op Fl p Ar psm 65.Op Fl p Ar psm
66.Op Fl s Ar service 66.Op Fl s Ar service
67.Op Fl t Ar tty 67.Op Fl t Ar tty
68.Brq Fl a Ar address | Fl c Ar channel 68.Brq Fl a Ar address | Op Fl c Ar channel
69.Sh DESCRIPTION 69.Sh DESCRIPTION
70The 70The
71.Nm 71.Nm
72utility is a Serial Port Profile daemon, providing serial access over 72utility is a Serial Port Profile daemon, providing serial access over
73an RFCOMM connection to a remote device. 73an RFCOMM connection to a remote device.
74.Nm 74.Nm
75can work in client or server mode. 75can work in client or server mode.
76.Pp 76.Pp
77In client mode, 77In client mode,
78.Nm 78.Nm
79initiates an RFCOMM connection to the 79initiates an RFCOMM connection to the
80.Ar service 80.Ar service
81at the remote 81at the remote
82.Ar address . 82.Ar address .
83.Pp 83.Pp
84In server mode, 84In server mode,
85.Nm 85.Nm
86registers the 86registers the
87.Ar service 87.Ar service
88with the local SDP server and listens on the specified RFCOMM 88with the local SDP server and listens on the specified RFCOMM
89.Ar channel 89.Ar channel
90for an incoming connection. 90for an incoming connection, or the first unused channel if none
 91was given.
91.Pp 92.Pp
92The options are as follows: 93The options are as follows:
93.Bl -tag -width ".Fl c Ar channel" 94.Bl -tag -width ".Fl c Ar channel"
94.It Fl a Ar address 95.It Fl a Ar address
95Client mode. 96Client mode.
96Specify the address of the remote RFCOMM device. 97Specify the address of the remote RFCOMM device.
97The address can be specified as BD_ADDR or name. 98The address can be specified as BD_ADDR or name.
98If given as a name, then the 99If given as a name, then the
99.Nm 100.Nm
100utility will attempt to resolve the name via 101utility will attempt to resolve the name via
101.Xr bt_gethostbyname 3 . 102.Xr bt_gethostbyname 3 .
102.It Fl c Ar channel 103.It Fl c Ar channel
103Server mode. 104In server mode, specify the RFCOMM channel number to listen on.
104Specify the RFCOMM channel number to listen on. 
105.Nm 105.Nm
106will register the service with the local 106will register the service with the local
107.Xr sdpd 8 107.Xr sdpd 8
108daemon. 108daemon.
109Note that registering services with 109Note that registering services with
110.Xr sdpd 8 110.Xr sdpd 8
111is a privileged operation. 111is a privileged operation.
112.It Fl d Ar device 112.It Fl d Ar device
113Use the local device with the specified address. 113Use the local device with the specified address.
114The device can be specified by BD_ADDR or device name. 114The device can be specified by BD_ADDR or device name.
115See 115See
116.Xr btconfig 8 116.Xr btconfig 8
117for a list of available devices. 117for a list of available devices.
118If no 118If no
119.Ar device 119.Ar device
120is specified, the connection will be set up on a system determined device. 120is specified, the connection will be set up on a system determined device.
121.It Fl m Ar mode 121.It Fl m Ar mode
122Set connection link mode. 122Set connection link mode.
123Supported modes are: 123Supported modes are:
124.Pp 124.Pp
125.Bl -tag -compact -offset indent 125.Bl -tag -compact -offset indent
126.It auth 126.It auth
127require devices be paired. 127require devices be paired.
128.It encrypt 128.It encrypt
129auth, plus enable encryption. 129auth, plus enable encryption.
130.It secure 130.It secure
131encryption, plus change of link key. 131encryption, plus change of link key.
132.El 132.El
133.It Fl p Ar psm 133.It Fl p Ar psm
134Specify the 134Specify the
135.Qq Protocol/Service Multiplexer 135.Qq Protocol/Service Multiplexer
136value to be used for the RFCOMM protocol. 136value to be used for the RFCOMM protocol.
137In client mode where Service Discovery is being used, this value 137In client mode where Service Discovery is being used, this value
138will be ignored. 138will be ignored.
139.It Fl s Ar service 139.It Fl s Ar service
140Name of service class to connect to or register. 140Name of service class to connect to or register.
141If no 141If no
142.Ar service 142.Ar service
143is given, the default 143is given, the default
144.Qq Serial Port 144.Qq Serial Port
145service class will be used. 145service class will be used.
146Known service classes are: 146Known service classes are:
147.Pp 147.Pp
148.Bl -tag -compact -offset indent 148.Bl -tag -compact -offset indent
149.It DUN 149.It DUN
150Dialup Networking 150Dialup Networking
151.It LAN 151.It LAN
152LAN access using PPP 152LAN access using PPP
153.It SP 153.It SP
154Serial Port 154Serial Port
155.El 155.El
156.Pp 156.Pp
157In client mode, the service class may be given as a channel number, for instances 157In client mode, the service class may be given as a channel number, for instances
158where the remote device does not provide Service Discovery. 158where the remote device does not provide Service Discovery.
159.It Fl t Ar tty 159.It Fl t Ar tty
160Slave pseudo tty name. 160Slave pseudo tty name.
161If this option is given, 161If this option is given,
162.Nm 162.Nm
163will detach from the controlling process after the Bluetooth connection is 163will detach from the controlling process after the Bluetooth connection is
164made, and operate over the named 164made, and operate over the named
165.Xr pty 4 165.Xr pty 4
166pair. 166pair.
167Otherwise, stdin/stdout will be used. 167Otherwise, stdin/stdout will be used.
168.El 168.El
169.Sh EXIT STATUS 169.Sh EXIT STATUS
170.Ex -std 170.Ex -std
171.Sh FILES 171.Sh FILES
172.Bl -tag -width ".Pa /dev/tty[p-sP-S][0-9a-v]" -compact 172.Bl -tag -width ".Pa /dev/tty[p-sP-S][0-9a-v]" -compact
173.It Pa /dev/pty[p-sP-S][0-9a-v] 173.It Pa /dev/pty[p-sP-S][0-9a-v]
174master pseudo terminals 174master pseudo terminals
175.It Pa /dev/tty[p-sP-S][0-9a-v] 175.It Pa /dev/tty[p-sP-S][0-9a-v]
176slave pseudo terminals 176slave pseudo terminals
177.El 177.El
178.Sh EXAMPLES 178.Sh EXAMPLES
179.Dl rfcomm_sppd -a 00:01:02:03:04:05 -s 1 -t /dev/ttyp1 179.Dl rfcomm_sppd -a 00:01:02:03:04:05 -s 1 -t /dev/ttyp1
180.Pp 180.Pp
181Will open an RFCOMM connection to the server at 181Will open an RFCOMM connection to the server at
182.Li 00:01:02:03:04:05 182.Li 00:01:02:03:04:05
183on channel 183on channel
184.Li 1 . 184.Li 1 .
185Once the connection has been established, 185Once the connection has been established,
186.Nm 186.Nm
187will detach and 187will detach and
188.Pa /dev/ttyp1 188.Pa /dev/ttyp1
189can be used to communicate with the remote serial port on the 189can be used to communicate with the remote serial port on the
190server, e.g. with the use of 190server, e.g. with the use of
191.Pp 191.Pp
192.Dl cu -l /dev/ttyp1 192.Dl cu -l /dev/ttyp1
193.Pp 193.Pp
194In order to use 194In order to use
195.Nm 195.Nm
196to automatically create a secured link for 196to automatically create a secured link for
197.Xr pppd 8 , 197.Xr pppd 8 ,
198use 198use
199.Dl pty Qo rfcomm_sppd -a 00:01:02:03:04:05 -s DUN -m secure Qc 199.Dl pty Qo rfcomm_sppd -a 00:01:02:03:04:05 -s DUN -m secure Qc
200.Pp 200.Pp
201in your 201in your
202.Xr pppd 8 202.Xr pppd 8
203configuration file. 203configuration file.
204.Sh SEE ALSO 204.Sh SEE ALSO
205.Xr bluetooth 3 , 205.Xr bluetooth 3 ,
206.Xr bluetooth 4 , 206.Xr bluetooth 4 ,
207.Xr pty 4 , 207.Xr pty 4 ,
208.Xr btconfig 8 , 208.Xr btconfig 8 ,
209.Xr pppd 8 , 209.Xr pppd 8 ,
210.Xr sdpd 8 210.Xr sdpd 8
211.Sh HISTORY 211.Sh HISTORY
212The 212The
213.Nm 213.Nm
214program first appeared in 214program first appeared in
215.Fx 215.Fx
216and was ported to 216and was ported to
217.Nx 4.0 217.Nx 4.0
218by 218by
219.An Iain Hibbert 219.An Iain Hibbert
220under the sponsorship of 220under the sponsorship of
221.An Itronix, Inc . 221.An Itronix, Inc .
222.Sh AUTHORS 222.Sh AUTHORS
223.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com , 223.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com ,
224.An Iain Hibbert 224.An Iain Hibbert
225.Sh BUGS 225.Sh BUGS
226Please report if found. 226Please report if found.

cvs diff -r1.12 -r1.13 src/usr.bin/rfcomm_sppd/rfcomm_sppd.c (switch to unified diff)

--- src/usr.bin/rfcomm_sppd/rfcomm_sppd.c 2009/09/24 18:30:37 1.12
+++ src/usr.bin/rfcomm_sppd/rfcomm_sppd.c 2010/11/03 08:27:27 1.13
@@ -1,691 +1,698 @@ @@ -1,691 +1,698 @@
1/* $NetBSD: rfcomm_sppd.c,v 1.12 2009/09/24 18:30:37 plunky Exp $ */ 1/* $NetBSD: rfcomm_sppd.c,v 1.13 2010/11/03 08:27:27 plunky Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2006 Itronix Inc. 4 * Copyright (c) 2006 Itronix Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of Itronix Inc. may not be used to endorse 15 * 3. The name of Itronix Inc. may not be used to endorse
16 * or promote products derived from this software without specific 16 * or promote products derived from this software without specific
17 * prior written permission. 17 * prior written permission.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN 26 * ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31/* 31/*
32 * Copyright (c) 2009 The NetBSD Foundation, Inc. 32 * Copyright (c) 2009 The NetBSD Foundation, Inc.
33 * Copyright (c) 2007 Iain Hibbert 33 * Copyright (c) 2007 Iain Hibbert
34 * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 34 * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
35 * All rights reserved. 35 * All rights reserved.
36 * 36 *
37 * Redistribution and use in source and binary forms, with or without 37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions 38 * modification, are permitted provided that the following conditions
39 * are met: 39 * are met:
40 * 1. Redistributions of source code must retain the above copyright 40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer. 41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright 42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the 43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution. 44 * documentation and/or other materials provided with the distribution.
45 * 45 *
46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE. 56 * SUCH DAMAGE.
57 */ 57 */
58 58
59#include <sys/cdefs.h> 59#include <sys/cdefs.h>
60__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc.\ 60__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc.\
61 Copyright (c) 2007 Iain Hibbert.\ 61 Copyright (c) 2007 Iain Hibbert.\
62 Copyright (c) 2006 Itronix, Inc.\ 62 Copyright (c) 2006 Itronix, Inc.\
63 Copyright (c) 2003 Maksim Yevmenkin m_evmenkin@yahoo.com.\ 63 Copyright (c) 2003 Maksim Yevmenkin m_evmenkin@yahoo.com.\
64 All rights reserved."); 64 All rights reserved.");
65__RCSID("$NetBSD: rfcomm_sppd.c,v 1.12 2009/09/24 18:30:37 plunky Exp $"); 65__RCSID("$NetBSD: rfcomm_sppd.c,v 1.13 2010/11/03 08:27:27 plunky Exp $");
66 66
67#include <sys/param.h> 67#include <sys/param.h>
68 68
69#include <bluetooth.h> 69#include <bluetooth.h>
70#include <ctype.h> 70#include <ctype.h>
71#include <err.h> 71#include <err.h>
72#include <errno.h> 72#include <errno.h>
73#include <fcntl.h> 73#include <fcntl.h>
74#include <grp.h> 74#include <grp.h>
75#include <limits.h> 75#include <limits.h>
76#include <paths.h> 76#include <paths.h>
77#include <sdp.h> 77#include <sdp.h>
78#include <signal.h> 78#include <signal.h>
79#include <stdarg.h> 79#include <stdarg.h>
80#include <stdio.h> 80#include <stdio.h>
81#include <stdlib.h> 81#include <stdlib.h>
82#include <string.h> 82#include <string.h>
83#include <syslog.h> 83#include <syslog.h>
84#include <termios.h> 84#include <termios.h>
85#include <unistd.h> 85#include <unistd.h>
86 86
87#include <netbt/rfcomm.h> 87#include <netbt/rfcomm.h>
88 88
89int open_tty(const char *); 89int open_tty(const char *);
90int open_client(bdaddr_t *, bdaddr_t *, int, uintmax_t, const char *); 90int open_client(bdaddr_t *, bdaddr_t *, int, uintmax_t, const char *);
91int open_server(bdaddr_t *, uint16_t, uint8_t, int, const char *); 91int open_server(bdaddr_t *, uint16_t, uint8_t, int, const char *);
92void copy_data(int, int); 92void copy_data(int, int);
93int service_search(const bdaddr_t *, const bdaddr_t *, uint16_t, uintmax_t *, uintmax_t *); 93int service_search(const bdaddr_t *, const bdaddr_t *, uint16_t, uintmax_t *, uintmax_t *);
94void sighandler(int); 94void sighandler(int);
95void usage(void); 95void usage(void);
96void reset_tio(void); 96void reset_tio(void);
97 97
98int done; /* got a signal */ 98int done; /* got a signal */
99struct termios tio; /* stored termios for reset on exit */ 99struct termios tio; /* stored termios for reset on exit */
100 100
101struct service { 101struct service {
102 const char * name; 102 const char * name;
103 const char * description; 103 const char * description;
104 uint16_t class; 104 uint16_t class;
105} services[] = { 105} services[] = {
106 { "DUN", "Dialup Networking", 106 { "DUN", "Dialup Networking",
107 SDP_SERVICE_CLASS_DIALUP_NETWORKING }, 107 SDP_SERVICE_CLASS_DIALUP_NETWORKING },
108 { "LAN", "LAN access using PPP", 108 { "LAN", "LAN access using PPP",
109 SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP }, 109 SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP },
110 { "SP", "Serial Port", 110 { "SP", "Serial Port",
111 SDP_SERVICE_CLASS_SERIAL_PORT }, 111 SDP_SERVICE_CLASS_SERIAL_PORT },
112 { NULL, NULL, 0 } 112 { NULL, NULL, 0 }
113}; 113};
114 114
115int 115int
116main(int argc, char *argv[]) 116main(int argc, char *argv[])
117{ 117{
118 struct termios t; 118 struct termios t;
119 bdaddr_t laddr, raddr; 119 bdaddr_t laddr, raddr;
120 fd_set rdset; 120 fd_set rdset;
121 const char *service; 121 const char *service;
122 char *ep, *tty; 122 char *ep, *tty;
123 int lm, n, rfcomm, tty_in, tty_out; 123 int lm, n, rfcomm, tty_in, tty_out;
124 uint16_t psm; 124 uint16_t psm;
125 uint8_t channel; 125 uint8_t channel;
126 126
127 bdaddr_copy(&laddr, BDADDR_ANY); 127 bdaddr_copy(&laddr, BDADDR_ANY);
128 bdaddr_copy(&raddr, BDADDR_ANY); 128 bdaddr_copy(&raddr, BDADDR_ANY);
129 service = "SP"; 129 service = "SP";
130 tty = NULL; 130 tty = NULL;
131 channel = 0; 131 channel = RFCOMM_CHANNEL_ANY;
132 psm = L2CAP_PSM_RFCOMM; 132 psm = L2CAP_PSM_RFCOMM;
133 lm = 0; 133 lm = 0;
134 134
135 /* Parse command line options */ 135 /* Parse command line options */
136 while ((n = getopt(argc, argv, "a:c:d:hm:p:s:t:")) != -1) { 136 while ((n = getopt(argc, argv, "a:c:d:hm:p:s:t:")) != -1) {
137 switch (n) { 137 switch (n) {
138 case 'a': /* remote device address */ 138 case 'a': /* remote device address */
139 if (!bt_aton(optarg, &raddr)) { 139 if (!bt_aton(optarg, &raddr)) {
140 struct hostent *he = NULL; 140 struct hostent *he = NULL;
141 141
142 if ((he = bt_gethostbyname(optarg)) == NULL) 142 if ((he = bt_gethostbyname(optarg)) == NULL)
143 errx(EXIT_FAILURE, "%s: %s", optarg, 143 errx(EXIT_FAILURE, "%s: %s", optarg,
144 hstrerror(h_errno)); 144 hstrerror(h_errno));
145 145
146 bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr); 146 bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr);
147 } 147 }
148 break; 148 break;
149 149
150 case 'c': /* RFCOMM channel */ 150 case 'c': /* RFCOMM channel */
151 channel = strtoul(optarg, &ep, 10); 151 channel = strtoul(optarg, &ep, 10);
152 if (*ep != '\0' || channel < 1 || channel > 30) 152 if (*ep != '\0'
 153 || channel < RFCOMM_CHANNEL_MIN
 154 || channel > RFCOMM_CHANNEL_MAX)
153 errx(EXIT_FAILURE, "Invalid channel: %s", optarg); 155 errx(EXIT_FAILURE, "Invalid channel: %s", optarg);
154 156
155 break; 157 break;
156 158
157 case 'd': /* local device address */ 159 case 'd': /* local device address */
158 if (!bt_devaddr(optarg, &laddr)) 160 if (!bt_devaddr(optarg, &laddr))
159 err(EXIT_FAILURE, "%s", optarg); 161 err(EXIT_FAILURE, "%s", optarg);
160 162
161 break; 163 break;
162 164
163 case 'm': /* Link Mode */ 165 case 'm': /* Link Mode */
164 if (strcasecmp(optarg, "auth") == 0) 166 if (strcasecmp(optarg, "auth") == 0)
165 lm = RFCOMM_LM_AUTH; 167 lm = RFCOMM_LM_AUTH;
166 else if (strcasecmp(optarg, "encrypt") == 0) 168 else if (strcasecmp(optarg, "encrypt") == 0)
167 lm = RFCOMM_LM_ENCRYPT; 169 lm = RFCOMM_LM_ENCRYPT;
168 else if (strcasecmp(optarg, "secure") == 0) 170 else if (strcasecmp(optarg, "secure") == 0)
169 lm = RFCOMM_LM_SECURE; 171 lm = RFCOMM_LM_SECURE;
170 else 172 else
171 errx(EXIT_FAILURE, "%s: unknown mode", optarg); 173 errx(EXIT_FAILURE, "%s: unknown mode", optarg);
172 174
173 break; 175 break;
174 176
175 case 'p': /* PSM */ 177 case 'p': /* PSM */
176 psm = strtoul(optarg, &ep, 0); 178 psm = strtoul(optarg, &ep, 0);
177 if (*ep != '\0' || L2CAP_PSM_INVALID(psm)) 179 if (*ep != '\0' || L2CAP_PSM_INVALID(psm))
178 errx(EXIT_FAILURE, "Invalid PSM: %s", optarg); 180 errx(EXIT_FAILURE, "Invalid PSM: %s", optarg);
179 181
180 break; 182 break;
181 183
182 case 's': /* service class */ 184 case 's': /* service class */
183 service = optarg; 185 service = optarg;
184 break; 186 break;
185 187
186 case 't': /* Slave TTY name */ 188 case 't': /* Slave TTY name */
187 if (optarg[0] != '/') 189 if (optarg[0] != '/')
188 asprintf(&tty, "%s%s", _PATH_DEV, optarg); 190 asprintf(&tty, "%s%s", _PATH_DEV, optarg);
189 else 191 else
190 tty = optarg; 192 tty = optarg;
191 193
192 break; 194 break;
193 195
194 case 'h': 196 case 'h':
195 default: 197 default:
196 usage(); 198 usage();
197 /* NOT REACHED */ 199 /* NOT REACHED */
198 } 200 }
199 } 201 }
200 202
201 /* 203 /*
202 * validate options: 204 * validate options:
203 * must have channel or remote address but not both 205 * cannot have remote address if channel was given
204 */ 206 */
205 if ((channel == 0 && bdaddr_any(&raddr)) 207 if (channel != RFCOMM_CHANNEL_ANY && !bdaddr_any(&raddr))
206 || (channel != 0 && !bdaddr_any(&raddr))) 
207 usage(); 208 usage();
208 209
209 /* 210 /*
210 * grab ttys before we start the bluetooth 211 * grab ttys before we start the bluetooth
211 */ 212 */
212 if (tty == NULL) { 213 if (tty == NULL) {
213 tty_in = STDIN_FILENO; 214 tty_in = STDIN_FILENO;
214 tty_out = STDOUT_FILENO; 215 tty_out = STDOUT_FILENO;
215 } else { 216 } else {
216 tty_in = open_tty(tty); 217 tty_in = open_tty(tty);
217 tty_out = tty_in; 218 tty_out = tty_in;
218 } 219 }
219 220
220 /* open RFCOMM */ 221 /* open RFCOMM */
221 if (channel == 0) 222 if (!bdaddr_any(&raddr))
222 rfcomm = open_client(&laddr, &raddr, lm, psm, service); 223 rfcomm = open_client(&laddr, &raddr, lm, psm, service);
223 else 224 else
224 rfcomm = open_server(&laddr, psm, channel, lm, service); 225 rfcomm = open_server(&laddr, psm, channel, lm, service);
225 226
226 /* 227 /*
227 * now we are ready to go, so either detach or maybe turn 228 * now we are ready to go, so either detach or maybe turn
228 * off some input processing, so that rfcomm_sppd can 229 * off some input processing, so that rfcomm_sppd can
229 * be used directly with stdio 230 * be used directly with stdio
230 */ 231 */
231 if (tty == NULL) { 232 if (tty == NULL) {
232 if (tcgetattr(tty_in, &t) < 0) 233 if (tcgetattr(tty_in, &t) < 0)
233 err(EXIT_FAILURE, "tcgetattr"); 234 err(EXIT_FAILURE, "tcgetattr");
234 235
235 memcpy(&tio, &t, sizeof(tio)); 236 memcpy(&tio, &t, sizeof(tio));
236 t.c_lflag &= ~(ECHO | ICANON); 237 t.c_lflag &= ~(ECHO | ICANON);
237 t.c_iflag &= ~(ICRNL); 238 t.c_iflag &= ~(ICRNL);
238 239
239 if (memcmp(&tio, &t, sizeof(tio))) { 240 if (memcmp(&tio, &t, sizeof(tio))) {
240 if (tcsetattr(tty_in, TCSANOW, &t) < 0) 241 if (tcsetattr(tty_in, TCSANOW, &t) < 0)
241 err(EXIT_FAILURE, "tcsetattr"); 242 err(EXIT_FAILURE, "tcsetattr");
242 243
243 atexit(reset_tio); 244 atexit(reset_tio);
244 } 245 }
245 } else { 246 } else {
246 if (daemon(0, 0) < 0) 247 if (daemon(0, 0) < 0)
247 err(EXIT_FAILURE, "daemon() failed"); 248 err(EXIT_FAILURE, "daemon() failed");
248 } 249 }
249 250
250 /* catch signals */ 251 /* catch signals */
251 done = 0; 252 done = 0;
252 (void)signal(SIGHUP, sighandler); 253 (void)signal(SIGHUP, sighandler);
253 (void)signal(SIGINT, sighandler); 254 (void)signal(SIGINT, sighandler);
254 (void)signal(SIGPIPE, sighandler); 255 (void)signal(SIGPIPE, sighandler);
255 (void)signal(SIGTERM, sighandler); 256 (void)signal(SIGTERM, sighandler);
256 257
257 openlog(getprogname(), LOG_PERROR | LOG_PID, LOG_DAEMON); 258 openlog(getprogname(), LOG_PERROR | LOG_PID, LOG_DAEMON);
258 syslog(LOG_INFO, "Starting on %s...", (tty ? tty : "stdio")); 259 syslog(LOG_INFO, "Starting on %s...", (tty ? tty : "stdio"));
259 260
260 n = MAX(tty_in, rfcomm) + 1; 261 n = MAX(tty_in, rfcomm) + 1;
261 while (!done) { 262 while (!done) {
262 FD_ZERO(&rdset); 263 FD_ZERO(&rdset);
263 FD_SET(tty_in, &rdset); 264 FD_SET(tty_in, &rdset);
264 FD_SET(rfcomm, &rdset); 265 FD_SET(rfcomm, &rdset);
265 266
266 if (select(n, &rdset, NULL, NULL, NULL) < 0) { 267 if (select(n, &rdset, NULL, NULL, NULL) < 0) {
267 if (errno == EINTR) 268 if (errno == EINTR)
268 continue; 269 continue;
269 270
270 syslog(LOG_ERR, "select error: %m"); 271 syslog(LOG_ERR, "select error: %m");
271 exit(EXIT_FAILURE); 272 exit(EXIT_FAILURE);
272 } 273 }
273 274
274 if (FD_ISSET(tty_in, &rdset)) 275 if (FD_ISSET(tty_in, &rdset))
275 copy_data(tty_in, rfcomm); 276 copy_data(tty_in, rfcomm);
276 277
277 if (FD_ISSET(rfcomm, &rdset)) 278 if (FD_ISSET(rfcomm, &rdset))
278 copy_data(rfcomm, tty_out); 279 copy_data(rfcomm, tty_out);
279 } 280 }
280 281
281 syslog(LOG_INFO, "Completed on %s", (tty ? tty : "stdio")); 282 syslog(LOG_INFO, "Completed on %s", (tty ? tty : "stdio"));
282 exit(EXIT_SUCCESS); 283 exit(EXIT_SUCCESS);
283} 284}
284 285
285int 286int
286open_tty(const char *tty) 287open_tty(const char *tty)
287{ 288{
288 char pty[PATH_MAX], *slash; 289 char pty[PATH_MAX], *slash;
289 struct group *gr = NULL; 290 struct group *gr = NULL;
290 gid_t ttygid; 291 gid_t ttygid;
291 int master; 292 int master;
292 293
293 /* 294 /*
294 * Construct master PTY name. The slave tty name must be less then 295 * Construct master PTY name. The slave tty name must be less then
295 * PATH_MAX characters in length, must contain '/' character and 296 * PATH_MAX characters in length, must contain '/' character and
296 * must not end with '/'. 297 * must not end with '/'.
297 */ 298 */
298 if (strlen(tty) >= sizeof(pty)) 299 if (strlen(tty) >= sizeof(pty))
299 errx(EXIT_FAILURE, ": tty name too long"); 300 errx(EXIT_FAILURE, ": tty name too long");
300 301
301 strlcpy(pty, tty, sizeof(pty)); 302 strlcpy(pty, tty, sizeof(pty));
302 slash = strrchr(pty, '/'); 303 slash = strrchr(pty, '/');
303 if (slash == NULL || slash[1] == '\0') 304 if (slash == NULL || slash[1] == '\0')
304 errx(EXIT_FAILURE, "%s: invalid tty", tty); 305 errx(EXIT_FAILURE, "%s: invalid tty", tty);
305 306
306 slash[1] = 'p'; 307 slash[1] = 'p';
307 if (strcmp(pty, tty) == 0) 308 if (strcmp(pty, tty) == 0)
308 errx(EXIT_FAILURE, "Master and slave tty are the same (%s)", tty); 309 errx(EXIT_FAILURE, "Master and slave tty are the same (%s)", tty);
309 310
310 if ((master = open(pty, O_RDWR, 0)) < 0) 311 if ((master = open(pty, O_RDWR, 0)) < 0)
311 err(EXIT_FAILURE, "%s", pty); 312 err(EXIT_FAILURE, "%s", pty);
312 313
313 /* 314 /*
314 * Slave TTY 315 * Slave TTY
315 */ 316 */
316 317
317 if ((gr = getgrnam("tty")) != NULL) 318 if ((gr = getgrnam("tty")) != NULL)
318 ttygid = gr->gr_gid; 319 ttygid = gr->gr_gid;
319 else 320 else
320 ttygid = (gid_t)-1; 321 ttygid = (gid_t)-1;
321 322
322 (void)chown(tty, getuid(), ttygid); 323 (void)chown(tty, getuid(), ttygid);
323 (void)chmod(tty, S_IRUSR | S_IWUSR | S_IWGRP); 324 (void)chmod(tty, S_IRUSR | S_IWUSR | S_IWGRP);
324 (void)revoke(tty); 325 (void)revoke(tty);
325 326
326 return master; 327 return master;
327} 328}
328 329
329int 330int
330open_client(bdaddr_t *laddr, bdaddr_t *raddr, int lm, uintmax_t psm, const char *service) 331open_client(bdaddr_t *laddr, bdaddr_t *raddr, int lm, uintmax_t psm, const char *service)
331{ 332{
332 struct sockaddr_bt sa; 333 struct sockaddr_bt sa;
333 struct service *s; 334 struct service *s;
334 struct linger l; 335 struct linger l;
335 char *ep; 336 char *ep;
336 int fd, error; 337 int fd, error;
337 uintmax_t channel; 338 uintmax_t channel;
338 339
339 for (s = services ; ; s++) { 340 for (s = services ; ; s++) {
340 if (s->name == NULL) { 341 if (s->name == NULL) {
341 channel = strtoul(service, &ep, 10); 342 channel = strtoul(service, &ep, 10);
342 if (*ep != '\0') 343 if (*ep != '\0')
343 errx(EXIT_FAILURE, "Unknown service: %s", service); 344 errx(EXIT_FAILURE, "Unknown service: %s", service);
344 345
345 break; 346 break;
346 } 347 }
347 348
348 if (strcasecmp(s->name, service) == 0) { 349 if (strcasecmp(s->name, service) == 0) {
349 error = service_search(laddr, raddr, s->class, &psm, &channel); 350 error = service_search(laddr, raddr, s->class, &psm, &channel);
350 if (error != 0) 351 if (error != 0)
351 errx(EXIT_FAILURE, "%s: %s", s->name, strerror(error)); 352 errx(EXIT_FAILURE, "%s: %s", s->name, strerror(error));
352 353
353 break; 354 break;
354 } 355 }
355 } 356 }
356 357
357 if (channel < RFCOMM_CHANNEL_MIN || channel > RFCOMM_CHANNEL_MAX) 358 if (channel < RFCOMM_CHANNEL_MIN || channel > RFCOMM_CHANNEL_MAX)
358 errx(EXIT_FAILURE, "Invalid channel %"PRIuMAX, channel); 359 errx(EXIT_FAILURE, "Invalid channel %"PRIuMAX, channel);
359 360
360 if (L2CAP_PSM_INVALID(psm)) 361 if (L2CAP_PSM_INVALID(psm))
361 errx(EXIT_FAILURE, "Invalid PSM 0x%04"PRIxMAX, psm); 362 errx(EXIT_FAILURE, "Invalid PSM 0x%04"PRIxMAX, psm);
362 363
363 memset(&sa, 0, sizeof(sa)); 364 memset(&sa, 0, sizeof(sa));
364 sa.bt_len = sizeof(sa); 365 sa.bt_len = sizeof(sa);
365 sa.bt_family = AF_BLUETOOTH; 366 sa.bt_family = AF_BLUETOOTH;
366 bdaddr_copy(&sa.bt_bdaddr, laddr); 367 bdaddr_copy(&sa.bt_bdaddr, laddr);
367 368
368 fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); 369 fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
369 if (fd < 0) 370 if (fd < 0)
370 err(EXIT_FAILURE, "socket()"); 371 err(EXIT_FAILURE, "socket()");
371 372
372 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) 373 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
373 err(EXIT_FAILURE, "bind(%s)", bt_ntoa(laddr, NULL)); 374 err(EXIT_FAILURE, "bind(%s)", bt_ntoa(laddr, NULL));
374 375
375 memset(&l, 0, sizeof(l)); 376 memset(&l, 0, sizeof(l));
376 l.l_onoff = 1; 377 l.l_onoff = 1;
377 l.l_linger = 5; 378 l.l_linger = 5;
378 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) 379 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
379 err(EXIT_FAILURE, "linger()"); 380 err(EXIT_FAILURE, "linger()");
380 381
381 if (setsockopt(fd, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0) 382 if (setsockopt(fd, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
382 err(EXIT_FAILURE, "link mode"); 383 err(EXIT_FAILURE, "link mode");
383 384
384 sa.bt_psm = psm; 385 sa.bt_psm = psm;
385 sa.bt_channel = channel; 386 sa.bt_channel = channel;
386 bdaddr_copy(&sa.bt_bdaddr, raddr); 387 bdaddr_copy(&sa.bt_bdaddr, raddr);
387 388
388 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) 389 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
389 err(EXIT_FAILURE, "connect(%s, 0x%04"PRIxMAX", %"PRIuMAX")", 390 err(EXIT_FAILURE, "connect(%s, 0x%04"PRIxMAX", %"PRIuMAX")",
390 bt_ntoa(raddr, NULL), psm, channel); 391 bt_ntoa(raddr, NULL), psm, channel);
391 392
392 return fd; 393 return fd;
393} 394}
394 395
395int 396int
396open_server(bdaddr_t *laddr, uint16_t psm, uint8_t channel, int lm, const char *service) 397open_server(bdaddr_t *laddr, uint16_t psm, uint8_t channel, int lm, const char *service)
397{ 398{
398 uint8_t buffer[256]; 399 uint8_t buffer[256];
399 struct sockaddr_bt sa; 400 struct sockaddr_bt sa;
400 struct service *s; 401 struct service *s;
401 struct linger l; 402 struct linger l;
402 socklen_t len; 403 socklen_t len;
403 sdp_session_t ss; 404 sdp_session_t ss;
404 sdp_data_t rec; 405 sdp_data_t rec;
405 int sv, fd; 406 int sv, fd;
406 407
407 for (s = services; ; s++) { 408 for (s = services; ; s++) {
408 if (s->name == NULL) 409 if (s->name == NULL)
409 usage(); 410 usage();
410 411
411 if (strcasecmp(s->name, service) == 0) 412 if (strcasecmp(s->name, service) == 0)
412 break; 413 break;
413 } 414 }
414 415
415 /* Open server socket */ 416 /* Open server socket */
416 sv = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); 417 sv = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
417 if (sv < 0) 418 if (sv < 0)
418 err(EXIT_FAILURE, "socket()"); 419 err(EXIT_FAILURE, "socket()");
419 420
420 memset(&sa, 0, sizeof(sa)); 421 memset(&sa, 0, sizeof(sa));
421 sa.bt_len = sizeof(sa); 422 sa.bt_len = sizeof(sa);
422 sa.bt_family = AF_BLUETOOTH; 423 sa.bt_family = AF_BLUETOOTH;
423 sa.bt_psm = psm; 424 sa.bt_psm = psm;
424 sa.bt_channel = channel; 425 sa.bt_channel = channel;
425 bdaddr_copy(&sa.bt_bdaddr, laddr); 426 bdaddr_copy(&sa.bt_bdaddr, laddr);
426 if (bind(sv, (struct sockaddr *)&sa, sizeof(sa)) < 0) 427 if (bind(sv, (struct sockaddr *)&sa, sizeof(sa)) < 0)
427 err(EXIT_FAILURE, "bind(%s, 0x%04x, %d)", 428 err(EXIT_FAILURE, "bind(%s, 0x%04x, %d)",
428 bt_ntoa(laddr, NULL), psm, channel); 429 bt_ntoa(laddr, NULL), psm, channel);
429 430
430 if (setsockopt(sv, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0) 431 if (setsockopt(sv, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
431 err(EXIT_FAILURE, "link mode"); 432 err(EXIT_FAILURE, "link mode");
432 433
433 if (listen(sv, 1) < 0) 434 if (listen(sv, 1) < 0)
434 err(EXIT_FAILURE, "listen()"); 435 err(EXIT_FAILURE, "listen()");
435 436
 437 len = sizeof(sa);
 438 if (getsockname(sv, (struct sockaddr *)&sa, &len) < 0)
 439 err(EXIT_FAILURE, "getsockname()");
 440 if (len != sizeof(sa))
 441 errx(EXIT_FAILURE, "getsockname()");
 442
436 /* Build SDP record */ 443 /* Build SDP record */
437 rec.next = buffer; 444 rec.next = buffer;
438 rec.end = buffer + sizeof(buffer); 445 rec.end = buffer + sizeof(buffer);
439 446
440 sdp_put_uint16(&rec, SDP_ATTR_SERVICE_RECORD_HANDLE); 447 sdp_put_uint16(&rec, SDP_ATTR_SERVICE_RECORD_HANDLE);
441 sdp_put_uint32(&rec, 0x00000000); 448 sdp_put_uint32(&rec, 0x00000000);
442 449
443 sdp_put_uint16(&rec, SDP_ATTR_SERVICE_CLASS_ID_LIST); 450 sdp_put_uint16(&rec, SDP_ATTR_SERVICE_CLASS_ID_LIST);
444 sdp_put_seq(&rec, 3); 451 sdp_put_seq(&rec, 3);
445 sdp_put_uuid16(&rec, s->class); 452 sdp_put_uuid16(&rec, s->class);
446 453
447 len = (psm == L2CAP_PSM_RFCOMM ? 0 : 3); 454 len = (psm == L2CAP_PSM_RFCOMM ? 0 : 3);
448 455
449 sdp_put_uint16(&rec, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST); 456 sdp_put_uint16(&rec, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
450 sdp_put_seq(&rec, 12 + len); 457 sdp_put_seq(&rec, 12 + len);
451 sdp_put_seq(&rec, 3 + len); 458 sdp_put_seq(&rec, 3 + len);
452 sdp_put_uuid16(&rec, SDP_UUID_PROTOCOL_L2CAP); 459 sdp_put_uuid16(&rec, SDP_UUID_PROTOCOL_L2CAP);
453 if (len > 0) 460 if (len > 0)
454 sdp_put_uint16(&rec, psm); 461 sdp_put_uint16(&rec, psm);
455 sdp_put_seq(&rec, 5); 462 sdp_put_seq(&rec, 5);
456 sdp_put_uuid16(&rec, SDP_UUID_PROTOCOL_RFCOMM); 463 sdp_put_uuid16(&rec, SDP_UUID_PROTOCOL_RFCOMM);
457 sdp_put_uint8(&rec, channel); 464 sdp_put_uint8(&rec, sa.bt_channel);
458 465
459 sdp_put_uint16(&rec, SDP_ATTR_BROWSE_GROUP_LIST); 466 sdp_put_uint16(&rec, SDP_ATTR_BROWSE_GROUP_LIST);
460 sdp_put_seq(&rec, 3); 467 sdp_put_seq(&rec, 3);
461 sdp_put_uuid16(&rec, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP); 468 sdp_put_uuid16(&rec, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
462 469
463 sdp_put_uint16(&rec, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST); 470 sdp_put_uint16(&rec, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
464 sdp_put_seq(&rec, 9); 471 sdp_put_seq(&rec, 9);
465 sdp_put_uint16(&rec, 0x656e); /* "en" */ 472 sdp_put_uint16(&rec, 0x656e); /* "en" */
466 sdp_put_uint16(&rec, 106); /* UTF-8 */ 473 sdp_put_uint16(&rec, 106); /* UTF-8 */
467 sdp_put_uint16(&rec, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID); 474 sdp_put_uint16(&rec, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
468 475
469 if (s->class == SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP) { 476 if (s->class == SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP) {
470 sdp_put_uint16(&rec, SDP_ATTR_SERVICE_AVAILABILITY); 477 sdp_put_uint16(&rec, SDP_ATTR_SERVICE_AVAILABILITY);
471 sdp_put_uint8(&rec, 0x00); 478 sdp_put_uint8(&rec, 0x00);
472 } 479 }
473 480
474 sdp_put_uint16(&rec, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST); 481 sdp_put_uint16(&rec, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
475 sdp_put_seq(&rec, 8); 482 sdp_put_seq(&rec, 8);
476 sdp_put_seq(&rec, 6); 483 sdp_put_seq(&rec, 6);
477 sdp_put_uuid16(&rec, s->class); 484 sdp_put_uuid16(&rec, s->class);
478 sdp_put_uint16(&rec, 0x0100); /* v1.0 */ 485 sdp_put_uint16(&rec, 0x0100); /* v1.0 */
479 486
480 sdp_put_uint16(&rec, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID 487 sdp_put_uint16(&rec, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID
481 + SDP_ATTR_SERVICE_NAME_OFFSET); 488 + SDP_ATTR_SERVICE_NAME_OFFSET);
482 sdp_put_str(&rec, s->description, -1); 489 sdp_put_str(&rec, s->description, -1);
483 490
484 if (s->class == SDP_SERVICE_CLASS_DIALUP_NETWORKING) { 491 if (s->class == SDP_SERVICE_CLASS_DIALUP_NETWORKING) {
485 sdp_put_uint16(&rec, SDP_ATTR_AUDIO_FEEDBACK_SUPPORT); 492 sdp_put_uint16(&rec, SDP_ATTR_AUDIO_FEEDBACK_SUPPORT);
486 sdp_put_bool(&rec, false); 493 sdp_put_bool(&rec, false);
487 } 494 }
488 495
489#if 0 496#if 0
490 if (s->class == SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP) { 497 if (s->class == SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP) {
491 sdp_put_uint16(&rec, SDP_ATTR_IP_SUBNET); /* TODO */ 498 sdp_put_uint16(&rec, SDP_ATTR_IP_SUBNET); /* TODO */
492 sdp_put_str(&rec, "0.0.0.0/0", -1); 499 sdp_put_str(&rec, "0.0.0.0/0", -1);
493 } 500 }
494#endif 501#endif
495 502
496 rec.end = rec.next; 503 rec.end = rec.next;
497 rec.next = buffer; 504 rec.next = buffer;
498 505
499 /* Register service with SDP server */ 506 /* Register service with SDP server */
500 ss = sdp_open_local(NULL); 507 ss = sdp_open_local(NULL);
501 if (ss == NULL) 508 if (ss == NULL)
502 err(EXIT_FAILURE, "sdp_open_local"); 509 err(EXIT_FAILURE, "sdp_open_local");
503 510
504 if (!sdp_record_insert(ss, laddr, NULL, &rec)) 511 if (!sdp_record_insert(ss, laddr, NULL, &rec))
505 err(EXIT_FAILURE, "sdp_record_insert"); 512 err(EXIT_FAILURE, "sdp_record_insert");
506 513
507 /* Accept client connection */ 514 /* Accept client connection */
508 len = sizeof(sa); 515 len = sizeof(sa);
509 fd = accept(sv, (struct sockaddr *)&sa, &len); 516 fd = accept(sv, (struct sockaddr *)&sa, &len);
510 if (fd < 0) 517 if (fd < 0)
511 err(EXIT_FAILURE, "accept"); 518 err(EXIT_FAILURE, "accept");
512 519
513 memset(&l, 0, sizeof(l)); 520 memset(&l, 0, sizeof(l));
514 l.l_onoff = 1; 521 l.l_onoff = 1;
515 l.l_linger = 5; 522 l.l_linger = 5;
516 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) 523 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
517 err(EXIT_FAILURE, "linger()"); 524 err(EXIT_FAILURE, "linger()");
518 525
519 close(sv); 526 close(sv);
520 return fd; 527 return fd;
521} 528}
522 529
523void 530void
524copy_data(int src, int dst) 531copy_data(int src, int dst)
525{ 532{
526 static char buf[BUFSIZ]; 533 static char buf[BUFSIZ];
527 ssize_t nr, nw, off; 534 ssize_t nr, nw, off;
528 535
529 while ((nr = read(src, buf, sizeof(buf))) == -1) { 536 while ((nr = read(src, buf, sizeof(buf))) == -1) {
530 if (errno != EINTR) { 537 if (errno != EINTR) {
531 syslog(LOG_ERR, "read failed: %m"); 538 syslog(LOG_ERR, "read failed: %m");
532 exit(EXIT_FAILURE); 539 exit(EXIT_FAILURE);
533 } 540 }
534 } 541 }
535 542
536 if (nr == 0) /* reached EOF */ 543 if (nr == 0) /* reached EOF */
537 done++; 544 done++;
538 545
539 for (off = 0 ; nr ; nr -= nw, off += nw) { 546 for (off = 0 ; nr ; nr -= nw, off += nw) {
540 if ((nw = write(dst, buf + off, (size_t)nr)) == -1) { 547 if ((nw = write(dst, buf + off, (size_t)nr)) == -1) {
541 syslog(LOG_ERR, "write failed: %m"); 548 syslog(LOG_ERR, "write failed: %m");
542 exit(EXIT_FAILURE); 549 exit(EXIT_FAILURE);
543 } 550 }
544 } 551 }
545} 552}
546 553
547int 554int
548service_search(bdaddr_t const *laddr, bdaddr_t const *raddr, 555service_search(bdaddr_t const *laddr, bdaddr_t const *raddr,
549 uint16_t class, uintmax_t *psm, uintmax_t *channel) 556 uint16_t class, uintmax_t *psm, uintmax_t *channel)
550{ 557{
551 uint8_t buffer[6]; /* SSP (3 bytes) + AIL (3 bytes) */ 558 uint8_t buffer[6]; /* SSP (3 bytes) + AIL (3 bytes) */
552 sdp_session_t ss; 559 sdp_session_t ss;
553 sdp_data_t ail, ssp, rsp, rec, value, pdl, seq; 560 sdp_data_t ail, ssp, rsp, rec, value, pdl, seq;
554 uint16_t attr; 561 uint16_t attr;
555 bool rv; 562 bool rv;
556 563
557 seq.next = buffer; 564 seq.next = buffer;
558 seq.end = buffer + sizeof(buffer); 565 seq.end = buffer + sizeof(buffer);
559 566
560 /* 567 /*
561 * build ServiceSearchPattern (3 bytes) 568 * build ServiceSearchPattern (3 bytes)
562 */ 569 */
563 ssp.next = seq.next; 570 ssp.next = seq.next;
564 sdp_put_uuid16(&seq, class); 571 sdp_put_uuid16(&seq, class);
565 ssp.end = seq.next; 572 ssp.end = seq.next;
566 573
567 /* 574 /*
568 * build AttributeIDList (3 bytes) 575 * build AttributeIDList (3 bytes)
569 */ 576 */
570 ail.next = seq.next; 577 ail.next = seq.next;
571 sdp_put_uint16(&seq, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST); 578 sdp_put_uint16(&seq, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
572 ail.end = seq.next; 579 ail.end = seq.next;
573 580
574 ss = sdp_open(laddr, raddr); 581 ss = sdp_open(laddr, raddr);
575 if (ss == NULL) 582 if (ss == NULL)
576 return errno; 583 return errno;
577 584
578 rv = sdp_service_search_attribute(ss, &ssp, &ail, &rsp); 585 rv = sdp_service_search_attribute(ss, &ssp, &ail, &rsp);
579 if (!rv) { 586 if (!rv) {
580 sdp_close(ss); 587 sdp_close(ss);
581 return errno; 588 return errno;
582 } 589 }
583 590
584 /* 591 /*
585 * The response will be a list of records that matched our 592 * The response will be a list of records that matched our
586 * ServiceSearchPattern, where each record is a sequence 593 * ServiceSearchPattern, where each record is a sequence
587 * containing a single ProtocolDescriptorList attribute and 594 * containing a single ProtocolDescriptorList attribute and
588 * value 595 * value
589 * 596 *
590 * seq 597 * seq
591 * uint16 ProtocolDescriptorList 598 * uint16 ProtocolDescriptorList
592 * value 599 * value
593 * seq 600 * seq
594 * uint16 ProtocolDescriptorList 601 * uint16 ProtocolDescriptorList
595 * value 602 * value
596 * 603 *
597 * If the ProtocolDescriptorList describes a single stack, 604 * If the ProtocolDescriptorList describes a single stack,
598 * the attribute value takes the form of a single Data Element 605 * the attribute value takes the form of a single Data Element
599 * Sequence where each member is a protocol descriptor. 606 * Sequence where each member is a protocol descriptor.
600 * 607 *
601 * seq 608 * seq
602 * list 609 * list
603 * 610 *
604 * If it is possible for more than one kind of protocol 611 * If it is possible for more than one kind of protocol
605 * stack to be used to gain access to the service, the 612 * stack to be used to gain access to the service, the
606 * ProtocolDescriptorList takes the form of a Data Element 613 * ProtocolDescriptorList takes the form of a Data Element
607 * Alternative where each member is a Data Element Sequence 614 * Alternative where each member is a Data Element Sequence
608 * describing an alternative protocol stack. 615 * describing an alternative protocol stack.
609 * 616 *
610 * alt 617 * alt
611 * seq 618 * seq
612 * list 619 * list
613 * seq 620 * seq
614 * list 621 * list
615 * 622 *
616 * Each protocol stack description contains a sequence for each 623 * Each protocol stack description contains a sequence for each
617 * protocol, where each sequence contains the protocol UUID as 624 * protocol, where each sequence contains the protocol UUID as
618 * the first element, and any ProtocolSpecificParameters. We are 625 * the first element, and any ProtocolSpecificParameters. We are
619 * interested in the L2CAP psm if provided, and the RFCOMM channel 626 * interested in the L2CAP psm if provided, and the RFCOMM channel
620 * number, stored as parameter#1 in each case. 627 * number, stored as parameter#1 in each case.
621 * 628 *
622 * seq 629 * seq
623 * uuid L2CAP 630 * uuid L2CAP
624 * uint16 psm 631 * uint16 psm
625 * seq 632 * seq
626 * uuid RFCOMM 633 * uuid RFCOMM
627 * uint8 channel 634 * uint8 channel
628 */ 635 */
629 636
630 rv = false; 637 rv = false;
631 while (!rv && sdp_get_seq(&rsp, &rec)) { 638 while (!rv && sdp_get_seq(&rsp, &rec)) {
632 if (!sdp_get_attr(&rec, &attr, &value) 639 if (!sdp_get_attr(&rec, &attr, &value)
633 || attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST) 640 || attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST)
634 continue; 641 continue;
635 642
636 sdp_get_alt(&value, &value); /* strip any alt container */ 643 sdp_get_alt(&value, &value); /* strip any alt container */
637 while (!rv && sdp_get_seq(&value, &pdl)) { 644 while (!rv && sdp_get_seq(&value, &pdl)) {
638 *psm = L2CAP_PSM_RFCOMM; 645 *psm = L2CAP_PSM_RFCOMM;
639 if (sdp_get_seq(&pdl, &seq) 646 if (sdp_get_seq(&pdl, &seq)
640 && sdp_match_uuid16(&seq, SDP_UUID_PROTOCOL_L2CAP) 647 && sdp_match_uuid16(&seq, SDP_UUID_PROTOCOL_L2CAP)
641 && (sdp_get_uint(&seq, psm) || true) 648 && (sdp_get_uint(&seq, psm) || true)
642 && sdp_get_seq(&pdl, &seq) 649 && sdp_get_seq(&pdl, &seq)
643 && sdp_match_uuid16(&seq, SDP_UUID_PROTOCOL_RFCOMM) 650 && sdp_match_uuid16(&seq, SDP_UUID_PROTOCOL_RFCOMM)
644 && sdp_get_uint(&seq, channel)) 651 && sdp_get_uint(&seq, channel))
645 rv = true; 652 rv = true;
646 } 653 }
647 } 654 }
648 655
649 sdp_close(ss); 656 sdp_close(ss);
650 return (rv) ? 0 : ENOATTR; 657 return (rv) ? 0 : ENOATTR;
651} 658}
652 659
653void 660void
654sighandler(int s) 661sighandler(int s)
655{ 662{
656 663
657 done++; 664 done++;
658} 665}
659 666
660void 667void
661reset_tio(void) 668reset_tio(void)
662{ 669{
663 670
664 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio); 671 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
665} 672}
666 673
667void 674void
668usage(void) 675usage(void)
669{ 676{
670 const char *cmd = getprogname(); 677 const char *cmd = getprogname();
671 struct service *s; 678 struct service *s;
672 679
673 fprintf(stderr, "Usage: %s [-d device] [-m mode] [-p psm] [-s service] [-t tty]\n" 680 fprintf(stderr, "Usage: %s [-d device] [-m mode] [-p psm] [-s service] [-t tty]\n"
674 " %*s {-a bdaddr | -c channel}\n" 681 " %*s {-a bdaddr | [-c channel]}\n"
675 "\n" 682 "\n"
676 "Where:\n" 683 "Where:\n"
677 "\t-a bdaddr remote device address\n" 684 "\t-a bdaddr remote device address\n"
678 "\t-c channel local RFCOMM channel\n" 685 "\t-c channel local RFCOMM channel\n"
679 "\t-d device local device address\n" 686 "\t-d device local device address\n"
680 "\t-m mode link mode\n" 687 "\t-m mode link mode\n"
681 "\t-p psm protocol/service multiplexer\n" 688 "\t-p psm protocol/service multiplexer\n"
682 "\t-s service service class\n" 689 "\t-s service service class\n"
683 "\t-t tty run in background using pty\n" 690 "\t-t tty run in background using pty\n"
684 "\n", cmd, (int)strlen(cmd), ""); 691 "\n", cmd, (int)strlen(cmd), "");
685 692
686 fprintf(stderr, "Known service classes:\n"); 693 fprintf(stderr, "Known service classes:\n");
687 for (s = services ; s->name != NULL ; s++) 694 for (s = services ; s->name != NULL ; s++)
688 fprintf(stderr, "\t%-13s%s\n", s->name, s->description); 695 fprintf(stderr, "\t%-13s%s\n", s->name, s->description);
689 696
690 exit(EXIT_FAILURE); 697 exit(EXIT_FAILURE);
691} 698}