11a63eb31SJulian Elischer /*
21a63eb31SJulian Elischer * rfcomm_pppd.c
3a09e0965SMaksim Yevmenkin */
4a09e0965SMaksim Yevmenkin
5a09e0965SMaksim Yevmenkin /*-
6*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
71de7b4b8SPedro F. Giffuni *
8a09e0965SMaksim Yevmenkin * Copyright (c) 2001-2008 Maksim Yevmenkin <m_evmenkin@yahoo.com>
91a63eb31SJulian Elischer * All rights reserved.
101a63eb31SJulian Elischer *
111a63eb31SJulian Elischer * Redistribution and use in source and binary forms, with or without
121a63eb31SJulian Elischer * modification, are permitted provided that the following conditions
131a63eb31SJulian Elischer * are met:
141a63eb31SJulian Elischer * 1. Redistributions of source code must retain the above copyright
151a63eb31SJulian Elischer * notice, this list of conditions and the following disclaimer.
161a63eb31SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright
171a63eb31SJulian Elischer * notice, this list of conditions and the following disclaimer in the
181a63eb31SJulian Elischer * documentation and/or other materials provided with the distribution.
191a63eb31SJulian Elischer *
201a63eb31SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
211a63eb31SJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221a63eb31SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231a63eb31SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
241a63eb31SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251a63eb31SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261a63eb31SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271a63eb31SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281a63eb31SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291a63eb31SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301a63eb31SJulian Elischer * SUCH DAMAGE.
311a63eb31SJulian Elischer *
320986ab12SMaksim Yevmenkin * $Id: rfcomm_pppd.c,v 1.5 2003/09/07 18:32:11 max Exp $
331a63eb31SJulian Elischer */
348d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
350986ab12SMaksim Yevmenkin #include <bluetooth.h>
360986ab12SMaksim Yevmenkin #include <ctype.h>
370986ab12SMaksim Yevmenkin #include <err.h>
381a63eb31SJulian Elischer #include <errno.h>
391a63eb31SJulian Elischer #include <fcntl.h>
400986ab12SMaksim Yevmenkin #include <sdp.h>
411a63eb31SJulian Elischer #include <signal.h>
421a63eb31SJulian Elischer #include <stdarg.h>
431a63eb31SJulian Elischer #include <stdio.h>
441a63eb31SJulian Elischer #include <stdlib.h>
451a63eb31SJulian Elischer #include <string.h>
461a63eb31SJulian Elischer #include <syslog.h>
471a63eb31SJulian Elischer #include <unistd.h>
481a63eb31SJulian Elischer
491a63eb31SJulian Elischer #define RFCOMM_PPPD "rfcomm_pppd"
501a63eb31SJulian Elischer
510986ab12SMaksim Yevmenkin int rfcomm_channel_lookup (bdaddr_t const *local,
520986ab12SMaksim Yevmenkin bdaddr_t const *remote,
530986ab12SMaksim Yevmenkin int service, int *channel, int *error);
540986ab12SMaksim Yevmenkin
5513706e45SMaksim Yevmenkin static void exec_ppp (int s, char *unit, char *label);
561a63eb31SJulian Elischer static void sighandler (int s);
571a63eb31SJulian Elischer static void usage (void);
581a63eb31SJulian Elischer
591a63eb31SJulian Elischer static int done;
601a63eb31SJulian Elischer
611a63eb31SJulian Elischer /* Main */
621a63eb31SJulian Elischer int
main(int argc,char * argv[])631a63eb31SJulian Elischer main(int argc, char *argv[])
641a63eb31SJulian Elischer {
651a63eb31SJulian Elischer struct sockaddr_rfcomm sock_addr;
6613706e45SMaksim Yevmenkin char *label = NULL, *unit = NULL, *ep = NULL;
671a63eb31SJulian Elischer bdaddr_t addr;
68b1fae135SMaksim Yevmenkin int s, channel, detach, server, service,
69b1fae135SMaksim Yevmenkin regdun, regsp;
701a63eb31SJulian Elischer pid_t pid;
711a63eb31SJulian Elischer
721a63eb31SJulian Elischer memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));
731a63eb31SJulian Elischer channel = 0;
741a63eb31SJulian Elischer detach = 1;
751a63eb31SJulian Elischer server = 0;
760986ab12SMaksim Yevmenkin service = 0;
77b1fae135SMaksim Yevmenkin regdun = 0;
781985a3a3SMaksim Yevmenkin regsp = 0;
791a63eb31SJulian Elischer
801a63eb31SJulian Elischer /* Parse command line arguments */
81b1fae135SMaksim Yevmenkin while ((s = getopt(argc, argv, "a:cC:dDhl:sSu:")) != -1) {
821a63eb31SJulian Elischer switch (s) {
830986ab12SMaksim Yevmenkin case 'a': /* BDADDR */
840986ab12SMaksim Yevmenkin if (!bt_aton(optarg, &addr)) {
850986ab12SMaksim Yevmenkin struct hostent *he = NULL;
861a63eb31SJulian Elischer
870986ab12SMaksim Yevmenkin if ((he = bt_gethostbyname(optarg)) == NULL)
880986ab12SMaksim Yevmenkin errx(1, "%s: %s", optarg, hstrerror(h_errno));
891a63eb31SJulian Elischer
900986ab12SMaksim Yevmenkin memcpy(&addr, he->h_addr, sizeof(addr));
910986ab12SMaksim Yevmenkin }
920986ab12SMaksim Yevmenkin break;
931a63eb31SJulian Elischer
941a63eb31SJulian Elischer case 'c': /* client */
951a63eb31SJulian Elischer server = 0;
961a63eb31SJulian Elischer break;
971a63eb31SJulian Elischer
981a63eb31SJulian Elischer case 'C': /* RFCOMM channel */
990986ab12SMaksim Yevmenkin channel = strtoul(optarg, &ep, 10);
10013706e45SMaksim Yevmenkin if (*ep != '\0') {
1010986ab12SMaksim Yevmenkin channel = 0;
1020986ab12SMaksim Yevmenkin switch (tolower(optarg[0])) {
1030986ab12SMaksim Yevmenkin case 'd': /* DialUp Networking */
1040986ab12SMaksim Yevmenkin service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
1050986ab12SMaksim Yevmenkin break;
1060986ab12SMaksim Yevmenkin
1070986ab12SMaksim Yevmenkin case 'l': /* LAN Access Using PPP */
1080986ab12SMaksim Yevmenkin service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
1090986ab12SMaksim Yevmenkin break;
1100986ab12SMaksim Yevmenkin }
1110986ab12SMaksim Yevmenkin }
1121a63eb31SJulian Elischer break;
1131a63eb31SJulian Elischer
1141a63eb31SJulian Elischer case 'd': /* do not detach */
1151a63eb31SJulian Elischer detach = 0;
1161a63eb31SJulian Elischer break;
1171a63eb31SJulian Elischer
118b1fae135SMaksim Yevmenkin case 'D': /* Register DUN service as well as LAN service */
119b1fae135SMaksim Yevmenkin regdun = 1;
120b1fae135SMaksim Yevmenkin break;
121b1fae135SMaksim Yevmenkin
1221a63eb31SJulian Elischer case 'l': /* PPP label */
1231a63eb31SJulian Elischer label = optarg;
1241a63eb31SJulian Elischer break;
1251a63eb31SJulian Elischer
12613706e45SMaksim Yevmenkin case 's': /* server */
1271a63eb31SJulian Elischer server = 1;
1281a63eb31SJulian Elischer break;
1291a63eb31SJulian Elischer
1301985a3a3SMaksim Yevmenkin case 'S': /* Register SP service as well as LAN service */
1311985a3a3SMaksim Yevmenkin regsp = 1;
1321985a3a3SMaksim Yevmenkin break;
1331985a3a3SMaksim Yevmenkin
13413706e45SMaksim Yevmenkin case 'u': /* PPP -unit option */
13513706e45SMaksim Yevmenkin strtoul(optarg, &ep, 10);
13613706e45SMaksim Yevmenkin if (*ep != '\0')
13713706e45SMaksim Yevmenkin usage();
13813706e45SMaksim Yevmenkin /* NOT REACHED */
13913706e45SMaksim Yevmenkin
14013706e45SMaksim Yevmenkin unit = optarg;
14113706e45SMaksim Yevmenkin break;
14213706e45SMaksim Yevmenkin
1431a63eb31SJulian Elischer case 'h':
1441a63eb31SJulian Elischer default:
1451a63eb31SJulian Elischer usage();
1461a63eb31SJulian Elischer /* NOT REACHED */
1471a63eb31SJulian Elischer }
1481a63eb31SJulian Elischer }
1491a63eb31SJulian Elischer
1501a63eb31SJulian Elischer /* Check if we got everything we wanted */
1510986ab12SMaksim Yevmenkin if (label == NULL)
1520986ab12SMaksim Yevmenkin errx(1, "Must specify PPP label");
1530986ab12SMaksim Yevmenkin
1540986ab12SMaksim Yevmenkin if (!server) {
1550986ab12SMaksim Yevmenkin if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)
1560986ab12SMaksim Yevmenkin errx(1, "Must specify server BD_ADDR");
1570986ab12SMaksim Yevmenkin
1580986ab12SMaksim Yevmenkin /* Check channel, if was not set then obtain it via SDP */
1590986ab12SMaksim Yevmenkin if (channel == 0 && service != 0)
1600986ab12SMaksim Yevmenkin if (rfcomm_channel_lookup(NULL, &addr, service,
1610986ab12SMaksim Yevmenkin &channel, &s) != 0)
1620986ab12SMaksim Yevmenkin errc(1, s, "Could not obtain RFCOMM channel");
1630986ab12SMaksim Yevmenkin }
1640986ab12SMaksim Yevmenkin
1650986ab12SMaksim Yevmenkin if (channel <= 0 || channel > 30)
1660986ab12SMaksim Yevmenkin errx(1, "Invalid RFCOMM channel number %d", channel);
1671a63eb31SJulian Elischer
1681a63eb31SJulian Elischer openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER);
1691a63eb31SJulian Elischer
170d37245a0SMaksim Yevmenkin if (detach && daemon(0, 0) < 0) {
1711a63eb31SJulian Elischer syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
1721a63eb31SJulian Elischer strerror(errno), errno);
1731a63eb31SJulian Elischer exit(1);
1741a63eb31SJulian Elischer }
1751a63eb31SJulian Elischer
1761a63eb31SJulian Elischer s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
1771a63eb31SJulian Elischer if (s < 0) {
1781a63eb31SJulian Elischer syslog(LOG_ERR, "Could not create socket. %s (%d)",
1791a63eb31SJulian Elischer strerror(errno), errno);
1801a63eb31SJulian Elischer exit(1);
1811a63eb31SJulian Elischer }
1821a63eb31SJulian Elischer
1831a63eb31SJulian Elischer if (server) {
1841a63eb31SJulian Elischer struct sigaction sa;
18513706e45SMaksim Yevmenkin void *ss = NULL;
18613706e45SMaksim Yevmenkin sdp_lan_profile_t lan;
1871a63eb31SJulian Elischer
1881a63eb31SJulian Elischer /* Install signal handler */
1891a63eb31SJulian Elischer memset(&sa, 0, sizeof(sa));
1901a63eb31SJulian Elischer sa.sa_handler = sighandler;
1911a63eb31SJulian Elischer
1921a63eb31SJulian Elischer if (sigaction(SIGTERM, &sa, NULL) < 0) {
1931a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
1941a63eb31SJulian Elischer strerror(errno), errno);
1951a63eb31SJulian Elischer exit(1);
1961a63eb31SJulian Elischer }
1971a63eb31SJulian Elischer
1981a63eb31SJulian Elischer if (sigaction(SIGHUP, &sa, NULL) < 0) {
1991a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
2001a63eb31SJulian Elischer strerror(errno), errno);
2011a63eb31SJulian Elischer exit(1);
2021a63eb31SJulian Elischer }
2031a63eb31SJulian Elischer
2041a63eb31SJulian Elischer if (sigaction(SIGINT, &sa, NULL) < 0) {
2051a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
2061a63eb31SJulian Elischer strerror(errno), errno);
2071a63eb31SJulian Elischer exit(1);
2081a63eb31SJulian Elischer }
2091a63eb31SJulian Elischer
2101a63eb31SJulian Elischer sa.sa_handler = SIG_IGN;
2111a63eb31SJulian Elischer sa.sa_flags = SA_NOCLDWAIT;
2121a63eb31SJulian Elischer
2131a63eb31SJulian Elischer if (sigaction(SIGCHLD, &sa, NULL) < 0) {
2141a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)",
2151a63eb31SJulian Elischer strerror(errno), errno);
2161a63eb31SJulian Elischer exit(1);
2171a63eb31SJulian Elischer }
2181a63eb31SJulian Elischer
2191a63eb31SJulian Elischer /* bind socket and listen for incoming connections */
2201a63eb31SJulian Elischer sock_addr.rfcomm_len = sizeof(sock_addr);
2211a63eb31SJulian Elischer sock_addr.rfcomm_family = AF_BLUETOOTH;
2221a63eb31SJulian Elischer memcpy(&sock_addr.rfcomm_bdaddr, &addr,
2231a63eb31SJulian Elischer sizeof(sock_addr.rfcomm_bdaddr));
2241a63eb31SJulian Elischer sock_addr.rfcomm_channel = channel;
2251a63eb31SJulian Elischer
2261a63eb31SJulian Elischer if (bind(s, (struct sockaddr *) &sock_addr,
2271a63eb31SJulian Elischer sizeof(sock_addr)) < 0) {
2281a63eb31SJulian Elischer syslog(LOG_ERR, "Could not bind socket. %s (%d)",
2291a63eb31SJulian Elischer strerror(errno), errno);
2301a63eb31SJulian Elischer exit(1);
2311a63eb31SJulian Elischer }
2321a63eb31SJulian Elischer
2331a63eb31SJulian Elischer if (listen(s, 10) < 0) {
2341a63eb31SJulian Elischer syslog(LOG_ERR, "Could not listen on socket. %s (%d)",
2351a63eb31SJulian Elischer strerror(errno), errno);
2361a63eb31SJulian Elischer exit(1);
2371a63eb31SJulian Elischer }
2381a63eb31SJulian Elischer
23913706e45SMaksim Yevmenkin ss = sdp_open_local(NULL);
24013706e45SMaksim Yevmenkin if (ss == NULL) {
24113706e45SMaksim Yevmenkin syslog(LOG_ERR, "Unable to create local SDP session");
24213706e45SMaksim Yevmenkin exit(1);
24313706e45SMaksim Yevmenkin }
24413706e45SMaksim Yevmenkin
24513706e45SMaksim Yevmenkin if (sdp_error(ss) != 0) {
24613706e45SMaksim Yevmenkin syslog(LOG_ERR, "Unable to open local SDP session. " \
24713706e45SMaksim Yevmenkin "%s (%d)", strerror(sdp_error(ss)),
24813706e45SMaksim Yevmenkin sdp_error(ss));
24913706e45SMaksim Yevmenkin exit(1);
25013706e45SMaksim Yevmenkin }
25113706e45SMaksim Yevmenkin
25213706e45SMaksim Yevmenkin memset(&lan, 0, sizeof(lan));
25313706e45SMaksim Yevmenkin lan.server_channel = channel;
25413706e45SMaksim Yevmenkin
25513706e45SMaksim Yevmenkin if (sdp_register_service(ss,
25613706e45SMaksim Yevmenkin SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
25713706e45SMaksim Yevmenkin &addr, (void *) &lan, sizeof(lan), NULL) != 0) {
25813706e45SMaksim Yevmenkin syslog(LOG_ERR, "Unable to register LAN service with " \
25913706e45SMaksim Yevmenkin "local SDP daemon. %s (%d)",
26013706e45SMaksim Yevmenkin strerror(sdp_error(ss)), sdp_error(ss));
26113706e45SMaksim Yevmenkin exit(1);
26213706e45SMaksim Yevmenkin }
26313706e45SMaksim Yevmenkin
2641985a3a3SMaksim Yevmenkin /*
265b1fae135SMaksim Yevmenkin * Register DUN (Dial-Up Networking) service on the same
266b1fae135SMaksim Yevmenkin * RFCOMM channel if requested. There is really no good reason
267b1fae135SMaksim Yevmenkin * to not to support this. AT-command exchange can be faked
268b1fae135SMaksim Yevmenkin * with chat script in ppp.conf
269b1fae135SMaksim Yevmenkin */
270b1fae135SMaksim Yevmenkin
271b1fae135SMaksim Yevmenkin if (regdun) {
272b1fae135SMaksim Yevmenkin sdp_dun_profile_t dun;
273b1fae135SMaksim Yevmenkin
274b1fae135SMaksim Yevmenkin memset(&dun, 0, sizeof(dun));
275b1fae135SMaksim Yevmenkin dun.server_channel = channel;
276b1fae135SMaksim Yevmenkin
277b1fae135SMaksim Yevmenkin if (sdp_register_service(ss,
278b1fae135SMaksim Yevmenkin SDP_SERVICE_CLASS_DIALUP_NETWORKING,
279b1fae135SMaksim Yevmenkin &addr, (void *) &dun, sizeof(dun),
280b1fae135SMaksim Yevmenkin NULL) != 0) {
281b1fae135SMaksim Yevmenkin syslog(LOG_ERR, "Unable to register DUN " \
282b1fae135SMaksim Yevmenkin "service with local SDP daemon. " \
283b1fae135SMaksim Yevmenkin "%s (%d)", strerror(sdp_error(ss)),
284b1fae135SMaksim Yevmenkin sdp_error(ss));
285b1fae135SMaksim Yevmenkin exit(1);
286b1fae135SMaksim Yevmenkin }
287b1fae135SMaksim Yevmenkin }
288b1fae135SMaksim Yevmenkin
289b1fae135SMaksim Yevmenkin /*
2901985a3a3SMaksim Yevmenkin * Register SP (Serial Port) service on the same RFCOMM channel
2911985a3a3SMaksim Yevmenkin * if requested. It appears that some cell phones are using so
2921985a3a3SMaksim Yevmenkin * called "callback mechanism". In this scenario user is trying
2931985a3a3SMaksim Yevmenkin * to connect his cell phone to the Internet, and, user's host
2941985a3a3SMaksim Yevmenkin * computer is acting as the gateway server. It seems that it
2951985a3a3SMaksim Yevmenkin * is not possible to tell the phone to just connect and start
2961985a3a3SMaksim Yevmenkin * using the LAN service. Instead the user's host computer must
2971985a3a3SMaksim Yevmenkin * "jump start" the phone by connecting to the phone's SP
2981985a3a3SMaksim Yevmenkin * service. What happens next is the phone kills the existing
2991985a3a3SMaksim Yevmenkin * connection and opens another connection back to the user's
3001985a3a3SMaksim Yevmenkin * host computer. The phone really wants to use LAN service,
3011985a3a3SMaksim Yevmenkin * but for whatever reason it looks for SP service on the
3021985a3a3SMaksim Yevmenkin * user's host computer. This brain damaged behavior was
3031985a3a3SMaksim Yevmenkin * reported for Nokia 6600 and Sony/Ericsson P900. Both phones
3041985a3a3SMaksim Yevmenkin * are Symbian-based phones. Perhaps this is a Symbian problem?
3051985a3a3SMaksim Yevmenkin */
3061985a3a3SMaksim Yevmenkin
3071985a3a3SMaksim Yevmenkin if (regsp) {
3081985a3a3SMaksim Yevmenkin sdp_sp_profile_t sp;
3091985a3a3SMaksim Yevmenkin
3101985a3a3SMaksim Yevmenkin memset(&sp, 0, sizeof(sp));
3111985a3a3SMaksim Yevmenkin sp.server_channel = channel;
3121985a3a3SMaksim Yevmenkin
3131985a3a3SMaksim Yevmenkin if (sdp_register_service(ss,
3141985a3a3SMaksim Yevmenkin SDP_SERVICE_CLASS_SERIAL_PORT,
3151985a3a3SMaksim Yevmenkin &addr, (void *) &sp, sizeof(sp),
3161985a3a3SMaksim Yevmenkin NULL) != 0) {
3171985a3a3SMaksim Yevmenkin syslog(LOG_ERR, "Unable to register SP " \
3181985a3a3SMaksim Yevmenkin "service with local SDP daemon. " \
3191985a3a3SMaksim Yevmenkin "%s (%d)", strerror(sdp_error(ss)),
3201985a3a3SMaksim Yevmenkin sdp_error(ss));
3211985a3a3SMaksim Yevmenkin exit(1);
3221985a3a3SMaksim Yevmenkin }
3231985a3a3SMaksim Yevmenkin }
3241985a3a3SMaksim Yevmenkin
3251a63eb31SJulian Elischer for (done = 0; !done; ) {
326831a4264SMaksim Yevmenkin socklen_t len = sizeof(sock_addr);
3271a63eb31SJulian Elischer int s1 = accept(s, (struct sockaddr *) &sock_addr, &len);
3281a63eb31SJulian Elischer
3291a63eb31SJulian Elischer if (s1 < 0) {
3301a63eb31SJulian Elischer syslog(LOG_ERR, "Could not accept connection " \
3311a63eb31SJulian Elischer "on socket. %s (%d)", strerror(errno),
3321a63eb31SJulian Elischer errno);
3331a63eb31SJulian Elischer exit(1);
3341a63eb31SJulian Elischer }
3351a63eb31SJulian Elischer
3361a63eb31SJulian Elischer pid = fork();
3371a63eb31SJulian Elischer if (pid == (pid_t) -1) {
3381a63eb31SJulian Elischer syslog(LOG_ERR, "Could not fork(). %s (%d)",
3391a63eb31SJulian Elischer strerror(errno), errno);
3401a63eb31SJulian Elischer exit(1);
3411a63eb31SJulian Elischer }
3421a63eb31SJulian Elischer
3431a63eb31SJulian Elischer if (pid == 0) {
34413706e45SMaksim Yevmenkin sdp_close(ss);
3451a63eb31SJulian Elischer close(s);
3461a63eb31SJulian Elischer
3471a63eb31SJulian Elischer /* Reset signal handler */
3481a63eb31SJulian Elischer memset(&sa, 0, sizeof(sa));
3491a63eb31SJulian Elischer sa.sa_handler = SIG_DFL;
3501a63eb31SJulian Elischer
3511a63eb31SJulian Elischer sigaction(SIGTERM, &sa, NULL);
3521a63eb31SJulian Elischer sigaction(SIGHUP, &sa, NULL);
3531a63eb31SJulian Elischer sigaction(SIGINT, &sa, NULL);
3541a63eb31SJulian Elischer sigaction(SIGCHLD, &sa, NULL);
3551a63eb31SJulian Elischer
3561a63eb31SJulian Elischer /* Become daemon */
3571a63eb31SJulian Elischer daemon(0, 0);
3581a63eb31SJulian Elischer
35913706e45SMaksim Yevmenkin /*
36013706e45SMaksim Yevmenkin * XXX Make sure user does not shoot himself
36113706e45SMaksim Yevmenkin * in the foot. Do not pass unit option to the
36213706e45SMaksim Yevmenkin * PPP when operating in the server mode.
36313706e45SMaksim Yevmenkin */
36413706e45SMaksim Yevmenkin
36513706e45SMaksim Yevmenkin exec_ppp(s1, NULL, label);
3661a63eb31SJulian Elischer } else
3671a63eb31SJulian Elischer close(s1);
3681a63eb31SJulian Elischer }
3691a63eb31SJulian Elischer } else {
3701a63eb31SJulian Elischer sock_addr.rfcomm_len = sizeof(sock_addr);
3711a63eb31SJulian Elischer sock_addr.rfcomm_family = AF_BLUETOOTH;
3721a63eb31SJulian Elischer memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY,
3731a63eb31SJulian Elischer sizeof(sock_addr.rfcomm_bdaddr));
3741a63eb31SJulian Elischer sock_addr.rfcomm_channel = 0;
3751a63eb31SJulian Elischer
3761a63eb31SJulian Elischer if (bind(s, (struct sockaddr *) &sock_addr,
3771a63eb31SJulian Elischer sizeof(sock_addr)) < 0) {
3781a63eb31SJulian Elischer syslog(LOG_ERR, "Could not bind socket. %s (%d)",
3791a63eb31SJulian Elischer strerror(errno), errno);
3801a63eb31SJulian Elischer exit(1);
3811a63eb31SJulian Elischer }
3821a63eb31SJulian Elischer
3831a63eb31SJulian Elischer memcpy(&sock_addr.rfcomm_bdaddr, &addr,
3841a63eb31SJulian Elischer sizeof(sock_addr.rfcomm_bdaddr));
3851a63eb31SJulian Elischer sock_addr.rfcomm_channel = channel;
3861a63eb31SJulian Elischer
3871a63eb31SJulian Elischer if (connect(s, (struct sockaddr *) &sock_addr,
3881a63eb31SJulian Elischer sizeof(sock_addr)) < 0) {
3891a63eb31SJulian Elischer syslog(LOG_ERR, "Could not connect socket. %s (%d)",
3901a63eb31SJulian Elischer strerror(errno), errno);
3911a63eb31SJulian Elischer exit(1);
3921a63eb31SJulian Elischer }
3931a63eb31SJulian Elischer
39413706e45SMaksim Yevmenkin exec_ppp(s, unit, label);
3951a63eb31SJulian Elischer }
3961a63eb31SJulian Elischer
3971a63eb31SJulian Elischer exit(0);
3981a63eb31SJulian Elischer } /* main */
3991a63eb31SJulian Elischer
4001a63eb31SJulian Elischer /*
40113706e45SMaksim Yevmenkin * Redirects stdin/stdout to s, stderr to /dev/null and exec
40213706e45SMaksim Yevmenkin * 'ppp -direct -quiet [-unit N] label'. Never returns.
4031a63eb31SJulian Elischer */
4041a63eb31SJulian Elischer
4051a63eb31SJulian Elischer static void
exec_ppp(int s,char * unit,char * label)40613706e45SMaksim Yevmenkin exec_ppp(int s, char *unit, char *label)
4071a63eb31SJulian Elischer {
4081a63eb31SJulian Elischer char ppp[] = "/usr/sbin/ppp";
40913706e45SMaksim Yevmenkin char *ppp_args[] = { ppp, "-direct", "-quiet",
41013706e45SMaksim Yevmenkin NULL, NULL, NULL, NULL };
4111a63eb31SJulian Elischer
4121a63eb31SJulian Elischer close(0);
4131a63eb31SJulian Elischer if (dup(s) < 0) {
4141a63eb31SJulian Elischer syslog(LOG_ERR, "Could not dup(0). %s (%d)",
4151a63eb31SJulian Elischer strerror(errno), errno);
4161a63eb31SJulian Elischer exit(1);
4171a63eb31SJulian Elischer }
4181a63eb31SJulian Elischer
4191a63eb31SJulian Elischer close(1);
4201a63eb31SJulian Elischer if (dup(s) < 0) {
4211a63eb31SJulian Elischer syslog(LOG_ERR, "Could not dup(1). %s (%d)",
4221a63eb31SJulian Elischer strerror(errno), errno);
4231a63eb31SJulian Elischer exit(1);
4241a63eb31SJulian Elischer }
4251a63eb31SJulian Elischer
4261a63eb31SJulian Elischer close(2);
4271a63eb31SJulian Elischer open("/dev/null", O_RDWR);
4281a63eb31SJulian Elischer
42913706e45SMaksim Yevmenkin if (unit != NULL) {
43013706e45SMaksim Yevmenkin ppp_args[3] = "-unit";
43113706e45SMaksim Yevmenkin ppp_args[4] = unit;
43213706e45SMaksim Yevmenkin ppp_args[5] = label;
43313706e45SMaksim Yevmenkin } else
43413706e45SMaksim Yevmenkin ppp_args[3] = label;
43513706e45SMaksim Yevmenkin
4361a63eb31SJulian Elischer if (execv(ppp, ppp_args) < 0) {
43713706e45SMaksim Yevmenkin syslog(LOG_ERR, "Could not exec(%s -direct -quiet%s%s %s). " \
43813706e45SMaksim Yevmenkin "%s (%d)", ppp, (unit != NULL)? " -unit " : "",
43913706e45SMaksim Yevmenkin (unit != NULL)? unit : "", label,
44013706e45SMaksim Yevmenkin strerror(errno), errno);
4411a63eb31SJulian Elischer exit(1);
4421a63eb31SJulian Elischer }
4431a63eb31SJulian Elischer } /* run_ppp */
4441a63eb31SJulian Elischer
4451a63eb31SJulian Elischer /* Signal handler */
4461a63eb31SJulian Elischer static void
sighandler(int s)4471a63eb31SJulian Elischer sighandler(int s)
4481a63eb31SJulian Elischer {
4491a63eb31SJulian Elischer done = 1;
4501a63eb31SJulian Elischer } /* sighandler */
4511a63eb31SJulian Elischer
4521a63eb31SJulian Elischer /* Display usage and exit */
4531a63eb31SJulian Elischer static void
usage(void)4541a63eb31SJulian Elischer usage(void)
4551a63eb31SJulian Elischer {
4561a63eb31SJulian Elischer fprintf(stdout,
4571a63eb31SJulian Elischer "Usage: %s options\n" \
4581a63eb31SJulian Elischer "Where options are:\n" \
4592aa65cf7SMaksim Yevmenkin "\t-a address Address to listen on or connect to (required for client)\n" \
4601a63eb31SJulian Elischer "\t-c Act as a clinet (default)\n" \
4611a63eb31SJulian Elischer "\t-C channel RFCOMM channel to listen on or connect to (required)\n" \
4621a63eb31SJulian Elischer "\t-d Run in foreground\n" \
463a09e0965SMaksim Yevmenkin "\t-D Register Dial-Up Networking service (server mode only)\n" \
4641a63eb31SJulian Elischer "\t-l label Use PPP label (required)\n" \
4651a63eb31SJulian Elischer "\t-s Act as a server\n" \
4661985a3a3SMaksim Yevmenkin "\t-S Register Serial Port service (server mode only)\n" \
46713706e45SMaksim Yevmenkin "\t-u N Tell PPP to operate on /dev/tunN (client mode only)\n" \
4681a63eb31SJulian Elischer "\t-h Display this message\n", RFCOMM_PPPD);
4691a63eb31SJulian Elischer
4701a63eb31SJulian Elischer exit(255);
4711a63eb31SJulian Elischer } /* usage */
4721a63eb31SJulian Elischer
473