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