if_tap.c revision 126845
1276305Sngie/*
2236769Sobrien * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
3236769Sobrien * All rights reserved.
4236769Sobrien *
5236769Sobrien * Redistribution and use in source and binary forms, with or without
6236769Sobrien * modification, are permitted provided that the following conditions
7236769Sobrien * are met:
8236769Sobrien * 1. Redistributions of source code must retain the above copyright
9236769Sobrien *    notice, this list of conditions and the following disclaimer.
10236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11236769Sobrien *    notice, this list of conditions and the following disclaimer in the
12236769Sobrien *    documentation and/or other materials provided with the distribution.
13236769Sobrien *
14236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17236769Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24236769Sobrien * SUCH DAMAGE.
25236769Sobrien *
26236769Sobrien * BASED ON:
27236769Sobrien * -------------------------------------------------------------------------
28236769Sobrien *
29236769Sobrien * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
30236769Sobrien * Nottingham University 1987.
31236769Sobrien */
32236769Sobrien
33236769Sobrien/*
34236769Sobrien * $FreeBSD: head/sys/net/if_tap.c 126845 2004-03-11 12:58:55Z phk $
35236769Sobrien * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
36236769Sobrien */
37236769Sobrien
38236769Sobrien#include "opt_inet.h"
39236769Sobrien
40236769Sobrien#include <sys/param.h>
41236769Sobrien#include <sys/conf.h>
42236769Sobrien#include <sys/filedesc.h>
43236769Sobrien#include <sys/filio.h>
44236769Sobrien#include <sys/kernel.h>
45236769Sobrien#include <sys/malloc.h>
46236769Sobrien#include <sys/mbuf.h>
47236769Sobrien#include <sys/poll.h>
48236769Sobrien#include <sys/proc.h>
49236769Sobrien#include <sys/signalvar.h>
50236769Sobrien#include <sys/socket.h>
51236769Sobrien#include <sys/sockio.h>
52236769Sobrien#include <sys/sysctl.h>
53236769Sobrien#include <sys/systm.h>
54236769Sobrien#include <sys/ttycom.h>
55236769Sobrien#include <sys/uio.h>
56236769Sobrien#include <sys/vnode.h>
57236769Sobrien#include <sys/queue.h>
58236769Sobrien
59236769Sobrien#include <net/bpf.h>
60236769Sobrien#include <net/ethernet.h>
61236769Sobrien#include <net/if.h>
62236769Sobrien#include <net/if_arp.h>
63236769Sobrien#include <net/route.h>
64236769Sobrien
65236769Sobrien#include <netinet/in.h>
66236769Sobrien
67236769Sobrien#include <net/if_tapvar.h>
68236769Sobrien#include <net/if_tap.h>
69236769Sobrien
70236769Sobrien
71236769Sobrien#define CDEV_NAME	"tap"
72236769Sobrien#define TAPDEBUG	if (tapdebug) printf
73276305Sngie
74236769Sobrien#define TAP		"tap"
75236769Sobrien#define VMNET		"vmnet"
76236769Sobrien#define TAPMAXUNIT	0x7fff
77236769Sobrien#define VMNET_DEV_MASK	CLONE_FLAG0
78236769Sobrien
79236769Sobrien/* module */
80276305Sngiestatic int		tapmodevent(module_t, int, void *);
81236769Sobrien
82236769Sobrien/* device */
83236769Sobrienstatic void		tapclone(void *, char *, int, dev_t *);
84236769Sobrienstatic void		tapcreate(dev_t);
85236769Sobrien
86236769Sobrien/* network interface */
87236769Sobrienstatic void		tapifstart(struct ifnet *);
88236769Sobrienstatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
89236769Sobrienstatic void		tapifinit(void *);
90236769Sobrien
91236769Sobrien/* character device */
92236769Sobrienstatic d_open_t		tapopen;
93236769Sobrienstatic d_close_t	tapclose;
94236769Sobrienstatic d_read_t		tapread;
95236769Sobrienstatic d_write_t	tapwrite;
96236769Sobrienstatic d_ioctl_t	tapioctl;
97236769Sobrienstatic d_poll_t		tappoll;
98236769Sobrien
99236769Sobrienstatic struct cdevsw	tap_cdevsw = {
100236769Sobrien	.d_version =	D_VERSION,
101236769Sobrien	.d_flags =	D_PSEUDO | D_NEEDGIANT,
102236769Sobrien	.d_open =	tapopen,
103236769Sobrien	.d_close =	tapclose,
104236769Sobrien	.d_read =	tapread,
105236769Sobrien	.d_write =	tapwrite,
106236769Sobrien	.d_ioctl =	tapioctl,
107236769Sobrien	.d_poll =	tappoll,
108236769Sobrien	.d_name =	CDEV_NAME,
109236769Sobrien};
110236769Sobrien
111236769Sobrienstatic int			tapdebug = 0;        /* debug flag   */
112236769Sobrienstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
113236769Sobrienstatic struct clonedevs 	*tapclones;
114236769Sobrien
115236769SobrienMALLOC_DECLARE(M_TAP);
116236769SobrienMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
117236769SobrienSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
118236769SobrienDEV_MODULE(if_tap, tapmodevent, NULL);
119236769Sobrien
120236769Sobrien/*
121236769Sobrien * tapmodevent
122236769Sobrien *
123236769Sobrien * module event handler
124236769Sobrien */
125236769Sobrienstatic int
126236769Sobrientapmodevent(mod, type, data)
127236769Sobrien	module_t	 mod;
128236769Sobrien	int		 type;
129236769Sobrien	void		*data;
130236769Sobrien{
131236769Sobrien	static eventhandler_tag	 eh_tag = NULL;
132236769Sobrien	struct tap_softc	*tp = NULL;
133236769Sobrien	struct ifnet		*ifp = NULL;
134236769Sobrien	int			 s;
135236769Sobrien
136236769Sobrien	switch (type) {
137236769Sobrien	case MOD_LOAD:
138236769Sobrien
139236769Sobrien		/* intitialize device */
140236769Sobrien
141236769Sobrien		SLIST_INIT(&taphead);
142236769Sobrien
143236769Sobrien		clone_setup(&tapclones);
144236769Sobrien		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
145236769Sobrien		if (eh_tag == NULL)
146236769Sobrien			return (ENOMEM);
147236769Sobrien		return (0);
148236769Sobrien
149236769Sobrien	case MOD_UNLOAD:
150236769Sobrien		SLIST_FOREACH(tp, &taphead, tap_next)
151236769Sobrien			if (tp->tap_flags & TAP_OPEN)
152236769Sobrien				return (EBUSY);
153236769Sobrien
154236769Sobrien		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
155236769Sobrien
156236769Sobrien		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
157236769Sobrien			SLIST_REMOVE_HEAD(&taphead, tap_next);
158236769Sobrien
159236769Sobrien			ifp = &tp->tap_if;
160236769Sobrien
161236769Sobrien			TAPDEBUG("detaching %s\n", ifp->if_xname);
162236769Sobrien
163236769Sobrien			KASSERT(!(tp->tap_flags & TAP_OPEN),
164236769Sobrien				("%s flags is out of sync", ifp->if_xname));
165236769Sobrien
166236769Sobrien			destroy_dev(tp->tap_dev);
167236769Sobrien			s = splimp();
168236769Sobrien			ether_ifdetach(ifp);
169236769Sobrien			splx(s);
170236769Sobrien
171236769Sobrien			free(tp, M_TAP);
172236769Sobrien		}
173236769Sobrien		clone_cleanup(&tapclones);
174236769Sobrien
175236769Sobrien		break;
176236769Sobrien
177236769Sobrien	default:
178236769Sobrien		return (EOPNOTSUPP);
179236769Sobrien	}
180236769Sobrien
181236769Sobrien	return (0);
182236769Sobrien} /* tapmodevent */
183236769Sobrien
184236769Sobrien
185236769Sobrien/*
186236769Sobrien * DEVFS handler
187236769Sobrien *
188236769Sobrien * We need to support two kind of devices - tap and vmnet
189236769Sobrien */
190236769Sobrienstatic void
191236769Sobrientapclone(arg, name, namelen, dev)
192236769Sobrien	void	*arg;
193236769Sobrien	char	*name;
194236769Sobrien	int	 namelen;
195236769Sobrien	dev_t	*dev;
196236769Sobrien{
197236769Sobrien	u_int		extra;
198236769Sobrien	int		i, unit;
199236769Sobrien	char		*device_name = name;
200236769Sobrien
201236769Sobrien	if (*dev != NODEV)
202236769Sobrien		return;
203236769Sobrien
204236769Sobrien	device_name = TAP;
205236769Sobrien	extra = 0;
206236769Sobrien	if (strcmp(name, TAP) == 0) {
207236769Sobrien		unit = -1;
208236769Sobrien	} else if (strcmp(name, VMNET) == 0) {
209236769Sobrien		device_name = VMNET;
210236769Sobrien		extra = VMNET_DEV_MASK;
211236769Sobrien		unit = -1;
212236769Sobrien	} else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
213236769Sobrien		device_name = VMNET;
214236769Sobrien		extra = VMNET_DEV_MASK;
215236769Sobrien		if (dev_stdclone(name, NULL, device_name, &unit) != 1)
216236769Sobrien			return;
217236769Sobrien	}
218236769Sobrien
219236769Sobrien	/* find any existing device, or allocate new unit number */
220236769Sobrien	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
221236769Sobrien	if (i) {
222236769Sobrien		*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
223236769Sobrien		     UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
224276305Sngie		if (*dev != NULL)
225276305Sngie			(*dev)->si_flags |= SI_CHEAPCLONE;
226276305Sngie	}
227236769Sobrien} /* tapclone */
228236769Sobrien
229236769Sobrien
230236769Sobrien/*
231236769Sobrien * tapcreate
232236769Sobrien *
233236769Sobrien * to create interface
234236769Sobrien */
235236769Sobrienstatic void
236236769Sobrientapcreate(dev)
237236769Sobrien	dev_t	dev;
238236769Sobrien{
239236769Sobrien	struct ifnet		*ifp = NULL;
240236769Sobrien	struct tap_softc	*tp = NULL;
241236769Sobrien	unsigned short		 macaddr_hi;
242236769Sobrien	int			 unit, s;
243236769Sobrien	char			*name = NULL;
244236769Sobrien
245236769Sobrien	dev->si_flags &= ~SI_CHEAPCLONE;
246236769Sobrien
247236769Sobrien	/* allocate driver storage and create device */
248236769Sobrien	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
249236769Sobrien	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
250236769Sobrien
251236769Sobrien	unit = dev2unit(dev);
252236769Sobrien
253236769Sobrien	/* select device: tap or vmnet */
254236769Sobrien	if (unit & VMNET_DEV_MASK) {
255236769Sobrien		name = VMNET;
256236769Sobrien		tp->tap_flags |= TAP_VMNET;
257236769Sobrien	} else
258236769Sobrien		name = TAP;
259236769Sobrien
260236769Sobrien	unit &= TAPMAXUNIT;
261236769Sobrien
262236769Sobrien	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
263236769Sobrien
264236769Sobrien	/* generate fake MAC address: 00 bd xx xx xx unit_no */
265236769Sobrien	macaddr_hi = htons(0x00bd);
266236769Sobrien	bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
267236769Sobrien	bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
268236769Sobrien	tp->arpcom.ac_enaddr[5] = (u_char)unit;
269236769Sobrien
270236769Sobrien	/* fill the rest and attach interface */
271236769Sobrien	ifp = &tp->tap_if;
272236769Sobrien	ifp->if_softc = tp;
273236769Sobrien	if_initname(ifp, name, unit);
274236769Sobrien	ifp->if_init = tapifinit;
275236769Sobrien	ifp->if_start = tapifstart;
276236769Sobrien	ifp->if_ioctl = tapifioctl;
277236769Sobrien	ifp->if_mtu = ETHERMTU;
278236769Sobrien	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
279236769Sobrien	ifp->if_snd.ifq_maxlen = ifqmaxlen;
280236769Sobrien
281236769Sobrien	dev->si_drv1 = tp;
282236769Sobrien	tp->tap_dev = dev;
283236769Sobrien
284236769Sobrien	s = splimp();
285236769Sobrien	ether_ifattach(ifp, tp->arpcom.ac_enaddr);
286236769Sobrien	splx(s);
287236769Sobrien
288236769Sobrien	tp->tap_flags |= TAP_INITED;
289236769Sobrien
290236769Sobrien	TAPDEBUG("interface %s is created. minor = %#x\n",
291236769Sobrien		ifp->if_xname, minor(dev));
292236769Sobrien} /* tapcreate */
293236769Sobrien
294236769Sobrien
295236769Sobrien/*
296236769Sobrien * tapopen
297236769Sobrien *
298236769Sobrien * to open tunnel. must be superuser
299236769Sobrien */
300236769Sobrienstatic int
301236769Sobrientapopen(dev, flag, mode, td)
302236769Sobrien	dev_t		 dev;
303236769Sobrien	int		 flag;
304236769Sobrien	int		 mode;
305236769Sobrien	struct thread	*td;
306236769Sobrien{
307236769Sobrien	struct tap_softc	*tp = NULL;
308236769Sobrien	int			 error;
309236769Sobrien
310236769Sobrien	if ((error = suser(td)) != 0)
311236769Sobrien		return (error);
312236769Sobrien
313236769Sobrien	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
314236769Sobrien		return (ENXIO);
315236769Sobrien
316236769Sobrien	tp = dev->si_drv1;
317236769Sobrien	if (tp == NULL) {
318236769Sobrien		tapcreate(dev);
319236769Sobrien		tp = dev->si_drv1;
320236769Sobrien	}
321236769Sobrien
322236769Sobrien	KASSERT(!(tp->tap_flags & TAP_OPEN),
323236769Sobrien		("%s flags is out of sync", tp->tap_if.if_xname));
324236769Sobrien
325236769Sobrien	bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
326236769Sobrien
327236769Sobrien	tp->tap_pid = td->td_proc->p_pid;
328236769Sobrien	tp->tap_flags |= TAP_OPEN;
329236769Sobrien
330236769Sobrien	TAPDEBUG("%s is open. minor = %#x\n",
331236769Sobrien		tp->tap_if.if_xname, minor(dev));
332236769Sobrien
333236769Sobrien	return (0);
334236769Sobrien} /* tapopen */
335236769Sobrien
336236769Sobrien
337236769Sobrien/*
338236769Sobrien * tapclose
339236769Sobrien *
340236769Sobrien * close the device - mark i/f down & delete routing info
341236769Sobrien */
342236769Sobrienstatic int
343236769Sobrientapclose(dev, foo, bar, td)
344236769Sobrien	dev_t		 dev;
345236769Sobrien	int		 foo;
346236769Sobrien	int		 bar;
347236769Sobrien	struct thread	*td;
348236769Sobrien{
349236769Sobrien	struct tap_softc	*tp = dev->si_drv1;
350236769Sobrien	struct ifnet		*ifp = &tp->tap_if;
351236769Sobrien	int			s;
352236769Sobrien
353236769Sobrien	/* junk all pending output */
354236769Sobrien	IF_DRAIN(&ifp->if_snd);
355236769Sobrien
356236769Sobrien	/*
357236769Sobrien	 * do not bring the interface down, and do not anything with
358236769Sobrien	 * interface, if we are in VMnet mode. just close the device.
359236769Sobrien	 */
360236769Sobrien
361236769Sobrien	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
362236769Sobrien		s = splimp();
363236769Sobrien		if_down(ifp);
364236769Sobrien		if (ifp->if_flags & IFF_RUNNING) {
365236769Sobrien			/* find internet addresses and delete routes */
366236769Sobrien			struct ifaddr	*ifa = NULL;
367236769Sobrien
368236769Sobrien			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
369236769Sobrien				if (ifa->ifa_addr->sa_family == AF_INET) {
370236769Sobrien					rtinit(ifa, (int)RTM_DELETE, 0);
371236769Sobrien
372236769Sobrien					/* remove address from interface */
373236769Sobrien					bzero(ifa->ifa_addr,
374236769Sobrien						   sizeof(*(ifa->ifa_addr)));
375236769Sobrien					bzero(ifa->ifa_dstaddr,
376236769Sobrien						   sizeof(*(ifa->ifa_dstaddr)));
377236769Sobrien					bzero(ifa->ifa_netmask,
378236769Sobrien						   sizeof(*(ifa->ifa_netmask)));
379236769Sobrien				}
380236769Sobrien			}
381236769Sobrien
382236769Sobrien			ifp->if_flags &= ~IFF_RUNNING;
383236769Sobrien		}
384236769Sobrien		splx(s);
385236769Sobrien	}
386236769Sobrien
387236769Sobrien	funsetown(&tp->tap_sigio);
388236769Sobrien	selwakeuppri(&tp->tap_rsel, PZERO+1);
389236769Sobrien
390236769Sobrien	tp->tap_flags &= ~TAP_OPEN;
391236769Sobrien	tp->tap_pid = 0;
392236769Sobrien
393236769Sobrien	TAPDEBUG("%s is closed. minor = %#x\n",
394236769Sobrien		ifp->if_xname, minor(dev));
395236769Sobrien
396236769Sobrien	return (0);
397236769Sobrien} /* tapclose */
398236769Sobrien
399236769Sobrien
400236769Sobrien/*
401236769Sobrien * tapifinit
402236769Sobrien *
403236769Sobrien * network interface initialization function
404236769Sobrien */
405236769Sobrienstatic void
406236769Sobrientapifinit(xtp)
407236769Sobrien	void	*xtp;
408236769Sobrien{
409236769Sobrien	struct tap_softc	*tp = (struct tap_softc *)xtp;
410236769Sobrien	struct ifnet		*ifp = &tp->tap_if;
411236769Sobrien
412236769Sobrien	TAPDEBUG("initializing %s\n", ifp->if_xname);
413236769Sobrien
414236769Sobrien	ifp->if_flags |= IFF_RUNNING;
415236769Sobrien	ifp->if_flags &= ~IFF_OACTIVE;
416236769Sobrien
417236769Sobrien	/* attempt to start output */
418236769Sobrien	tapifstart(ifp);
419236769Sobrien} /* tapifinit */
420236769Sobrien
421236769Sobrien
422236769Sobrien/*
423236769Sobrien * tapifioctl
424236769Sobrien *
425236769Sobrien * Process an ioctl request on network interface
426236769Sobrien */
427236769Sobrienstatic int
428236769Sobrientapifioctl(ifp, cmd, data)
429236769Sobrien	struct ifnet	*ifp;
430236769Sobrien	u_long		 cmd;
431236769Sobrien	caddr_t		 data;
432236769Sobrien{
433236769Sobrien	struct tap_softc	*tp = (struct tap_softc *)(ifp->if_softc);
434236769Sobrien	struct ifstat		*ifs = NULL;
435236769Sobrien	int			 s, dummy;
436236769Sobrien
437236769Sobrien	switch (cmd) {
438236769Sobrien		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
439236769Sobrien		case SIOCADDMULTI:
440236769Sobrien		case SIOCDELMULTI:
441236769Sobrien			break;
442236769Sobrien
443236769Sobrien		case SIOCGIFSTATUS:
444236769Sobrien			s = splimp();
445236769Sobrien			ifs = (struct ifstat *)data;
446236769Sobrien			dummy = strlen(ifs->ascii);
447236769Sobrien			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
448236769Sobrien				snprintf(ifs->ascii + dummy,
449236769Sobrien					sizeof(ifs->ascii) - dummy,
450236769Sobrien					"\tOpened by PID %d\n", tp->tap_pid);
451236769Sobrien			splx(s);
452236769Sobrien			break;
453236769Sobrien
454236769Sobrien		default:
455236769Sobrien			s = splimp();
456236769Sobrien			dummy = ether_ioctl(ifp, cmd, data);
457236769Sobrien			splx(s);
458236769Sobrien			return (dummy);
459236769Sobrien	}
460236769Sobrien
461236769Sobrien	return (0);
462236769Sobrien} /* tapifioctl */
463236769Sobrien
464236769Sobrien
465236769Sobrien/*
466236769Sobrien * tapifstart
467 *
468 * queue packets from higher level ready to put out
469 */
470static void
471tapifstart(ifp)
472	struct ifnet	*ifp;
473{
474	struct tap_softc	*tp = ifp->if_softc;
475	int			 s;
476
477	TAPDEBUG("%s starting\n", ifp->if_xname);
478
479	/*
480	 * do not junk pending output if we are in VMnet mode.
481	 * XXX: can this do any harm because of queue overflow?
482	 */
483
484	if (((tp->tap_flags & TAP_VMNET) == 0) &&
485	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
486		struct mbuf	*m = NULL;
487
488		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
489		    tp->tap_flags);
490
491		s = splimp();
492		do {
493			IF_DEQUEUE(&ifp->if_snd, m);
494			if (m != NULL)
495				m_freem(m);
496			ifp->if_oerrors ++;
497		} while (m != NULL);
498		splx(s);
499
500		return;
501	}
502
503	s = splimp();
504	ifp->if_flags |= IFF_OACTIVE;
505
506	if (ifp->if_snd.ifq_len != 0) {
507		if (tp->tap_flags & TAP_RWAIT) {
508			tp->tap_flags &= ~TAP_RWAIT;
509			wakeup(tp);
510		}
511
512		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
513			pgsigio(&tp->tap_sigio, SIGIO, 0);
514
515		selwakeuppri(&tp->tap_rsel, PZERO+1);
516		ifp->if_opackets ++; /* obytes are counted in ether_output */
517	}
518
519	ifp->if_flags &= ~IFF_OACTIVE;
520	splx(s);
521} /* tapifstart */
522
523
524/*
525 * tapioctl
526 *
527 * the cdevsw interface is now pretty minimal
528 */
529static int
530tapioctl(dev, cmd, data, flag, td)
531	dev_t		 dev;
532	u_long		 cmd;
533	caddr_t		 data;
534	int		 flag;
535	struct thread	*td;
536{
537	struct tap_softc	*tp = dev->si_drv1;
538	struct ifnet		*ifp = &tp->tap_if;
539	struct tapinfo		*tapp = NULL;
540	int			 s;
541	int			 f;
542
543	switch (cmd) {
544		case TAPSIFINFO:
545			s = splimp();
546			tapp = (struct tapinfo *)data;
547			ifp->if_mtu = tapp->mtu;
548			ifp->if_type = tapp->type;
549			ifp->if_baudrate = tapp->baudrate;
550			splx(s);
551			break;
552
553		case TAPGIFINFO:
554			tapp = (struct tapinfo *)data;
555			tapp->mtu = ifp->if_mtu;
556			tapp->type = ifp->if_type;
557			tapp->baudrate = ifp->if_baudrate;
558			break;
559
560		case TAPSDEBUG:
561			tapdebug = *(int *)data;
562			break;
563
564		case TAPGDEBUG:
565			*(int *)data = tapdebug;
566			break;
567
568		case FIONBIO:
569			break;
570
571		case FIOASYNC:
572			s = splimp();
573			if (*(int *)data)
574				tp->tap_flags |= TAP_ASYNC;
575			else
576				tp->tap_flags &= ~TAP_ASYNC;
577			splx(s);
578			break;
579
580		case FIONREAD:
581			s = splimp();
582			if (ifp->if_snd.ifq_head) {
583				struct mbuf	*mb = ifp->if_snd.ifq_head;
584
585				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
586					*(int *)data += mb->m_len;
587			} else
588				*(int *)data = 0;
589			splx(s);
590			break;
591
592		case FIOSETOWN:
593			return (fsetown(*(int *)data, &tp->tap_sigio));
594
595		case FIOGETOWN:
596			*(int *)data = fgetown(&tp->tap_sigio);
597			return (0);
598
599		/* this is deprecated, FIOSETOWN should be used instead */
600		case TIOCSPGRP:
601			return (fsetown(-(*(int *)data), &tp->tap_sigio));
602
603		/* this is deprecated, FIOGETOWN should be used instead */
604		case TIOCGPGRP:
605			*(int *)data = -fgetown(&tp->tap_sigio);
606			return (0);
607
608		/* VMware/VMnet port ioctl's */
609
610		case SIOCGIFFLAGS:	/* get ifnet flags */
611			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
612			break;
613
614		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
615			f = *(int *)data;
616			f &= 0x0fff;
617			f &= ~IFF_CANTCHANGE;
618			f |= IFF_UP;
619
620			s = splimp();
621			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
622			splx(s);
623			break;
624
625		case OSIOCGIFADDR:	/* get MAC address of the remote side */
626		case SIOCGIFADDR:
627			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
628			break;
629
630		case SIOCSIFADDR:	/* set MAC address of the remote side */
631			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
632			break;
633
634		default:
635			return (ENOTTY);
636	}
637	return (0);
638} /* tapioctl */
639
640
641/*
642 * tapread
643 *
644 * the cdevsw read interface - reads a packet at a time, or at
645 * least as much of a packet as can be read
646 */
647static int
648tapread(dev, uio, flag)
649	dev_t		 dev;
650	struct uio	*uio;
651	int		 flag;
652{
653	struct tap_softc	*tp = dev->si_drv1;
654	struct ifnet		*ifp = &tp->tap_if;
655	struct mbuf		*m = NULL;
656	int			 error = 0, len, s;
657
658	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
659
660	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
661		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
662			ifp->if_xname, minor(dev), tp->tap_flags);
663
664		return (EHOSTDOWN);
665	}
666
667	tp->tap_flags &= ~TAP_RWAIT;
668
669	/* sleep until we get a packet */
670	do {
671		s = splimp();
672		IF_DEQUEUE(&ifp->if_snd, m);
673		splx(s);
674
675		if (m == NULL) {
676			if (flag & IO_NDELAY)
677				return (EWOULDBLOCK);
678
679			tp->tap_flags |= TAP_RWAIT;
680			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
681			if (error)
682				return (error);
683		}
684	} while (m == NULL);
685
686	/* feed packet to bpf */
687	BPF_MTAP(ifp, m);
688
689	/* xfer packet to user space */
690	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
691		len = min(uio->uio_resid, m->m_len);
692		if (len == 0)
693			break;
694
695		error = uiomove(mtod(m, void *), len, uio);
696		m = m_free(m);
697	}
698
699	if (m != NULL) {
700		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
701			minor(dev));
702		m_freem(m);
703	}
704
705	return (error);
706} /* tapread */
707
708
709/*
710 * tapwrite
711 *
712 * the cdevsw write interface - an atomic write is a packet - or else!
713 */
714static int
715tapwrite(dev, uio, flag)
716	dev_t		 dev;
717	struct uio	*uio;
718	int		 flag;
719{
720	struct tap_softc	*tp = dev->si_drv1;
721	struct ifnet		*ifp = &tp->tap_if;
722	struct mbuf		*top = NULL, **mp = NULL, *m = NULL;
723	int			 error = 0, tlen, mlen;
724
725	TAPDEBUG("%s writting, minor = %#x\n",
726		ifp->if_xname, minor(dev));
727
728	if (uio->uio_resid == 0)
729		return (0);
730
731	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
732		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
733			ifp->if_xname, uio->uio_resid, minor(dev));
734
735		return (EIO);
736	}
737	tlen = uio->uio_resid;
738
739	/* get a header mbuf */
740	MGETHDR(m, M_DONTWAIT, MT_DATA);
741	if (m == NULL)
742		return (ENOBUFS);
743	mlen = MHLEN;
744
745	top = 0;
746	mp = &top;
747	while ((error == 0) && (uio->uio_resid > 0)) {
748		m->m_len = min(mlen, uio->uio_resid);
749		error = uiomove(mtod(m, void *), m->m_len, uio);
750		*mp = m;
751		mp = &m->m_next;
752		if (uio->uio_resid > 0) {
753			MGET(m, M_DONTWAIT, MT_DATA);
754			if (m == NULL) {
755				error = ENOBUFS;
756				break;
757			}
758			mlen = MLEN;
759		}
760	}
761	if (error) {
762		ifp->if_ierrors ++;
763		if (top)
764			m_freem(top);
765		return (error);
766	}
767
768	top->m_pkthdr.len = tlen;
769	top->m_pkthdr.rcvif = ifp;
770
771	/* Pass packet up to parent. */
772	(*ifp->if_input)(ifp, top);
773	ifp->if_ipackets ++; /* ibytes are counted in parent */
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 */
786static int
787tappoll(dev, events, td)
788	dev_t		 dev;
789	int		 events;
790	struct thread	*td;
791{
792	struct tap_softc	*tp = dev->si_drv1;
793	struct ifnet		*ifp = &tp->tap_if;
794	int			 s, revents = 0;
795
796	TAPDEBUG("%s polling, minor = %#x\n",
797		ifp->if_xname, minor(dev));
798
799	s = splimp();
800	if (events & (POLLIN | POLLRDNORM)) {
801		if (ifp->if_snd.ifq_len > 0) {
802			TAPDEBUG("%s have data in queue. len = %d, " \
803				"minor = %#x\n", ifp->if_xname,
804				ifp->if_snd.ifq_len, minor(dev));
805
806			revents |= (events & (POLLIN | POLLRDNORM));
807		} else {
808			TAPDEBUG("%s waiting for data, minor = %#x\n",
809				ifp->if_xname, minor(dev));
810
811			selrecord(td, &tp->tap_rsel);
812		}
813	}
814
815	if (events & (POLLOUT | POLLWRNORM))
816		revents |= (events & (POLLOUT | POLLWRNORM));
817
818	splx(s);
819	return (revents);
820} /* tappoll */
821