Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:28:48 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, flag, mode, p)
268         dev_t            dev;
269         int              flag;
270         int              mode;
271         struct proc     *p;
272 {
273         struct tap_softc        *tp = NULL;
274         int                      error;
275
276         if ((error = suser(p)) != 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_pid = p->p_pid;
291         tp->tap_flags |= TAP_OPEN;
292         taprefcnt ++;
293
294         TAPDEBUG("%s%d is open. minor = %#x, refcnt = %d, taplastunit = %d\n",
295                 tp->tap_if.if_name, tp->tap_if.if_unit,
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, foo, bar, p)
309         dev_t            dev;
310         int              foo;
311         int              bar;
312         struct proc     *p;
313 {
314         int                      s;
315         struct tap_softc        *tp = dev->si_drv1;
316         struct ifnet            *ifp = &tp->tap_if;
317         struct mbuf             *m = NULL;
318
319         /* junk all pending output */
320
321         s = splimp();
322         do {
323                 IF_DEQUEUE(&ifp->if_snd, m);
324                 if (m != NULL)
325                         m_freem(m);
326         } while (m != NULL);
327         splx(s);
328
329         /*
330          * do not bring the interface down, and do not anything with
331          * interface, if we are in VMnet mode. just close the device.
332          */
333
334         if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
335                 s = splimp();
336                 if_down(ifp);
337                 if (ifp->if_flags & IFF_RUNNING) {
338                         /* find internet addresses and delete routes */
339                         struct ifaddr   *ifa = NULL;
340
341                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
342                                 if (ifa->ifa_addr->sa_family == AF_INET) {
343                                         rtinit(ifa, (int)RTM_DELETE, 0);
344
345                                         /* remove address from interface */
346                                         bzero(ifa->ifa_addr, 
347                                                    sizeof(*(ifa->ifa_addr)));
348                                         bzero(ifa->ifa_dstaddr, 
349                                                    sizeof(*(ifa->ifa_dstaddr)));
350                                         bzero(ifa->ifa_netmask, 
351                                                    sizeof(*(ifa->ifa_netmask)));
352                                 }
353                         }
354
355                         ifp->if_flags &= ~IFF_RUNNING;
356                 }
357                 splx(s);
358         }
359
360         funsetown(tp->tap_sigio);
361         selwakeup(&tp->tap_rsel);
362
363         tp->tap_flags &= ~TAP_OPEN;
364         tp->tap_pid = 0;
365
366         taprefcnt --;
367         if (taprefcnt < 0) {
368                 taprefcnt = 0;
369                 printf("%s%d minor = %#x, refcnt = %d is out of sync. " \
370                         "set refcnt to 0\n", ifp->if_name, ifp->if_unit, 
371                         minor(tp->tap_dev), taprefcnt);
372         }
373
374         TAPDEBUG("%s%d is closed. minor = %#x, refcnt = %d, taplastunit = %d\n",
375                         ifp->if_name, ifp->if_unit, minor(tp->tap_dev),
376                         taprefcnt, taplastunit);
377
378         return (0);
379 } /* tapclose */
380
381
382 /*
383  * tapifinit
384  *
385  * network interface initialization function
386  */
387 static void
388 tapifinit(xtp)
389         void    *xtp;
390 {
391         struct tap_softc        *tp = (struct tap_softc *)xtp;
392         struct ifnet            *ifp = &tp->tap_if;
393
394         TAPDEBUG("initializing %s%d, minor = %#x\n",
395                         ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
396
397         ifp->if_flags |= IFF_RUNNING;
398         ifp->if_flags &= ~IFF_OACTIVE;
399
400         /* attempt to start output */
401         tapifstart(ifp);
402 } /* tapifinit */
403
404
405 /*
406  * tapifioctl
407  *
408  * Process an ioctl request on network interface
409  */
410 int
411 tapifioctl(ifp, cmd, data)
412         struct ifnet    *ifp;
413         u_long           cmd;
414         caddr_t          data;
415 {
416         struct tap_softc        *tp = (struct tap_softc *)(ifp->if_softc);
417         struct ifstat           *ifs = NULL;
418         int                      s, dummy;
419
420         switch (cmd) {
421                 case SIOCSIFADDR:
422                 case SIOCGIFADDR:
423                 case SIOCSIFMTU:
424                         s = splimp();
425                         dummy = ether_ioctl(ifp, cmd, data);
426                         splx(s);
427                         return (dummy);
428
429                 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
430                 case SIOCADDMULTI:
431                 case SIOCDELMULTI:
432                 break;
433
434                 case SIOCGIFSTATUS:
435                         s = splimp();
436                         ifs = (struct ifstat *)data;
437                         dummy = strlen(ifs->ascii);
438                         if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
439                                 snprintf(ifs->ascii + dummy,
440                                         sizeof(ifs->ascii) - dummy,
441                                         "\tOpened by PID %d\n", tp->tap_pid);
442                         splx(s);
443                 break;
444
445                 default:
446                         return (EINVAL);
447         }
448
449         return (0);
450 } /* tapifioctl */
451
452
453 /*
454  * tapifstart 
455  * 
456  * queue packets from higher level ready to put out
457  */
458 static void
459 tapifstart(ifp)
460         struct ifnet    *ifp;
461 {
462         struct tap_softc        *tp = ifp->if_softc;
463         int                      s;
464
465         TAPDEBUG("%s%d starting, minor = %#x\n", 
466                         ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
467
468         /*
469          * do not junk pending output if we are in VMnet mode.
470          * XXX: can this do any harm because of queue overflow?
471          */
472
473         if (((tp->tap_flags & TAP_VMNET) == 0) && 
474             ((tp->tap_flags & TAP_READY) != TAP_READY)) {
475                 struct mbuf     *m = NULL;
476
477                 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
478                         ifp->if_name, ifp->if_unit,
479                         minor(tp->tap_dev), tp->tap_flags);
480
481                 s = splimp();
482                 do {
483                         IF_DEQUEUE(&ifp->if_snd, m);
484                         if (m != NULL)
485                                 m_freem(m);
486                         ifp->if_oerrors ++;
487                 } while (m != NULL);
488                 splx(s);
489
490                 return;
491         }
492
493         s = splimp();
494         ifp->if_flags |= IFF_OACTIVE;
495
496         if (ifp->if_snd.ifq_len != 0) {
497                 if (tp->tap_flags & TAP_RWAIT) {
498                         tp->tap_flags &= ~TAP_RWAIT;
499                         wakeup((caddr_t)tp);
500                 }
501
502                 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
503                         pgsigio(tp->tap_sigio, SIGIO, 0);
504
505                 selwakeup(&tp->tap_rsel);
506                 ifp->if_opackets ++; /* obytes are counted in ether_output */
507         }
508
509         ifp->if_flags &= ~IFF_OACTIVE;
510         splx(s);
511 } /* tapifstart */
512
513
514 /*
515  * tapioctl
516  *
517  * the cdevsw interface is now pretty minimal
518  */
519 static int
520 tapioctl(dev, cmd, data, flag, p)
521         dev_t            dev;
522         u_long           cmd;
523         caddr_t          data;
524         int              flag;
525         struct proc     *p;
526 {
527         struct tap_softc        *tp = dev->si_drv1;
528         struct ifnet            *ifp = &tp->tap_if;
529         struct tapinfo          *tapp = NULL;
530         int                      s;
531
532         switch (cmd) {
533                 case TAPSIFINFO:
534                         s = splimp();
535                         tapp = (struct tapinfo *)data;
536                         ifp->if_mtu = tapp->mtu;
537                         ifp->if_type = tapp->type;
538                         ifp->if_baudrate = tapp->baudrate;
539                         splx(s);
540                 break;
541
542                 case TAPGIFINFO:
543                         tapp = (struct tapinfo *)data;
544                         tapp->mtu = ifp->if_mtu;
545                         tapp->type = ifp->if_type;
546                         tapp->baudrate = ifp->if_baudrate;
547                 break;
548
549                 case TAPSDEBUG:
550                         tapdebug = *(int *)data;
551                 break;
552
553                 case TAPGDEBUG:
554                         *(int *)data = tapdebug;
555                 break;
556
557                 case FIONBIO:
558                 break;
559
560                 case FIOASYNC:
561                         s = splimp();
562                         if (*(int *)data)
563                                 tp->tap_flags |= TAP_ASYNC;
564                         else
565                                 tp->tap_flags &= ~TAP_ASYNC;
566                         splx(s);
567                 break;
568
569                 case FIONREAD:
570                         s = splimp();
571                         if (ifp->if_snd.ifq_head) {
572                                 struct mbuf     *mb = ifp->if_snd.ifq_head;
573
574                                 for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
575                                         *(int *)data += mb->m_len;
576                         } 
577                         else
578                                 *(int *)data = 0;
579                         splx(s);
580                 break;
581
582                 case FIOSETOWN:
583                         return (fsetown(*(int *)data, &tp->tap_sigio));
584
585                 case FIOGETOWN:
586                         *(int *)data = fgetown(tp->tap_sigio);
587                         return (0);
588
589                 /* this is deprecated, FIOSETOWN should be used instead */
590                 case TIOCSPGRP:
591                         return (fsetown(-(*(int *)data), &tp->tap_sigio));
592
593                 /* this is deprecated, FIOGETOWN should be used instead */
594                 case TIOCGPGRP:
595                         *(int *)data = -fgetown(tp->tap_sigio);
596                         return (0);
597
598                 /* VMware/VMnet port ioctl's */
599
600                 case SIOCGIFFLAGS:      /* get ifnet flags */
601                         bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
602                 break;
603
604                 case VMIO_SIOCSIFFLAGS: { /* VMware/VMnet SIOCSIFFLAGS */
605                         short   f = *(short *)data;
606
607                         f &= 0x0fff;
608                         f &= ~IFF_CANTCHANGE;
609                         f |= IFF_UP;
610
611                         s = splimp();
612                         ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
613                         splx(s);
614                 } break;
615
616                 case OSIOCGIFADDR:      /* get MAC address of the remote side */
617                 case SIOCGIFADDR:
618                         bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
619                 break;
620
621                 case SIOCSIFADDR:       /* set MAC address of the remote side */
622                         bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
623                 break;
624
625                 default:
626                         return (ENOTTY);
627         }
628         return (0);
629 } /* tapioctl */
630
631
632 /*
633  * tapread
634  *
635  * the cdevsw read interface - reads a packet at a time, or at
636  * least as much of a packet as can be read
637  */
638 static int
639 tapread(dev, uio, flag)
640         dev_t            dev;
641         struct uio      *uio;
642         int              flag;
643 {
644         struct tap_softc        *tp = dev->si_drv1;
645         struct ifnet            *ifp = &tp->tap_if;
646         struct mbuf             *m0 = NULL;
647         int                      error = 0, len, s;
648
649         TAPDEBUG("%s%d reading, minor = %#x\n",
650                         ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
651
652         if ((tp->tap_flags & TAP_READY) != TAP_READY) {
653                 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
654                                 ifp->if_name, ifp->if_unit, 
655                                 minor(tp->tap_dev), tp->tap_flags);
656
657                 return (EHOSTDOWN);
658         }
659
660         tp->tap_flags &= ~TAP_RWAIT;
661
662         /* sleep until we get a packet */
663         do {
664                 s = splimp();
665                 IF_DEQUEUE(&ifp->if_snd, m0);
666                 splx(s);
667
668                 if (m0 == NULL) {
669                         if (flag & IO_NDELAY)
670                                 return (EWOULDBLOCK);
671                         
672                         tp->tap_flags |= TAP_RWAIT;
673                         error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0);
674                         if (error)
675                                 return (error);
676                 }
677         } while (m0 == NULL);
678
679         /* feed packet to bpf */
680         if (ifp->if_bpf != NULL)
681                 bpf_mtap(ifp, m0);
682
683         /* xfer packet to user space */
684         while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) {
685                 len = min(uio->uio_resid, m0->m_len);
686                 if (len == 0)
687                         break;
688
689                 error = uiomove(mtod(m0, caddr_t), len, uio);
690                 m0 = m_free(m0);
691         }
692
693         if (m0 != NULL) {
694                 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n",
695                                 ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
696                 m_freem(m0);
697         }
698
699         return (error);
700 } /* tapread */
701
702
703 /*
704  * tapwrite
705  *
706  * the cdevsw write interface - an atomic write is a packet - or else!
707  */
708 static int
709 tapwrite(dev, uio, flag)
710         dev_t            dev;
711         struct uio      *uio;
712         int              flag;
713 {
714         struct tap_softc        *tp = dev->si_drv1;
715         struct ifnet            *ifp = &tp->tap_if;
716         struct mbuf             *top = NULL, **mp = NULL, *m = NULL;
717         struct ether_header     *eh = NULL;
718         int                      error = 0, tlen, mlen;
719
720         TAPDEBUG("%s%d writting, minor = %#x\n",
721                                 ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
722
723         if (uio->uio_resid == 0)
724                 return (0);
725
726         if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
727                 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n",
728                                 ifp->if_name, ifp->if_unit, 
729                                 uio->uio_resid, minor(tp->tap_dev));
730
731                 return (EIO);
732         }
733         tlen = uio->uio_resid;
734
735         /* get a header mbuf */
736         MGETHDR(m, M_DONTWAIT, MT_DATA);
737         if (m == NULL)
738                 return (ENOBUFS);
739         mlen = MHLEN;
740
741         top = 0;
742         mp = &top;
743         while ((error == 0) && (uio->uio_resid > 0)) {
744                 m->m_len = min(mlen, uio->uio_resid);
745                 error = uiomove(mtod(m, caddr_t), m->m_len, uio);
746                 *mp = m;
747                 mp = &m->m_next;
748                 if (uio->uio_resid > 0) {
749                         MGET(m, M_DONTWAIT, MT_DATA);
750                         if (m == NULL) {
751                                 error = ENOBUFS;
752                                 break;
753                         }
754                         mlen = MLEN;
755                 }
756         }
757         if (error) {
758                 ifp->if_ierrors ++;
759                 if (top)
760                         m_freem(top);
761                 return (error);
762         }
763
764         top->m_pkthdr.len = tlen;
765         top->m_pkthdr.rcvif = ifp;
766         
767         /*
768          * Ethernet bridge and bpf are handled in ether_input
769          *
770          * adjust mbuf and give packet to the ether_input
771          */
772
773         eh = mtod(top, struct ether_header *);
774         m_adj(top, sizeof(struct ether_header));
775         ether_input(ifp, eh, top);
776         ifp->if_ipackets ++; /* ibytes are counted in ether_input */
777
778         return (0);
779 } /* tapwrite */
780
781
782 /*
783  * tappoll
784  *
785  * the poll interface, this is only useful on reads
786  * really. the write detect always returns true, write never blocks
787  * anyway, it either accepts the packet or drops it
788  */
789 static int
790 tappoll(dev, events, p)
791         dev_t            dev;
792         int              events;
793         struct proc     *p;
794 {
795         struct tap_softc        *tp = dev->si_drv1;
796         struct ifnet            *ifp = &tp->tap_if;
797         int                      s, revents = 0;
798
799         TAPDEBUG("%s%d polling, minor = %#x\n",
800                                 ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
801
802         s = splimp();
803         if (events & (POLLIN | POLLRDNORM)) {
804                 if (ifp->if_snd.ifq_len > 0) {
805                         TAPDEBUG("%s%d have data in queue. len = %d, " \
806                                 "minor = %#x\n", ifp->if_name, ifp->if_unit,
807                                 ifp->if_snd.ifq_len, minor(tp->tap_dev));
808
809                         revents |= (events & (POLLIN | POLLRDNORM));
810                 } 
811                 else {
812                         TAPDEBUG("%s%d waiting for data, minor = %#x\n",
813                                 ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
814
815                         selrecord(p, &tp->tap_rsel);
816                 }
817         }
818
819         if (events & (POLLOUT | POLLWRNORM))
820                 revents |= (events & (POLLOUT | POLLWRNORM));
821
822         splx(s);
823         return (revents);
824 } /* tappoll */