1 /* $NetBSD: btpand.c,v 1.4 2009/05/12 21:50:38 plunky Exp $ */
4 * Copyright (c) 2008-2009 Iain Hibbert
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/cdefs.h>
29 __COPYRIGHT("@(#) Copyright (c) 2008-2009 Iain Hibbert. All rights reserved.");
30 __RCSID("$NetBSD: btpand.c,v 1.4 2009/05/12 21:50:38 plunky Exp $");
34 #include <bluetooth.h>
47 /* global variables */
48 const char * control_path
; /* -c <path> */
49 const char * interface_name
; /* -i <ifname> */
50 const char * service_type
; /* -s <service> */
51 uint16_t service_class
;
52 const char * service_name
;
53 const char * service_desc
;
55 bdaddr_t local_bdaddr
; /* -d <addr> */
56 bdaddr_t remote_bdaddr
; /* -a <addr> */
57 uint16_t l2cap_psm
; /* -p <psm> */
58 int l2cap_mode
; /* -m <mode> */
59 int server_limit
; /* -n <limit> */
67 { "PANU", SDP_SERVICE_CLASS_PANU
,
68 "Personal Ad-hoc User Service",
69 "Personal Ad-hoc User Service"
71 { "NAP", SDP_SERVICE_CLASS_NAP
,
72 "Network Acess Point",
73 "Personal Ad-hoc Network Service"
75 { "GN", SDP_SERVICE_CLASS_GN
,
76 "Group Ad-hoc Network",
77 "Personal Group Ad-hoc Network Service"
81 static void main_exit(int);
82 static void main_detach(void);
83 static void usage(void);
86 main(int argc
, char *argv
[])
92 while ((ch
= getopt(argc
, argv
, "a:c:d:i:l:m:p:S:s:")) != -1) {
94 case 'a': /* remote address */
95 if (!bt_aton(optarg
, &remote_bdaddr
)) {
98 if ((he
= bt_gethostbyname(optarg
)) == NULL
)
99 errx(EXIT_FAILURE
, "%s: %s",
100 optarg
, hstrerror(h_errno
));
102 bdaddr_copy(&remote_bdaddr
, (bdaddr_t
*)he
->h_addr
);
107 case 'c': /* control socket path */
108 control_path
= optarg
;
111 case 'd': /* local address */
112 if (!bt_devaddr(optarg
, &local_bdaddr
))
113 err(EXIT_FAILURE
, "%s", optarg
);
117 case 'i': /* tap interface name */
118 if (strchr(optarg
, '/') == NULL
) {
119 asprintf(&ep
, "/dev/%s", optarg
);
122 interface_name
= optarg
;
127 case 'l': /* limit server sessions */
128 ul
= strtoul(optarg
, &ep
, 10);
129 if (*optarg
== '\0' || *ep
!= '\0' || ul
== 0)
130 errx(EXIT_FAILURE
, "%s: invalid session limit", optarg
);
135 case 'm': /* link mode */
136 if (strcasecmp(optarg
, "auth") == 0)
137 l2cap_mode
= L2CAP_LM_AUTH
;
138 else if (strcasecmp(optarg
, "encrypt") == 0)
139 l2cap_mode
= L2CAP_LM_ENCRYPT
;
140 else if (strcasecmp(optarg
, "secure") == 0)
141 l2cap_mode
= L2CAP_LM_SECURE
;
142 else if (strcasecmp(optarg
, "none"))
143 errx(EXIT_FAILURE
, "%s: unknown mode", optarg
);
147 case 'p': /* protocol/service multiplexer */
148 ul
= strtoul(optarg
, &ep
, 0);
149 if (*optarg
== '\0' || *ep
!= '\0'
150 || ul
> 0xffff || L2CAP_PSM_INVALID(ul
))
151 errx(EXIT_FAILURE
, "%s: invalid PSM", optarg
);
153 l2cap_psm
= (uint16_t)ul
;
156 case 's': /* service */
157 case 'S': /* service (no SDP) */
158 for (ul
= 0; strcasecmp(optarg
, services
[ul
].type
); ul
++) {
159 if (ul
== __arraycount(services
))
160 errx(EXIT_FAILURE
, "%s: unknown service", optarg
);
164 service_type
= services
[ul
].type
;
165 service_name
= services
[ul
].name
;
166 service_desc
= services
[ul
].desc
;
169 service_class
= services
[ul
].class;
181 /* validate options */
182 if (bdaddr_any(&local_bdaddr
) || service_class
== 0)
185 if (!bdaddr_any(&remote_bdaddr
) && (server_limit
!= 0 ||
186 control_path
!= 0 || (service_type
!= NULL
&& l2cap_psm
!= 0)))
189 /* default options */
190 if (interface_name
== NULL
)
191 interface_name
= "/dev/tap";
194 l2cap_psm
= L2CAP_PSM_BNEP
;
196 if (bdaddr_any(&remote_bdaddr
) && server_limit
== 0) {
197 if (service_class
== SDP_SERVICE_CLASS_PANU
)
203 #ifdef L2CAP_LM_MASTER
204 if (server_limit
> 1 && service_class
!= SDP_SERVICE_CLASS_PANU
)
205 l2cap_mode
|= L2CAP_LM_MASTER
;
209 * fork() now so that the setup can be done in the child process
210 * (as kqueue is not inherited) but block in the parent until the
211 * setup is finished so we can return an error if necessary.
215 err(EXIT_FAILURE
, "fork() failed");
218 openlog(getprogname(), LOG_NDELAY
| LOG_PERROR
| LOG_PID
, LOG_DAEMON
);
231 default: /* parent */
232 signal(SIGUSR1
, main_exit
);
235 if (WIFEXITED(status
))
236 exit(WEXITSTATUS(status
));
241 err(EXIT_FAILURE
, "exiting");
248 /* child is all grown up */
257 if (kill(getppid(), SIGUSR1
) == -1)
258 log_err("Could not signal main process: %m");
261 log_err("setsid() failed");
263 fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
265 log_err("Could not open %s", _PATH_DEVNULL
);
267 (void)dup2(fd
, STDIN_FILENO
);
268 (void)dup2(fd
, STDOUT_FILENO
);
269 (void)dup2(fd
, STDERR_FILENO
);
277 const char *p
= getprogname();
278 size_t n
= strlen(p
);
281 "usage: %s [-i ifname] [-m mode] -a address -d device\n"
282 " %*s {-s service | -S service [-p psm]}\n"
283 " %s [-c path] [-i ifname] [-l limit] [-m mode] [-p psm] -d device\n"
284 " %*s {-s service | -S service}\n"
287 "\t-a address remote bluetooth device\n"
288 "\t-c path SDP server socket\n"
289 "\t-d device local bluetooth device\n"
290 "\t-i ifname tap interface\n"
291 "\t-l limit limit server sessions\n"
292 "\t-m mode L2CAP link mode\n"
293 "\t-p psm L2CAP PSM\n"
294 "\t-S service service name (no SDP)\n"
295 "\t-s service service name\n"
298 "", p
, (int)n
, "", p
, (int)n
, "");
300 for (n
= 0; n
< __arraycount(services
); n
++)
301 fprintf(stderr
, "\t%s\t%s\n", services
[n
].type
, services
[n
].name
);