Deleted Added
full compact
if_tap.c (111119) if_tap.c (111741)
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/*
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: head/sys/net/if_tap.c 111119 2003-02-19 05:47:46Z imp $
34 * $FreeBSD: head/sys/net/if_tap.c 111741 2003-03-02 15:50:23Z des $
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>
42#include <sys/filedesc.h>
43#include <sys/filio.h>
44#include <sys/kernel.h>
45#include <sys/malloc.h>
46#include <sys/mbuf.h>
47#include <sys/poll.h>
48#include <sys/proc.h>
49#include <sys/signalvar.h>
50#include <sys/socket.h>
51#include <sys/sockio.h>
52#include <sys/sysctl.h>
53#include <sys/systm.h>
54#include <sys/ttycom.h>
55#include <sys/uio.h>
56#include <sys/vnode.h>
57#include <machine/bus.h> /* XXX: Shouldn't really be required! */
58#include <sys/rman.h>
59#include <sys/queue.h>
60
61#include <net/bpf.h>
62#include <net/ethernet.h>
63#include <net/if.h>
64#include <net/if_arp.h>
65#include <net/route.h>
66
67#include <netinet/in.h>
68
69#include <net/if_tapvar.h>
70#include <net/if_tap.h>
71
72
73#define CDEV_NAME "tap"
74#define CDEV_MAJOR 149
75#define TAPDEBUG if (tapdebug) printf
76
77#define TAP "tap"
78#define VMNET "vmnet"
79#define TAPMAXUNIT 0x7fff
80#define VMNET_DEV_MASK 0x00800000
81 /* 0x007f00ff */
82
83/* module */
84static int tapmodevent(module_t, int, void *);
85
86/* device */
87static void tapclone(void *, char *, int, dev_t *);
88static void tapcreate(dev_t);
89
90/* network interface */
91static void tapifstart(struct ifnet *);
92static int tapifioctl(struct ifnet *, u_long, caddr_t);
93static void tapifinit(void *);
94
95/* character device */
96static d_open_t tapopen;
97static d_close_t tapclose;
98static d_read_t tapread;
99static d_write_t tapwrite;
100static d_ioctl_t tapioctl;
101static d_poll_t tappoll;
102
103static struct cdevsw tap_cdevsw = {
104 /* open */ tapopen,
105 /* close */ tapclose,
106 /* read */ tapread,
107 /* write */ tapwrite,
108 /* ioctl */ tapioctl,
109 /* poll */ tappoll,
110 /* mmap */ nommap,
111 /* startegy */ nostrategy,
112 /* dev name */ CDEV_NAME,
113 /* dev major */ CDEV_MAJOR,
114 /* dump */ nodump,
115 /* psize */ nopsize,
116 /* flags */ 0,
117};
118
119static int tapdebug = 0; /* debug flag */
120static SLIST_HEAD(, tap_softc) taphead; /* first device */
121static udev_t tapbasedev = NOUDEV; /* base device */
122static struct rman tapdevunits[2]; /* device units */
123#define tapunits tapdevunits
124#define vmnetunits (tapdevunits + 1)
125
126MALLOC_DECLARE(M_TAP);
127MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
128SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
129DEV_MODULE(if_tap, tapmodevent, NULL);
130
131/*
132 * tapmodevent
133 *
134 * module event handler
135 */
136static int
137tapmodevent(mod, type, data)
138 module_t mod;
139 int type;
140 void *data;
141{
142 static eventhandler_tag eh_tag = NULL;
143 struct tap_softc *tp = NULL;
144 struct ifnet *ifp = NULL;
145 int error, s;
146
147 switch (type) {
148 case MOD_LOAD:
149 /* initialize resources */
150 tapunits->rm_type = RMAN_ARRAY;
151 tapunits->rm_descr = "open tap units";
152 vmnetunits->rm_type = RMAN_ARRAY;
153 vmnetunits->rm_descr = "open vmnet units";
154
155 error = rman_init(tapunits);
156 if (error != 0)
157 goto bail;
158
159 error = rman_init(vmnetunits);
160 if (error != 0)
161 goto bail1;
162
163 error = rman_manage_region(tapunits, 0, TAPMAXUNIT);
164 if (error != 0)
165 goto bail2;
166
167 error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT);
168 if (error != 0)
169 goto bail2;
170
171 /* intitialize device */
172
173 SLIST_INIT(&taphead);
174
175 eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
176 if (eh_tag == NULL) {
177 error = ENOMEM;
178 goto bail2;
179 }
180
181
182 return (0);
183bail2:
184 rman_fini(vmnetunits);
185bail1:
186 rman_fini(tapunits);
187bail:
188 return (error);
189
190 case MOD_UNLOAD:
191 SLIST_FOREACH(tp, &taphead, tap_next)
192 if (tp->tap_unit != NULL)
193 return (EBUSY);
194
195 EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
196
197 error = rman_fini(tapunits);
198 KASSERT((error == 0), ("Could not fini tap units"));
199 error = rman_fini(vmnetunits);
200 KASSERT((error == 0), ("Could not fini vmnet units"));
201
202 while ((tp = SLIST_FIRST(&taphead)) != NULL) {
203 SLIST_REMOVE_HEAD(&taphead, tap_next);
204
205 ifp = &tp->tap_if;
206
207 TAPDEBUG("detaching %s%d\n", ifp->if_name,ifp->if_unit);
208
209 KASSERT(!(tp->tap_flags & TAP_OPEN),
210 ("%s%d flags is out of sync", ifp->if_name,
211 ifp->if_unit));
212
213 /* XXX makedev check? nah.. not right now :) */
214
215 s = splimp();
216 ether_ifdetach(ifp);
217 splx(s);
218
219 free(tp, M_TAP);
220 }
221
222 if (tapbasedev != NOUDEV)
223 destroy_dev(udev2dev(tapbasedev, 0));
224
225
226 break;
227
228 default:
229 return (EOPNOTSUPP);
230 }
231
232 return (0);
233} /* tapmodevent */
234
235
236/*
237 * DEVFS handler
238 *
239 * We need to support two kind of devices - tap and vmnet
240 */
241static void
242tapclone(arg, name, namelen, dev)
243 void *arg;
244 char *name;
245 int namelen;
246 dev_t *dev;
247{
248 int unit, minor = 0 /* XXX avoid warning */ , error;
249 char *device_name = name;
250 struct resource *r = NULL;
251
252 if (*dev != NODEV)
253 return;
254
255 if (strcmp(device_name, TAP) == 0) {
256 /* get first free tap unit */
257 r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1,
258 RF_ALLOCATED | RF_ACTIVE, NULL);
259 unit = rman_get_start(r);
260 minor = unit2minor(unit);
261 }
262 else if (strcmp(device_name, VMNET) == 0) {
263 /* get first free vmnet unit */
264 r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1,
265 RF_ALLOCATED | RF_ACTIVE, NULL);
266 unit = rman_get_start(r);
267 minor = unit2minor(unit) | VMNET_DEV_MASK;
268 }
269
270 if (r != NULL) { /* need cloning */
271 TAPDEBUG("%s%d is available. minor = %#x\n",
272 device_name, unit, minor);
273
274 error = rman_release_resource(r);
275 KASSERT((error == 0), ("Could not release tap/vmnet unit"));
276
277 /* check if device for the unit has been created */
278 *dev = makedev(CDEV_MAJOR, minor);
279 if ((*dev)->si_flags & SI_NAMED) {
280 TAPDEBUG("%s%d device exists. minor = %#x\n",
281 device_name, unit, minor);
282 return; /* device has been created */
283 }
284 } else { /* try to match name/unit, first try tap then vmnet */
285 device_name = TAP;
286 if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
287 device_name = VMNET;
288
289 if (dev_stdclone(name, NULL, device_name, &unit) != 1)
290 return;
291
292 minor = unit2minor(unit) | VMNET_DEV_MASK;
293 } else
294 minor = unit2minor(unit);
295 }
296
297 TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor);
298
299 *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d",
300 device_name, unit);
301
302 if (tapbasedev == NOUDEV)
303 tapbasedev = (*dev)->si_udev;
304 else {
305 (*dev)->si_flags |= SI_CHEAPCLONE;
306 dev_depends(udev2dev(tapbasedev, 0), *dev);
307 }
308} /* tapclone */
309
310
311/*
312 * tapcreate
313 *
314 * to create interface
315 */
316static void
317tapcreate(dev)
318 dev_t dev;
319{
320 struct ifnet *ifp = NULL;
321 struct tap_softc *tp = NULL;
322 unsigned short macaddr_hi;
323 int unit, s;
324 char *name = NULL;
325
326 /* allocate driver storage and create device */
327 MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
328 SLIST_INSERT_HEAD(&taphead, tp, tap_next);
329
330 unit = dev2unit(dev) & TAPMAXUNIT;
331
332 /* select device: tap or vmnet */
333 if (minor(dev) & VMNET_DEV_MASK) {
334 name = VMNET;
335 tp->tap_flags |= TAP_VMNET;
336 } else
337 name = TAP;
338
339 TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
340
341 if (!(dev->si_flags & SI_NAMED))
342 dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL,
343 0600, "%s%d", name, unit);
344
345 /* generate fake MAC address: 00 bd xx xx xx unit_no */
346 macaddr_hi = htons(0x00bd);
347 bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
348 bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
349 tp->arpcom.ac_enaddr[5] = (u_char)unit;
350
351 /* fill the rest and attach interface */
352 ifp = &tp->tap_if;
353 ifp->if_softc = tp;
354 ifp->if_unit = unit;
355 ifp->if_name = name;
356 ifp->if_init = tapifinit;
357 ifp->if_start = tapifstart;
358 ifp->if_ioctl = tapifioctl;
359 ifp->if_mtu = ETHERMTU;
360 ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
361 ifp->if_snd.ifq_maxlen = ifqmaxlen;
362
363 dev->si_drv1 = tp;
364
365 s = splimp();
366 ether_ifattach(ifp, tp->arpcom.ac_enaddr);
367 splx(s);
368
369 tp->tap_flags |= TAP_INITED;
370
371 TAPDEBUG("interface %s%d is created. minor = %#x\n",
372 ifp->if_name, ifp->if_unit, minor(dev));
373} /* tapcreate */
374
375
376/*
377 * tapopen
378 *
379 * to open tunnel. must be superuser
380 */
381static int
382tapopen(dev, flag, mode, td)
383 dev_t dev;
384 int flag;
385 int mode;
386 struct thread *td;
387{
388 struct tap_softc *tp = NULL;
389 int unit, error;
390 struct resource *r = NULL;
391
392 if ((error = suser(td)) != 0)
393 return (error);
394
395 unit = dev2unit(dev) & TAPMAXUNIT;
396
397 if (minor(dev) & VMNET_DEV_MASK)
398 r = rman_reserve_resource(vmnetunits, unit, unit, 1,
399 RF_ALLOCATED | RF_ACTIVE, NULL);
400 else
401 r = rman_reserve_resource(tapunits, unit, unit, 1,
402 RF_ALLOCATED | RF_ACTIVE, NULL);
403
404 if (r == NULL)
405 return (EBUSY);
406
407 dev->si_flags &= ~SI_CHEAPCLONE;
408
409 tp = dev->si_drv1;
410 if (tp == NULL) {
411 tapcreate(dev);
412 tp = dev->si_drv1;
413 }
414
415 KASSERT(!(tp->tap_flags & TAP_OPEN),
416 ("%s%d flags is out of sync", tp->tap_if.if_name, unit));
417
418 bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
419
420 tp->tap_unit = r;
421 tp->tap_pid = td->td_proc->p_pid;
422 tp->tap_flags |= TAP_OPEN;
423
424 TAPDEBUG("%s%d is open. minor = %#x\n",
425 tp->tap_if.if_name, unit, minor(dev));
426
427 return (0);
428} /* tapopen */
429
430
431/*
432 * tapclose
433 *
434 * close the device - mark i/f down & delete routing info
435 */
436static int
437tapclose(dev, foo, bar, td)
438 dev_t dev;
439 int foo;
440 int bar;
441 struct thread *td;
442{
443 int s, error;
444 struct tap_softc *tp = dev->si_drv1;
445 struct ifnet *ifp = &tp->tap_if;
446
447 KASSERT((tp->tap_unit != NULL),
448 ("%s%d is not open", ifp->if_name, ifp->if_unit));
449
450 /* junk all pending output */
451 IF_DRAIN(&ifp->if_snd);
452
453 /*
454 * do not bring the interface down, and do not anything with
455 * interface, if we are in VMnet mode. just close the device.
456 */
457
458 if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
459 s = splimp();
460 if_down(ifp);
461 if (ifp->if_flags & IFF_RUNNING) {
462 /* find internet addresses and delete routes */
463 struct ifaddr *ifa = NULL;
464
465 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
466 if (ifa->ifa_addr->sa_family == AF_INET) {
467 rtinit(ifa, (int)RTM_DELETE, 0);
468
469 /* remove address from interface */
470 bzero(ifa->ifa_addr,
471 sizeof(*(ifa->ifa_addr)));
472 bzero(ifa->ifa_dstaddr,
473 sizeof(*(ifa->ifa_dstaddr)));
474 bzero(ifa->ifa_netmask,
475 sizeof(*(ifa->ifa_netmask)));
476 }
477 }
478
479 ifp->if_flags &= ~IFF_RUNNING;
480 }
481 splx(s);
482 }
483
484 funsetown(&tp->tap_sigio);
485 selwakeup(&tp->tap_rsel);
486
487 tp->tap_flags &= ~TAP_OPEN;
488 tp->tap_pid = 0;
489 error = rman_release_resource(tp->tap_unit);
490 KASSERT((error == 0),
491 ("%s%d could not release unit", ifp->if_name, ifp->if_unit));
492 tp->tap_unit = NULL;
493
494 TAPDEBUG("%s%d is closed. minor = %#x\n",
495 ifp->if_name, ifp->if_unit, minor(dev));
496
497 return (0);
498} /* tapclose */
499
500
501/*
502 * tapifinit
503 *
504 * network interface initialization function
505 */
506static void
507tapifinit(xtp)
508 void *xtp;
509{
510 struct tap_softc *tp = (struct tap_softc *)xtp;
511 struct ifnet *ifp = &tp->tap_if;
512
513 TAPDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit);
514
515 ifp->if_flags |= IFF_RUNNING;
516 ifp->if_flags &= ~IFF_OACTIVE;
517
518 /* attempt to start output */
519 tapifstart(ifp);
520} /* tapifinit */
521
522
523/*
524 * tapifioctl
525 *
526 * Process an ioctl request on network interface
527 */
528static int
529tapifioctl(ifp, cmd, data)
530 struct ifnet *ifp;
531 u_long cmd;
532 caddr_t data;
533{
534 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc);
535 struct ifstat *ifs = NULL;
536 int s, dummy;
537
538 switch (cmd) {
539 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
540 case SIOCADDMULTI:
541 case SIOCDELMULTI:
542 break;
543
544 case SIOCGIFSTATUS:
545 s = splimp();
546 ifs = (struct ifstat *)data;
547 dummy = strlen(ifs->ascii);
548 if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
549 snprintf(ifs->ascii + dummy,
550 sizeof(ifs->ascii) - dummy,
551 "\tOpened by PID %d\n", tp->tap_pid);
552 splx(s);
553 break;
554
555 default:
556 s = splimp();
557 dummy = ether_ioctl(ifp, cmd, data);
558 splx(s);
559 return (dummy);
560 }
561
562 return (0);
563} /* tapifioctl */
564
565
566/*
567 * tapifstart
568 *
569 * queue packets from higher level ready to put out
570 */
571static void
572tapifstart(ifp)
573 struct ifnet *ifp;
574{
575 struct tap_softc *tp = ifp->if_softc;
576 int s;
577
578 TAPDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit);
579
580 /*
581 * do not junk pending output if we are in VMnet mode.
582 * XXX: can this do any harm because of queue overflow?
583 */
584
585 if (((tp->tap_flags & TAP_VMNET) == 0) &&
586 ((tp->tap_flags & TAP_READY) != TAP_READY)) {
587 struct mbuf *m = NULL;
588
589 TAPDEBUG("%s%d not ready, tap_flags = 0x%x\n", ifp->if_name,
590 ifp->if_unit, tp->tap_flags);
591
592 s = splimp();
593 do {
594 IF_DEQUEUE(&ifp->if_snd, m);
595 if (m != NULL)
596 m_freem(m);
597 ifp->if_oerrors ++;
598 } while (m != NULL);
599 splx(s);
600
601 return;
602 }
603
604 s = splimp();
605 ifp->if_flags |= IFF_OACTIVE;
606
607 if (ifp->if_snd.ifq_len != 0) {
608 if (tp->tap_flags & TAP_RWAIT) {
609 tp->tap_flags &= ~TAP_RWAIT;
610 wakeup((caddr_t)tp);
611 }
612
613 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
614 pgsigio(&tp->tap_sigio, SIGIO, 0);
615
616 selwakeup(&tp->tap_rsel);
617 ifp->if_opackets ++; /* obytes are counted in ether_output */
618 }
619
620 ifp->if_flags &= ~IFF_OACTIVE;
621 splx(s);
622} /* tapifstart */
623
624
625/*
626 * tapioctl
627 *
628 * the cdevsw interface is now pretty minimal
629 */
630static int
631tapioctl(dev, cmd, data, flag, td)
632 dev_t dev;
633 u_long cmd;
634 caddr_t data;
635 int flag;
636 struct thread *td;
637{
638 struct tap_softc *tp = dev->si_drv1;
639 struct ifnet *ifp = &tp->tap_if;
640 struct tapinfo *tapp = NULL;
641 int s;
642 int f;
643
644 switch (cmd) {
645 case TAPSIFINFO:
646 s = splimp();
647 tapp = (struct tapinfo *)data;
648 ifp->if_mtu = tapp->mtu;
649 ifp->if_type = tapp->type;
650 ifp->if_baudrate = tapp->baudrate;
651 splx(s);
652 break;
653
654 case TAPGIFINFO:
655 tapp = (struct tapinfo *)data;
656 tapp->mtu = ifp->if_mtu;
657 tapp->type = ifp->if_type;
658 tapp->baudrate = ifp->if_baudrate;
659 break;
660
661 case TAPSDEBUG:
662 tapdebug = *(int *)data;
663 break;
664
665 case TAPGDEBUG:
666 *(int *)data = tapdebug;
667 break;
668
669 case FIONBIO:
670 break;
671
672 case FIOASYNC:
673 s = splimp();
674 if (*(int *)data)
675 tp->tap_flags |= TAP_ASYNC;
676 else
677 tp->tap_flags &= ~TAP_ASYNC;
678 splx(s);
679 break;
680
681 case FIONREAD:
682 s = splimp();
683 if (ifp->if_snd.ifq_head) {
684 struct mbuf *mb = ifp->if_snd.ifq_head;
685
686 for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
687 *(int *)data += mb->m_len;
688 } else
689 *(int *)data = 0;
690 splx(s);
691 break;
692
693 case FIOSETOWN:
694 return (fsetown(*(int *)data, &tp->tap_sigio));
695
696 case FIOGETOWN:
697 *(int *)data = fgetown(&tp->tap_sigio);
698 return (0);
699
700 /* this is deprecated, FIOSETOWN should be used instead */
701 case TIOCSPGRP:
702 return (fsetown(-(*(int *)data), &tp->tap_sigio));
703
704 /* this is deprecated, FIOGETOWN should be used instead */
705 case TIOCGPGRP:
706 *(int *)data = -fgetown(&tp->tap_sigio);
707 return (0);
708
709 /* VMware/VMnet port ioctl's */
710
711 case SIOCGIFFLAGS: /* get ifnet flags */
712 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
713 break;
714
715 case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
716 f = *(int *)data;
717 f &= 0x0fff;
718 f &= ~IFF_CANTCHANGE;
719 f |= IFF_UP;
720
721 s = splimp();
722 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
723 splx(s);
724 break;
725
726 case OSIOCGIFADDR: /* get MAC address of the remote side */
727 case SIOCGIFADDR:
728 bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
729 break;
730
731 case SIOCSIFADDR: /* set MAC address of the remote side */
732 bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
733 break;
734
735 default:
736 return (ENOTTY);
737 }
738 return (0);
739} /* tapioctl */
740
741
742/*
743 * tapread
744 *
745 * the cdevsw read interface - reads a packet at a time, or at
746 * least as much of a packet as can be read
747 */
748static int
749tapread(dev, uio, flag)
750 dev_t dev;
751 struct uio *uio;
752 int flag;
753{
754 struct tap_softc *tp = dev->si_drv1;
755 struct ifnet *ifp = &tp->tap_if;
756 struct mbuf *m = NULL;
757 int error = 0, len, s;
758
759 TAPDEBUG("%s%d reading, minor = %#x\n",
760 ifp->if_name, ifp->if_unit, minor(dev));
761
762 if ((tp->tap_flags & TAP_READY) != TAP_READY) {
763 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
764 ifp->if_name, ifp->if_unit, minor(dev), tp->tap_flags);
765
766 return (EHOSTDOWN);
767 }
768
769 tp->tap_flags &= ~TAP_RWAIT;
770
771 /* sleep until we get a packet */
772 do {
773 s = splimp();
774 IF_DEQUEUE(&ifp->if_snd, m);
775 splx(s);
776
777 if (m == NULL) {
778 if (flag & IO_NDELAY)
779 return (EWOULDBLOCK);
780
781 tp->tap_flags |= TAP_RWAIT;
782 error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0);
783 if (error)
784 return (error);
785 }
786 } while (m == NULL);
787
788 /* feed packet to bpf */
789 BPF_MTAP(ifp, m);
790
791 /* xfer packet to user space */
792 while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
793 len = min(uio->uio_resid, m->m_len);
794 if (len == 0)
795 break;
796
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>
42#include <sys/filedesc.h>
43#include <sys/filio.h>
44#include <sys/kernel.h>
45#include <sys/malloc.h>
46#include <sys/mbuf.h>
47#include <sys/poll.h>
48#include <sys/proc.h>
49#include <sys/signalvar.h>
50#include <sys/socket.h>
51#include <sys/sockio.h>
52#include <sys/sysctl.h>
53#include <sys/systm.h>
54#include <sys/ttycom.h>
55#include <sys/uio.h>
56#include <sys/vnode.h>
57#include <machine/bus.h> /* XXX: Shouldn't really be required! */
58#include <sys/rman.h>
59#include <sys/queue.h>
60
61#include <net/bpf.h>
62#include <net/ethernet.h>
63#include <net/if.h>
64#include <net/if_arp.h>
65#include <net/route.h>
66
67#include <netinet/in.h>
68
69#include <net/if_tapvar.h>
70#include <net/if_tap.h>
71
72
73#define CDEV_NAME "tap"
74#define CDEV_MAJOR 149
75#define TAPDEBUG if (tapdebug) printf
76
77#define TAP "tap"
78#define VMNET "vmnet"
79#define TAPMAXUNIT 0x7fff
80#define VMNET_DEV_MASK 0x00800000
81 /* 0x007f00ff */
82
83/* module */
84static int tapmodevent(module_t, int, void *);
85
86/* device */
87static void tapclone(void *, char *, int, dev_t *);
88static void tapcreate(dev_t);
89
90/* network interface */
91static void tapifstart(struct ifnet *);
92static int tapifioctl(struct ifnet *, u_long, caddr_t);
93static void tapifinit(void *);
94
95/* character device */
96static d_open_t tapopen;
97static d_close_t tapclose;
98static d_read_t tapread;
99static d_write_t tapwrite;
100static d_ioctl_t tapioctl;
101static d_poll_t tappoll;
102
103static struct cdevsw tap_cdevsw = {
104 /* open */ tapopen,
105 /* close */ tapclose,
106 /* read */ tapread,
107 /* write */ tapwrite,
108 /* ioctl */ tapioctl,
109 /* poll */ tappoll,
110 /* mmap */ nommap,
111 /* startegy */ nostrategy,
112 /* dev name */ CDEV_NAME,
113 /* dev major */ CDEV_MAJOR,
114 /* dump */ nodump,
115 /* psize */ nopsize,
116 /* flags */ 0,
117};
118
119static int tapdebug = 0; /* debug flag */
120static SLIST_HEAD(, tap_softc) taphead; /* first device */
121static udev_t tapbasedev = NOUDEV; /* base device */
122static struct rman tapdevunits[2]; /* device units */
123#define tapunits tapdevunits
124#define vmnetunits (tapdevunits + 1)
125
126MALLOC_DECLARE(M_TAP);
127MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
128SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
129DEV_MODULE(if_tap, tapmodevent, NULL);
130
131/*
132 * tapmodevent
133 *
134 * module event handler
135 */
136static int
137tapmodevent(mod, type, data)
138 module_t mod;
139 int type;
140 void *data;
141{
142 static eventhandler_tag eh_tag = NULL;
143 struct tap_softc *tp = NULL;
144 struct ifnet *ifp = NULL;
145 int error, s;
146
147 switch (type) {
148 case MOD_LOAD:
149 /* initialize resources */
150 tapunits->rm_type = RMAN_ARRAY;
151 tapunits->rm_descr = "open tap units";
152 vmnetunits->rm_type = RMAN_ARRAY;
153 vmnetunits->rm_descr = "open vmnet units";
154
155 error = rman_init(tapunits);
156 if (error != 0)
157 goto bail;
158
159 error = rman_init(vmnetunits);
160 if (error != 0)
161 goto bail1;
162
163 error = rman_manage_region(tapunits, 0, TAPMAXUNIT);
164 if (error != 0)
165 goto bail2;
166
167 error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT);
168 if (error != 0)
169 goto bail2;
170
171 /* intitialize device */
172
173 SLIST_INIT(&taphead);
174
175 eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
176 if (eh_tag == NULL) {
177 error = ENOMEM;
178 goto bail2;
179 }
180
181
182 return (0);
183bail2:
184 rman_fini(vmnetunits);
185bail1:
186 rman_fini(tapunits);
187bail:
188 return (error);
189
190 case MOD_UNLOAD:
191 SLIST_FOREACH(tp, &taphead, tap_next)
192 if (tp->tap_unit != NULL)
193 return (EBUSY);
194
195 EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
196
197 error = rman_fini(tapunits);
198 KASSERT((error == 0), ("Could not fini tap units"));
199 error = rman_fini(vmnetunits);
200 KASSERT((error == 0), ("Could not fini vmnet units"));
201
202 while ((tp = SLIST_FIRST(&taphead)) != NULL) {
203 SLIST_REMOVE_HEAD(&taphead, tap_next);
204
205 ifp = &tp->tap_if;
206
207 TAPDEBUG("detaching %s%d\n", ifp->if_name,ifp->if_unit);
208
209 KASSERT(!(tp->tap_flags & TAP_OPEN),
210 ("%s%d flags is out of sync", ifp->if_name,
211 ifp->if_unit));
212
213 /* XXX makedev check? nah.. not right now :) */
214
215 s = splimp();
216 ether_ifdetach(ifp);
217 splx(s);
218
219 free(tp, M_TAP);
220 }
221
222 if (tapbasedev != NOUDEV)
223 destroy_dev(udev2dev(tapbasedev, 0));
224
225
226 break;
227
228 default:
229 return (EOPNOTSUPP);
230 }
231
232 return (0);
233} /* tapmodevent */
234
235
236/*
237 * DEVFS handler
238 *
239 * We need to support two kind of devices - tap and vmnet
240 */
241static void
242tapclone(arg, name, namelen, dev)
243 void *arg;
244 char *name;
245 int namelen;
246 dev_t *dev;
247{
248 int unit, minor = 0 /* XXX avoid warning */ , error;
249 char *device_name = name;
250 struct resource *r = NULL;
251
252 if (*dev != NODEV)
253 return;
254
255 if (strcmp(device_name, TAP) == 0) {
256 /* get first free tap unit */
257 r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1,
258 RF_ALLOCATED | RF_ACTIVE, NULL);
259 unit = rman_get_start(r);
260 minor = unit2minor(unit);
261 }
262 else if (strcmp(device_name, VMNET) == 0) {
263 /* get first free vmnet unit */
264 r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1,
265 RF_ALLOCATED | RF_ACTIVE, NULL);
266 unit = rman_get_start(r);
267 minor = unit2minor(unit) | VMNET_DEV_MASK;
268 }
269
270 if (r != NULL) { /* need cloning */
271 TAPDEBUG("%s%d is available. minor = %#x\n",
272 device_name, unit, minor);
273
274 error = rman_release_resource(r);
275 KASSERT((error == 0), ("Could not release tap/vmnet unit"));
276
277 /* check if device for the unit has been created */
278 *dev = makedev(CDEV_MAJOR, minor);
279 if ((*dev)->si_flags & SI_NAMED) {
280 TAPDEBUG("%s%d device exists. minor = %#x\n",
281 device_name, unit, minor);
282 return; /* device has been created */
283 }
284 } else { /* try to match name/unit, first try tap then vmnet */
285 device_name = TAP;
286 if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
287 device_name = VMNET;
288
289 if (dev_stdclone(name, NULL, device_name, &unit) != 1)
290 return;
291
292 minor = unit2minor(unit) | VMNET_DEV_MASK;
293 } else
294 minor = unit2minor(unit);
295 }
296
297 TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor);
298
299 *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d",
300 device_name, unit);
301
302 if (tapbasedev == NOUDEV)
303 tapbasedev = (*dev)->si_udev;
304 else {
305 (*dev)->si_flags |= SI_CHEAPCLONE;
306 dev_depends(udev2dev(tapbasedev, 0), *dev);
307 }
308} /* tapclone */
309
310
311/*
312 * tapcreate
313 *
314 * to create interface
315 */
316static void
317tapcreate(dev)
318 dev_t dev;
319{
320 struct ifnet *ifp = NULL;
321 struct tap_softc *tp = NULL;
322 unsigned short macaddr_hi;
323 int unit, s;
324 char *name = NULL;
325
326 /* allocate driver storage and create device */
327 MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
328 SLIST_INSERT_HEAD(&taphead, tp, tap_next);
329
330 unit = dev2unit(dev) & TAPMAXUNIT;
331
332 /* select device: tap or vmnet */
333 if (minor(dev) & VMNET_DEV_MASK) {
334 name = VMNET;
335 tp->tap_flags |= TAP_VMNET;
336 } else
337 name = TAP;
338
339 TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
340
341 if (!(dev->si_flags & SI_NAMED))
342 dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL,
343 0600, "%s%d", name, unit);
344
345 /* generate fake MAC address: 00 bd xx xx xx unit_no */
346 macaddr_hi = htons(0x00bd);
347 bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
348 bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
349 tp->arpcom.ac_enaddr[5] = (u_char)unit;
350
351 /* fill the rest and attach interface */
352 ifp = &tp->tap_if;
353 ifp->if_softc = tp;
354 ifp->if_unit = unit;
355 ifp->if_name = name;
356 ifp->if_init = tapifinit;
357 ifp->if_start = tapifstart;
358 ifp->if_ioctl = tapifioctl;
359 ifp->if_mtu = ETHERMTU;
360 ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
361 ifp->if_snd.ifq_maxlen = ifqmaxlen;
362
363 dev->si_drv1 = tp;
364
365 s = splimp();
366 ether_ifattach(ifp, tp->arpcom.ac_enaddr);
367 splx(s);
368
369 tp->tap_flags |= TAP_INITED;
370
371 TAPDEBUG("interface %s%d is created. minor = %#x\n",
372 ifp->if_name, ifp->if_unit, minor(dev));
373} /* tapcreate */
374
375
376/*
377 * tapopen
378 *
379 * to open tunnel. must be superuser
380 */
381static int
382tapopen(dev, flag, mode, td)
383 dev_t dev;
384 int flag;
385 int mode;
386 struct thread *td;
387{
388 struct tap_softc *tp = NULL;
389 int unit, error;
390 struct resource *r = NULL;
391
392 if ((error = suser(td)) != 0)
393 return (error);
394
395 unit = dev2unit(dev) & TAPMAXUNIT;
396
397 if (minor(dev) & VMNET_DEV_MASK)
398 r = rman_reserve_resource(vmnetunits, unit, unit, 1,
399 RF_ALLOCATED | RF_ACTIVE, NULL);
400 else
401 r = rman_reserve_resource(tapunits, unit, unit, 1,
402 RF_ALLOCATED | RF_ACTIVE, NULL);
403
404 if (r == NULL)
405 return (EBUSY);
406
407 dev->si_flags &= ~SI_CHEAPCLONE;
408
409 tp = dev->si_drv1;
410 if (tp == NULL) {
411 tapcreate(dev);
412 tp = dev->si_drv1;
413 }
414
415 KASSERT(!(tp->tap_flags & TAP_OPEN),
416 ("%s%d flags is out of sync", tp->tap_if.if_name, unit));
417
418 bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
419
420 tp->tap_unit = r;
421 tp->tap_pid = td->td_proc->p_pid;
422 tp->tap_flags |= TAP_OPEN;
423
424 TAPDEBUG("%s%d is open. minor = %#x\n",
425 tp->tap_if.if_name, unit, minor(dev));
426
427 return (0);
428} /* tapopen */
429
430
431/*
432 * tapclose
433 *
434 * close the device - mark i/f down & delete routing info
435 */
436static int
437tapclose(dev, foo, bar, td)
438 dev_t dev;
439 int foo;
440 int bar;
441 struct thread *td;
442{
443 int s, error;
444 struct tap_softc *tp = dev->si_drv1;
445 struct ifnet *ifp = &tp->tap_if;
446
447 KASSERT((tp->tap_unit != NULL),
448 ("%s%d is not open", ifp->if_name, ifp->if_unit));
449
450 /* junk all pending output */
451 IF_DRAIN(&ifp->if_snd);
452
453 /*
454 * do not bring the interface down, and do not anything with
455 * interface, if we are in VMnet mode. just close the device.
456 */
457
458 if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
459 s = splimp();
460 if_down(ifp);
461 if (ifp->if_flags & IFF_RUNNING) {
462 /* find internet addresses and delete routes */
463 struct ifaddr *ifa = NULL;
464
465 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
466 if (ifa->ifa_addr->sa_family == AF_INET) {
467 rtinit(ifa, (int)RTM_DELETE, 0);
468
469 /* remove address from interface */
470 bzero(ifa->ifa_addr,
471 sizeof(*(ifa->ifa_addr)));
472 bzero(ifa->ifa_dstaddr,
473 sizeof(*(ifa->ifa_dstaddr)));
474 bzero(ifa->ifa_netmask,
475 sizeof(*(ifa->ifa_netmask)));
476 }
477 }
478
479 ifp->if_flags &= ~IFF_RUNNING;
480 }
481 splx(s);
482 }
483
484 funsetown(&tp->tap_sigio);
485 selwakeup(&tp->tap_rsel);
486
487 tp->tap_flags &= ~TAP_OPEN;
488 tp->tap_pid = 0;
489 error = rman_release_resource(tp->tap_unit);
490 KASSERT((error == 0),
491 ("%s%d could not release unit", ifp->if_name, ifp->if_unit));
492 tp->tap_unit = NULL;
493
494 TAPDEBUG("%s%d is closed. minor = %#x\n",
495 ifp->if_name, ifp->if_unit, minor(dev));
496
497 return (0);
498} /* tapclose */
499
500
501/*
502 * tapifinit
503 *
504 * network interface initialization function
505 */
506static void
507tapifinit(xtp)
508 void *xtp;
509{
510 struct tap_softc *tp = (struct tap_softc *)xtp;
511 struct ifnet *ifp = &tp->tap_if;
512
513 TAPDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit);
514
515 ifp->if_flags |= IFF_RUNNING;
516 ifp->if_flags &= ~IFF_OACTIVE;
517
518 /* attempt to start output */
519 tapifstart(ifp);
520} /* tapifinit */
521
522
523/*
524 * tapifioctl
525 *
526 * Process an ioctl request on network interface
527 */
528static int
529tapifioctl(ifp, cmd, data)
530 struct ifnet *ifp;
531 u_long cmd;
532 caddr_t data;
533{
534 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc);
535 struct ifstat *ifs = NULL;
536 int s, dummy;
537
538 switch (cmd) {
539 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
540 case SIOCADDMULTI:
541 case SIOCDELMULTI:
542 break;
543
544 case SIOCGIFSTATUS:
545 s = splimp();
546 ifs = (struct ifstat *)data;
547 dummy = strlen(ifs->ascii);
548 if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
549 snprintf(ifs->ascii + dummy,
550 sizeof(ifs->ascii) - dummy,
551 "\tOpened by PID %d\n", tp->tap_pid);
552 splx(s);
553 break;
554
555 default:
556 s = splimp();
557 dummy = ether_ioctl(ifp, cmd, data);
558 splx(s);
559 return (dummy);
560 }
561
562 return (0);
563} /* tapifioctl */
564
565
566/*
567 * tapifstart
568 *
569 * queue packets from higher level ready to put out
570 */
571static void
572tapifstart(ifp)
573 struct ifnet *ifp;
574{
575 struct tap_softc *tp = ifp->if_softc;
576 int s;
577
578 TAPDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit);
579
580 /*
581 * do not junk pending output if we are in VMnet mode.
582 * XXX: can this do any harm because of queue overflow?
583 */
584
585 if (((tp->tap_flags & TAP_VMNET) == 0) &&
586 ((tp->tap_flags & TAP_READY) != TAP_READY)) {
587 struct mbuf *m = NULL;
588
589 TAPDEBUG("%s%d not ready, tap_flags = 0x%x\n", ifp->if_name,
590 ifp->if_unit, tp->tap_flags);
591
592 s = splimp();
593 do {
594 IF_DEQUEUE(&ifp->if_snd, m);
595 if (m != NULL)
596 m_freem(m);
597 ifp->if_oerrors ++;
598 } while (m != NULL);
599 splx(s);
600
601 return;
602 }
603
604 s = splimp();
605 ifp->if_flags |= IFF_OACTIVE;
606
607 if (ifp->if_snd.ifq_len != 0) {
608 if (tp->tap_flags & TAP_RWAIT) {
609 tp->tap_flags &= ~TAP_RWAIT;
610 wakeup((caddr_t)tp);
611 }
612
613 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
614 pgsigio(&tp->tap_sigio, SIGIO, 0);
615
616 selwakeup(&tp->tap_rsel);
617 ifp->if_opackets ++; /* obytes are counted in ether_output */
618 }
619
620 ifp->if_flags &= ~IFF_OACTIVE;
621 splx(s);
622} /* tapifstart */
623
624
625/*
626 * tapioctl
627 *
628 * the cdevsw interface is now pretty minimal
629 */
630static int
631tapioctl(dev, cmd, data, flag, td)
632 dev_t dev;
633 u_long cmd;
634 caddr_t data;
635 int flag;
636 struct thread *td;
637{
638 struct tap_softc *tp = dev->si_drv1;
639 struct ifnet *ifp = &tp->tap_if;
640 struct tapinfo *tapp = NULL;
641 int s;
642 int f;
643
644 switch (cmd) {
645 case TAPSIFINFO:
646 s = splimp();
647 tapp = (struct tapinfo *)data;
648 ifp->if_mtu = tapp->mtu;
649 ifp->if_type = tapp->type;
650 ifp->if_baudrate = tapp->baudrate;
651 splx(s);
652 break;
653
654 case TAPGIFINFO:
655 tapp = (struct tapinfo *)data;
656 tapp->mtu = ifp->if_mtu;
657 tapp->type = ifp->if_type;
658 tapp->baudrate = ifp->if_baudrate;
659 break;
660
661 case TAPSDEBUG:
662 tapdebug = *(int *)data;
663 break;
664
665 case TAPGDEBUG:
666 *(int *)data = tapdebug;
667 break;
668
669 case FIONBIO:
670 break;
671
672 case FIOASYNC:
673 s = splimp();
674 if (*(int *)data)
675 tp->tap_flags |= TAP_ASYNC;
676 else
677 tp->tap_flags &= ~TAP_ASYNC;
678 splx(s);
679 break;
680
681 case FIONREAD:
682 s = splimp();
683 if (ifp->if_snd.ifq_head) {
684 struct mbuf *mb = ifp->if_snd.ifq_head;
685
686 for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
687 *(int *)data += mb->m_len;
688 } else
689 *(int *)data = 0;
690 splx(s);
691 break;
692
693 case FIOSETOWN:
694 return (fsetown(*(int *)data, &tp->tap_sigio));
695
696 case FIOGETOWN:
697 *(int *)data = fgetown(&tp->tap_sigio);
698 return (0);
699
700 /* this is deprecated, FIOSETOWN should be used instead */
701 case TIOCSPGRP:
702 return (fsetown(-(*(int *)data), &tp->tap_sigio));
703
704 /* this is deprecated, FIOGETOWN should be used instead */
705 case TIOCGPGRP:
706 *(int *)data = -fgetown(&tp->tap_sigio);
707 return (0);
708
709 /* VMware/VMnet port ioctl's */
710
711 case SIOCGIFFLAGS: /* get ifnet flags */
712 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
713 break;
714
715 case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
716 f = *(int *)data;
717 f &= 0x0fff;
718 f &= ~IFF_CANTCHANGE;
719 f |= IFF_UP;
720
721 s = splimp();
722 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
723 splx(s);
724 break;
725
726 case OSIOCGIFADDR: /* get MAC address of the remote side */
727 case SIOCGIFADDR:
728 bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
729 break;
730
731 case SIOCSIFADDR: /* set MAC address of the remote side */
732 bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
733 break;
734
735 default:
736 return (ENOTTY);
737 }
738 return (0);
739} /* tapioctl */
740
741
742/*
743 * tapread
744 *
745 * the cdevsw read interface - reads a packet at a time, or at
746 * least as much of a packet as can be read
747 */
748static int
749tapread(dev, uio, flag)
750 dev_t dev;
751 struct uio *uio;
752 int flag;
753{
754 struct tap_softc *tp = dev->si_drv1;
755 struct ifnet *ifp = &tp->tap_if;
756 struct mbuf *m = NULL;
757 int error = 0, len, s;
758
759 TAPDEBUG("%s%d reading, minor = %#x\n",
760 ifp->if_name, ifp->if_unit, minor(dev));
761
762 if ((tp->tap_flags & TAP_READY) != TAP_READY) {
763 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
764 ifp->if_name, ifp->if_unit, minor(dev), tp->tap_flags);
765
766 return (EHOSTDOWN);
767 }
768
769 tp->tap_flags &= ~TAP_RWAIT;
770
771 /* sleep until we get a packet */
772 do {
773 s = splimp();
774 IF_DEQUEUE(&ifp->if_snd, m);
775 splx(s);
776
777 if (m == NULL) {
778 if (flag & IO_NDELAY)
779 return (EWOULDBLOCK);
780
781 tp->tap_flags |= TAP_RWAIT;
782 error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0);
783 if (error)
784 return (error);
785 }
786 } while (m == NULL);
787
788 /* feed packet to bpf */
789 BPF_MTAP(ifp, m);
790
791 /* xfer packet to user space */
792 while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
793 len = min(uio->uio_resid, m->m_len);
794 if (len == 0)
795 break;
796
797 error = uiomove(mtod(m, caddr_t), len, uio);
797 error = uiomove(mtod(m, void *), len, uio);
798 m = m_free(m);
799 }
800
801 if (m != NULL) {
802 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", ifp->if_name,
803 ifp->if_unit, minor(dev));
804 m_freem(m);
805 }
806
807 return (error);
808} /* tapread */
809
810
811/*
812 * tapwrite
813 *
814 * the cdevsw write interface - an atomic write is a packet - or else!
815 */
816static int
817tapwrite(dev, uio, flag)
818 dev_t dev;
819 struct uio *uio;
820 int flag;
821{
822 struct tap_softc *tp = dev->si_drv1;
823 struct ifnet *ifp = &tp->tap_if;
824 struct mbuf *top = NULL, **mp = NULL, *m = NULL;
825 int error = 0, tlen, mlen;
826
827 TAPDEBUG("%s%d writting, minor = %#x\n",
828 ifp->if_name, ifp->if_unit, minor(dev));
829
830 if (uio->uio_resid == 0)
831 return (0);
832
833 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
834 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n",
835 ifp->if_name, ifp->if_unit, uio->uio_resid, minor(dev));
836
837 return (EIO);
838 }
839 tlen = uio->uio_resid;
840
841 /* get a header mbuf */
842 MGETHDR(m, M_DONTWAIT, MT_DATA);
843 if (m == NULL)
844 return (ENOBUFS);
845 mlen = MHLEN;
846
847 top = 0;
848 mp = &top;
849 while ((error == 0) && (uio->uio_resid > 0)) {
850 m->m_len = min(mlen, uio->uio_resid);
798 m = m_free(m);
799 }
800
801 if (m != NULL) {
802 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", ifp->if_name,
803 ifp->if_unit, minor(dev));
804 m_freem(m);
805 }
806
807 return (error);
808} /* tapread */
809
810
811/*
812 * tapwrite
813 *
814 * the cdevsw write interface - an atomic write is a packet - or else!
815 */
816static int
817tapwrite(dev, uio, flag)
818 dev_t dev;
819 struct uio *uio;
820 int flag;
821{
822 struct tap_softc *tp = dev->si_drv1;
823 struct ifnet *ifp = &tp->tap_if;
824 struct mbuf *top = NULL, **mp = NULL, *m = NULL;
825 int error = 0, tlen, mlen;
826
827 TAPDEBUG("%s%d writting, minor = %#x\n",
828 ifp->if_name, ifp->if_unit, minor(dev));
829
830 if (uio->uio_resid == 0)
831 return (0);
832
833 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
834 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n",
835 ifp->if_name, ifp->if_unit, uio->uio_resid, minor(dev));
836
837 return (EIO);
838 }
839 tlen = uio->uio_resid;
840
841 /* get a header mbuf */
842 MGETHDR(m, M_DONTWAIT, MT_DATA);
843 if (m == NULL)
844 return (ENOBUFS);
845 mlen = MHLEN;
846
847 top = 0;
848 mp = &top;
849 while ((error == 0) && (uio->uio_resid > 0)) {
850 m->m_len = min(mlen, uio->uio_resid);
851 error = uiomove(mtod(m, caddr_t), m->m_len, uio);
851 error = uiomove(mtod(m, void *), m->m_len, uio);
852 *mp = m;
853 mp = &m->m_next;
854 if (uio->uio_resid > 0) {
855 MGET(m, M_DONTWAIT, MT_DATA);
856 if (m == NULL) {
857 error = ENOBUFS;
858 break;
859 }
860 mlen = MLEN;
861 }
862 }
863 if (error) {
864 ifp->if_ierrors ++;
865 if (top)
866 m_freem(top);
867 return (error);
868 }
869
870 top->m_pkthdr.len = tlen;
871 top->m_pkthdr.rcvif = ifp;
872
873 /* Pass packet up to parent. */
874 (*ifp->if_input)(ifp, top);
875 ifp->if_ipackets ++; /* ibytes are counted in parent */
876
877 return (0);
878} /* tapwrite */
879
880
881/*
882 * tappoll
883 *
884 * the poll interface, this is only useful on reads
885 * really. the write detect always returns true, write never blocks
886 * anyway, it either accepts the packet or drops it
887 */
888static int
889tappoll(dev, events, td)
890 dev_t dev;
891 int events;
892 struct thread *td;
893{
894 struct tap_softc *tp = dev->si_drv1;
895 struct ifnet *ifp = &tp->tap_if;
896 int s, revents = 0;
897
898 TAPDEBUG("%s%d polling, minor = %#x\n",
899 ifp->if_name, ifp->if_unit, minor(dev));
900
901 s = splimp();
902 if (events & (POLLIN | POLLRDNORM)) {
903 if (ifp->if_snd.ifq_len > 0) {
904 TAPDEBUG("%s%d have data in queue. len = %d, " \
905 "minor = %#x\n", ifp->if_name, ifp->if_unit,
906 ifp->if_snd.ifq_len, minor(dev));
907
908 revents |= (events & (POLLIN | POLLRDNORM));
909 } else {
910 TAPDEBUG("%s%d waiting for data, minor = %#x\n",
911 ifp->if_name, ifp->if_unit, minor(dev));
912
913 selrecord(td, &tp->tap_rsel);
914 }
915 }
916
917 if (events & (POLLOUT | POLLWRNORM))
918 revents |= (events & (POLLOUT | POLLWRNORM));
919
920 splx(s);
921 return (revents);
922} /* tappoll */
852 *mp = m;
853 mp = &m->m_next;
854 if (uio->uio_resid > 0) {
855 MGET(m, M_DONTWAIT, MT_DATA);
856 if (m == NULL) {
857 error = ENOBUFS;
858 break;
859 }
860 mlen = MLEN;
861 }
862 }
863 if (error) {
864 ifp->if_ierrors ++;
865 if (top)
866 m_freem(top);
867 return (error);
868 }
869
870 top->m_pkthdr.len = tlen;
871 top->m_pkthdr.rcvif = ifp;
872
873 /* Pass packet up to parent. */
874 (*ifp->if_input)(ifp, top);
875 ifp->if_ipackets ++; /* ibytes are counted in parent */
876
877 return (0);
878} /* tapwrite */
879
880
881/*
882 * tappoll
883 *
884 * the poll interface, this is only useful on reads
885 * really. the write detect always returns true, write never blocks
886 * anyway, it either accepts the packet or drops it
887 */
888static int
889tappoll(dev, events, td)
890 dev_t dev;
891 int events;
892 struct thread *td;
893{
894 struct tap_softc *tp = dev->si_drv1;
895 struct ifnet *ifp = &tp->tap_if;
896 int s, revents = 0;
897
898 TAPDEBUG("%s%d polling, minor = %#x\n",
899 ifp->if_name, ifp->if_unit, minor(dev));
900
901 s = splimp();
902 if (events & (POLLIN | POLLRDNORM)) {
903 if (ifp->if_snd.ifq_len > 0) {
904 TAPDEBUG("%s%d have data in queue. len = %d, " \
905 "minor = %#x\n", ifp->if_name, ifp->if_unit,
906 ifp->if_snd.ifq_len, minor(dev));
907
908 revents |= (events & (POLLIN | POLLRDNORM));
909 } else {
910 TAPDEBUG("%s%d waiting for data, minor = %#x\n",
911 ifp->if_name, ifp->if_unit, minor(dev));
912
913 selrecord(td, &tp->tap_rsel);
914 }
915 }
916
917 if (events & (POLLOUT | POLLWRNORM))
918 revents |= (events & (POLLOUT | POLLWRNORM));
919
920 splx(s);
921 return (revents);
922} /* tappoll */