Fix build break for rpm
[framework/connectivity/bluez.git] / compat / dund.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
6  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <syslog.h>
36 #include <signal.h>
37 #include <getopt.h>
38
39 #include <sys/socket.h>
40
41 #include <bluetooth/bluetooth.h>
42 #include <bluetooth/hci.h>
43 #include <bluetooth/hci_lib.h>
44 #include <bluetooth/rfcomm.h>
45 #include <bluetooth/hidp.h>
46
47 #include "sdp.h"
48 #include "dund.h"
49 #include "lib.h"
50
51 volatile sig_atomic_t __io_canceled;
52
53 /* MS dialup networking support (i.e. CLIENT / CLIENTSERVER thing) */
54 static int msdun = 0;
55
56 static char *pppd = "/usr/sbin/pppd";
57 static char *pppd_opts[DUN_MAX_PPP_OPTS] =
58         {
59                 /* First 3 are reserved */
60                 "", "", "",
61                 "noauth",
62                 "noipdefault",
63                 NULL
64         };
65
66 static int  detach = 1;
67 static int  persist;
68 static int  use_sdp = 1;
69 static int  auth;
70 static int  encrypt;
71 static int  secure;
72 static int  master;
73 static int  type = LANACCESS;
74 static int  search_duration = 10;
75 static uint use_cache;
76
77 static int  channel;
78
79 static struct {
80         uint     valid;
81         char     dst[40];
82         bdaddr_t bdaddr;
83         int      channel;
84 } cache;
85
86 static bdaddr_t src_addr = *BDADDR_ANY;
87 static int src_dev = -1;
88
89 volatile int terminate;
90
91 enum {
92         NONE,
93         SHOW,
94         LISTEN,
95         CONNECT,
96         KILL
97 } modes;
98
99 static int create_connection(char *dst, bdaddr_t *bdaddr, int mrouter);
100
101 static int do_listen(void)
102 {
103         struct sockaddr_rc sa;
104         int sk, lm;
105
106         if (type == MROUTER) {
107                 if (!cache.valid)
108                         return -1;
109
110                 if (create_connection(cache.dst, &cache.bdaddr, type) < 0) {
111                         syslog(LOG_ERR, "Cannot connect to mRouter device. %s(%d)",
112                                                                 strerror(errno), errno);
113                         return -1;
114                 }
115         }
116
117         if (!channel)
118                 channel = DUN_DEFAULT_CHANNEL;
119
120         if (use_sdp)
121                 dun_sdp_register(&src_addr, channel, type);
122
123         if (type == MROUTER)
124                 syslog(LOG_INFO, "Waiting for mRouter callback on channel %d", channel);
125
126         /* Create RFCOMM socket */
127         sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
128         if (sk < 0) {
129                 syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)",
130                                 strerror(errno), errno);
131                 return -1;
132         }
133
134         sa.rc_family  = AF_BLUETOOTH;
135         sa.rc_channel = channel;
136         sa.rc_bdaddr  = src_addr;
137
138         if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {
139                 syslog(LOG_ERR, "Bind failed. %s(%d)", strerror(errno), errno);
140                 return -1;
141         }
142
143         /* Set link mode */
144         lm = 0;
145         if (master)
146                 lm |= RFCOMM_LM_MASTER;
147         if (auth)
148                 lm |= RFCOMM_LM_AUTH;
149         if (encrypt)
150                 lm |= RFCOMM_LM_ENCRYPT;
151         if (secure)
152                 lm |= RFCOMM_LM_SECURE;
153
154         if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
155                 syslog(LOG_ERR, "Failed to set link mode. %s(%d)", strerror(errno), errno);
156                 return -1;
157         }
158
159         listen(sk, 10);
160
161         while (!terminate) {
162                 socklen_t alen = sizeof(sa);
163                 int nsk;
164                 char ba[40];
165                 char ch[10];
166
167                 nsk = accept(sk, (struct sockaddr *) &sa, &alen);
168                 if (nsk < 0) {
169                         syslog(LOG_ERR, "Accept failed. %s(%d)", strerror(errno), errno);
170                         continue;
171                 }
172
173                 switch (fork()) {
174                 case 0:
175                         break;
176                 case -1:
177                         syslog(LOG_ERR, "Fork failed. %s(%d)", strerror(errno), errno);
178                 default:
179                         close(nsk);
180                         if (type == MROUTER) {
181                                 close(sk);
182                                 terminate = 1;
183                         }
184                         continue;
185                 }
186
187                 close(sk);
188
189                 if (msdun && ms_dun(nsk, 1, msdun) < 0) {
190                         syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno);
191                         exit(0);
192                 }
193
194                 ba2str(&sa.rc_bdaddr, ba);
195                 snprintf(ch, sizeof(ch), "%d", channel);
196
197                 /* Setup environment */
198                 setenv("DUN_BDADDR",  ba, 1);
199                 setenv("DUN_CHANNEL", ch, 1);
200
201                 if (!dun_open_connection(nsk, pppd, pppd_opts, 0))
202                         syslog(LOG_INFO, "New connection from %s", ba);
203
204                 close(nsk);
205                 exit(0);
206         }
207
208         if (use_sdp)
209                 dun_sdp_unregister();
210         return 0;
211 }
212
213 /* Connect and initiate RFCOMM session
214  * Returns:
215  *   -1 - critical error (exit persist mode)
216  *   1  - non critical error
217  *   0  - success
218  */
219 static int create_connection(char *dst, bdaddr_t *bdaddr, int mrouter)
220 {
221         struct sockaddr_rc sa;
222         int sk, err = 0, ch;
223
224         if (use_cache && cache.valid && cache.channel) {
225                 /* Use cached channel */
226                 ch = cache.channel;
227
228         } else if (!channel) {
229                 syslog(LOG_INFO, "Searching for %s on %s", mrouter ? "SP" : "LAP", dst);
230
231                 if (dun_sdp_search(&src_addr, bdaddr, &ch, mrouter) <= 0)
232                         return 0;
233         } else
234                 ch = channel;
235
236         syslog(LOG_INFO, "Connecting to %s channel %d", dst, ch);
237
238         sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
239         if (sk < 0) {
240                 syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)",
241                      strerror(errno), errno);
242                 return -1;
243         }
244
245         sa.rc_family  = AF_BLUETOOTH;
246         sa.rc_channel = 0;
247         sa.rc_bdaddr  = src_addr;
248
249         if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)))
250                 syslog(LOG_ERR, "Bind failed. %s(%d)",
251                         strerror(errno), errno);
252
253         sa.rc_channel = ch;
254         sa.rc_bdaddr  = *bdaddr;
255
256         if (!connect(sk, (struct sockaddr *) &sa, sizeof(sa)) ) {
257                 if (mrouter) {
258                         sleep(1);
259                         close(sk);
260                         return 0;
261                 }
262
263                 syslog(LOG_INFO, "Connection established");
264
265                 if (msdun && ms_dun(sk, 0, msdun) < 0) {
266                         syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno);
267                         err = 1;
268                         goto out;
269                 }
270
271                 if (!dun_open_connection(sk, pppd, pppd_opts, (persist > 0)))
272                         err = 0;
273                 else
274                         err = 1;
275         } else {
276                 syslog(LOG_ERR, "Connect to %s failed. %s(%d)",
277                                 dst, strerror(errno), errno);
278                 err = 1;
279         }
280
281 out:
282         if (use_cache) {
283                 if (!err) {
284                         /* Succesesful connection, validate cache */
285                         strcpy(cache.dst, dst);
286                         bacpy(&cache.bdaddr, bdaddr);
287                         cache.channel = ch;
288                         cache.valid   = use_cache;
289                 } else {
290                         cache.channel = 0;
291                         cache.valid--;
292                 }
293         }
294
295         close(sk);
296         return err;
297 }
298
299 /* Search and connect
300  * Returns:
301  *   -1 - critical error (exit persist mode)
302  *   1  - non critical error
303  *   0  - success
304  */
305 static int do_connect(void)
306 {
307         inquiry_info *ii;
308         int reconnect = 0;
309         int i, n, r = 0;
310
311         do {
312                 if (reconnect)
313                         sleep(persist);
314                 reconnect = 1;
315
316                 if (cache.valid) {
317                         /* Use cached bdaddr */
318                         r = create_connection(cache.dst, &cache.bdaddr, 0);
319                         if (r < 0) {
320                                 terminate = 1;
321                                 break;
322                         }
323                         continue;
324                 }
325
326                 syslog(LOG_INFO, "Inquiring");
327
328                 /* FIXME: Should we use non general LAP here ? */
329
330                 ii = NULL;
331                 n  = hci_inquiry(src_dev, search_duration, 0, NULL, &ii, 0);
332                 if (n < 0) {
333                         syslog(LOG_ERR, "Inquiry failed. %s(%d)", strerror(errno), errno);
334                         continue;
335                 }
336
337                 for (i = 0; i < n; i++) {
338                         char dst[40];
339                         ba2str(&ii[i].bdaddr, dst);
340
341                         r = create_connection(dst, &ii[i].bdaddr, 0);
342                         if (r < 0) {
343                                 terminate = 1;
344                                 break;
345                         }
346                 }
347                 bt_free(ii);
348         } while (!terminate && persist);
349
350         return r;
351 }
352
353 static void do_show(void)
354 {
355         dun_show_connections();
356 }
357
358 static void do_kill(char *dst)
359 {
360         if (dst) {
361                 bdaddr_t ba;
362                 str2ba(dst, &ba);
363                 dun_kill_connection((void *) &ba);
364         } else
365                 dun_kill_all_connections();
366 }
367
368 static void sig_hup(int sig)
369 {
370         return;
371 }
372
373 static void sig_term(int sig)
374 {
375         io_cancel();
376         terminate = 1;
377 }
378
379 static struct option main_lopts[] = {
380         { "help",       0, 0, 'h' },
381         { "listen",     0, 0, 's' },
382         { "connect",    1, 0, 'c' },
383         { "search",     2, 0, 'Q' },
384         { "kill",       1, 0, 'k' },
385         { "killall",    0, 0, 'K' },
386         { "channel",    1, 0, 'P' },
387         { "device",     1, 0, 'i' },
388         { "nosdp",      0, 0, 'D' },
389         { "list",       0, 0, 'l' },
390         { "show",       0, 0, 'l' },
391         { "nodetach",   0, 0, 'n' },
392         { "persist",    2, 0, 'p' },
393         { "auth",       0, 0, 'A' },
394         { "encrypt",    0, 0, 'E' },
395         { "secure",     0, 0, 'S' },
396         { "master",     0, 0, 'M' },
397         { "cache",      0, 0, 'C' },
398         { "pppd",       1, 0, 'd' },
399         { "msdun",      2, 0, 'X' },
400         { "activesync", 0, 0, 'a' },
401         { "mrouter",    1, 0, 'm' },
402         { "dialup",     0, 0, 'u' },
403         { 0, 0, 0, 0 }
404 };
405
406 static const char *main_sopts = "hsc:k:Kr:i:lnp::DQ::AESMP:C::P:Xam:u";
407
408 static const char *main_help =
409         "Bluetooth LAP (LAN Access over PPP) daemon version %s\n"
410         "Usage:\n"
411         "\tdund <options> [pppd options]\n"
412         "Options:\n"
413         "\t--show --list -l          Show active LAP connections\n"
414         "\t--listen -s               Listen for LAP connections\n"
415         "\t--dialup -u               Pretend to be a dialup/telephone\n"
416         "\t--connect -c <bdaddr>     Create LAP connection\n"
417         "\t--mrouter -m <bdaddr>     Create mRouter connection\n"
418         "\t--search -Q[duration]     Search and connect\n"
419         "\t--kill -k <bdaddr>        Kill LAP connection\n"
420         "\t--killall -K              Kill all LAP connections\n"
421         "\t--channel -P <channel>    RFCOMM channel\n"
422         "\t--device -i <bdaddr>      Source bdaddr\n"
423         "\t--nosdp -D                Disable SDP\n"
424         "\t--auth -A                 Enable authentication\n"
425         "\t--encrypt -E              Enable encryption\n"
426         "\t--secure -S               Secure connection\n"
427         "\t--master -M               Become the master of a piconet\n"
428         "\t--nodetach -n             Do not become a daemon\n"
429         "\t--persist -p[interval]    Persist mode\n"
430         "\t--pppd -d <pppd>          Location of the PPP daemon (pppd)\n"
431         "\t--msdun -X[timeo]         Enable Microsoft dialup networking support\n"
432         "\t--activesync -a           Enable Microsoft ActiveSync networking\n"
433         "\t--cache -C[valid]         Enable address cache\n";
434
435 int main(int argc, char *argv[])
436 {
437         char *dst = NULL, *src = NULL;
438         struct sigaction sa;
439         int mode = NONE;
440         int opt;
441
442         while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) {
443                 switch(opt) {
444                 case 'l':
445                         mode = SHOW;
446                         detach = 0;
447                         break;
448
449                 case 's':
450                         mode = LISTEN;
451                         type = LANACCESS;
452                         break;
453
454                 case 'c':
455                         mode = CONNECT;
456                         dst  = strdup(optarg);
457                         break;
458
459                 case 'Q':
460                         mode = CONNECT;
461                         dst  = NULL;
462                         if (optarg)
463                                 search_duration = atoi(optarg);
464                         break;
465
466                 case 'k':
467                         mode = KILL;
468                         detach = 0;
469                         dst  = strdup(optarg);
470                         break;
471
472                 case 'K':
473                         mode = KILL;
474                         detach = 0;
475                         dst  = NULL;
476                         break;
477
478                 case 'P':
479                         channel = atoi(optarg);
480                         break;
481
482                 case 'i':
483                         src = strdup(optarg);
484                         break;
485
486                 case 'D':
487                         use_sdp = 0;
488                         break;
489
490                 case 'A':
491                         auth = 1;
492                         break;
493
494                 case 'E':
495                         encrypt = 1;
496                         break;
497
498                 case 'S':
499                         secure = 1;
500                         break;
501
502                 case 'M':
503                         master = 1;
504                         break;
505
506                 case 'n':
507                         detach = 0;
508                         break;
509
510                 case 'p':
511                         if (optarg)
512                                 persist = atoi(optarg);
513                         else
514                                 persist = 5;
515                         break;
516
517                 case 'C':
518                         if (optarg)
519                                 use_cache = atoi(optarg);
520                         else
521                                 use_cache = 2;
522                         break;
523
524                 case 'd':
525                         pppd  = strdup(optarg);
526                         break;
527
528                 case 'X':
529                         if (optarg)
530                                 msdun = atoi(optarg);
531                         else
532                                 msdun = 10;
533                         break;
534
535                 case 'a':
536                         msdun = 10;
537                         type = ACTIVESYNC;
538                         break;
539
540                 case 'm':
541                         mode = LISTEN;
542                         dst  = strdup(optarg);
543                         type = MROUTER;
544                         break;
545
546                 case 'u':
547                         mode = LISTEN;
548                         type = DIALUP;
549                         break;
550
551                 case 'h':
552                 default:
553                         printf(main_help, VERSION);
554                         exit(0);
555                 }
556         }
557
558         argc -= optind;
559         argv += optind;
560
561         /* The rest is pppd options */
562         if (argc > 0) {
563                 for (opt = 3; argc && opt < DUN_MAX_PPP_OPTS - 1;
564                                                         argc--, opt++)
565                         pppd_opts[opt] = *argv++;
566                 pppd_opts[opt] = NULL;
567         }
568
569         io_init();
570
571         if (dun_init()) {
572                 free(dst);
573                 return -1;
574         }
575
576         /* Check non daemon modes first */
577         switch (mode) {
578         case SHOW:
579                 do_show();
580                 free(dst);
581                 return 0;
582
583         case KILL:
584                 do_kill(dst);
585                 free(dst);
586                 return 0;
587
588         case NONE:
589                 printf(main_help, VERSION);
590                 free(dst);
591                 return 0;
592         }
593
594         /* Initialize signals */
595         memset(&sa, 0, sizeof(sa));
596         sa.sa_flags   = SA_NOCLDSTOP;
597         sa.sa_handler = SIG_IGN;
598         sigaction(SIGCHLD, &sa, NULL);
599         sigaction(SIGPIPE, &sa, NULL);
600
601         sa.sa_handler = sig_term;
602         sigaction(SIGTERM, &sa, NULL);
603         sigaction(SIGINT,  &sa, NULL);
604
605         sa.sa_handler = sig_hup;
606         sigaction(SIGHUP, &sa, NULL);
607
608         if (detach && daemon(0, 0)) {
609                 perror("Can't start daemon");
610                 exit(1);
611         }
612
613         openlog("dund", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
614         syslog(LOG_INFO, "Bluetooth DUN daemon version %s", VERSION);
615
616         if (src) {
617                 src_dev = hci_devid(src);
618                 if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) {
619                         syslog(LOG_ERR, "Invalid source. %s(%d)", strerror(errno), errno);
620                         free(dst);
621                         return -1;
622                 }
623         }
624
625         if (dst) {
626                 strncpy(cache.dst, dst, sizeof(cache.dst) - 1);
627                 str2ba(dst, &cache.bdaddr);
628
629                 /* Disable cache invalidation */
630                 use_cache = cache.valid = ~0;
631         }
632
633         switch (mode) {
634         case CONNECT:
635                 do_connect();
636                 break;
637
638         case LISTEN:
639                 do_listen();
640                 break;
641         }
642
643         free(dst);
644         return 0;
645 }