summaryrefslogtreecommitdiffstats
path: root/pand/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'pand/main.c')
-rw-r--r--pand/main.c798
1 files changed, 0 insertions, 798 deletions
diff --git a/pand/main.c b/pand/main.c
deleted file mode 100644
index ce3b8ebb..00000000
--- a/pand/main.c
+++ /dev/null
@@ -1,798 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <signal.h>
-#include <getopt.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/bnep.h>
-
-#include "pand.h"
-
-#ifdef NEED_PPOLL
-#include "ppoll.h"
-#endif
-
-static uint16_t role = BNEP_SVC_PANU; /* Local role (ie service) */
-static uint16_t service = BNEP_SVC_NAP; /* Remote service */
-
-static int detach = 1;
-static int persist;
-static int use_sdp = 1;
-static int use_cache;
-static int link_mode = 0;
-static int cleanup;
-static int search_duration = 10;
-
-static struct {
- int valid;
- char dst[40];
- bdaddr_t bdaddr;
-} cache;
-
-static char netdev[16] = "bnep%d";
-static char *pidfile = NULL;
-static char *devupcmd = NULL;
-static char *devdowncmd = NULL;
-
-static bdaddr_t src_addr = *BDADDR_ANY;
-static int src_dev = -1;
-
-static volatile int terminate;
-
-static void do_kill(char *dst);
-
-enum {
- NONE,
- SHOW,
- LISTEN,
- CONNECT,
- KILL
-} modes;
-
-struct script_arg {
- char dev[20];
- char dst[20];
- int sk;
- int nsk;
-};
-
-static void run_script(char *script, char *dev, char *dst, int sk, int nsk)
-{
- char *argv[4];
- struct sigaction sa;
-
- if (!script)
- return;
-
- if (access(script, R_OK | X_OK))
- return;
-
- if (fork())
- return;
-
- if (sk >= 0)
- close(sk);
-
- if (nsk >= 0)
- close(nsk);
-
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = SIG_DFL;
- sigaction(SIGCHLD, &sa, NULL);
- sigaction(SIGPIPE, &sa, NULL);
-
- argv[0] = script;
- argv[1] = dev;
- argv[2] = dst;
- argv[3] = NULL;
-
- execv(script, argv);
-
- exit(1);
-}
-
-/* Wait for disconnect or error condition on the socket */
-static int w4_hup(int sk, struct script_arg *down_cmd)
-{
- struct pollfd pf;
- sigset_t sigs;
- int n;
-
- sigfillset(&sigs);
- sigdelset(&sigs, SIGCHLD);
- sigdelset(&sigs, SIGPIPE);
- sigdelset(&sigs, SIGTERM);
- sigdelset(&sigs, SIGINT);
- sigdelset(&sigs, SIGHUP);
-
- while (!terminate) {
- pf.fd = sk;
- pf.events = POLLERR | POLLHUP;
-
- n = ppoll(&pf, 1, NULL, &sigs);
-
- if (n < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
-
- syslog(LOG_ERR, "Poll failed. %s(%d)",
- strerror(errno), errno);
-
- return 1;
- }
-
- if (n) {
- int err = 0;
- socklen_t olen = sizeof(err);
-
- getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &olen);
-
- syslog(LOG_INFO, "%s disconnected%s%s", netdev,
- err ? " : " : "", err ? strerror(err) : "");
-
- if (down_cmd)
- run_script(devdowncmd,
- down_cmd->dev, down_cmd->dst,
- down_cmd->sk, down_cmd->nsk);
-
- close(sk);
-
- return 0;
- }
- }
-
- return 0;
-}
-
-static int do_listen(void)
-{
- struct l2cap_options l2o;
- struct sockaddr_l2 l2a;
- socklen_t olen;
- int sk, lm;
-
- if (use_sdp)
- bnep_sdp_register(&src_addr, role);
-
- /* Create L2CAP socket and bind it to PSM BNEP */
- sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
- if (sk < 0) {
- syslog(LOG_ERR, "Cannot create L2CAP socket. %s(%d)",
- strerror(errno), errno);
- return -1;
- }
-
- memset(&l2a, 0, sizeof(l2a));
- l2a.l2_family = AF_BLUETOOTH;
- bacpy(&l2a.l2_bdaddr, &src_addr);
- l2a.l2_psm = htobs(BNEP_PSM);
-
- if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a))) {
- syslog(LOG_ERR, "Bind failed. %s(%d)",
- strerror(errno), errno);
- return -1;
- }
-
- /* Setup L2CAP options according to BNEP spec */
- memset(&l2o, 0, sizeof(l2o));
- olen = sizeof(l2o);
- if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen) < 0) {
- syslog(LOG_ERR, "Failed to get L2CAP options. %s(%d)",
- strerror(errno), errno);
- return -1;
- }
-
- l2o.imtu = l2o.omtu = BNEP_MTU;
- if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)) < 0) {
- syslog(LOG_ERR, "Failed to set L2CAP options. %s(%d)",
- strerror(errno), errno);
- return -1;
- }
-
- /* Set link mode */
- lm = link_mode;
- if (lm && setsockopt(sk, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)) < 0) {
- syslog(LOG_ERR, "Failed to set link mode. %s(%d)",
- strerror(errno), errno);
- return -1;
- }
-
- listen(sk, 10);
-
- while (!terminate) {
- socklen_t alen = sizeof(l2a);
- char devname[16];
- int nsk;
-
- nsk = accept(sk, (struct sockaddr *) &l2a, &alen);
- if (nsk < 0) {
- syslog(LOG_ERR, "Accept failed. %s(%d)",
- strerror(errno), errno);
- continue;
- }
-
- switch (fork()) {
- case 0:
- break;
- case -1:
- syslog(LOG_ERR, "Fork failed. %s(%d)",
- strerror(errno), errno);
- default:
- close(nsk);
- continue;
- }
-
- strncpy(devname, netdev, 16);
- devname[15] = '\0';
-
- if (!bnep_accept_connection(nsk, role, devname)) {
- char str[40];
- struct script_arg down_cmd;
-
- ba2str(&l2a.l2_bdaddr, str);
-
- syslog(LOG_INFO, "New connection from %s at %s",
- str, devname);
-
- run_script(devupcmd, devname, str, sk, nsk);
-
- memset(&down_cmd, 0, sizeof(struct script_arg));
- strncpy(down_cmd.dev, devname, strlen(devname) + 1);
- strncpy(down_cmd.dst, str, strlen(str) + 1);
- down_cmd.sk = sk;
- down_cmd.nsk = nsk;
- w4_hup(nsk, &down_cmd);
- } else {
- syslog(LOG_ERR, "Connection failed. %s(%d)",
- strerror(errno), errno);
- }
-
- close(nsk);
- exit(0);
- }
-
- if (use_sdp)
- bnep_sdp_unregister();
-
- return 0;
-}
-
-/* Connect and initiate BNEP session
- * Returns:
- * -1 - critical error (exit persist mode)
- * 1 - non critical error
- * 0 - success
- */
-static int create_connection(char *dst, bdaddr_t *bdaddr)
-{
- struct l2cap_options l2o;
- struct sockaddr_l2 l2a;
- socklen_t olen;
- int sk, r = 0;
- struct script_arg down_cmd;
-
- syslog(LOG_INFO, "Connecting to %s", dst);
-
- sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
- if (sk < 0) {
- syslog(LOG_ERR, "Cannot create L2CAP socket. %s(%d)",
- strerror(errno), errno);
- return -1;
- }
-
- /* Setup L2CAP options according to BNEP spec */
- memset(&l2o, 0, sizeof(l2o));
- olen = sizeof(l2o);
- getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen);
- l2o.imtu = l2o.omtu = BNEP_MTU;
- setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o));
-
- memset(&l2a, 0, sizeof(l2a));
- l2a.l2_family = AF_BLUETOOTH;
- bacpy(&l2a.l2_bdaddr, &src_addr);
-
- if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a)))
- syslog(LOG_ERR, "Bind failed. %s(%d)",
- strerror(errno), errno);
-
- memset(&l2a, 0, sizeof(l2a));
- l2a.l2_family = AF_BLUETOOTH;
- bacpy(&l2a.l2_bdaddr, bdaddr);
- l2a.l2_psm = htobs(BNEP_PSM);
-
- if (!connect(sk, (struct sockaddr *) &l2a, sizeof(l2a)) &&
- !bnep_create_connection(sk, role, service, netdev)) {
-
- syslog(LOG_INFO, "%s connected", netdev);
-
- run_script(devupcmd, netdev, dst, sk, -1);
-
- if (persist || devdowncmd) {
- memset(&down_cmd, 0, sizeof(struct script_arg));
- strncpy(down_cmd.dev, netdev, strlen(netdev) + 1);
- strncpy(down_cmd.dst, dst, strlen(dst) + 1);
- down_cmd.sk = sk;
- down_cmd.nsk = -1;
- w4_hup(sk, &down_cmd);
-
- if (terminate && cleanup) {
- syslog(LOG_INFO, "Disconnecting from %s.", dst);
- do_kill(dst);
- }
- }
-
- r = 0;
- } else {
- syslog(LOG_ERR, "Connect to %s failed. %s(%d)",
- dst, strerror(errno), errno);
- r = 1;
- }
-
- close(sk);
-
- if (use_cache) {
- if (!r) {
- /* Succesesful connection, validate cache */
- strcpy(cache.dst, dst);
- bacpy(&cache.bdaddr, bdaddr);
- cache.valid = use_cache;
- } else
- cache.valid--;
- }
-
- return r;
-}
-
-/* Search and connect
- * Returns:
- * -1 - critical error (exit persist mode)
- * 1 - non critical error
- * 0 - success
- */
-static int do_connect(void)
-{
- inquiry_info *ii;
- int reconnect = 0;
- int i, n, r = 0;
-
- do {
- if (reconnect)
- sleep(persist);
- reconnect = 1;
-
- if (cache.valid > 0) {
- /* Use cached bdaddr */
- r = create_connection(cache.dst, &cache.bdaddr);
- if (r < 0) {
- terminate = 1;
- break;
- }
- continue;
- }
-
- syslog(LOG_INFO, "Inquiring");
-
- /* FIXME: Should we use non general LAP here ? */
-
- ii = NULL;
- n = hci_inquiry(src_dev, search_duration, 0, NULL, &ii, 0);
- if (n < 0) {
- syslog(LOG_ERR, "Inquiry failed. %s(%d)",
- strerror(errno), errno);
- continue;
- }
-
- for (i = 0; i < n; i++) {
- char dst[40];
- ba2str(&ii[i].bdaddr, dst);
-
- if (use_sdp) {
- syslog(LOG_INFO, "Searching for %s on %s",
- bnep_svc2str(service), dst);
-
- if (bnep_sdp_search(&src_addr, &ii[i].bdaddr, service) <= 0)
- continue;
- }
-
- r = create_connection(dst, &ii[i].bdaddr);
- if (r < 0) {
- terminate = 1;
- break;
- }
- }
- bt_free(ii);
- } while (!terminate && persist);
-
- return r;
-}
-
-static void do_show(void)
-{
- bnep_show_connections();
-}
-
-static void do_kill(char *dst)
-{
- if (dst)
- bnep_kill_connection((void *) strtoba(dst));
- else
- bnep_kill_all_connections();
-}
-
-static void sig_hup(int sig)
-{
- return;
-}
-
-static void sig_term(int sig)
-{
- terminate = 1;
-}
-
-static int write_pidfile(void)
-{
- int fd;
- FILE *f;
- pid_t pid;
-
- do {
- fd = open(pidfile, O_WRONLY|O_TRUNC|O_CREAT|O_EXCL, 0644);
- if (fd == -1) {
- /* Try to open the file for read. */
- fd = open(pidfile, O_RDONLY);
- if (fd < 0) {
- syslog(LOG_ERR, "Could not read old pidfile: %s(%d)",
- strerror(errno), errno);
- return -1;
- }
-
- /* We're already running; send a SIGHUP (we presume that they
- * are calling ifup for a reason, so they probably want to
- * rescan) and then exit cleanly and let things go on in the
- * background. Muck with the filename so that we don't go
- * deleting the pid file for the already-running instance.
- */
- f = fdopen(fd, "r");
- if (!f) {
- syslog(LOG_ERR, "Could not fdopen old pidfile: %s(%d)",
- strerror(errno), errno);
- close(fd);
- return -1;
- }
-
- pid = 0;
- if (fscanf(f, "%d", &pid) != 1)
- pid = 0;
- fclose(f);
-
- if (pid) {
- /* Try to kill it. */
- if (kill(pid, SIGHUP) == -1) {
- /* No such pid; remove the bogus pid file. */
- syslog(LOG_INFO, "Removing stale pidfile");
- unlink(pidfile);
- fd = -1;
- } else {
- /* Got it. Don't mess with the pid file on
- * our way out. */
- syslog(LOG_INFO, "Signalling existing process %d and exiting\n", pid);
- pidfile = NULL;
- return -1;
- }
- }
- }
- } while(fd == -1);
-
- f = fdopen(fd, "w");
- if (!f) {
- syslog(LOG_ERR, "Could not fdopen new pidfile: %s(%d)",
- strerror(errno), errno);
- close(fd);
- unlink(pidfile);
- return -1;
- }
-
- fprintf(f, "%d\n", getpid());
- fclose(f);
-
- return 0;
-}
-
-static struct option main_lopts[] = {
- { "help", 0, 0, 'h' },
- { "listen", 0, 0, 's' },
- { "connect", 1, 0, 'c' },
- { "search", 2, 0, 'Q' },
- { "kill", 1, 0, 'k' },
- { "killall", 0, 0, 'K' },
- { "role", 1, 0, 'r' },
- { "service", 1, 0, 'd' },
- { "ethernet", 1, 0, 'e' },
- { "device", 1, 0, 'i' },
- { "nosdp", 0, 0, 'D' },
- { "list", 0, 0, 'l' },
- { "show", 0, 0, 'l' },
- { "nodetach", 0, 0, 'n' },
- { "persist", 2, 0, 'p' },
- { "auth", 0, 0, 'A' },
- { "encrypt", 0, 0, 'E' },
- { "secure", 0, 0, 'S' },
- { "master", 0, 0, 'M' },
- { "cache", 0, 0, 'C' },
- { "pidfile", 1, 0, 'P' },
- { "devup", 1, 0, 'u' },
- { "devdown", 1, 0, 'o' },
- { "autozap", 0, 0, 'z' },
- { 0, 0, 0, 0 }
-};
-
-static char main_sopts[] = "hsc:k:Kr:d:e:i:lnp::DQ::AESMC::P:u:o:z";
-
-static char main_help[] =
- "Bluetooth PAN daemon version " VERSION " \n"
- "Usage:\n"
- "\tpand <options>\n"
- "Options:\n"
- "\t--show --list -l Show active PAN connections\n"
- "\t--listen -s Listen for PAN connections\n"
- "\t--connect -c <bdaddr> Create PAN connection\n"
- "\t--autozap -z Disconnect automatically on exit\n"
- "\t--search -Q[duration] Search and connect\n"
- "\t--kill -k <bdaddr> Kill PAN connection\n"
- "\t--killall -K Kill all PAN connections\n"
- "\t--role -r <role> Local PAN role (PANU, NAP, GN)\n"
- "\t--service -d <role> Remote PAN service (PANU, NAP, GN)\n"
- "\t--ethernet -e <name> Network interface name\n"
- "\t--device -i <bdaddr> Source bdaddr\n"
- "\t--nosdp -D Disable SDP\n"
- "\t--auth -A Enable authentication\n"
- "\t--encrypt -E Enable encryption\n"
- "\t--secure -S Secure connection\n"
- "\t--master -M Become the master of a piconet\n"
- "\t--nodetach -n Do not become a daemon\n"
- "\t--persist -p[interval] Persist mode\n"
- "\t--cache -C[valid] Cache addresses\n"
- "\t--pidfile -P <pidfile> Create PID file\n"
- "\t--devup -u <script> Script to run when interface comes up\n"
- "\t--devdown -o <script> Script to run when interface comes down\n";
-
-int main(int argc, char *argv[])
-{
- char *dst = NULL, *src = NULL;
- struct sigaction sa;
- int mode = NONE;
- int opt;
-
- while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) {
- switch(opt) {
- case 'l':
- mode = SHOW;
- detach = 0;
- break;
-
- case 's':
- mode = LISTEN;
- break;
-
- case 'c':
- mode = CONNECT;
- dst = strdup(optarg);
- break;
-
- case 'Q':
- mode = CONNECT;
- if (optarg)
- search_duration = atoi(optarg);
- break;
-
- case 'k':
- mode = KILL;
- detach = 0;
- dst = strdup(optarg);
- break;
-
- case 'K':
- mode = KILL;
- detach = 0;
- break;
-
- case 'i':
- src = strdup(optarg);
- break;
-
- case 'r':
- bnep_str2svc(optarg, &role);
- break;
-
- case 'd':
- bnep_str2svc(optarg, &service);
- break;
-
- case 'D':
- use_sdp = 0;
- break;
-
- case 'A':
- link_mode |= L2CAP_LM_AUTH;
- break;
-
- case 'E':
- link_mode |= L2CAP_LM_ENCRYPT;
- break;
-
- case 'S':
- link_mode |= L2CAP_LM_SECURE;
- break;
-
- case 'M':
- link_mode |= L2CAP_LM_MASTER;
- break;
-
- case 'e':
- strncpy(netdev, optarg, 16);
- netdev[15] = '\0';
- break;
-
- case 'n':
- detach = 0;
- break;
-
- case 'p':
- if (optarg)
- persist = atoi(optarg);
- else
- persist = 5;
- break;
-
- case 'C':
- if (optarg)
- use_cache = atoi(optarg);
- else
- use_cache = 2;
- break;
-
- case 'P':
- pidfile = strdup(optarg);
- break;
-
- case 'u':
- devupcmd = strdup(optarg);
- break;
-
- case 'o':
- devdowncmd = strdup(optarg);
- break;
-
- case 'z':
- cleanup = 1;
- break;
-
- case 'h':
- default:
- printf(main_help);
- exit(0);
- }
- }
-
- argc -= optind;
- argv += optind;
- optind = 0;
-
- if (bnep_init())
- return -1;
-
- /* Check non daemon modes first */
- switch (mode) {
- case SHOW:
- do_show();
- return 0;
-
- case KILL:
- do_kill(dst);
- return 0;
-
- case NONE:
- printf(main_help);
- return 0;
- }
-
- /* Initialize signals */
- memset(&sa, 0, sizeof(sa));
- sa.sa_flags = SA_NOCLDSTOP;
- sa.sa_handler = SIG_IGN;
- sigaction(SIGCHLD, &sa, NULL);
- sigaction(SIGPIPE, &sa, NULL);
-
- sa.sa_handler = sig_hup;
- sigaction(SIGHUP, &sa, NULL);
-
- sa.sa_handler = sig_term;
- sigaction(SIGTERM, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
-
- if (detach && daemon(0, 0)) {
- perror("Can't start daemon");
- exit(1);
- }
-
- openlog("pand", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
- syslog(LOG_INFO, "Bluetooth PAN daemon version %s", VERSION);
-
- if (src) {
- src_dev = hci_devid(src);
- if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) {
- syslog(LOG_ERR, "Invalid source. %s(%d)",
- strerror(errno), errno);
- return -1;
- }
- }
-
- if (pidfile && write_pidfile())
- return -1;
-
- if (dst) {
- /* Disable cache invalidation */
- use_cache = 0;
-
- strncpy(cache.dst, dst, sizeof(cache.dst) - 1);
- str2ba(dst, &cache.bdaddr);
- cache.valid = 1;
- free(dst);
- }
-
- switch (mode) {
- case CONNECT:
- do_connect();
- break;
-
- case LISTEN:
- do_listen();
- break;
- }
-
- if (pidfile)
- unlink(pidfile);
-
- return 0;
-}