rfcomm_sppd.c revision 1.8 1 1.8 dsl /* $NetBSD: rfcomm_sppd.c,v 1.8 2007/04/21 10:39:30 dsl Exp $ */
2 1.1 gdamore
3 1.1 gdamore /*-
4 1.1 gdamore * Copyright (c) 2006 Itronix Inc.
5 1.1 gdamore * All rights reserved.
6 1.1 gdamore *
7 1.1 gdamore * Redistribution and use in source and binary forms, with or without
8 1.1 gdamore * modification, are permitted provided that the following conditions
9 1.1 gdamore * are met:
10 1.1 gdamore * 1. Redistributions of source code must retain the above copyright
11 1.1 gdamore * notice, this list of conditions and the following disclaimer.
12 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 gdamore * notice, this list of conditions and the following disclaimer in the
14 1.1 gdamore * documentation and/or other materials provided with the distribution.
15 1.1 gdamore * 3. The name of Itronix Inc. may not be used to endorse
16 1.1 gdamore * or promote products derived from this software without specific
17 1.1 gdamore * prior written permission.
18 1.1 gdamore *
19 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20 1.1 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 gdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 gdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
23 1.1 gdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 1.1 gdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 1.1 gdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 1.1 gdamore * ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 gdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 gdamore * POSSIBILITY OF SUCH DAMAGE.
30 1.1 gdamore */
31 1.1 gdamore /*
32 1.1 gdamore * rfcomm_sppd.c
33 1.1 gdamore *
34 1.2 plunky * Copyright (c) 2007 Iain Hibbert
35 1.1 gdamore * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin (at) yahoo.com>
36 1.1 gdamore * All rights reserved.
37 1.1 gdamore *
38 1.1 gdamore * Redistribution and use in source and binary forms, with or without
39 1.1 gdamore * modification, are permitted provided that the following conditions
40 1.1 gdamore * are met:
41 1.1 gdamore * 1. Redistributions of source code must retain the above copyright
42 1.1 gdamore * notice, this list of conditions and the following disclaimer.
43 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright
44 1.1 gdamore * notice, this list of conditions and the following disclaimer in the
45 1.1 gdamore * documentation and/or other materials provided with the distribution.
46 1.1 gdamore *
47 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
48 1.1 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 1.1 gdamore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 1.1 gdamore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
51 1.1 gdamore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 1.1 gdamore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 1.1 gdamore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 1.1 gdamore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 1.1 gdamore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 1.1 gdamore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 1.1 gdamore * SUCH DAMAGE.
58 1.1 gdamore */
59 1.1 gdamore
60 1.1 gdamore #include <sys/cdefs.h>
61 1.2 plunky __COPYRIGHT("@(#) Copyright (c) 2007 Iain Hibbert\n"
62 1.2 plunky "@(#) Copyright (c) 2006 Itronix, Inc.\n"
63 1.1 gdamore "@(#) Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin (at) yahoo.com>\n"
64 1.1 gdamore "All rights reserved.\n");
65 1.8 dsl __RCSID("$NetBSD: rfcomm_sppd.c,v 1.8 2007/04/21 10:39:30 dsl Exp $");
66 1.1 gdamore
67 1.1 gdamore #include <bluetooth.h>
68 1.1 gdamore #include <ctype.h>
69 1.1 gdamore #include <err.h>
70 1.1 gdamore #include <errno.h>
71 1.1 gdamore #include <fcntl.h>
72 1.1 gdamore #include <grp.h>
73 1.1 gdamore #include <limits.h>
74 1.1 gdamore #include <paths.h>
75 1.1 gdamore #include <sdp.h>
76 1.1 gdamore #include <signal.h>
77 1.1 gdamore #include <stdarg.h>
78 1.1 gdamore #include <stdio.h>
79 1.1 gdamore #include <stdlib.h>
80 1.1 gdamore #include <string.h>
81 1.1 gdamore #include <syslog.h>
82 1.1 gdamore #include <termios.h>
83 1.1 gdamore #include <unistd.h>
84 1.1 gdamore
85 1.7 plunky #include <netbt/rfcomm.h>
86 1.7 plunky
87 1.1 gdamore #include "rfcomm_sdp.h"
88 1.1 gdamore
89 1.2 plunky #define max(a, b) ((a) > (b) ? (a) : (b))
90 1.1 gdamore
91 1.2 plunky int open_tty(const char *);
92 1.7 plunky int open_client(bdaddr_t *, bdaddr_t *, int, const char *);
93 1.7 plunky int open_server(bdaddr_t *, uint8_t, int, const char *);
94 1.2 plunky void copy_data(int, int);
95 1.2 plunky void sighandler(int);
96 1.2 plunky void usage(void);
97 1.2 plunky void reset_tio(void);
98 1.2 plunky
99 1.2 plunky int done; /* got a signal */
100 1.2 plunky struct termios tio; /* stored termios for reset on exit */
101 1.2 plunky
102 1.2 plunky struct service {
103 1.2 plunky const char *name;
104 1.2 plunky const char *description;
105 1.2 plunky uint16_t class;
106 1.2 plunky int pdulen;
107 1.2 plunky } services[] = {
108 1.2 plunky { "DUN", "Dialup Networking",
109 1.2 plunky SDP_SERVICE_CLASS_DIALUP_NETWORKING,
110 1.2 plunky sizeof(struct sdp_dun_profile)
111 1.2 plunky },
112 1.2 plunky { "LAN", "Lan access using PPP",
113 1.2 plunky SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
114 1.2 plunky sizeof(struct sdp_lan_profile)
115 1.2 plunky },
116 1.2 plunky { "SP", "Serial Port",
117 1.2 plunky SDP_SERVICE_CLASS_SERIAL_PORT,
118 1.2 plunky sizeof(struct sdp_sp_profile)
119 1.2 plunky },
120 1.6 plunky { NULL, NULL,
121 1.6 plunky 0,
122 1.6 plunky 0
123 1.6 plunky }
124 1.2 plunky };
125 1.1 gdamore
126 1.1 gdamore int
127 1.1 gdamore main(int argc, char *argv[])
128 1.1 gdamore {
129 1.2 plunky struct termios t;
130 1.2 plunky bdaddr_t laddr, raddr;
131 1.2 plunky fd_set rdset;
132 1.6 plunky const char *service;
133 1.6 plunky char *ep, *tty;
134 1.7 plunky int lm, n, rfcomm, tty_in, tty_out;
135 1.2 plunky uint8_t channel;
136 1.1 gdamore
137 1.1 gdamore bdaddr_copy(&laddr, BDADDR_ANY);
138 1.1 gdamore bdaddr_copy(&raddr, BDADDR_ANY);
139 1.3 plunky service = "SP";
140 1.3 plunky tty = NULL;
141 1.2 plunky channel = 0;
142 1.7 plunky lm = 0;
143 1.1 gdamore
144 1.1 gdamore /* Parse command line options */
145 1.7 plunky while ((n = getopt(argc, argv, "a:c:d:hm:s:t:")) != -1) {
146 1.1 gdamore switch (n) {
147 1.2 plunky case 'a': /* remote device address */
148 1.1 gdamore if (!bt_aton(optarg, &raddr)) {
149 1.1 gdamore struct hostent *he = NULL;
150 1.1 gdamore
151 1.1 gdamore if ((he = bt_gethostbyname(optarg)) == NULL)
152 1.2 plunky errx(EXIT_FAILURE, "%s: %s", optarg,
153 1.2 plunky hstrerror(h_errno));
154 1.1 gdamore
155 1.1 gdamore bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr);
156 1.1 gdamore }
157 1.1 gdamore break;
158 1.1 gdamore
159 1.1 gdamore case 'c': /* RFCOMM channel */
160 1.1 gdamore channel = strtoul(optarg, &ep, 10);
161 1.3 plunky if (*ep != '\0' || channel < 1 || channel > 30)
162 1.3 plunky errx(EXIT_FAILURE, "Invalid channel: %s", optarg);
163 1.3 plunky
164 1.1 gdamore break;
165 1.1 gdamore
166 1.2 plunky case 'd': /* local device address */
167 1.2 plunky if (!bt_devaddr(optarg, &laddr))
168 1.2 plunky err(EXIT_FAILURE, "%s", optarg);
169 1.2 plunky
170 1.1 gdamore break;
171 1.1 gdamore
172 1.7 plunky case 'm': /* Link Mode */
173 1.7 plunky if (strcasecmp(optarg, "auth") == 0)
174 1.7 plunky lm = RFCOMM_LM_AUTH;
175 1.7 plunky else if (strcasecmp(optarg, "encrypt") == 0)
176 1.7 plunky lm = RFCOMM_LM_ENCRYPT;
177 1.7 plunky else if (strcasecmp(optarg, "secure") == 0)
178 1.7 plunky lm = RFCOMM_LM_SECURE;
179 1.7 plunky else
180 1.7 plunky errx(EXIT_FAILURE, "%s: unknown mode", optarg);
181 1.7 plunky
182 1.7 plunky break;
183 1.7 plunky
184 1.3 plunky case 's': /* service class */
185 1.2 plunky service = optarg;
186 1.1 gdamore break;
187 1.1 gdamore
188 1.1 gdamore case 't': /* Slave TTY name */
189 1.1 gdamore if (optarg[0] != '/')
190 1.1 gdamore asprintf(&tty, "%s%s", _PATH_DEV, optarg);
191 1.1 gdamore else
192 1.1 gdamore tty = optarg;
193 1.2 plunky
194 1.1 gdamore break;
195 1.1 gdamore
196 1.1 gdamore case 'h':
197 1.1 gdamore default:
198 1.1 gdamore usage();
199 1.1 gdamore /* NOT REACHED */
200 1.1 gdamore }
201 1.1 gdamore }
202 1.1 gdamore
203 1.2 plunky /*
204 1.2 plunky * validate options:
205 1.3 plunky * must have channel or remote address but not both
206 1.2 plunky */
207 1.3 plunky if ((channel == 0 && bdaddr_any(&raddr))
208 1.3 plunky || (channel != 0 && !bdaddr_any(&raddr)))
209 1.1 gdamore usage();
210 1.1 gdamore
211 1.2 plunky /*
212 1.2 plunky * grab ttys before we start the bluetooth
213 1.2 plunky */
214 1.1 gdamore if (tty == NULL) {
215 1.2 plunky tty_in = STDIN_FILENO;
216 1.2 plunky tty_out = STDOUT_FILENO;
217 1.2 plunky } else {
218 1.2 plunky tty_in = open_tty(tty);
219 1.2 plunky tty_out = tty_in;
220 1.2 plunky }
221 1.1 gdamore
222 1.2 plunky /* open RFCOMM */
223 1.3 plunky if (channel == 0)
224 1.7 plunky rfcomm = open_client(&laddr, &raddr, lm, service);
225 1.2 plunky else
226 1.7 plunky rfcomm = open_server(&laddr, channel, lm, service);
227 1.1 gdamore
228 1.2 plunky /*
229 1.4 plunky * now we are ready to go, so either detach or maybe turn
230 1.2 plunky * off some input processing, so that rfcomm_sppd can
231 1.2 plunky * be used directly with stdio
232 1.2 plunky */
233 1.2 plunky if (tty == NULL) {
234 1.2 plunky if (tcgetattr(tty_in, &t) < 0)
235 1.2 plunky err(EXIT_FAILURE, "tcgetattr");
236 1.1 gdamore
237 1.2 plunky memcpy(&tio, &t, sizeof(tio));
238 1.2 plunky t.c_lflag &= ~(ECHO | ICANON);
239 1.2 plunky t.c_iflag &= ~(ICRNL);
240 1.1 gdamore
241 1.4 plunky if (memcmp(&tio, &t, sizeof(tio))) {
242 1.4 plunky if (tcsetattr(tty_in, TCSANOW, &t) < 0)
243 1.4 plunky err(EXIT_FAILURE, "tcsetattr");
244 1.1 gdamore
245 1.4 plunky atexit(reset_tio);
246 1.4 plunky }
247 1.2 plunky } else {
248 1.2 plunky if (daemon(0, 0) < 0)
249 1.2 plunky err(EXIT_FAILURE, "daemon() failed");
250 1.1 gdamore }
251 1.1 gdamore
252 1.2 plunky /* catch signals */
253 1.2 plunky done = 0;
254 1.2 plunky (void)signal(SIGHUP, sighandler);
255 1.2 plunky (void)signal(SIGINT, sighandler);
256 1.2 plunky (void)signal(SIGPIPE, sighandler);
257 1.2 plunky (void)signal(SIGTERM, sighandler);
258 1.2 plunky
259 1.2 plunky openlog(getprogname(), LOG_PERROR | LOG_PID, LOG_DAEMON);
260 1.2 plunky syslog(LOG_INFO, "Starting on %s...", (tty ? tty : "stdio"));
261 1.2 plunky
262 1.2 plunky n = max(tty_in, rfcomm) + 1;
263 1.2 plunky while (!done) {
264 1.2 plunky FD_ZERO(&rdset);
265 1.2 plunky FD_SET(tty_in, &rdset);
266 1.2 plunky FD_SET(rfcomm, &rdset);
267 1.1 gdamore
268 1.2 plunky if (select(n, &rdset, NULL, NULL, NULL) < 0) {
269 1.1 gdamore if (errno == EINTR)
270 1.1 gdamore continue;
271 1.1 gdamore
272 1.2 plunky syslog(LOG_ERR, "select error: %m");
273 1.1 gdamore exit(EXIT_FAILURE);
274 1.1 gdamore }
275 1.1 gdamore
276 1.2 plunky if (FD_ISSET(tty_in, &rdset))
277 1.2 plunky copy_data(tty_in, rfcomm);
278 1.1 gdamore
279 1.2 plunky if (FD_ISSET(rfcomm, &rdset))
280 1.2 plunky copy_data(rfcomm, tty_out);
281 1.2 plunky }
282 1.1 gdamore
283 1.2 plunky syslog(LOG_INFO, "Completed on %s", (tty ? tty : "stdio"));
284 1.2 plunky exit(EXIT_SUCCESS);
285 1.2 plunky }
286 1.1 gdamore
287 1.2 plunky int
288 1.2 plunky open_tty(const char *tty)
289 1.1 gdamore {
290 1.1 gdamore char pty[PATH_MAX], *slash;
291 1.1 gdamore struct group *gr = NULL;
292 1.1 gdamore gid_t ttygid;
293 1.2 plunky int master;
294 1.1 gdamore
295 1.1 gdamore /*
296 1.1 gdamore * Construct master PTY name. The slave tty name must be less then
297 1.1 gdamore * PATH_MAX characters in length, must contain '/' character and
298 1.1 gdamore * must not end with '/'.
299 1.1 gdamore */
300 1.2 plunky if (strlen(tty) >= sizeof(pty))
301 1.2 plunky errx(EXIT_FAILURE, ": tty name too long");
302 1.1 gdamore
303 1.1 gdamore strlcpy(pty, tty, sizeof(pty));
304 1.1 gdamore slash = strrchr(pty, '/');
305 1.2 plunky if (slash == NULL || slash[1] == '\0')
306 1.2 plunky errx(EXIT_FAILURE, "%s: invalid tty", tty);
307 1.1 gdamore
308 1.1 gdamore slash[1] = 'p';
309 1.2 plunky if (strcmp(pty, tty) == 0)
310 1.2 plunky errx(EXIT_FAILURE, "Master and slave tty are the same (%s)", tty);
311 1.1 gdamore
312 1.2 plunky if ((master = open(pty, O_RDWR, 0)) < 0)
313 1.2 plunky err(EXIT_FAILURE, "%s", pty);
314 1.1 gdamore
315 1.1 gdamore /*
316 1.1 gdamore * Slave TTY
317 1.1 gdamore */
318 1.1 gdamore
319 1.1 gdamore if ((gr = getgrnam("tty")) != NULL)
320 1.1 gdamore ttygid = gr->gr_gid;
321 1.1 gdamore else
322 1.1 gdamore ttygid = (gid_t)-1;
323 1.1 gdamore
324 1.2 plunky (void)chown(tty, getuid(), ttygid);
325 1.2 plunky (void)chmod(tty, S_IRUSR | S_IWUSR | S_IWGRP);
326 1.2 plunky (void)revoke(tty);
327 1.2 plunky
328 1.2 plunky return master;
329 1.2 plunky }
330 1.1 gdamore
331 1.2 plunky int
332 1.7 plunky open_client(bdaddr_t *laddr, bdaddr_t *raddr, int lm, const char *service)
333 1.2 plunky {
334 1.2 plunky struct sockaddr_bt sa;
335 1.3 plunky struct service *s;
336 1.2 plunky struct linger l;
337 1.3 plunky char *ep;
338 1.2 plunky int fd;
339 1.3 plunky uint8_t channel;
340 1.3 plunky
341 1.3 plunky for (s = services ; ; s++) {
342 1.3 plunky if (s->name == NULL) {
343 1.5 plunky channel = strtoul(service, &ep, 10);
344 1.3 plunky if (*ep != '\0' || channel < 1 || channel > 30)
345 1.3 plunky errx(EXIT_FAILURE, "Invalid service: %s", service);
346 1.3 plunky
347 1.3 plunky break;
348 1.3 plunky }
349 1.3 plunky
350 1.3 plunky if (strcasecmp(s->name, service) == 0) {
351 1.3 plunky if (rfcomm_channel_lookup(laddr, raddr, s->class, &channel, &errno) < 0)
352 1.3 plunky err(EXIT_FAILURE, "%s", s->name);
353 1.3 plunky
354 1.3 plunky break;
355 1.3 plunky }
356 1.3 plunky }
357 1.1 gdamore
358 1.2 plunky memset(&sa, 0, sizeof(sa));
359 1.2 plunky sa.bt_len = sizeof(sa);
360 1.2 plunky sa.bt_family = AF_BLUETOOTH;
361 1.2 plunky bdaddr_copy(&sa.bt_bdaddr, laddr);
362 1.2 plunky
363 1.2 plunky fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
364 1.2 plunky if (fd < 0)
365 1.2 plunky err(EXIT_FAILURE, "socket()");
366 1.2 plunky
367 1.2 plunky if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
368 1.2 plunky err(EXIT_FAILURE, "bind(%s)", bt_ntoa(laddr, NULL));
369 1.2 plunky
370 1.2 plunky memset(&l, 0, sizeof(l));
371 1.2 plunky l.l_onoff = 1;
372 1.2 plunky l.l_linger = 5;
373 1.2 plunky if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
374 1.2 plunky err(EXIT_FAILURE, "linger()");
375 1.2 plunky
376 1.7 plunky if (setsockopt(fd, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
377 1.7 plunky err(EXIT_FAILURE, "link mode");
378 1.7 plunky
379 1.2 plunky sa.bt_channel = channel;
380 1.2 plunky bdaddr_copy(&sa.bt_bdaddr, raddr);
381 1.2 plunky
382 1.2 plunky if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
383 1.2 plunky err(EXIT_FAILURE, "connect(%s, %d)", bt_ntoa(raddr, NULL),
384 1.2 plunky channel);
385 1.1 gdamore
386 1.2 plunky return fd;
387 1.2 plunky }
388 1.1 gdamore
389 1.2 plunky /*
390 1.2 plunky * In all the profiles we currently support registering, the channel
391 1.2 plunky * is the first octet in the PDU, and it seems all the rest can be
392 1.2 plunky * zero, so we just use an array of uint8_t big enough to store the
393 1.2 plunky * largest, currently LAN. See <sdp.h> for definitions..
394 1.2 plunky */
395 1.2 plunky #define pdu_len sizeof(struct sdp_lan_profile)
396 1.1 gdamore
397 1.2 plunky int
398 1.7 plunky open_server(bdaddr_t *laddr, uint8_t channel, int lm, const char *service)
399 1.1 gdamore {
400 1.2 plunky struct sockaddr_bt sa;
401 1.2 plunky struct linger l;
402 1.2 plunky socklen_t len;
403 1.2 plunky void *ss;
404 1.2 plunky int sv, fd, n;
405 1.2 plunky uint8_t pdu[pdu_len];
406 1.1 gdamore
407 1.2 plunky memset(&sa, 0, sizeof(sa));
408 1.2 plunky sa.bt_len = sizeof(sa);
409 1.2 plunky sa.bt_family = AF_BLUETOOTH;
410 1.2 plunky bdaddr_copy(&sa.bt_bdaddr, laddr);
411 1.2 plunky sa.bt_channel = channel;
412 1.2 plunky
413 1.2 plunky sv = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
414 1.2 plunky if (sv < 0)
415 1.2 plunky err(EXIT_FAILURE, "socket()");
416 1.2 plunky
417 1.2 plunky if (bind(sv, (struct sockaddr *)&sa, sizeof(sa)) < 0)
418 1.2 plunky err(EXIT_FAILURE, "bind(%s, %d)", bt_ntoa(laddr, NULL),
419 1.2 plunky channel);
420 1.2 plunky
421 1.7 plunky if (setsockopt(sv, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
422 1.7 plunky err(EXIT_FAILURE, "link mode");
423 1.7 plunky
424 1.2 plunky if (listen(sv, 1) < 0)
425 1.2 plunky err(EXIT_FAILURE, "listen()");
426 1.2 plunky
427 1.2 plunky /* Register service with SDP server */
428 1.2 plunky for (n = 0 ; ; n++) {
429 1.2 plunky if (services[n].name == NULL)
430 1.2 plunky usage();
431 1.1 gdamore
432 1.2 plunky if (strcasecmp(services[n].name, service) == 0)
433 1.2 plunky break;
434 1.1 gdamore }
435 1.1 gdamore
436 1.2 plunky memset(pdu, 0, pdu_len);
437 1.2 plunky pdu[0] = channel;
438 1.2 plunky
439 1.2 plunky ss = sdp_open_local(NULL);
440 1.2 plunky if (ss == NULL || (errno = sdp_error(ss)) != 0)
441 1.2 plunky err(EXIT_FAILURE, "sdp_open_local");
442 1.2 plunky
443 1.2 plunky if (sdp_register_service(ss, services[n].class, laddr,
444 1.2 plunky pdu, services[n].pdulen, NULL) != 0) {
445 1.2 plunky errno = sdp_error(ss);
446 1.2 plunky err(EXIT_FAILURE, "sdp_register_service");
447 1.2 plunky }
448 1.2 plunky
449 1.2 plunky len = sizeof(sa);
450 1.2 plunky fd = accept(sv, (struct sockaddr *)&sa, &len);
451 1.2 plunky if (fd < 0)
452 1.2 plunky err(EXIT_FAILURE, "accept");
453 1.2 plunky
454 1.2 plunky memset(&l, 0, sizeof(l));
455 1.2 plunky l.l_onoff = 1;
456 1.2 plunky l.l_linger = 5;
457 1.2 plunky if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
458 1.2 plunky err(EXIT_FAILURE, "linger()");
459 1.2 plunky
460 1.2 plunky close(sv);
461 1.2 plunky return fd;
462 1.2 plunky }
463 1.1 gdamore
464 1.2 plunky void
465 1.2 plunky copy_data(int src, int dst)
466 1.1 gdamore {
467 1.2 plunky static char buf[BUFSIZ];
468 1.2 plunky ssize_t nr, nw, off;
469 1.1 gdamore
470 1.2 plunky while ((nr = read(src, buf, sizeof(buf))) == -1) {
471 1.2 plunky if (errno != EINTR) {
472 1.2 plunky syslog(LOG_ERR, "read failed: %m");
473 1.2 plunky exit(EXIT_FAILURE);
474 1.2 plunky }
475 1.2 plunky }
476 1.1 gdamore
477 1.3 plunky if (nr == 0) /* reached EOF */
478 1.3 plunky done++;
479 1.3 plunky
480 1.2 plunky for (off = 0 ; nr ; nr -= nw, off += nw) {
481 1.2 plunky if ((nw = write(dst, buf + off, (size_t)nr)) == -1) {
482 1.2 plunky syslog(LOG_ERR, "write failed: %m");
483 1.2 plunky exit(EXIT_FAILURE);
484 1.1 gdamore }
485 1.1 gdamore }
486 1.2 plunky }
487 1.1 gdamore
488 1.2 plunky void
489 1.2 plunky sighandler(int s)
490 1.2 plunky {
491 1.1 gdamore
492 1.2 plunky done++;
493 1.2 plunky }
494 1.2 plunky
495 1.2 plunky void
496 1.2 plunky reset_tio(void)
497 1.1 gdamore {
498 1.1 gdamore
499 1.2 plunky tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
500 1.2 plunky }
501 1.2 plunky
502 1.2 plunky void
503 1.1 gdamore usage(void)
504 1.1 gdamore {
505 1.7 plunky const char *cmd = getprogname();
506 1.2 plunky struct service *s;
507 1.2 plunky
508 1.7 plunky fprintf(stderr, "Usage: %s [-d device] [-m mode] [-s service] [-t tty]\n"
509 1.7 plunky " %*s {-a bdaddr | -c channel}\n"
510 1.2 plunky "\n"
511 1.2 plunky "Where:\n"
512 1.2 plunky "\t-a bdaddr remote device address\n"
513 1.3 plunky "\t-c channel local RFCOMM channel\n"
514 1.2 plunky "\t-d device local device address\n"
515 1.7 plunky "\t-m mode link mode\n"
516 1.3 plunky "\t-s service service class\n"
517 1.2 plunky "\t-t tty run in background using pty\n"
518 1.8 dsl "\n", cmd, (int)strlen(cmd), "");
519 1.2 plunky
520 1.3 plunky fprintf(stderr, "Known service classes:\n");
521 1.2 plunky for (s = services ; s->name != NULL ; s++)
522 1.3 plunky fprintf(stderr, "\t%-13s%s\n", s->name, s->description);
523 1.1 gdamore
524 1.1 gdamore exit(EXIT_FAILURE);
525 1.2 plunky }
526