FreeBSD/Linux Kernel Cross Reference
sys/net/if_tap.c
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: releng/5.1/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 */
84 static int tapmodevent(module_t, int, void *);
85
86 /* device */
87 static void tapclone(void *, char *, int, dev_t *);
88 static void tapcreate(dev_t);
89
90 /* network interface */
91 static void tapifstart(struct ifnet *);
92 static int tapifioctl(struct ifnet *, u_long, caddr_t);
93 static void tapifinit(void *);
94
95 /* character device */
96 static d_open_t tapopen;
97 static d_close_t tapclose;
98 static d_read_t tapread;
99 static d_write_t tapwrite;
100 static d_ioctl_t tapioctl;
101 static d_poll_t tappoll;
102
103 static struct cdevsw tap_cdevsw = {
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,
112 };
113
114 static int tapdebug = 0; /* debug flag */
115 static SLIST_HEAD(, tap_softc) taphead; /* first device */
116 static udev_t tapbasedev = NOUDEV; /* base device */
117 static struct rman tapdevunits[2]; /* device units */
118 #define tapunits tapdevunits
119 #define vmnetunits (tapdevunits + 1)
120
121 MALLOC_DECLARE(M_TAP);
122 MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
123 SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
124 DEV_MODULE(if_tap, tapmodevent, NULL);
125
126 /*
127 * tapmodevent
128 *
129 * module event handler
130 */
131 static int
132 tapmodevent(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);
178 bail2:
179 rman_fini(vmnetunits);
180 bail1:
181 rman_fini(tapunits);
182 bail:
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 */
236 static void
237 tapclone(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 */
311 static void
312 tapcreate(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 */
376 static int
377 tapopen(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 */
431 static int
432 tapclose(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 */
501 static void
502 tapifinit(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 */
523 static int
524 tapifioctl(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 */
566 static void
567 tapifstart(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 */
625 static int
626 tapioctl(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 */
743 static int
744 tapread(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 */
811 static int
812 tapwrite(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 = ⊤
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 */
883 static int
884 tappoll(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 */
Cache object: d2d0bfe801130c007a60388efe7509a3
|