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