if_xname support Part 2/2: Convert remaining netif devices and implement full
[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  * $DragonFly: src/sys/net/tap/if_tap.c,v 1.9 2004/01/06 03:17:27 dillon Exp $
36  * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
37  */
38
39 #include "opt_inet.h"
40
41 #include <sys/param.h>
42 #include <sys/conf.h>
43 #include <sys/filedesc.h>
44 #include <sys/filio.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/mbuf.h>
48 #include <sys/poll.h>
49 #include <sys/proc.h>
50 #include <sys/signalvar.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/sysctl.h>
54 #include <sys/systm.h>
55 #include <sys/ttycom.h>
56 #include <sys/uio.h>
57 #include <sys/vnode.h>
58
59 #include <net/bpf.h>
60 #include <net/ethernet.h>
61 #include <net/if.h>
62 #include <net/if_arp.h>
63 #include <net/route.h>
64
65 #include <netinet/in.h>
66
67 #include "if_tapvar.h"
68 #include "if_tap.h"
69
70
71 #define CDEV_NAME       "tap"
72 #define CDEV_MAJOR      149
73 #define TAPDEBUG        if (tapdebug) printf
74
75 #define TAP             "tap"
76 #define VMNET           "vmnet"
77 #define VMNET_DEV_MASK  0x00010000
78
79 /* module */
80 static int              tapmodevent     (module_t, int, void *);
81
82 /* device */
83 static void             tapcreate       (dev_t);
84
85 /* network interface */
86 static void             tapifstart      (struct ifnet *);
87 static int              tapifioctl      (struct ifnet *, u_long, caddr_t);
88 static void             tapifinit       (void *);
89
90 /* character device */
91 static d_open_t         tapopen;
92 static d_close_t        tapclose;
93 static d_read_t         tapread;
94 static d_write_t        tapwrite;
95 static d_ioctl_t        tapioctl;
96 static d_poll_t         tappoll;
97
98 static struct cdevsw    tap_cdevsw = {
99         /* dev name */  CDEV_NAME,
100         /* dev major */ CDEV_MAJOR,
101         /* flags */     0,
102         /* port */      NULL,
103         /* autoq */     0,
104
105         /* open */      tapopen,
106         /* close */     tapclose,
107         /* read */      tapread,
108         /* write */     tapwrite,
109         /* ioctl */     tapioctl,
110         /* poll */      tappoll,
111         /* mmap */      nommap,
112         /* startegy */  nostrategy,
113         /* dump */      nodump,
114         /* psize */     nopsize
115 };
116
117 static int              taprefcnt = 0;          /* module ref. counter   */
118 static int              taplastunit = -1;       /* max. open unit number */
119 static int              tapdebug = 0;           /* debug flag            */
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 int               attached = 0;
138         struct ifnet            *ifp = NULL;
139         int                      unit, s;
140
141         switch (type) {
142         case MOD_LOAD:
143                 if (attached)
144                         return (EEXIST);
145
146                 cdevsw_add(&tap_cdevsw);
147                 attached = 1;
148         break;
149
150         case MOD_UNLOAD:
151                 if (taprefcnt > 0)
152                         return (EBUSY);
153
154                 cdevsw_remove(&tap_cdevsw);
155
156                 /* XXX: maintain tap ifs in a local list */
157                 unit = 0;
158                 while (unit <= taplastunit) {
159                         s = splimp();
160                         TAILQ_FOREACH(ifp, &ifnet, if_link)
161                                 if ((strcmp(ifp->if_dname, TAP) == 0) ||
162                                     (strcmp(ifp->if_dname, VMNET) == 0))
163                                         if (ifp->if_dunit == unit)
164                                                 break;
165                         splx(s);
166
167                         if (ifp != NULL) {
168                                 struct tap_softc        *tp = ifp->if_softc;
169
170                                 TAPDEBUG("detaching %s. minor = %#x, " \
171                                         "taplastunit = %d\n",
172                                         ifp->if_xname, minor(tp->tap_dev),
173                                         taplastunit);
174
175                                 s = splimp();
176                                 ether_ifdetach(ifp, 1);
177                                 splx(s);
178                                 destroy_dev(tp->tap_dev);
179                                 free(tp, M_TAP);
180                         }
181                         else
182                                 unit ++;
183                 }
184
185                 attached = 0;
186         break;
187
188         default:
189                 return (EOPNOTSUPP);
190         }
191
192         return (0);
193 } /* tapmodevent */
194
195
196 /*
197  * tapcreate
198  *
199  * to create interface
200  */
201 static void
202 tapcreate(dev)
203         dev_t   dev;
204 {
205         struct ifnet            *ifp = NULL;
206         struct tap_softc        *tp = NULL;
207         unsigned short           macaddr_hi;
208         int                      unit, s;
209         char                    *name = NULL;
210
211         /* allocate driver storage and create device */
212         MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK);
213         bzero(tp, sizeof(*tp));
214
215         /* select device: tap or vmnet */
216         if (minor(dev) & VMNET_DEV_MASK) {
217                 name = VMNET;
218                 unit = lminor(dev) & 0xff;
219                 tp->tap_flags |= TAP_VMNET;
220         }
221         else {
222                 name = TAP;
223                 unit = lminor(dev);
224         }
225
226         tp->tap_dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 
227                                                 0600, "%s%d", name, unit);
228         tp->tap_dev->si_drv1 = dev->si_drv1 = tp;
229
230         /* generate fake MAC address: 00 bd xx xx xx unit_no */
231         macaddr_hi = htons(0x00bd);
232         bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
233         bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
234         tp->arpcom.ac_enaddr[5] = (u_char)unit;
235
236         /* fill the rest and attach interface */        
237         ifp = &tp->tap_if;
238         ifp->if_softc = tp;
239
240         if_initname(ifp, name, unit);
241         if (unit > taplastunit)
242                 taplastunit = unit;
243
244         ifp->if_init = tapifinit;
245         ifp->if_output = ether_output;
246         ifp->if_start = tapifstart;
247         ifp->if_ioctl = tapifioctl;
248         ifp->if_mtu = ETHERMTU;
249         ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
250         ifp->if_snd.ifq_maxlen = ifqmaxlen;
251
252         s = splimp();
253         ether_ifattach(ifp, 1);
254         splx(s);
255
256         tp->tap_flags |= TAP_INITED;
257
258         TAPDEBUG("interface %s created. minor = %#x\n",
259                         ifp->if_xname, minor(tp->tap_dev));
260 } /* tapcreate */
261
262
263 /*
264  * tapopen 
265  *
266  * to open tunnel. must be superuser
267  */
268 static int
269 tapopen(dev_t dev, int flag, int mode, d_thread_t *td)
270 {
271         struct tap_softc        *tp = NULL;
272         int                      error;
273
274         KKASSERT(p != NULL);
275
276         if ((error = suser(td)) != 0)
277                 return (error);
278
279         tp = dev->si_drv1;
280         if (tp == NULL) {
281                 tapcreate(dev);
282                 tp = dev->si_drv1;
283         }
284
285         if (tp->tap_flags & TAP_OPEN)
286                 return (EBUSY);
287
288         bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
289
290         tp->tap_td = td;
291         tp->tap_flags |= TAP_OPEN;
292         taprefcnt ++;
293
294         TAPDEBUG("%s is open. minor = %#x, refcnt = %d, taplastunit = %d\n",
295                 tp->tap_if.if_xname,
296                 minor(tp->tap_dev), taprefcnt, taplastunit);
297
298         return (0);
299 } /* tapopen */
300
301
302 /*
303  * tapclose
304  *
305  * close the device - mark i/f down & delete routing info
306  */
307 static int
308 tapclose(dev_t dev, int foo, int bar, d_thread_t *td)
309 {
310         int                      s;
311         struct tap_softc        *tp = dev->si_drv1;
312         struct ifnet            *ifp = &tp->tap_if;
313         struct mbuf             *m = NULL;
314
315         /* junk all pending output */
316
317         s = splimp();
318         do {
319                 IF_DEQUEUE(&ifp->if_snd, m);
320                 if (m != NULL)
321                         m_freem(m);
322         } while (m != NULL);
323         splx(s);
324
325         /*
326          * do not bring the interface down, and do not anything with
327          * interface, if we are in VMnet mode. just close the device.
328          */
329
330         if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
331                 s = splimp();
332                 if_down(ifp);
333                 if (ifp->if_flags & IFF_RUNNING) {
334                         /* find internet addresses and delete routes */
335                         struct ifaddr   *ifa = NULL;
336
337                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
338                                 if (ifa->ifa_addr->sa_family == AF_INET) {
339                                         rtinit(ifa, (int)RTM_DELETE, 0);
340
341                                         /* remove address from interface */
342                                         bzero(ifa->ifa_addr, 
343                                                    sizeof(*(ifa->ifa_addr)));
344                                         bzero(ifa->ifa_dstaddr, 
345                                                    sizeof(*(ifa->ifa_dstaddr)));
346                                         bzero(ifa->ifa_netmask, 
347                                                    sizeof(*(ifa->ifa_netmask)));
348                                 }
349                         }
350
351                         ifp->if_flags &= ~IFF_RUNNING;
352                 }
353                 splx(s);
354         }
355
356         funsetown(tp->tap_sigio);
357         selwakeup(&tp->tap_rsel);
358
359         tp->tap_flags &= ~TAP_OPEN;
360         tp->tap_td = NULL;
361
362         taprefcnt --;
363         if (taprefcnt < 0) {
364                 taprefcnt = 0;
365                 printf("%s minor = %#x, refcnt = %d is out of sync. " \
366                         "set refcnt to 0\n", ifp->if_xname,
367                         minor(tp->tap_dev), taprefcnt);
368         }
369
370         TAPDEBUG("%s is closed. minor = %#x, refcnt = %d, taplastunit = %d\n",
371                         ifp->if_xname, minor(tp->tap_dev),
372                         taprefcnt, taplastunit);
373
374         return (0);
375 } /* tapclose */
376
377
378 /*
379  * tapifinit
380  *
381  * network interface initialization function
382  */
383 static void
384 tapifinit(xtp)
385         void    *xtp;
386 {
387         struct tap_softc        *tp = (struct tap_softc *)xtp;
388         struct ifnet            *ifp = &tp->tap_if;
389
390         TAPDEBUG("initializing %s, minor = %#x\n",
391                         ifp->if_xname, minor(tp->tap_dev));
392
393         ifp->if_flags |= IFF_RUNNING;
394         ifp->if_flags &= ~IFF_OACTIVE;
395
396         /* attempt to start output */
397         tapifstart(ifp);
398 } /* tapifinit */
399
400
401 /*
402  * tapifioctl
403  *
404  * Process an ioctl request on network interface
405  */
406 int
407 tapifioctl(ifp, cmd, data)
408         struct ifnet    *ifp;
409         u_long           cmd;
410         caddr_t          data;
411 {
412         struct tap_softc        *tp = (struct tap_softc *)(ifp->if_softc);
413         struct ifstat           *ifs = NULL;
414         int                      s, dummy;
415
416         switch (cmd) {
417                 case SIOCSIFADDR:
418                 case SIOCGIFADDR:
419                 case SIOCSIFMTU:
420                         s = splimp();
421                         dummy = ether_ioctl(ifp, cmd, data);
422                         splx(s);
423                         return (dummy);
424
425                 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
426                 case SIOCADDMULTI:
427                 case SIOCDELMULTI:
428                 break;
429
430                 case SIOCGIFSTATUS:
431                         s = splimp();
432                         ifs = (struct ifstat *)data;
433                         dummy = strlen(ifs->ascii);
434                         if (tp->tap_td != NULL && dummy < sizeof(ifs->ascii)) {
435                                 if (tp->tap_td->td_proc) {
436                                     snprintf(ifs->ascii + dummy,
437                                         sizeof(ifs->ascii) - dummy,
438                                         "\tOpened by pid %d\n",
439                                         (int)tp->tap_td->td_proc->p_pid);
440                                 } else {
441                                     snprintf(ifs->ascii + dummy,
442                                         sizeof(ifs->ascii) - dummy,
443                                         "\tOpened by td %p\n", tp->tap_td);
444                                 }
445                         }
446                         splx(s);
447                 break;
448
449                 default:
450                         return (EINVAL);
451         }
452
453         return (0);
454 } /* tapifioctl */
455
456
457 /*
458  * tapifstart 
459  * 
460  * queue packets from higher level ready to put out
461  */
462 static void
463 tapifstart(ifp)
464         struct ifnet    *ifp;
465 {
466         struct tap_softc        *tp = ifp->if_softc;
467         int                      s;
468
469         TAPDEBUG("%s starting, minor = %#x\n", 
470                         ifp->if_xname, minor(tp->tap_dev));
471
472         /*
473          * do not junk pending output if we are in VMnet mode.
474          * XXX: can this do any harm because of queue overflow?
475          */
476
477         if (((tp->tap_flags & TAP_VMNET) == 0) && 
478             ((tp->tap_flags & TAP_READY) != TAP_READY)) {
479                 struct mbuf     *m = NULL;
480
481                 TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
482                         ifp->if_xname,
483                         minor(tp->tap_dev), tp->tap_flags);
484
485                 s = splimp();
486                 do {
487                         IF_DEQUEUE(&ifp->if_snd, m);
488                         if (m != NULL)
489                                 m_freem(m);
490                         ifp->if_oerrors ++;
491                 } while (m != NULL);
492                 splx(s);
493
494                 return;
495         }
496
497         s = splimp();
498         ifp->if_flags |= IFF_OACTIVE;
499
500         if (ifp->if_snd.ifq_len != 0) {
501                 if (tp->tap_flags & TAP_RWAIT) {
502                         tp->tap_flags &= ~TAP_RWAIT;
503                         wakeup((caddr_t)tp);
504                 }
505
506                 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
507                         pgsigio(tp->tap_sigio, SIGIO, 0);
508
509                 selwakeup(&tp->tap_rsel);
510                 ifp->if_opackets ++; /* obytes are counted in ether_output */
511         }
512
513         ifp->if_flags &= ~IFF_OACTIVE;
514         splx(s);
515 } /* tapifstart */
516
517
518 /*
519  * tapioctl
520  *
521  * the cdevsw interface is now pretty minimal
522  */
523 static int
524 tapioctl(dev_t dev, u_long cmd, caddr_t data, int flag, d_thread_t *td)
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 reading, minor = %#x\n",
649                         ifp->if_xname, minor(tp->tap_dev));
650
651         if ((tp->tap_flags & TAP_READY) != TAP_READY) {
652                 TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
653                                 ifp->if_xname,
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, "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 dropping mbuf, minor = %#x\n",
694                                 ifp->if_xname, 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 writting, minor = %#x\n",
720                                 ifp->if_xname, 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 invalid packet len = %d, minor = %#x\n",
727                                 ifp->if_xname,
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_t dev, int events, d_thread_t *td)
790 {
791         struct tap_softc        *tp = dev->si_drv1;
792         struct ifnet            *ifp = &tp->tap_if;
793         int                      s, revents = 0;
794
795         TAPDEBUG("%s polling, minor = %#x\n",
796                                 ifp->if_xname, minor(tp->tap_dev));
797
798         s = splimp();
799         if (events & (POLLIN | POLLRDNORM)) {
800                 if (ifp->if_snd.ifq_len > 0) {
801                         TAPDEBUG("%s have data in queue. len = %d, " \
802                                 "minor = %#x\n", ifp->if_xname,
803                                 ifp->if_snd.ifq_len, minor(tp->tap_dev));
804
805                         revents |= (events & (POLLIN | POLLRDNORM));
806                 } 
807                 else {
808                         TAPDEBUG("%s waiting for data, minor = %#x\n",
809                                 ifp->if_xname, minor(tp->tap_dev));
810
811                         selrecord(td, &tp->tap_rsel);
812                 }
813         }
814
815         if (events & (POLLOUT | POLLWRNORM))
816                 revents |= (events & (POLLOUT | POLLWRNORM));
817
818         splx(s);
819         return (revents);
820 } /* tappoll */