1 /* $NetBSD: rfcomm_sppd.c,v 1.8 2007/04/21 10:39:30 dsl Exp $ */
2 /* $DragonFly: src/usr.bin/rfcomm_sppd/rfcomm_sppd.c,v 1.2 2008/02/11 20:10:23 swildner Exp $ */
5 * Copyright (c) 2006 Itronix Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of Itronix Inc. may not be used to endorse
17 * or promote products derived from this software without specific
18 * prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
35 * Copyright (c) 2007 Iain Hibbert
36 * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
37 * All rights reserved.
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
48 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 #include <bluetooth.h>
80 #include <netbt/rfcomm.h>
82 #include "rfcomm_sdp.h"
84 #define max(a, b) ((a) > (b) ? (a) : (b))
86 int open_tty(const char *);
87 int open_client(bdaddr_t
*, bdaddr_t
*, int, const char *);
88 int open_server(bdaddr_t
*, uint8_t, int, const char *);
89 void copy_data(int, int);
94 int done
; /* got a signal */
95 struct termios tio
; /* stored termios for reset on exit */
99 const char *description
;
103 { "DUN", "Dialup Networking",
104 SDP_SERVICE_CLASS_DIALUP_NETWORKING
,
105 sizeof(struct sdp_dun_profile
)
107 { "LAN", "Lan access using PPP",
108 SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP
,
109 sizeof(struct sdp_lan_profile
)
111 { "SP", "Serial Port",
112 SDP_SERVICE_CLASS_SERIAL_PORT
,
113 sizeof(struct sdp_sp_profile
)
122 main(int argc
, char *argv
[])
125 bdaddr_t laddr
, raddr
;
129 int lm
, n
, rfcomm
, tty_in
, tty_out
;
132 bdaddr_copy(&laddr
, BDADDR_ANY
);
133 bdaddr_copy(&raddr
, BDADDR_ANY
);
139 /* Parse command line options */
140 while ((n
= getopt(argc
, argv
, "a:c:d:hm:s:t:")) != -1) {
142 case 'a': /* remote device address */
143 if (!bt_aton(optarg
, &raddr
)) {
144 struct hostent
*he
= NULL
;
146 if ((he
= bt_gethostbyname(optarg
)) == NULL
)
147 errx(EXIT_FAILURE
, "%s: %s", optarg
,
150 bdaddr_copy(&raddr
, (bdaddr_t
*)he
->h_addr
);
154 case 'c': /* RFCOMM channel */
155 channel
= strtoul(optarg
, &ep
, 10);
156 if (*ep
!= '\0' || channel
< 1 || channel
> 30)
157 errx(EXIT_FAILURE
, "Invalid channel: %s", optarg
);
161 case 'd': /* local device address */
162 if (!bt_devaddr(optarg
, &laddr
))
163 err(EXIT_FAILURE
, "%s", optarg
);
167 case 'm': /* Link Mode */
168 if (strcasecmp(optarg
, "auth") == 0)
170 else if (strcasecmp(optarg
, "encrypt") == 0)
171 lm
= RFCOMM_LM_ENCRYPT
;
172 else if (strcasecmp(optarg
, "secure") == 0)
173 lm
= RFCOMM_LM_SECURE
;
175 errx(EXIT_FAILURE
, "%s: unknown mode", optarg
);
179 case 's': /* service class */
183 case 't': /* Slave TTY name */
184 if (optarg
[0] != '/')
185 asprintf(&tty
, "%s%s", _PATH_DEV
, optarg
);
200 * must have channel or remote address but not both
202 if ((channel
== 0 && bdaddr_any(&raddr
))
203 || (channel
!= 0 && !bdaddr_any(&raddr
)))
207 * grab ttys before we start the bluetooth
210 tty_in
= STDIN_FILENO
;
211 tty_out
= STDOUT_FILENO
;
213 tty_in
= open_tty(tty
);
219 rfcomm
= open_client(&laddr
, &raddr
, lm
, service
);
221 rfcomm
= open_server(&laddr
, channel
, lm
, service
);
224 * now we are ready to go, so either detach or maybe turn
225 * off some input processing, so that rfcomm_sppd can
226 * be used directly with stdio
229 if (tcgetattr(tty_in
, &t
) < 0)
230 err(EXIT_FAILURE
, "tcgetattr");
232 memcpy(&tio
, &t
, sizeof(tio
));
233 t
.c_lflag
&= ~(ECHO
| ICANON
);
234 t
.c_iflag
&= ~(ICRNL
);
236 if (memcmp(&tio
, &t
, sizeof(tio
))) {
237 if (tcsetattr(tty_in
, TCSANOW
, &t
) < 0)
238 err(EXIT_FAILURE
, "tcsetattr");
243 if (daemon(0, 0) < 0)
244 err(EXIT_FAILURE
, "daemon() failed");
249 (void)signal(SIGHUP
, sighandler
);
250 (void)signal(SIGINT
, sighandler
);
251 (void)signal(SIGPIPE
, sighandler
);
252 (void)signal(SIGTERM
, sighandler
);
254 openlog(getprogname(), LOG_PERROR
| LOG_PID
, LOG_DAEMON
);
255 syslog(LOG_INFO
, "Starting on %s...", (tty
? tty
: "stdio"));
257 n
= max(tty_in
, rfcomm
) + 1;
260 FD_SET(tty_in
, &rdset
);
261 FD_SET(rfcomm
, &rdset
);
263 if (select(n
, &rdset
, NULL
, NULL
, NULL
) < 0) {
267 syslog(LOG_ERR
, "select error: %m");
271 if (FD_ISSET(tty_in
, &rdset
))
272 copy_data(tty_in
, rfcomm
);
274 if (FD_ISSET(rfcomm
, &rdset
))
275 copy_data(rfcomm
, tty_out
);
278 syslog(LOG_INFO
, "Completed on %s", (tty
? tty
: "stdio"));
283 open_tty(const char *tty
)
285 char pty
[PATH_MAX
], *slash
;
286 struct group
*gr
= NULL
;
291 * Construct master PTY name. The slave tty name must be less then
292 * PATH_MAX characters in length, must contain '/' character and
293 * must not end with '/'.
295 if (strlen(tty
) >= sizeof(pty
))
296 errx(EXIT_FAILURE
, ": tty name too long");
298 strlcpy(pty
, tty
, sizeof(pty
));
299 slash
= strrchr(pty
, '/');
300 if (slash
== NULL
|| slash
[1] == '\0')
301 errx(EXIT_FAILURE
, "%s: invalid tty", tty
);
304 if (strcmp(pty
, tty
) == 0)
305 errx(EXIT_FAILURE
, "Master and slave tty are the same (%s)", tty
);
307 if ((master
= open(pty
, O_RDWR
, 0)) < 0)
308 err(EXIT_FAILURE
, "%s", pty
);
314 if ((gr
= getgrnam("tty")) != NULL
)
319 (void)chown(tty
, getuid(), ttygid
);
320 (void)chmod(tty
, S_IRUSR
| S_IWUSR
| S_IWGRP
);
327 open_client(bdaddr_t
*laddr
, bdaddr_t
*raddr
, int lm
, const char *service
)
329 struct sockaddr_bt sa
;
336 for (s
= services
; ; s
++) {
337 if (s
->name
== NULL
) {
338 channel
= strtoul(service
, &ep
, 10);
339 if (*ep
!= '\0' || channel
< 1 || channel
> 30)
340 errx(EXIT_FAILURE
, "Invalid service: %s", service
);
345 if (strcasecmp(s
->name
, service
) == 0) {
346 if (rfcomm_channel_lookup(laddr
, raddr
, s
->class, &channel
, &errno
) < 0)
347 err(EXIT_FAILURE
, "%s", s
->name
);
353 memset(&sa
, 0, sizeof(sa
));
354 sa
.bt_len
= sizeof(sa
);
355 sa
.bt_family
= AF_BLUETOOTH
;
356 bdaddr_copy(&sa
.bt_bdaddr
, laddr
);
358 fd
= socket(PF_BLUETOOTH
, SOCK_STREAM
, BTPROTO_RFCOMM
);
360 err(EXIT_FAILURE
, "socket()");
362 if (bind(fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) < 0)
363 err(EXIT_FAILURE
, "bind(%s)", bt_ntoa(laddr
, NULL
));
365 memset(&l
, 0, sizeof(l
));
368 if (setsockopt(fd
, SOL_SOCKET
, SO_LINGER
, &l
, sizeof(l
)) < 0)
369 err(EXIT_FAILURE
, "linger()");
371 if (setsockopt(fd
, BTPROTO_RFCOMM
, SO_RFCOMM_LM
, &lm
, sizeof(lm
)) < 0)
372 err(EXIT_FAILURE
, "link mode");
374 sa
.bt_channel
= channel
;
375 bdaddr_copy(&sa
.bt_bdaddr
, raddr
);
377 if (connect(fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) < 0)
378 err(EXIT_FAILURE
, "connect(%s, %d)", bt_ntoa(raddr
, NULL
),
385 * In all the profiles we currently support registering, the channel
386 * is the first octet in the PDU, and it seems all the rest can be
387 * zero, so we just use an array of uint8_t big enough to store the
388 * largest, currently LAN. See <sdp.h> for definitions..
390 #define pdu_len sizeof(struct sdp_lan_profile)
393 open_server(bdaddr_t
*laddr
, uint8_t channel
, int lm
, const char *service
)
395 struct sockaddr_bt sa
;
400 uint8_t pdu
[pdu_len
];
402 memset(&sa
, 0, sizeof(sa
));
403 sa
.bt_len
= sizeof(sa
);
404 sa
.bt_family
= AF_BLUETOOTH
;
405 bdaddr_copy(&sa
.bt_bdaddr
, laddr
);
406 sa
.bt_channel
= channel
;
408 sv
= socket(PF_BLUETOOTH
, SOCK_STREAM
, BTPROTO_RFCOMM
);
410 err(EXIT_FAILURE
, "socket()");
412 if (bind(sv
, (struct sockaddr
*)&sa
, sizeof(sa
)) < 0)
413 err(EXIT_FAILURE
, "bind(%s, %d)", bt_ntoa(laddr
, NULL
),
416 if (setsockopt(sv
, BTPROTO_RFCOMM
, SO_RFCOMM_LM
, &lm
, sizeof(lm
)) < 0)
417 err(EXIT_FAILURE
, "link mode");
419 if (listen(sv
, 1) < 0)
420 err(EXIT_FAILURE
, "listen()");
422 /* Register service with SDP server */
423 for (n
= 0 ; ; n
++) {
424 if (services
[n
].name
== NULL
)
427 if (strcasecmp(services
[n
].name
, service
) == 0)
431 memset(pdu
, 0, pdu_len
);
434 ss
= sdp_open_local(NULL
);
435 if (ss
== NULL
|| (errno
= sdp_error(ss
)) != 0)
436 err(EXIT_FAILURE
, "sdp_open_local");
438 if (sdp_register_service(ss
, services
[n
].class, laddr
,
439 pdu
, services
[n
].pdulen
, NULL
) != 0) {
440 errno
= sdp_error(ss
);
441 err(EXIT_FAILURE
, "sdp_register_service");
445 fd
= accept(sv
, (struct sockaddr
*)&sa
, &len
);
447 err(EXIT_FAILURE
, "accept");
449 memset(&l
, 0, sizeof(l
));
452 if (setsockopt(fd
, SOL_SOCKET
, SO_LINGER
, &l
, sizeof(l
)) < 0)
453 err(EXIT_FAILURE
, "linger()");
460 copy_data(int src
, int dst
)
462 static char buf
[BUFSIZ
];
465 while ((nr
= read(src
, buf
, sizeof(buf
))) == -1) {
466 if (errno
!= EINTR
) {
467 syslog(LOG_ERR
, "read failed: %m");
472 if (nr
== 0) /* reached EOF */
475 for (off
= 0 ; nr
; nr
-= nw
, off
+= nw
) {
476 if ((nw
= write(dst
, buf
+ off
, (size_t)nr
)) == -1) {
477 syslog(LOG_ERR
, "write failed: %m");
484 sighandler(int s __unused
)
494 tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &tio
);
500 const char *cmd
= getprogname();
503 fprintf(stderr
, "Usage: %s [-d device] [-m mode] [-s service] [-t tty]\n"
504 " %*s {-a bdaddr | -c channel}\n"
507 "\t-a bdaddr remote device address\n"
508 "\t-c channel local RFCOMM channel\n"
509 "\t-d device local device address\n"
510 "\t-m mode link mode\n"
511 "\t-s service service class\n"
512 "\t-t tty run in background using pty\n"
513 "\n", cmd
, (int)strlen(cmd
), "");
515 fprintf(stderr
, "Known service classes:\n");
516 for (s
= services
; s
->name
!= NULL
; s
++)
517 fprintf(stderr
, "\t%-13s%s\n", s
->name
, s
->description
);