Path: blob/main/usr.sbin/bluetooth/btpand/btpand.c
106843 views
/* $NetBSD: btpand.c,v 1.1 2008/08/17 13:20:57 plunky Exp $ */12/*-3* SPDX-License-Identifier: BSD-2-Clause4*5* Copyright (c) 2008 Iain Hibbert6* All rights reserved.7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions10* are met:11* 1. Redistributions of source code must retain the above copyright12* notice, this list of conditions and the following disclaimer.13* 2. Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in the15* documentation and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR18* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES19* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.20* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,21* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT22* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF26* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.27*/282930#include <sys/wait.h>3132#define L2CAP_SOCKET_CHECKED33#include <bluetooth.h>34#include <err.h>35#include <fcntl.h>36#include <paths.h>37#include <sdp.h>38#include <stdio.h>39#include <signal.h>40#include <stdlib.h>41#include <string.h>42#include <unistd.h>4344#include "btpand.h"4546/* global variables */47const char * control_path; /* -c <path> */48const char * interface_name; /* -i <ifname> */49const char * service_name; /* -s <service> */50uint16_t service_class;5152bdaddr_t local_bdaddr; /* -d <addr> */53bdaddr_t remote_bdaddr; /* -a <addr> */54uint16_t l2cap_psm; /* -p <psm> */55int l2cap_mode; /* -m <mode> */5657int server_limit; /* -n <limit> */5859static const struct {60const char * name;61uint16_t class;62const char * desc;63} services[] = {64{ "PANU", SDP_SERVICE_CLASS_PANU, "Personal Area Networking User" },65{ "NAP", SDP_SERVICE_CLASS_NAP, "Network Access Point" },66{ "GN", SDP_SERVICE_CLASS_GN, "Group Network" },67};6869static void main_exit(int) __dead2;70static void main_detach(void);71static void usage(void) __dead2;7273int74main(int argc, char *argv[])75{76unsigned long ul;77char * ep;78int ch, status;7980while ((ch = getopt(argc, argv, "a:c:d:i:l:m:p:S:s:")) != -1) {81switch (ch) {82case 'a': /* remote address */83if (!bt_aton(optarg, &remote_bdaddr)) {84struct hostent *he;8586if ((he = bt_gethostbyname(optarg)) == NULL)87errx(EXIT_FAILURE, "%s: %s",88optarg, hstrerror(h_errno));8990bdaddr_copy(&remote_bdaddr,91(bdaddr_t *)he->h_addr);92}9394break;9596case 'c': /* control socket path */97control_path = optarg;98break;99100case 'd': /* local address */101if (!bt_devaddr(optarg, &local_bdaddr)) {102struct hostent *he;103104if ((he = bt_gethostbyname(optarg)) == NULL)105errx(EXIT_FAILURE, "%s: %s",106optarg, hstrerror(h_errno));107108bdaddr_copy(&local_bdaddr,109(bdaddr_t *)he->h_addr);110}111break;112113case 'i': /* tap interface name */114if (strchr(optarg, '/') == NULL) {115asprintf(&ep, "/dev/%s", optarg);116interface_name = ep;117} else118interface_name = optarg;119break;120121case 'l': /* limit server sessions */122ul = strtoul(optarg, &ep, 10);123if (*optarg == '\0' || *ep != '\0' || ul == 0)124errx(EXIT_FAILURE, "%s: invalid session limit",125optarg);126127server_limit = ul;128break;129130case 'm': /* link mode */131warnx("Setting link mode is not yet supported");132break;133134case 'p': /* protocol/service multiplexer */135ul = strtoul(optarg, &ep, 0);136if (*optarg == '\0' || *ep != '\0'137|| ul > 0xffff || L2CAP_PSM_INVALID(ul))138errx(EXIT_FAILURE, "%s: invalid PSM", optarg);139140l2cap_psm = ul;141break;142143case 's': /* service */144case 'S': /* service (no SDP) */145for (ul = 0; ul < __arraycount(services); ul++) {146if (strcasecmp(optarg, services[ul].name) == 0)147break;148}149150if (ul == __arraycount(services))151errx(EXIT_FAILURE, "%s: unknown service", optarg);152153if (ch == 's')154service_name = services[ul].name;155156service_class = services[ul].class;157break;158159default:160usage();161/* NOTREACHED */162}163}164165argc -= optind;166argv += optind;167168/* validate options */169if (bdaddr_any(&local_bdaddr) || service_class == 0)170usage();171172if (!bdaddr_any(&remote_bdaddr) && (server_limit != 0 ||173control_path != NULL || (service_name != NULL && l2cap_psm != 0)))174usage();175176/* default options */177if (interface_name == NULL)178interface_name = "/dev/tap";179180if (l2cap_psm == 0)181l2cap_psm = L2CAP_PSM_BNEP;182183if (bdaddr_any(&remote_bdaddr) && server_limit == 0) {184if (service_class == SDP_SERVICE_CLASS_PANU)185server_limit = 1;186else187server_limit = 7;188}189190#ifdef L2CAP_LM_MASTER191if (server_limit > 1 && service_class != SDP_SERVICE_CLASS_PANU)192l2cap_mode |= L2CAP_LM_MASTER;193#endif194195/*196* fork() now so that the setup can be done in the child process197* (as kqueue is not inherited) but block in the parent until the198* setup is finished so we can return an error if necessary.199*/200switch(fork()) {201case -1: /* bad */202err(EXIT_FAILURE, "fork() failed");203204case 0: /* child */205signal(SIGPIPE, SIG_IGN);206207openlog(getprogname(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON);208209channel_init();210server_init();211event_init();212client_init();213tap_init();214215main_detach();216217event_dispatch();218break;219220default: /* parent */221signal(SIGUSR1, main_exit);222wait(&status);223224if (WIFEXITED(status))225exit(WEXITSTATUS(status));226227break;228}229230err(EXIT_FAILURE, "exiting");231}232233static void234main_exit(int s)235{236237/* child is all grown up */238_exit(EXIT_SUCCESS);239}240241static void242main_detach(void)243{244int fd;245246if (kill(getppid(), SIGUSR1) == -1)247log_err("Could not signal main process: %m");248249if (setsid() == -1)250log_err("setsid() failed");251252fd = open(_PATH_DEVNULL, O_RDWR, 0);253if (fd == -1) {254log_err("Could not open %s", _PATH_DEVNULL);255} else {256(void)dup2(fd, STDIN_FILENO);257(void)dup2(fd, STDOUT_FILENO);258(void)dup2(fd, STDERR_FILENO);259close(fd);260}261}262263static void264usage(void)265{266const char *p = getprogname();267int n = strlen(p);268269fprintf(stderr,270"usage: %s [-i ifname] [-m mode] -a address -d device\n"271" %*s {-s service | -S service [-p psm]}\n"272" %s [-c path] [-i ifname] [-l limit] [-m mode] [-p psm] -d device\n"273" %*s {-s service | -S service}\n"274"\n"275"Where:\n"276"\t-a address remote bluetooth device\n"277"\t-c path SDP server socket\n"278"\t-d device local bluetooth device\n"279"\t-i ifname tap interface\n"280"\t-l limit limit server sessions\n"281"\t-m mode L2CAP link mode (NOT YET SUPPORTED)\n"282"\t-p psm L2CAP PSM\n"283"\t-S service service name (no SDP)\n"284"\t-s service service name\n"285"\n"286"Known services:\n"287"", p, n, "", p, n, "");288289for (n = 0; n < __arraycount(services); n++)290fprintf(stderr, "\t%s\t%s\n", services[n].name, services[n].desc);291292exit(EXIT_FAILURE);293}294295296