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