Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c
104792 views
1
/*
2
* rfcomm_pppd.c
3
*/
4
5
/*-
6
* SPDX-License-Identifier: BSD-2-Clause
7
*
8
* Copyright (c) 2001-2008 Maksim Yevmenkin <[email protected]>
9
* All rights reserved.
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
*
20
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
* SUCH DAMAGE.
31
*
32
* $Id: rfcomm_pppd.c,v 1.5 2003/09/07 18:32:11 max Exp $
33
*/
34
#define L2CAP_SOCKET_CHECKED
35
#include <bluetooth.h>
36
#include <ctype.h>
37
#include <err.h>
38
#include <errno.h>
39
#include <fcntl.h>
40
#include <sdp.h>
41
#include <signal.h>
42
#include <stdarg.h>
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <syslog.h>
47
#include <unistd.h>
48
49
#define RFCOMM_PPPD "rfcomm_pppd"
50
51
int rfcomm_channel_lookup (bdaddr_t const *local,
52
bdaddr_t const *remote,
53
int service, int *channel, int *error);
54
55
static void exec_ppp (int s, char *unit, char *label);
56
static void sighandler (int s);
57
static void usage (void);
58
59
static int done;
60
61
/* Main */
62
int
63
main(int argc, char *argv[])
64
{
65
struct sockaddr_rfcomm sock_addr;
66
char *label = NULL, *unit = NULL, *ep = NULL;
67
bdaddr_t addr;
68
int s, channel, detach, server, service,
69
regdun, regsp;
70
pid_t pid;
71
72
memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));
73
channel = 0;
74
detach = 1;
75
server = 0;
76
service = 0;
77
regdun = 0;
78
regsp = 0;
79
80
/* Parse command line arguments */
81
while ((s = getopt(argc, argv, "a:cC:dDhl:sSu:")) != -1) {
82
switch (s) {
83
case 'a': /* BDADDR */
84
if (!bt_aton(optarg, &addr)) {
85
struct hostent *he = NULL;
86
87
if ((he = bt_gethostbyname(optarg)) == NULL)
88
errx(1, "%s: %s", optarg, hstrerror(h_errno));
89
90
memcpy(&addr, he->h_addr, sizeof(addr));
91
}
92
break;
93
94
case 'c': /* client */
95
server = 0;
96
break;
97
98
case 'C': /* RFCOMM channel */
99
channel = strtoul(optarg, &ep, 10);
100
if (*ep != '\0') {
101
channel = 0;
102
switch (tolower(optarg[0])) {
103
case 'd': /* DialUp Networking */
104
service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
105
break;
106
107
case 'l': /* LAN Access Using PPP */
108
service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
109
break;
110
}
111
}
112
break;
113
114
case 'd': /* do not detach */
115
detach = 0;
116
break;
117
118
case 'D': /* Register DUN service as well as LAN service */
119
regdun = 1;
120
break;
121
122
case 'l': /* PPP label */
123
label = optarg;
124
break;
125
126
case 's': /* server */
127
server = 1;
128
break;
129
130
case 'S': /* Register SP service as well as LAN service */
131
regsp = 1;
132
break;
133
134
case 'u': /* PPP -unit option */
135
strtoul(optarg, &ep, 10);
136
if (*ep != '\0')
137
usage();
138
/* NOT REACHED */
139
140
unit = optarg;
141
break;
142
143
case 'h':
144
default:
145
usage();
146
/* NOT REACHED */
147
}
148
}
149
150
/* Check if we got everything we wanted */
151
if (label == NULL)
152
errx(1, "Must specify PPP label");
153
154
if (!server) {
155
if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)
156
errx(1, "Must specify server BD_ADDR");
157
158
/* Check channel, if was not set then obtain it via SDP */
159
if (channel == 0 && service != 0)
160
if (rfcomm_channel_lookup(NULL, &addr, service,
161
&channel, &s) != 0)
162
errc(1, s, "Could not obtain RFCOMM channel");
163
}
164
165
if (channel <= 0 || channel > 30)
166
errx(1, "Invalid RFCOMM channel number %d", channel);
167
168
openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER);
169
170
if (detach && daemon(0, 0) < 0) {
171
syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
172
strerror(errno), errno);
173
exit(1);
174
}
175
176
s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
177
if (s < 0) {
178
syslog(LOG_ERR, "Could not create socket. %s (%d)",
179
strerror(errno), errno);
180
exit(1);
181
}
182
183
if (server) {
184
struct sigaction sa;
185
void *ss = NULL;
186
sdp_lan_profile_t lan;
187
188
/* Install signal handler */
189
memset(&sa, 0, sizeof(sa));
190
sa.sa_handler = sighandler;
191
192
if (sigaction(SIGTERM, &sa, NULL) < 0) {
193
syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
194
strerror(errno), errno);
195
exit(1);
196
}
197
198
if (sigaction(SIGHUP, &sa, NULL) < 0) {
199
syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
200
strerror(errno), errno);
201
exit(1);
202
}
203
204
if (sigaction(SIGINT, &sa, NULL) < 0) {
205
syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
206
strerror(errno), errno);
207
exit(1);
208
}
209
210
sa.sa_handler = SIG_IGN;
211
sa.sa_flags = SA_NOCLDWAIT;
212
213
if (sigaction(SIGCHLD, &sa, NULL) < 0) {
214
syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)",
215
strerror(errno), errno);
216
exit(1);
217
}
218
219
/* bind socket and listen for incoming connections */
220
sock_addr.rfcomm_len = sizeof(sock_addr);
221
sock_addr.rfcomm_family = AF_BLUETOOTH;
222
memcpy(&sock_addr.rfcomm_bdaddr, &addr,
223
sizeof(sock_addr.rfcomm_bdaddr));
224
sock_addr.rfcomm_channel = channel;
225
226
if (bind(s, (struct sockaddr *) &sock_addr,
227
sizeof(sock_addr)) < 0) {
228
syslog(LOG_ERR, "Could not bind socket. %s (%d)",
229
strerror(errno), errno);
230
exit(1);
231
}
232
233
if (listen(s, 10) < 0) {
234
syslog(LOG_ERR, "Could not listen on socket. %s (%d)",
235
strerror(errno), errno);
236
exit(1);
237
}
238
239
ss = sdp_open_local(NULL);
240
if (ss == NULL) {
241
syslog(LOG_ERR, "Unable to create local SDP session");
242
exit(1);
243
}
244
245
if (sdp_error(ss) != 0) {
246
syslog(LOG_ERR, "Unable to open local SDP session. " \
247
"%s (%d)", strerror(sdp_error(ss)),
248
sdp_error(ss));
249
exit(1);
250
}
251
252
memset(&lan, 0, sizeof(lan));
253
lan.server_channel = channel;
254
255
if (sdp_register_service(ss,
256
SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
257
&addr, (void *) &lan, sizeof(lan), NULL) != 0) {
258
syslog(LOG_ERR, "Unable to register LAN service with " \
259
"local SDP daemon. %s (%d)",
260
strerror(sdp_error(ss)), sdp_error(ss));
261
exit(1);
262
}
263
264
/*
265
* Register DUN (Dial-Up Networking) service on the same
266
* RFCOMM channel if requested. There is really no good reason
267
* to not to support this. AT-command exchange can be faked
268
* with chat script in ppp.conf
269
*/
270
271
if (regdun) {
272
sdp_dun_profile_t dun;
273
274
memset(&dun, 0, sizeof(dun));
275
dun.server_channel = channel;
276
277
if (sdp_register_service(ss,
278
SDP_SERVICE_CLASS_DIALUP_NETWORKING,
279
&addr, (void *) &dun, sizeof(dun),
280
NULL) != 0) {
281
syslog(LOG_ERR, "Unable to register DUN " \
282
"service with local SDP daemon. " \
283
"%s (%d)", strerror(sdp_error(ss)),
284
sdp_error(ss));
285
exit(1);
286
}
287
}
288
289
/*
290
* Register SP (Serial Port) service on the same RFCOMM channel
291
* if requested. It appears that some cell phones are using so
292
* called "callback mechanism". In this scenario user is trying
293
* to connect his cell phone to the Internet, and, user's host
294
* computer is acting as the gateway server. It seems that it
295
* is not possible to tell the phone to just connect and start
296
* using the LAN service. Instead the user's host computer must
297
* "jump start" the phone by connecting to the phone's SP
298
* service. What happens next is the phone kills the existing
299
* connection and opens another connection back to the user's
300
* host computer. The phone really wants to use LAN service,
301
* but for whatever reason it looks for SP service on the
302
* user's host computer. This brain damaged behavior was
303
* reported for Nokia 6600 and Sony/Ericsson P900. Both phones
304
* are Symbian-based phones. Perhaps this is a Symbian problem?
305
*/
306
307
if (regsp) {
308
sdp_sp_profile_t sp;
309
310
memset(&sp, 0, sizeof(sp));
311
sp.server_channel = channel;
312
313
if (sdp_register_service(ss,
314
SDP_SERVICE_CLASS_SERIAL_PORT,
315
&addr, (void *) &sp, sizeof(sp),
316
NULL) != 0) {
317
syslog(LOG_ERR, "Unable to register SP " \
318
"service with local SDP daemon. " \
319
"%s (%d)", strerror(sdp_error(ss)),
320
sdp_error(ss));
321
exit(1);
322
}
323
}
324
325
for (done = 0; !done; ) {
326
socklen_t len = sizeof(sock_addr);
327
int s1 = accept(s, (struct sockaddr *) &sock_addr, &len);
328
329
if (s1 < 0) {
330
syslog(LOG_ERR, "Could not accept connection " \
331
"on socket. %s (%d)", strerror(errno),
332
errno);
333
exit(1);
334
}
335
336
pid = fork();
337
if (pid == (pid_t) -1) {
338
syslog(LOG_ERR, "Could not fork(). %s (%d)",
339
strerror(errno), errno);
340
exit(1);
341
}
342
343
if (pid == 0) {
344
sdp_close(ss);
345
close(s);
346
347
/* Reset signal handler */
348
memset(&sa, 0, sizeof(sa));
349
sa.sa_handler = SIG_DFL;
350
351
sigaction(SIGTERM, &sa, NULL);
352
sigaction(SIGHUP, &sa, NULL);
353
sigaction(SIGINT, &sa, NULL);
354
sigaction(SIGCHLD, &sa, NULL);
355
356
/* Become daemon */
357
daemon(0, 0);
358
359
/*
360
* XXX Make sure user does not shoot himself
361
* in the foot. Do not pass unit option to the
362
* PPP when operating in the server mode.
363
*/
364
365
exec_ppp(s1, NULL, label);
366
} else
367
close(s1);
368
}
369
} else {
370
sock_addr.rfcomm_len = sizeof(sock_addr);
371
sock_addr.rfcomm_family = AF_BLUETOOTH;
372
memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY,
373
sizeof(sock_addr.rfcomm_bdaddr));
374
sock_addr.rfcomm_channel = 0;
375
376
if (bind(s, (struct sockaddr *) &sock_addr,
377
sizeof(sock_addr)) < 0) {
378
syslog(LOG_ERR, "Could not bind socket. %s (%d)",
379
strerror(errno), errno);
380
exit(1);
381
}
382
383
memcpy(&sock_addr.rfcomm_bdaddr, &addr,
384
sizeof(sock_addr.rfcomm_bdaddr));
385
sock_addr.rfcomm_channel = channel;
386
387
if (connect(s, (struct sockaddr *) &sock_addr,
388
sizeof(sock_addr)) < 0) {
389
syslog(LOG_ERR, "Could not connect socket. %s (%d)",
390
strerror(errno), errno);
391
exit(1);
392
}
393
394
exec_ppp(s, unit, label);
395
}
396
397
exit(0);
398
} /* main */
399
400
/*
401
* Redirects stdin/stdout to s, stderr to /dev/null and exec
402
* 'ppp -direct -quiet [-unit N] label'. Never returns.
403
*/
404
405
static void
406
exec_ppp(int s, char *unit, char *label)
407
{
408
char ppp[] = "/usr/sbin/ppp";
409
char *ppp_args[] = { ppp, "-direct", "-quiet",
410
NULL, NULL, NULL, NULL };
411
412
close(0);
413
if (dup(s) < 0) {
414
syslog(LOG_ERR, "Could not dup(0). %s (%d)",
415
strerror(errno), errno);
416
exit(1);
417
}
418
419
close(1);
420
if (dup(s) < 0) {
421
syslog(LOG_ERR, "Could not dup(1). %s (%d)",
422
strerror(errno), errno);
423
exit(1);
424
}
425
426
close(2);
427
open("/dev/null", O_RDWR);
428
429
if (unit != NULL) {
430
ppp_args[3] = "-unit";
431
ppp_args[4] = unit;
432
ppp_args[5] = label;
433
} else
434
ppp_args[3] = label;
435
436
if (execv(ppp, ppp_args) < 0) {
437
syslog(LOG_ERR, "Could not exec(%s -direct -quiet%s%s %s). " \
438
"%s (%d)", ppp, (unit != NULL)? " -unit " : "",
439
(unit != NULL)? unit : "", label,
440
strerror(errno), errno);
441
exit(1);
442
}
443
} /* run_ppp */
444
445
/* Signal handler */
446
static void
447
sighandler(int s)
448
{
449
done = 1;
450
} /* sighandler */
451
452
/* Display usage and exit */
453
static void
454
usage(void)
455
{
456
fprintf(stdout,
457
"Usage: %s options\n" \
458
"Where options are:\n" \
459
"\t-a address Address to listen on or connect to (required for client)\n" \
460
"\t-c Act as a clinet (default)\n" \
461
"\t-C channel RFCOMM channel to listen on or connect to (required)\n" \
462
"\t-d Run in foreground\n" \
463
"\t-D Register Dial-Up Networking service (server mode only)\n" \
464
"\t-l label Use PPP label (required)\n" \
465
"\t-s Act as a server\n" \
466
"\t-S Register Serial Port service (server mode only)\n" \
467
"\t-u N Tell PPP to operate on /dev/tunN (client mode only)\n" \
468
"\t-h Display this message\n", RFCOMM_PPPD);
469
470
exit(255);
471
} /* usage */
472
473
474