Initial Leopard version. Untested.
[tuntaposx.git] / tuntap / src / tuntap_mgr.cc
blob698d9fa8e80d9ac3d2d21ab9412b30e9e9bf0342
1 /*
2 * ip tunnel/ethertap device for MacOSX.
4 * tuntap_manager definition.
5 */
6 /*
7 * Copyright (c) 2004, 2005, 2006, 2007 Mattias Nissler <mattias.nissler@gmx.de>
9 * Redistribution and use in source and binary forms, with or without modification, are permitted
10 * provided that the following conditions are met:
12 * 1. Redistributions of source code must retain the above copyright notice, this list of
13 * conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
15 * conditions and the following disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products derived from this
18 * software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "tuntap.h"
32 extern "C" {
34 #include <sys/conf.h>
35 #include <sys/param.h>
36 #include <sys/syslog.h>
37 #include <sys/systm.h>
38 #include <sys/malloc.h>
40 #include <vm/vm_kern.h>
42 #include <miscfs/devfs/devfs.h>
46 #if 0
47 #define dprintf(...) log(LOG_INFO, __VA_ARGS__)
48 #else
49 #define dprintf(...)
50 #endif
52 /* cdevsw for tuntap_manager */
53 static struct cdevsw mgr_cdevsw =
55 tuntap_manager::cdev_open,
56 tuntap_manager::cdev_close,
57 tuntap_manager::cdev_read,
58 tuntap_manager::cdev_write,
59 tuntap_manager::cdev_ioctl,
60 eno_stop,
61 eno_reset,
62 NULL,
63 tuntap_manager::cdev_select,
64 eno_mmap,
65 eno_strat,
66 eno_getc,
67 eno_putc,
71 /* tuntap_manager members */
72 tuntap_manager *tuntap_manager::mgr_map[MAX_CDEV];
74 bool tuntap_manager::statics_initialized = false;
76 /* static initializer */
77 void
78 tuntap_manager::initialize_statics()
80 dprintf("initializing mgr_map\n");
82 /* initialize the major-to-manager map */
83 for (int i = 0; i < MAX_CDEV; i++)
84 mgr_map[i] = NULL;
86 statics_initialized = true;
89 bool
90 tuntap_manager::initialize(unsigned int count, char *family)
92 this->count = count;
93 this->family = family;
94 this->tuntaps = NULL;
96 if (!statics_initialized)
97 initialize_statics();
99 /* make sure noone can access the character devices until we are done */
100 auto_lock l(&cdev_gate);
102 /* register the switch for the tap character devices */
103 dev_major = cdevsw_add(-1, &mgr_cdevsw);
104 if (dev_major == -1) {
105 log(LOG_ERR, "%s: could not register character device switch.\n", family);
106 return false;
109 /* allocate memory for the interface instance table */
110 tuntaps = (tuntap_interface **) kalloc(count * sizeof(tuntap_interface *));
112 if (tuntaps == NULL) {
113 log(LOG_ERR, "%s: no memory!\n", family);
114 return false;
117 bzero(tuntaps, count * sizeof(tuntap_interface *));
119 /* Create the interfaces. This will only add the character devices. The network devices will
120 * be created upon open()ing the corresponding character devices.
122 for (int i = 0; i < (int) count; i++)
124 tuntaps[i] = create_interface();
126 if (tuntaps[i] != NULL)
128 if (tuntaps[i]->initialize(dev_major, i))
130 continue;
133 /* error here. current interface needs to be shut down */
134 i++;
137 /* something went wrong. clean up. */
138 while (--i >= 0)
140 tuntaps[i]->shutdown();
141 delete tuntaps[i];
144 return false;
147 /* register the new family in the mgr switch */
148 mgr_map[dev_major] = this;
150 log(LOG_INFO, "%s kernel extension version %s <mattias.nissler@gmx.de>\n",
151 family, TUNTAP_VERSION);
153 return true;
156 bool
157 tuntap_manager::shutdown()
159 bool ok = true;
161 /* we halt the whole thing while we check whether we can shutdown */
162 auto_lock l(&cdev_gate);
164 /* anyone in? */
165 if (cdev_gate.is_anyone_in()) {
166 dprintf("tuntap_mgr: won't shutdown, threads still behind the gate.");
167 ok = false;
168 } else {
169 /* query the interfaces to see if shutting down is ok */
170 if (tuntaps != NULL) {
171 for (unsigned int i = 0; i < count; i++) {
172 if (tuntaps[i] != NULL)
173 ok &= tuntaps[i]->idle();
176 /* if yes, do it now */
177 if (ok) {
178 for (unsigned int i = 0; i < count; i++) {
179 if (tuntaps[i] != NULL) {
180 tuntaps[i]->shutdown();
181 delete tuntaps[i];
182 tuntaps[i] = NULL;
189 /* unregister the character device switch */
190 if (ok) {
191 if (dev_major != -1 && cdevsw_remove(dev_major, &mgr_cdevsw) == -1) {
192 log(LOG_WARNING,
193 "%s: character device switch got lost. strange.\n", family);
195 mgr_map[dev_major] = NULL;
196 dev_major = -1;
198 /* at this point there is still a chance that some thread hangs at the cdev_gate in
199 * one of the cdev service functions. I can't imagine any way that would aviod this.
200 * So lets unblock the gate such that they fail.
202 unsigned int old_number;
203 do {
204 old_number = cdev_gate.get_ticket_number();
205 l.unlock();
207 dprintf("tuntap_manager: waiting for other threads to give up.\n");
209 /* wait one second */
210 delay(1000000);
211 l.lock();
212 } while (cdev_gate.get_ticket_number() != old_number);
214 /* I hope it is safe to unload now. */
216 } else {
217 log(LOG_WARNING, "%s: won't unload, at least one interface is busy.\n", family);
220 dprintf("tuntap manager: shutdown %s\n", ok ? "ok" : "failed");
222 return ok;
225 tuntap_manager::~tuntap_manager()
227 dprintf("freeing interface table\n");
229 /* free memory */
230 if (tuntaps != NULL)
231 kfree(tuntaps, count * sizeof(tuntap_interface *));
234 /* service method dispatchers */
236 tuntap_manager::cdev_open(dev_t dev, int flags, int devtype, proc_t p)
238 return (mgr_map[major(dev)] == NULL ? ENOENT
239 : mgr_map[major(dev)]->do_cdev_open(dev, flags, devtype, p));
243 tuntap_manager::cdev_close(dev_t dev, int flags, int devtype, proc_t p)
245 return (mgr_map[major(dev)] == NULL ? EBADF
246 : mgr_map[major(dev)]->do_cdev_close(dev, flags, devtype, p));
250 tuntap_manager::cdev_read(dev_t dev, uio_t uio, int ioflag)
252 return (mgr_map[major(dev)] == NULL ? EBADF
253 : mgr_map[major(dev)]->do_cdev_read(dev, uio, ioflag));
257 tuntap_manager::cdev_write(dev_t dev, uio_t uio, int ioflag)
259 return (mgr_map[major(dev)] == NULL ? EBADF
260 : mgr_map[major(dev)]->do_cdev_write(dev, uio, ioflag));
264 tuntap_manager::cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, proc_t p)
266 return (mgr_map[major(dev)] == NULL ? EBADF
267 : mgr_map[major(dev)]->do_cdev_ioctl(dev, cmd, data, fflag, p));
271 tuntap_manager::cdev_select(dev_t dev, int which, void *wql, proc_t p)
273 return (mgr_map[major(dev)] == NULL ? EBADF
274 : mgr_map[major(dev)]->do_cdev_select(dev, which, wql, p));
277 /* character device service methods */
279 tuntap_manager::do_cdev_open(dev_t dev, int flags, int devtype, proc_t p)
281 int dmin = minor(dev);
282 int error = ENOENT;
284 cdev_gate.enter();
286 if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
287 error = tuntaps[dmin]->cdev_open(flags, devtype, p);
289 cdev_gate.exit();
291 return error;
295 tuntap_manager::do_cdev_close(dev_t dev, int flags, int devtype, proc_t p)
297 int dmin = minor(dev);
298 int error = EBADF;
300 cdev_gate.enter();
302 if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
303 error = tuntaps[dmin]->cdev_close(flags, devtype, p);
305 cdev_gate.exit();
307 return error;
311 tuntap_manager::do_cdev_read(dev_t dev, uio_t uio, int ioflag)
313 int dmin = minor(dev);
314 int error = EBADF;
316 cdev_gate.enter();
318 if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
319 error = tuntaps[dmin]->cdev_read(uio, ioflag);
321 cdev_gate.exit();
323 return error;
327 tuntap_manager::do_cdev_write(dev_t dev, uio_t uio, int ioflag)
329 int dmin = minor(dev);
330 int error = EBADF;
332 cdev_gate.enter();
334 if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
335 error = tuntaps[dmin]->cdev_write(uio, ioflag);
337 cdev_gate.exit();
339 return error;
343 tuntap_manager::do_cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, proc_t p)
345 int dmin = minor(dev);
346 int error = EBADF;
348 cdev_gate.enter();
350 if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
351 error = tuntaps[dmin]->cdev_ioctl(cmd, data, fflag, p);
353 cdev_gate.exit();
355 return error;
359 tuntap_manager::do_cdev_select(dev_t dev, int which, void *wql, proc_t p)
361 int dmin = minor(dev);
362 int error = EBADF;
364 cdev_gate.enter();
366 if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
367 error = tuntaps[dmin]->cdev_select(which, wql, p);
369 cdev_gate.exit();
371 return error;