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