kernel - Major bridging functionality completed
[dragonfly.git] / sys / net / tap / if_tap.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * BASED ON:
27 * -------------------------------------------------------------------------
28 *
29 * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
30 * Nottingham University 1987.
31 */
32
33/*
34 * $FreeBSD: src/sys/net/if_tap.c,v 1.3.2.3 2002/04/14 21:41:48 luigi Exp $
35 * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
36 */
37
38#include "opt_inet.h"
39
40#include <sys/param.h>
41#include <sys/conf.h>
fef8985e 42#include <sys/device.h>
984263bc
MD
43#include <sys/filedesc.h>
44#include <sys/filio.h>
45#include <sys/kernel.h>
46#include <sys/malloc.h>
47#include <sys/mbuf.h>
984263bc 48#include <sys/proc.h>
895c1f85 49#include <sys/priv.h>
984263bc
MD
50#include <sys/signalvar.h>
51#include <sys/socket.h>
52#include <sys/sockio.h>
53#include <sys/sysctl.h>
54#include <sys/systm.h>
55#include <sys/ttycom.h>
56#include <sys/uio.h>
57#include <sys/vnode.h>
78195a76 58#include <sys/serialize.h>
984263bc 59
684a93c4
MD
60#include <sys/thread2.h>
61#include <sys/mplock2.h>
62
984263bc
MD
63#include <net/bpf.h>
64#include <net/ethernet.h>
65#include <net/if.h>
2e558ed2 66#include <net/ifq_var.h>
984263bc 67#include <net/if_arp.h>
3cde3b9d 68#include <net/if_clone.h>
70d9a675 69#include <net/if_media.h>
984263bc 70#include <net/route.h>
2c1e28dd 71#include <sys/devfs.h>
984263bc
MD
72
73#include <netinet/in.h>
74
1f2de5d4
MD
75#include "if_tapvar.h"
76#include "if_tap.h"
984263bc 77
ca848e13 78#define TAP_IFFLAGS (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST)
984263bc 79
3c477c79
MD
80#define TAP_PREALLOCATED_UNITS 4
81
984263bc 82#define CDEV_NAME "tap"
dccb6d9c 83#define TAPDEBUG if (tapdebug) if_printf
984263bc
MD
84
85#define TAP "tap"
86#define VMNET "vmnet"
87#define VMNET_DEV_MASK 0x00010000
88
8be7edad
MD
89DEVFS_DECLARE_CLONE_BITMAP(tap);
90
984263bc 91/* module */
158abb01 92static int tapmodevent (module_t, int, void *);
984263bc
MD
93
94/* device */
3c477c79 95static struct tap_softc *tapcreate(int, cdev_t);
3cde3b9d
SZ
96static void tapdestroy(struct tap_softc *);
97
98/* clone */
d14ef41e 99static int tap_clone_create(struct if_clone *, int, caddr_t);
a7e9152e 100static int tap_clone_destroy(struct ifnet *);
3cde3b9d 101
984263bc
MD
102
103/* network interface */
158abb01 104static void tapifstart (struct ifnet *);
bd4539cc
JH
105static int tapifioctl (struct ifnet *, u_long, caddr_t,
106 struct ucred *);
158abb01 107static void tapifinit (void *);
7fbd95bc 108static void tapifstop(struct tap_softc *, int);
3cde3b9d 109static void tapifflags(struct tap_softc *);
984263bc 110
70d9a675 111
984263bc
MD
112/* character device */
113static d_open_t tapopen;
8be7edad 114static d_clone_t tapclone;
984263bc
MD
115static d_close_t tapclose;
116static d_read_t tapread;
117static d_write_t tapwrite;
118static d_ioctl_t tapioctl;
9e53850c 119static d_kqfilter_t tapkqfilter;
984263bc 120
fef8985e 121static struct dev_ops tap_ops = {
88abd8b5 122 { CDEV_NAME, 0, 0 },
fef8985e
MD
123 .d_open = tapopen,
124 .d_close = tapclose,
125 .d_read = tapread,
126 .d_write = tapwrite,
127 .d_ioctl = tapioctl,
9e53850c 128 .d_kqfilter = tapkqfilter
984263bc
MD
129};
130
131static int taprefcnt = 0; /* module ref. counter */
132static int taplastunit = -1; /* max. open unit number */
133static int tapdebug = 0; /* debug flag */
3cde3b9d
SZ
134static int tapuopen = 0; /* all user open() */
135static int tapuponopen = 0; /* IFF_UP */
984263bc
MD
136
137MALLOC_DECLARE(M_TAP);
138MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
3cde3b9d
SZ
139struct if_clone tap_cloner = IF_CLONE_INITIALIZER("tap",
140 tap_clone_create, tap_clone_destroy,
141 0, IF_MAXUNIT);
142static SLIST_HEAD(,tap_softc) tap_listhead =
143 SLIST_HEAD_INITIALIZER(&tap_listhead);
144
984263bc 145SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
3cde3b9d
SZ
146SYSCTL_DECL(_net_link);
147SYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
148 "Ethernet tunnel software network interface");
149SYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
150 "Allow user to open /dev/tap (based on node permissions)");
151SYSCTL_INT(_net_link_tap, OID_AUTO, up_on_open, CTLFLAG_RW, &tapuponopen, 0,
152 "Bring interface up when /dev/tap is opened");
153SYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
154
984263bc
MD
155DEV_MODULE(if_tap, tapmodevent, NULL);
156
157/*
158 * tapmodevent
159 *
160 * module event handler
161 */
162static int
bf8c57c6 163tapmodevent(module_t mod, int type, void *data)
984263bc 164{
3cde3b9d
SZ
165 static int attached = 0;
166 struct tap_softc *tp, *ntp;
3c477c79 167 int i;
984263bc
MD
168
169 switch (type) {
170 case MOD_LOAD:
171 if (attached)
172 return (EEXIST);
173
3c477c79
MD
174 make_autoclone_dev(&tap_ops, &DEVFS_CLONE_BITMAP(tap), tapclone,
175 UID_ROOT, GID_WHEEL, 0600, "tap");
3cde3b9d
SZ
176 SLIST_INIT(&tap_listhead);
177 if_clone_attach(&tap_cloner);
178
3c477c79
MD
179 for (i = 0; i < TAP_PREALLOCATED_UNITS; ++i) {
180 make_dev(&tap_ops, i, UID_ROOT, GID_WHEEL,
181 0600, "tap%d", i);
182 devfs_clone_bitmap_set(&DEVFS_CLONE_BITMAP(tap), i);
183 }
184
984263bc 185 attached = 1;
7fbd95bc 186 break;
984263bc
MD
187
188 case MOD_UNLOAD:
189 if (taprefcnt > 0)
190 return (EBUSY);
191
3cde3b9d 192 if_clone_detach(&tap_cloner);
984263bc 193
3cde3b9d
SZ
194 /* Maintain tap ifs in a local list */
195 SLIST_FOREACH_MUTABLE(tp, &tap_listhead, tap_link, ntp)
196 tapdestroy(tp);
984263bc 197
984263bc 198 attached = 0;
8be7edad
MD
199
200 devfs_clone_handler_del("tap");
201 dev_ops_remove_all(&tap_ops);
202 devfs_clone_bitmap_uninit(&DEVFS_CLONE_BITMAP(tap));
7fbd95bc 203 break;
984263bc
MD
204
205 default:
206 return (EOPNOTSUPP);
207 }
208
209 return (0);
210} /* tapmodevent */
211
212
213/*
3c477c79 214 * tapcreate - create or clone an interface
984263bc 215 */
3c477c79
MD
216static struct tap_softc *
217tapcreate(int unit, cdev_t dev)
984263bc 218{
3c477c79
MD
219 const char *name = TAP;
220 struct ifnet *ifp;
221 struct tap_softc *tp;
222 uint8_t ether_addr[ETHER_ADDR_LEN];
984263bc 223
3c477c79
MD
224 tp = kmalloc(sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
225 dev->si_drv1 = tp;
226 tp->tap_dev = dev;
227 tp->tap_unit = unit;
228
229 reference_dev(dev); /* tp association */
984263bc
MD
230
231 /* generate fake MAC address: 00 bd xx xx xx unit_no */
0a8b5977
JS
232 ether_addr[0] = 0x00;
233 ether_addr[1] = 0xbd;
d869938c 234 bcopy(&ticks, &ether_addr[2], 3);
0a8b5977 235 ether_addr[5] = (u_char)unit;
984263bc
MD
236
237 /* fill the rest and attach interface */
238 ifp = &tp->tap_if;
239 ifp->if_softc = tp;
240
3e4a09e7 241 if_initname(ifp, name, unit);
984263bc
MD
242 if (unit > taplastunit)
243 taplastunit = unit;
244
984263bc 245 ifp->if_init = tapifinit;
984263bc
MD
246 ifp->if_start = tapifstart;
247 ifp->if_ioctl = tapifioctl;
248 ifp->if_mtu = ETHERMTU;
ca848e13 249 ifp->if_flags = TAP_IFFLAGS;
2e558ed2
JS
250 ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
251 ifq_set_ready(&ifp->if_snd);
984263bc 252
78195a76 253 ether_ifattach(ifp, ether_addr, NULL);
984263bc
MD
254
255 tp->tap_flags |= TAP_INITED;
7fbd95bc 256 tp->tap_devq.ifq_maxlen = ifqmaxlen;
984263bc 257
3cde3b9d
SZ
258 SLIST_INSERT_HEAD(&tap_listhead, tp, tap_link);
259
3c477c79
MD
260 TAPDEBUG(ifp, "created. minor = %#x\n", minor(dev));
261 return (tp);
262}
263
264static
265struct tap_softc *
266tapfind(int unit)
267{
268 struct tap_softc *tp;
269
270 SLIST_FOREACH(tp, &tap_listhead, tap_link) {
271 if (tp->tap_unit == unit)
272 return(tp);
273 }
274 return (NULL);
275}
984263bc 276
3cde3b9d
SZ
277/*
278 * tap_clone_create:
279 *
3c477c79 280 * Create a new tap instance via ifconfig.
3cde3b9d
SZ
281 */
282static int
d14ef41e
RP
283tap_clone_create(struct if_clone *ifc __unused, int unit,
284 caddr_t param __unused)
3cde3b9d 285{
3c477c79 286 struct tap_softc *tp;
3cde3b9d 287 cdev_t dev;
3cde3b9d 288
3c477c79
MD
289 tp = tapfind(unit);
290 if (tp == NULL) {
527e4a21
AH
291 if (!devfs_clone_bitmap_chk(&DEVFS_CLONE_BITMAP(tap), unit)) {
292 devfs_clone_bitmap_set(&DEVFS_CLONE_BITMAP(tap), unit);
293 dev = make_dev(&tap_ops, unit, UID_ROOT, GID_WHEEL,
294 0600, "%s%d", TAP, unit);
295 } else {
296 dev = devfs_find_device_by_name("%s%d", TAP, unit);
297 }
298
299 KKASSERT(dev != NULL);
3c477c79
MD
300 tp = tapcreate(unit, dev);
301 }
3cde3b9d
SZ
302 tp->tap_flags |= TAP_CLONE;
303 TAPDEBUG(&tp->tap_if, "clone created. minor = %#x tap_flags = 0x%x\n",
304 minor(tp->tap_dev), tp->tap_flags);
305
306 return (0);
307}
984263bc
MD
308
309/*
310 * tapopen
311 *
312 * to open tunnel. must be superuser
313 */
314static int
fef8985e 315tapopen(struct dev_open_args *ap)
984263bc 316{
3cde3b9d 317 cdev_t dev = NULL;
ebee7c7f
SZ
318 struct tap_softc *tp = NULL;
319 struct ifnet *ifp = NULL;
320 int error;
41c20dac 321
3cde3b9d
SZ
322 if (tapuopen == 0 &&
323 (error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) != 0)
984263bc
MD
324 return (error);
325
da1d0ef7 326 get_mplock();
3cde3b9d 327 dev = ap->a_head.a_dev;
984263bc 328 tp = dev->si_drv1;
3c477c79
MD
329 if (tp == NULL)
330 tp = tapcreate(minor(dev), dev);
331 if (tp->tap_flags & TAP_OPEN) {
332 rel_mplock();
333 return (EBUSY);
334 }
335 ifp = &tp->arpcom.ac_if;
ebee7c7f 336
3c477c79
MD
337 if ((tp->tap_flags & TAP_CLONE) == 0) {
338 EVENTHANDLER_INVOKE(ifnet_attach_event, ifp);
ebee7c7f 339
3c477c79
MD
340 /* Announce the return of the interface. */
341 rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
984263bc
MD
342 }
343
984263bc
MD
344 bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
345
6be00a6c
MD
346 if (curthread->td_proc)
347 fsetown(curthread->td_proc->p_pid, &tp->tap_sigtd);
984263bc
MD
348 tp->tap_flags |= TAP_OPEN;
349 taprefcnt ++;
350
3cde3b9d
SZ
351 if (tapuponopen && (ifp->if_flags & IFF_UP) == 0) {
352 crit_enter();
353 if_up(ifp);
354 crit_exit();
355
356 ifnet_serialize_all(ifp);
357 tapifflags(tp);
358 ifnet_deserialize_all(ifp);
ca848e13
SZ
359
360 tp->tap_flags |= TAP_CLOSEDOWN;
3cde3b9d
SZ
361 }
362
ebee7c7f 363 TAPDEBUG(ifp, "opened. minor = %#x, refcnt = %d, taplastunit = %d\n",
dccb6d9c 364 minor(tp->tap_dev), taprefcnt, taplastunit);
984263bc 365
da1d0ef7 366 rel_mplock();
984263bc 367 return (0);
da1d0ef7 368}
984263bc 369
8be7edad
MD
370static int
371tapclone(struct dev_clone_args *ap)
372{
373 int unit;
374
375 unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(tap), 0);
3c477c79
MD
376 ap->a_dev = make_only_dev(&tap_ops, unit, UID_ROOT, GID_WHEEL,
377 0600, "%s%d", TAP, unit);
378 tapcreate(unit, ap->a_dev);
8be7edad
MD
379 return (0);
380}
984263bc
MD
381
382/*
383 * tapclose
384 *
385 * close the device - mark i/f down & delete routing info
386 */
387static int
fef8985e 388tapclose(struct dev_close_args *ap)
984263bc 389{
b13267a5 390 cdev_t dev = ap->a_head.a_dev;
5f9a4b8e
SZ
391 struct tap_softc *tp = dev->si_drv1;
392 struct ifnet *ifp = &tp->tap_if;
ca848e13 393 int clear_flags = 0;
984263bc 394
da1d0ef7 395 get_mplock();
ca848e13
SZ
396
397 /* Junk all pending output */
2e558ed2 398 ifq_purge(&ifp->if_snd);
984263bc
MD
399
400 /*
ca848e13 401 * Do not bring the interface down, and do not anything with
984263bc 402 * interface, if we are in VMnet mode. just close the device.
ca848e13
SZ
403 *
404 * If the interface is not cloned, we always bring it down.
405 *
406 * If the interface is cloned, then we bring it down during
407 * closing only if it was brought up during opening.
984263bc 408 */
ca848e13
SZ
409 if ((tp->tap_flags & TAP_VMNET) == 0 &&
410 ((tp->tap_flags & TAP_CLONE) == 0 ||
411 (tp->tap_flags & TAP_CLOSEDOWN))) {
7fbd95bc 412 if (ifp->if_flags & IFF_UP)
c727e142 413 if_down(ifp);
5f9a4b8e 414 clear_flags = 1;
984263bc 415 }
a3dd34d2 416 ifnet_serialize_all(ifp);
7fbd95bc 417 tapifstop(tp, clear_flags);
a3dd34d2 418 ifnet_deserialize_all(ifp);
7fbd95bc 419
3cde3b9d
SZ
420 if ((tp->tap_flags & TAP_CLONE) == 0) {
421 if_purgeaddrs_nolink(ifp);
c727e142 422
3cde3b9d 423 EVENTHANDLER_INVOKE(ifnet_detach_event, ifp);
c727e142 424
3cde3b9d
SZ
425 /* Announce the departure of the interface. */
426 rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
427 }
984263bc 428
58c2553a 429 funsetown(&tp->tap_sigio);
6be00a6c 430 tp->tap_sigio = NULL;
5b22f1a7 431 KNOTE(&tp->tap_rkq.ki_note, 0);
984263bc
MD
432
433 tp->tap_flags &= ~TAP_OPEN;
58c2553a 434 funsetown(&tp->tap_sigtd);
6be00a6c 435 tp->tap_sigtd = NULL;
984263bc
MD
436
437 taprefcnt --;
438 if (taprefcnt < 0) {
439 taprefcnt = 0;
dccb6d9c
JS
440 if_printf(ifp, "minor = %#x, refcnt = %d is out of sync. "
441 "set refcnt to 0\n", minor(tp->tap_dev), taprefcnt);
984263bc
MD
442 }
443
dccb6d9c
JS
444 TAPDEBUG(ifp, "closed. minor = %#x, refcnt = %d, taplastunit = %d\n",
445 minor(tp->tap_dev), taprefcnt, taplastunit);
984263bc 446
3c477c79 447 if (tp->tap_unit >= TAP_PREALLOCATED_UNITS)
3cde3b9d 448 tapdestroy(tp);
3cde3b9d 449
da1d0ef7 450 rel_mplock();
984263bc 451 return (0);
da1d0ef7 452}
984263bc 453
3cde3b9d
SZ
454/*
455 * tapdestroy:
456 *
457 * Destroy a tap instance.
458 */
459static void
460tapdestroy(struct tap_softc *tp)
461{
462 struct ifnet *ifp = &tp->arpcom.ac_if;
3c477c79 463 cdev_t dev;
3cde3b9d
SZ
464
465 TAPDEBUG(ifp, "destroyed. minor = %#x, refcnt = %d, taplastunit = %d\n",
466 minor(tp->tap_dev), taprefcnt, taplastunit);
467
468 ifnet_serialize_all(ifp);
469 tapifstop(tp, 1);
470 ifnet_deserialize_all(ifp);
471
472 ether_ifdetach(ifp);
473 SLIST_REMOVE(&tap_listhead, tp, tap_softc, tap_link);
474
3c477c79
MD
475 dev = tp->tap_dev;
476 tp->tap_dev = NULL;
477 dev->si_drv1 = NULL;
478
479 release_dev(dev); /* tp association */
480
481 /*
482 * Also destroy the cloned device
483 */
484 if (tp->tap_unit >= TAP_PREALLOCATED_UNITS) {
485 destroy_dev(dev);
486 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(tap), tp->tap_unit);
487 }
488
3cde3b9d
SZ
489 kfree(tp, M_TAP);
490
491 taplastunit--;
492}
493
494/*
495 * tap_clone_destroy:
496 *
497 * Destroy a tap instance.
498 */
a7e9152e 499static int
3cde3b9d
SZ
500tap_clone_destroy(struct ifnet *ifp)
501{
502 struct tap_softc *tp = ifp->if_softc;
503
a7e9152e
SZ
504 if ((tp->tap_flags & TAP_CLONE) == 0)
505 return ENXIO;
506
3cde3b9d
SZ
507 TAPDEBUG(&tp->tap_if, "clone destroyed. minor = %#x tap_flags = 0x%x\n",
508 minor(tp->tap_dev), tp->tap_flags);
a7e9152e
SZ
509 tapdestroy(tp);
510
511 return 0;
3cde3b9d 512}
984263bc
MD
513
514/*
515 * tapifinit
516 *
da1d0ef7
MD
517 * Network interface initialization function (called with if serializer held)
518 *
519 * MPSAFE
984263bc
MD
520 */
521static void
bf8c57c6 522tapifinit(void *xtp)
984263bc 523{
7fbd95bc
SZ
524 struct tap_softc *tp = xtp;
525 struct ifnet *ifp = &tp->tap_if;
984263bc 526
3cde3b9d
SZ
527 TAPDEBUG(ifp, "initializing, minor = %#x tap_flags = 0x%x\n",
528 minor(tp->tap_dev), tp->tap_flags);
984263bc 529
2c9effcf 530 ASSERT_IFNET_SERIALIZED_ALL(ifp);
7fbd95bc
SZ
531
532 tapifstop(tp, 1);
533
984263bc
MD
534 ifp->if_flags |= IFF_RUNNING;
535 ifp->if_flags &= ~IFF_OACTIVE;
536
537 /* attempt to start output */
538 tapifstart(ifp);
da1d0ef7 539}
984263bc
MD
540
541
542/*
543 * tapifioctl
544 *
da1d0ef7
MD
545 * Process an ioctl request on network interface (called with if serializer
546 * held).
78195a76
MD
547 *
548 * MPSAFE
984263bc 549 */
e6709a6e 550static int
bf8c57c6 551tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
984263bc
MD
552{
553 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc);
554 struct ifstat *ifs = NULL;
70d9a675
MD
555 struct ifmediareq *ifmr = NULL;
556 int error = 0;
557 int dummy;
984263bc
MD
558
559 switch (cmd) {
560 case SIOCSIFADDR:
561 case SIOCGIFADDR:
562 case SIOCSIFMTU:
70d9a675
MD
563 error = ether_ioctl(ifp, cmd, data);
564 break;
984263bc 565
ebee7c7f 566 case SIOCSIFFLAGS:
3cde3b9d 567 tapifflags(tp);
ebee7c7f 568 break;
3cde3b9d 569
ebee7c7f 570 case SIOCADDMULTI: /* XXX -- just like vmnet does */
984263bc 571 case SIOCDELMULTI:
5f3366c7 572 break;
984263bc 573
70d9a675
MD
574 case SIOCGIFMEDIA:
575 /*
576 * The bridge code needs this when running the
577 * spanning tree protocol.
578 */
579 ifmr = (struct ifmediareq *)data;
580 dummy = ifmr->ifm_count;
581 ifmr->ifm_count = 1;
582 ifmr->ifm_status = IFM_AVALID;
583 ifmr->ifm_active = IFM_ETHER;
584 if (tp->tap_flags & TAP_OPEN)
585 ifmr->ifm_status |= IFM_ACTIVE;
586 ifmr->ifm_current = ifmr->ifm_active;
587 if (dummy >= 1) {
588 int media = IFM_ETHER;
589 error = copyout(&media,
590 ifmr->ifm_ulist,
591 sizeof(int));
592 }
593 break;
594
984263bc 595 case SIOCGIFSTATUS:
984263bc
MD
596 ifs = (struct ifstat *)data;
597 dummy = strlen(ifs->ascii);
6be00a6c
MD
598 if ((tp->tap_flags & TAP_OPEN) &&
599 dummy < sizeof(ifs->ascii)) {
600 if (tp->tap_sigtd && tp->tap_sigtd->sio_proc) {
f8c7a42d 601 ksnprintf(ifs->ascii + dummy,
984263bc 602 sizeof(ifs->ascii) - dummy,
dadab5e9 603 "\tOpened by pid %d\n",
6be00a6c 604 (int)tp->tap_sigtd->sio_proc->p_pid);
dadab5e9 605 } else {
f8c7a42d 606 ksnprintf(ifs->ascii + dummy,
dadab5e9 607 sizeof(ifs->ascii) - dummy,
6be00a6c 608 "\tOpened by <unknown>\n");
dadab5e9
MD
609 }
610 }
5f3366c7 611 break;
984263bc
MD
612
613 default:
70d9a675
MD
614 error = EINVAL;
615 break;
984263bc
MD
616 }
617
70d9a675 618 return (error);
da1d0ef7 619}
984263bc
MD
620
621
622/*
623 * tapifstart
624 *
da1d0ef7
MD
625 * Queue packets from higher level ready to put out (called with if serializer
626 * held)
627 *
628 * MPSAFE
984263bc
MD
629 */
630static void
bf8c57c6 631tapifstart(struct ifnet *ifp)
984263bc 632{
7fbd95bc
SZ
633 struct tap_softc *tp = ifp->if_softc;
634 struct ifqueue *ifq;
635 struct mbuf *m;
636 int has_data = 0;
984263bc 637
dccb6d9c 638 TAPDEBUG(ifp, "starting, minor = %#x\n", minor(tp->tap_dev));
984263bc
MD
639
640 /*
641 * do not junk pending output if we are in VMnet mode.
642 * XXX: can this do any harm because of queue overflow?
643 */
644
645 if (((tp->tap_flags & TAP_VMNET) == 0) &&
646 ((tp->tap_flags & TAP_READY) != TAP_READY)) {
dccb6d9c
JS
647 TAPDEBUG(ifp, "not ready. minor = %#x, tap_flags = 0x%x\n",
648 minor(tp->tap_dev), tp->tap_flags);
2e558ed2 649 ifq_purge(&ifp->if_snd);
984263bc
MD
650 return;
651 }
652
984263bc
MD
653 ifp->if_flags |= IFF_OACTIVE;
654
7fbd95bc
SZ
655 ifq = &tp->tap_devq;
656 while ((m = ifq_dequeue(&ifp->if_snd, NULL)) != NULL) {
657 if (IF_QFULL(ifq)) {
658 IF_DROP(ifq);
659 ifp->if_oerrors++;
660 m_freem(m);
661 } else {
662 IF_ENQUEUE(ifq, m);
663 ifp->if_opackets++;
664 has_data = 1;
665 }
666 }
667
668 if (has_data) {
984263bc
MD
669 if (tp->tap_flags & TAP_RWAIT) {
670 tp->tap_flags &= ~TAP_RWAIT;
671 wakeup((caddr_t)tp);
672 }
dba32900 673
5b22f1a7 674 KNOTE(&tp->tap_rkq.ki_note, 0);
984263bc 675
da1d0ef7
MD
676 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
677 get_mplock();
984263bc 678 pgsigio(tp->tap_sigio, SIGIO, 0);
da1d0ef7
MD
679 rel_mplock();
680 }
984263bc
MD
681 }
682
683 ifp->if_flags &= ~IFF_OACTIVE;
da1d0ef7 684}
984263bc
MD
685
686
687/*
688 * tapioctl
689 *
da1d0ef7
MD
690 * The ops interface is now pretty minimal. Called via fileops with nothing
691 * held.
692 *
693 * MPSAFE
984263bc
MD
694 */
695static int
fef8985e 696tapioctl(struct dev_ioctl_args *ap)
984263bc 697{
b13267a5 698 cdev_t dev = ap->a_head.a_dev;
fef8985e 699 caddr_t data = ap->a_data;
984263bc
MD
700 struct tap_softc *tp = dev->si_drv1;
701 struct ifnet *ifp = &tp->tap_if;
702 struct tapinfo *tapp = NULL;
2e558ed2 703 struct mbuf *mb;
78195a76
MD
704 short f;
705 int error;
706
a3dd34d2 707 ifnet_serialize_all(ifp);
78195a76 708 error = 0;
984263bc 709
fef8985e 710 switch (ap->a_cmd) {
78195a76
MD
711 case TAPSIFINFO:
712 tapp = (struct tapinfo *)data;
713 ifp->if_mtu = tapp->mtu;
714 ifp->if_type = tapp->type;
715 ifp->if_baudrate = tapp->baudrate;
984263bc
MD
716 break;
717
78195a76
MD
718 case TAPGIFINFO:
719 tapp = (struct tapinfo *)data;
720 tapp->mtu = ifp->if_mtu;
721 tapp->type = ifp->if_type;
722 tapp->baudrate = ifp->if_baudrate;
984263bc
MD
723 break;
724
78195a76
MD
725 case TAPSDEBUG:
726 tapdebug = *(int *)data;
984263bc
MD
727 break;
728
78195a76
MD
729 case TAPGDEBUG:
730 *(int *)data = tapdebug;
984263bc
MD
731 break;
732
78195a76
MD
733 case FIOASYNC:
734 if (*(int *)data)
735 tp->tap_flags |= TAP_ASYNC;
736 else
737 tp->tap_flags &= ~TAP_ASYNC;
738 break;
984263bc 739
78195a76
MD
740 case FIONREAD:
741 *(int *)data = 0;
7fbd95bc
SZ
742
743 /* Take a look at devq first */
744 IF_POLL(&tp->tap_devq, mb);
745 if (mb == NULL)
746 mb = ifq_poll(&ifp->if_snd);
747
748 if (mb != NULL) {
78195a76
MD
749 for(; mb != NULL; mb = mb->m_next)
750 *(int *)data += mb->m_len;
751 }
752 break;
984263bc 753
78195a76
MD
754 case FIOSETOWN:
755 error = fsetown(*(int *)data, &tp->tap_sigio);
756 break;
984263bc 757
78195a76 758 case FIOGETOWN:
b5c4d81f 759 *(int *)data = fgetown(&tp->tap_sigio);
78195a76 760 break;
984263bc 761
78195a76
MD
762 /* this is deprecated, FIOSETOWN should be used instead */
763 case TIOCSPGRP:
764 error = fsetown(-(*(int *)data), &tp->tap_sigio);
765 break;
984263bc 766
78195a76
MD
767 /* this is deprecated, FIOGETOWN should be used instead */
768 case TIOCGPGRP:
b5c4d81f 769 *(int *)data = -fgetown(&tp->tap_sigio);
984263bc
MD
770 break;
771
78195a76 772 /* VMware/VMnet port ioctl's */
984263bc 773
78195a76
MD
774 case SIOCGIFFLAGS: /* get ifnet flags */
775 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
776 break;
984263bc 777
78195a76
MD
778 case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
779 f = *(short *)data;
780 f &= 0x0fff;
781 f &= ~IFF_CANTCHANGE;
782 f |= IFF_UP;
783 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
784 break;
984263bc 785
78195a76
MD
786 case OSIOCGIFADDR: /* get MAC address of the remote side */
787 case SIOCGIFADDR:
788 bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
984263bc
MD
789 break;
790
78195a76
MD
791 case SIOCSIFADDR: /* set MAC address of the remote side */
792 bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
984263bc
MD
793 break;
794
78195a76
MD
795 default:
796 error = ENOTTY;
797 break;
984263bc 798 }
a3dd34d2 799 ifnet_deserialize_all(ifp);
78195a76 800 return (error);
da1d0ef7 801}
984263bc
MD
802
803
804/*
805 * tapread
806 *
da1d0ef7
MD
807 * The ops read interface - reads a packet at a time, or at
808 * least as much of a packet as can be read.
809 *
810 * Called from the fileops interface with nothing held.
811 *
812 * MPSAFE
984263bc
MD
813 */
814static int
fef8985e 815tapread(struct dev_read_args *ap)
984263bc 816{
b13267a5 817 cdev_t dev = ap->a_head.a_dev;
fef8985e 818 struct uio *uio = ap->a_uio;
984263bc
MD
819 struct tap_softc *tp = dev->si_drv1;
820 struct ifnet *ifp = &tp->tap_if;
821 struct mbuf *m0 = NULL;
5f3366c7 822 int error = 0, len;
984263bc 823
dccb6d9c 824 TAPDEBUG(ifp, "reading, minor = %#x\n", minor(tp->tap_dev));
984263bc
MD
825
826 if ((tp->tap_flags & TAP_READY) != TAP_READY) {
dccb6d9c
JS
827 TAPDEBUG(ifp, "not ready. minor = %#x, tap_flags = 0x%x\n",
828 minor(tp->tap_dev), tp->tap_flags);
984263bc
MD
829
830 return (EHOSTDOWN);
831 }
832
833 tp->tap_flags &= ~TAP_RWAIT;
834
835 /* sleep until we get a packet */
836 do {
a3dd34d2 837 ifnet_serialize_all(ifp);
7fbd95bc 838 IF_DEQUEUE(&tp->tap_devq, m0);
984263bc 839 if (m0 == NULL) {
fef8985e 840 if (ap->a_ioflag & IO_NDELAY) {
a3dd34d2 841 ifnet_deserialize_all(ifp);
2775434d
SS
842 return (EWOULDBLOCK);
843 }
78195a76 844 tp->tap_flags |= TAP_RWAIT;
ae8e83e6 845 tsleep_interlock(tp, PCATCH);
a3dd34d2 846 ifnet_deserialize_all(ifp);
d9345d3a 847 error = tsleep(tp, PCATCH | PINTERLOCKED, "taprd", 0);
984263bc
MD
848 if (error)
849 return (error);
78195a76 850 } else {
a3dd34d2 851 ifnet_deserialize_all(ifp);
984263bc
MD
852 }
853 } while (m0 == NULL);
854
7600679e 855 BPF_MTAP(ifp, m0);
984263bc
MD
856
857 /* xfer packet to user space */
858 while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) {
e54488bb 859 len = (int)szmin(uio->uio_resid, m0->m_len);
984263bc
MD
860 if (len == 0)
861 break;
862
e54488bb 863 error = uiomove(mtod(m0, caddr_t), (size_t)len, uio);
984263bc
MD
864 m0 = m_free(m0);
865 }
866
867 if (m0 != NULL) {
dccb6d9c
JS
868 TAPDEBUG(ifp, "dropping mbuf, minor = %#x\n",
869 minor(tp->tap_dev));
984263bc
MD
870 m_freem(m0);
871 }
872
873 return (error);
da1d0ef7 874}
984263bc
MD
875
876/*
877 * tapwrite
878 *
da1d0ef7
MD
879 * The ops write interface - an atomic write is a packet - or else!
880 *
881 * Called from the fileops interface with nothing held.
882 *
883 * MPSAFE
984263bc
MD
884 */
885static int
fef8985e 886tapwrite(struct dev_write_args *ap)
984263bc 887{
b13267a5 888 cdev_t dev = ap->a_head.a_dev;
fef8985e 889 struct uio *uio = ap->a_uio;
984263bc
MD
890 struct tap_softc *tp = dev->si_drv1;
891 struct ifnet *ifp = &tp->tap_if;
892 struct mbuf *top = NULL, **mp = NULL, *m = NULL;
e54488bb
MD
893 int error = 0;
894 size_t tlen, mlen;
984263bc 895
84982e90 896 TAPDEBUG(ifp, "writing, minor = %#x\n", minor(tp->tap_dev));
984263bc 897
3cde3b9d
SZ
898 if ((tp->tap_flags & TAP_READY) != TAP_READY) {
899 TAPDEBUG(ifp, "not ready. minor = %#x, tap_flags = 0x%x\n",
900 minor(tp->tap_dev), tp->tap_flags);
901 return (EHOSTDOWN);
902 }
903
984263bc
MD
904 if (uio->uio_resid == 0)
905 return (0);
906
e54488bb 907 if (uio->uio_resid > TAPMRU) {
d557216f 908 TAPDEBUG(ifp, "invalid packet len = %zu, minor = %#x\n",
dccb6d9c 909 uio->uio_resid, minor(tp->tap_dev));
984263bc
MD
910
911 return (EIO);
912 }
913 tlen = uio->uio_resid;
914
915 /* get a header mbuf */
74f1caca 916 MGETHDR(m, MB_DONTWAIT, MT_DATA);
984263bc
MD
917 if (m == NULL)
918 return (ENOBUFS);
919 mlen = MHLEN;
920
921 top = 0;
922 mp = &top;
923 while ((error == 0) && (uio->uio_resid > 0)) {
e54488bb
MD
924 m->m_len = (int)szmin(mlen, uio->uio_resid);
925 error = uiomove(mtod(m, caddr_t), (size_t)m->m_len, uio);
984263bc
MD
926 *mp = m;
927 mp = &m->m_next;
928 if (uio->uio_resid > 0) {
74f1caca 929 MGET(m, MB_DONTWAIT, MT_DATA);
984263bc
MD
930 if (m == NULL) {
931 error = ENOBUFS;
932 break;
933 }
934 mlen = MLEN;
935 }
936 }
937 if (error) {
938 ifp->if_ierrors ++;
939 if (top)
940 m_freem(top);
941 return (error);
942 }
943
e54488bb 944 top->m_pkthdr.len = (int)tlen;
984263bc
MD
945 top->m_pkthdr.rcvif = ifp;
946
947 /*
948 * Ethernet bridge and bpf are handled in ether_input
949 *
950 * adjust mbuf and give packet to the ether_input
951 */
a3dd34d2 952 ifnet_serialize_all(ifp);
78195a76 953 ifp->if_input(ifp, top);
984263bc 954 ifp->if_ipackets ++; /* ibytes are counted in ether_input */
a3dd34d2 955 ifnet_deserialize_all(ifp);
984263bc
MD
956
957 return (0);
da1d0ef7 958}
984263bc
MD
959
960/*
da1d0ef7
MD
961 * tapkqfilter - called from the fileops interface with nothing held
962 *
963 * MPSAFE
964 */
9e53850c 965static int filt_tapread(struct knote *kn, long hint);
283dbecf 966static int filt_tapwrite(struct knote *kn, long hint);
9e53850c
MD
967static void filt_tapdetach(struct knote *kn);
968static struct filterops tapread_filtops =
4c91dbc9 969 { FILTEROP_ISFD, NULL, filt_tapdetach, filt_tapread };
283dbecf 970static struct filterops tapwrite_filtops =
4c91dbc9 971 { FILTEROP_ISFD, NULL, filt_tapdetach, filt_tapwrite };
9e53850c 972
e6709a6e 973static int
9e53850c
MD
974tapkqfilter(struct dev_kqfilter_args *ap)
975{
976 cdev_t dev = ap->a_head.a_dev;
977 struct knote *kn = ap->a_kn;
978 struct tap_softc *tp;
979 struct klist *list;
980 struct ifnet *ifp;
981
9e53850c 982 tp = dev->si_drv1;
5b22f1a7 983 list = &tp->tap_rkq.ki_note;
9e53850c
MD
984 ifp = &tp->tap_if;
985 ap->a_result =0;
986
987 switch(kn->kn_filter) {
988 case EVFILT_READ:
9e53850c
MD
989 kn->kn_fop = &tapread_filtops;
990 kn->kn_hook = (void *)tp;
991 break;
992 case EVFILT_WRITE:
283dbecf
SG
993 kn->kn_fop = &tapwrite_filtops;
994 kn->kn_hook = (void *)tp;
995 break;
9e53850c 996 default:
b287d649 997 ap->a_result = EOPNOTSUPP;
9e53850c
MD
998 return(0);
999 }
5b22f1a7
SG
1000
1001 knote_insert(list, kn);
9e53850c
MD
1002 return(0);
1003}
1004
1005static int
1006filt_tapread(struct knote *kn, long hint)
1007{
1008 struct tap_softc *tp = (void *)kn->kn_hook;
9e53850c 1009
7fbd95bc 1010 if (IF_QEMPTY(&tp->tap_devq) == 0) /* XXX serializer */
9e53850c 1011 return(1);
7fbd95bc 1012 else
9e53850c 1013 return(0);
9e53850c
MD
1014}
1015
283dbecf
SG
1016static int
1017filt_tapwrite(struct knote *kn, long hint)
1018{
1019 /* Always ready for a write */
1020 return (1);
1021}
1022
9e53850c
MD
1023static void
1024filt_tapdetach(struct knote *kn)
1025{
1026 struct tap_softc *tp = (void *)kn->kn_hook;
1027
5b22f1a7 1028 knote_remove(&tp->tap_rkq.ki_note, kn);
9e53850c 1029}
7fbd95bc
SZ
1030
1031static void
1032tapifstop(struct tap_softc *tp, int clear_flags)
1033{
1034 struct ifnet *ifp = &tp->tap_if;
1035
2c9effcf 1036 ASSERT_IFNET_SERIALIZED_ALL(ifp);
7fbd95bc 1037 IF_DRAIN(&tp->tap_devq);
ca848e13 1038 tp->tap_flags &= ~TAP_CLOSEDOWN;
7fbd95bc
SZ
1039 if (clear_flags)
1040 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1041}
3cde3b9d
SZ
1042
1043static void
1044tapifflags(struct tap_softc *tp)
1045{
1046 struct ifnet *ifp = &tp->arpcom.ac_if;
1047
1048 ASSERT_IFNET_SERIALIZED_ALL(ifp);
1049 if ((tp->tap_flags & TAP_VMNET) == 0) {
1050 /*
1051 * Only for non-vmnet tap(4)
1052 */
1053 if (ifp->if_flags & IFF_UP) {
1054 if ((ifp->if_flags & IFF_RUNNING) == 0)
1055 tapifinit(tp);
1056 } else {
1057 tapifstop(tp, 1);
1058 }
1059 } else {
1060 /* XXX */
1061 }
1062}