xref: /dflybsd-src/sys/net/tap/if_tap.c (revision dc77152fd0d00e1b1f8b8cb04d0706817b468ddd)
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 */
824