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