1 /* $NetBSD: rfcomm_sppd.c,v 1.8 2007/04/21 10:39:30 dsl Exp $ */
4 * Copyright (c) 2006 Itronix Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of Itronix Inc. may not be used to endorse
16 * or promote products derived from this software without specific
17 * prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
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
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
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
26 * ON ANY THEORY OF LIABILITY, WHETHER IN
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
29 * POSSIBILITY OF SUCH DAMAGE.
34 * Copyright (c) 2007 Iain Hibbert
35 * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
36 * All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 #include <bluetooth.h>
79 #include <netbt/rfcomm.h>
81 #include "rfcomm_sdp.h"
83 #define max(a, b) ((a) > (b) ? (a) : (b))
85 int open_tty(const char *);
86 int open_client(bdaddr_t
*, bdaddr_t
*, int, const char *);
87 int open_server(bdaddr_t
*, uint8_t, int, const char *);
88 void copy_data(int, int);
90 void usage(void) __dead2
;
93 int done
; /* got a signal */
94 struct termios tio
; /* stored termios for reset on exit */
98 const char *description
;
102 { "DUN", "Dialup Networking",
103 SDP_SERVICE_CLASS_DIALUP_NETWORKING
,
104 sizeof(struct sdp_dun_profile
)
106 { "LAN", "Lan access using PPP",
107 SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP
,
108 sizeof(struct sdp_lan_profile
)
110 { "SP", "Serial Port",
111 SDP_SERVICE_CLASS_SERIAL_PORT
,
112 sizeof(struct sdp_sp_profile
)
121 main(int argc
, char *argv
[])
124 bdaddr_t laddr
, raddr
;
128 int lm
, n
, rfcomm
, tty_in
, tty_out
;
131 bdaddr_copy(&laddr
, BDADDR_ANY
);
132 bdaddr_copy(&raddr
, BDADDR_ANY
);
138 /* Parse command line options */
139 while ((n
= getopt(argc
, argv
, "a:c:d:hm:s:t:")) != -1) {
141 case 'a': /* remote device address */
142 if (!bt_aton(optarg
, &raddr
)) {
143 struct hostent
*he
= NULL
;
145 if ((he
= bt_gethostbyname(optarg
)) == NULL
)
146 errx(EXIT_FAILURE
, "%s: %s", optarg
,
149 bdaddr_copy(&raddr
, (bdaddr_t
*)he
->h_addr
);
153 case 'c': /* RFCOMM channel */
154 channel
= strtoul(optarg
, &ep
, 10);
155 if (*ep
!= '\0' || channel
< 1 || channel
> 30)
156 errx(EXIT_FAILURE
, "Invalid channel: %s", optarg
);
160 case 'd': /* local device address */
161 if (!bt_devaddr(optarg
, &laddr
))
162 err(EXIT_FAILURE
, "%s", optarg
);
166 case 'm': /* Link Mode */
167 if (strcasecmp(optarg
, "auth") == 0)
169 else if (strcasecmp(optarg
, "encrypt") == 0)
170 lm
= RFCOMM_LM_ENCRYPT
;
171 else if (strcasecmp(optarg
, "secure") == 0)
172 lm
= RFCOMM_LM_SECURE
;
174 errx(EXIT_FAILURE
, "%s: unknown mode", optarg
);
178 case 's': /* service class */
182 case 't': /* Slave TTY name */
183 if (optarg
[0] != '/')
184 asprintf(&tty
, "%s%s", _PATH_DEV
, optarg
);
199 * must have channel or remote address but not both
201 if ((channel
== 0 && bdaddr_any(&raddr
))
202 || (channel
!= 0 && !bdaddr_any(&raddr
)))
206 * grab ttys before we start the bluetooth
209 tty_in
= STDIN_FILENO
;
210 tty_out
= STDOUT_FILENO
;
212 tty_in
= open_tty(tty
);
218 rfcomm
= open_client(&laddr
, &raddr
, lm
, service
);
220 rfcomm
= open_server(&laddr
, channel
, lm
, service
);
223 * now we are ready to go, so either detach or maybe turn
224 * off some input processing, so that rfcomm_sppd can
225 * be used directly with stdio
228 if (tcgetattr(tty_in
, &t
) < 0)
229 err(EXIT_FAILURE
, "tcgetattr");
231 memcpy(&tio
, &t
, sizeof(tio
));
232 t
.c_lflag
&= ~(ECHO
| ICANON
);
233 t
.c_iflag
&= ~(ICRNL
);
235 if (memcmp(&tio
, &t
, sizeof(tio
))) {
236 if (tcsetattr(tty_in
, TCSANOW
, &t
) < 0)
237 err(EXIT_FAILURE
, "tcsetattr");
242 if (daemon(0, 0) < 0)
243 err(EXIT_FAILURE
, "daemon() failed");
248 (void)signal(SIGHUP
, sighandler
);
249 (void)signal(SIGINT
, sighandler
);
250 (void)signal(SIGPIPE
, sighandler
);
251 (void)signal(SIGTERM
, sighandler
);
253 openlog(getprogname(), LOG_PERROR
| LOG_PID
, LOG_DAEMON
);
254 syslog(LOG_INFO
, "Starting on %s...", (tty
? tty
: "stdio"));
256 n
= max(tty_in
, rfcomm
) + 1;
259 FD_SET(tty_in
, &rdset
);
260 FD_SET(rfcomm
, &rdset
);
262 if (select(n
, &rdset
, NULL
, NULL
, NULL
) < 0) {
266 syslog(LOG_ERR
, "select error: %m");
270 if (FD_ISSET(tty_in
, &rdset
))
271 copy_data(tty_in
, rfcomm
);
273 if (FD_ISSET(rfcomm
, &rdset
))
274 copy_data(rfcomm
, tty_out
);
277 syslog(LOG_INFO
, "Completed on %s", (tty
? tty
: "stdio"));
282 open_tty(const char *tty
)
284 char pty
[PATH_MAX
], *slash
;
285 struct group
*gr
= NULL
;
290 * Construct master PTY name. The slave tty name must be less then
291 * PATH_MAX characters in length, must contain '/' character and
292 * must not end with '/'.
294 if (strlen(tty
) >= sizeof(pty
))
295 errx(EXIT_FAILURE
, ": tty name too long");
297 strlcpy(pty
, tty
, sizeof(pty
));
298 slash
= strrchr(pty
, '/');
299 if (slash
== NULL
|| slash
[1] == '\0')
300 errx(EXIT_FAILURE
, "%s: invalid tty", tty
);
303 if (strcmp(pty
, tty
) == 0)
304 errx(EXIT_FAILURE
, "Master and slave tty are the same (%s)", tty
);
306 if ((master
= open(pty
, O_RDWR
, 0)) < 0)
307 err(EXIT_FAILURE
, "%s", pty
);
313 if ((gr
= getgrnam("tty")) != NULL
)
318 (void)chown(tty
, getuid(), ttygid
);
319 (void)chmod(tty
, S_IRUSR
| S_IWUSR
| S_IWGRP
);
326 open_client(bdaddr_t
*laddr
, bdaddr_t
*raddr
, int lm
, const char *service
)
328 struct sockaddr_bt sa
;
333 uint8_t channel
= 0; /* avoid gcc warnings */
335 for (s
= services
; ; s
++) {
336 if (s
->name
== NULL
) {
337 channel
= strtoul(service
, &ep
, 10);
338 if (*ep
!= '\0' || channel
< 1 || channel
> 30)
339 errx(EXIT_FAILURE
, "Invalid service: %s", service
);
344 if (strcasecmp(s
->name
, service
) == 0) {
345 if (rfcomm_channel_lookup(laddr
, raddr
, s
->class, &channel
, &errno
) < 0)
346 err(EXIT_FAILURE
, "%s", s
->name
);
352 memset(&sa
, 0, sizeof(sa
));
353 sa
.bt_len
= sizeof(sa
);
354 sa
.bt_family
= AF_BLUETOOTH
;
355 bdaddr_copy(&sa
.bt_bdaddr
, laddr
);
357 fd
= socket(PF_BLUETOOTH
, SOCK_STREAM
, BTPROTO_RFCOMM
);
359 err(EXIT_FAILURE
, "socket()");
361 if (bind(fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) < 0)
362 err(EXIT_FAILURE
, "bind(%s)", bt_ntoa(laddr
, NULL
));
364 memset(&l
, 0, sizeof(l
));
367 if (setsockopt(fd
, SOL_SOCKET
, SO_LINGER
, &l
, sizeof(l
)) < 0)
368 err(EXIT_FAILURE
, "linger()");
370 if (setsockopt(fd
, BTPROTO_RFCOMM
, SO_RFCOMM_LM
, &lm
, sizeof(lm
)) < 0)
371 err(EXIT_FAILURE
, "link mode");
373 sa
.bt_channel
= channel
;
374 bdaddr_copy(&sa
.bt_bdaddr
, raddr
);
376 if (connect(fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) < 0)
377 err(EXIT_FAILURE
, "connect(%s, %d)", bt_ntoa(raddr
, NULL
),
384 * In all the profiles we currently support registering, the channel
385 * is the first octet in the PDU, and it seems all the rest can be
386 * zero, so we just use an array of uint8_t big enough to store the
387 * largest, currently LAN. See <sdp.h> for definitions..
389 #define pdu_len sizeof(struct sdp_lan_profile)
392 open_server(bdaddr_t
*laddr
, uint8_t channel
, int lm
, const char *service
)
394 struct sockaddr_bt sa
;
399 uint8_t pdu
[pdu_len
];
401 memset(&sa
, 0, sizeof(sa
));
402 sa
.bt_len
= sizeof(sa
);
403 sa
.bt_family
= AF_BLUETOOTH
;
404 bdaddr_copy(&sa
.bt_bdaddr
, laddr
);
405 sa
.bt_channel
= channel
;
407 sv
= socket(PF_BLUETOOTH
, SOCK_STREAM
, BTPROTO_RFCOMM
);
409 err(EXIT_FAILURE
, "socket()");
411 if (bind(sv
, (struct sockaddr
*)&sa
, sizeof(sa
)) < 0)
412 err(EXIT_FAILURE
, "bind(%s, %d)", bt_ntoa(laddr
, NULL
),
415 if (setsockopt(sv
, BTPROTO_RFCOMM
, SO_RFCOMM_LM
, &lm
, sizeof(lm
)) < 0)
416 err(EXIT_FAILURE
, "link mode");
418 if (listen(sv
, 1) < 0)
419 err(EXIT_FAILURE
, "listen()");
421 /* Register service with SDP server */
422 for (n
= 0 ; ; n
++) {
423 if (services
[n
].name
== NULL
)
426 if (strcasecmp(services
[n
].name
, service
) == 0)
430 memset(pdu
, 0, pdu_len
);
433 ss
= sdp_open_local(NULL
);
434 if (ss
== NULL
|| (errno
= sdp_error(ss
)) != 0)
435 err(EXIT_FAILURE
, "sdp_open_local");
437 if (sdp_register_service(ss
, services
[n
].class, laddr
,
438 pdu
, services
[n
].pdulen
, NULL
) != 0) {
439 errno
= sdp_error(ss
);
440 err(EXIT_FAILURE
, "sdp_register_service");
444 fd
= accept(sv
, (struct sockaddr
*)&sa
, &len
);
446 err(EXIT_FAILURE
, "accept");
448 memset(&l
, 0, sizeof(l
));
451 if (setsockopt(fd
, SOL_SOCKET
, SO_LINGER
, &l
, sizeof(l
)) < 0)
452 err(EXIT_FAILURE
, "linger()");
459 copy_data(int src
, int dst
)
461 static char buf
[BUFSIZ
];
464 while ((nr
= read(src
, buf
, sizeof(buf
))) == -1) {
465 if (errno
!= EINTR
) {
466 syslog(LOG_ERR
, "read failed: %m");
471 if (nr
== 0) /* reached EOF */
474 for (off
= 0 ; nr
; nr
-= nw
, off
+= nw
) {
475 if ((nw
= write(dst
, buf
+ off
, (size_t)nr
)) == -1) {
476 syslog(LOG_ERR
, "write failed: %m");
483 sighandler(int s __unused
)
493 tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &tio
);
499 const char *cmd
= getprogname();
502 fprintf(stderr
, "Usage: %s [-d device] [-m mode] [-s service] [-t tty]\n"
503 " %*s {-a bdaddr | -c channel}\n"
506 "\t-a bdaddr remote device address\n"
507 "\t-c channel local RFCOMM channel\n"
508 "\t-d device local device address\n"
509 "\t-m mode link mode\n"
510 "\t-s service service class\n"
511 "\t-t tty run in background using pty\n"
512 "\n", cmd
, (int)strlen(cmd
), "");
514 fprintf(stderr
, "Known service classes:\n");
515 for (s
= services
; s
->name
!= NULL
; s
++)
516 fprintf(stderr
, "\t%-13s%s\n", s
->name
, s
->description
);