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