if_tap.c revision 63803
12966Swollman/*
241035Sdima * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
31590Srgrimes * All rights reserved.
44699Sjkh *
534706Sbde * Redistribution and use in source and binary forms, with or without
65766Sbde * modification, are permitted provided that the following conditions
71930Swollman * are met:
81930Swollman * 1. Redistributions of source code must retain the above copyright
938653Sgpalmer *    notice, this list of conditions and the following disclaimer.
1038653Sgpalmer * 2. Redistributions in binary form must reproduce the above copyright
1138653Sgpalmer *    notice, this list of conditions and the following disclaimer in the
1238653Sgpalmer *    documentation and/or other materials provided with the distribution.
1338653Sgpalmer *
1438653Sgpalmer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538653Sgpalmer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638653Sgpalmer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738653Sgpalmer * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838653Sgpalmer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938653Sgpalmer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2039614Sbde * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138653Sgpalmer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238653Sgpalmer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338653Sgpalmer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438653Sgpalmer * SUCH DAMAGE.
2538653Sgpalmer *
2638653Sgpalmer * BASED ON:
2738653Sgpalmer * -------------------------------------------------------------------------
2838653Sgpalmer *
2938653Sgpalmer * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
3038653Sgpalmer * Nottingham University 1987.
3138653Sgpalmer */
3238653Sgpalmer
3338653Sgpalmer/*
3438653Sgpalmer * $FreeBSD: head/sys/net/if_tap.c 63803 2000-07-24 15:32:26Z nsayer $
3541003Sgpalmer * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
3638653Sgpalmer */
3741003Sgpalmer
3838653Sgpalmer#include "opt_inet.h"
3938653Sgpalmer
4040826Sjoerg#include <sys/param.h>
4138653Sgpalmer#include <sys/conf.h>
4238653Sgpalmer#include <sys/filedesc.h>
4338653Sgpalmer#include <sys/filio.h>
4438653Sgpalmer#include <sys/kernel.h>
4538653Sgpalmer#include <sys/malloc.h>
4638653Sgpalmer#include <sys/mbuf.h>
4738653Sgpalmer#include <sys/poll.h>
4838653Sgpalmer#include <sys/proc.h>
4938653Sgpalmer#include <sys/signalvar.h>
5038653Sgpalmer#include <sys/socket.h>
5138653Sgpalmer#include <sys/sockio.h>
5238653Sgpalmer#include <sys/sysctl.h>
5338653Sgpalmer#include <sys/systm.h>
5438653Sgpalmer#include <sys/ttycom.h>
5538653Sgpalmer#include <sys/uio.h>
5638653Sgpalmer#include <sys/vnode.h>
5738653Sgpalmer
5840334Speter#include <net/bpf.h>
5938653Sgpalmer#include <net/ethernet.h>
6038653Sgpalmer#include <net/if.h>
6138653Sgpalmer#include <net/if_arp.h>
6238653Sgpalmer#include <net/route.h>
6341003Sgpalmer
6438653Sgpalmer#include <netinet/in.h>
6538653Sgpalmer
6638653Sgpalmer#include <net/if_tapvar.h>
6738653Sgpalmer#include <net/if_tap.h>
6838653Sgpalmer
6938653Sgpalmer
7038653Sgpalmer#define CDEV_NAME	"tap"
7138653Sgpalmer#define CDEV_MAJOR	149
7238653Sgpalmer#define TAPDEBUG	if (tapdebug) printf
7338653Sgpalmer
7438653Sgpalmer#define TAP		"tap"
7538653Sgpalmer#define VMNET		"vmnet"
7638653Sgpalmer#define VMNET_DEV_MASK	0x00010000
7738653Sgpalmer
7838653Sgpalmer/* module */
7938653Sgpalmerstatic int 		tapmodevent	__P((module_t, int, void *));
8038653Sgpalmer
8138653Sgpalmer/* device */
8239614Sbdestatic void		tapcreate	__P((dev_t));
8338653Sgpalmer
8438653Sgpalmer/* network interface */
8538653Sgpalmerstatic void		tapifstart	__P((struct ifnet *));
8638653Sgpalmerstatic int		tapifioctl	__P((struct ifnet *, u_long, caddr_t));
8738653Sgpalmerstatic void		tapifinit	__P((void *));
8838653Sgpalmer
8938653Sgpalmer/* character device */
9038653Sgpalmerstatic d_open_t		tapopen;
9138653Sgpalmerstatic d_close_t	tapclose;
9238653Sgpalmerstatic d_read_t		tapread;
9338653Sgpalmerstatic d_write_t	tapwrite;
9438653Sgpalmerstatic d_ioctl_t	tapioctl;
9538653Sgpalmerstatic d_poll_t		tappoll;
9638653Sgpalmer
9738653Sgpalmerstatic struct cdevsw	tap_cdevsw = {
9838653Sgpalmer	/* open */	tapopen,
9939614Sbde	/* close */	tapclose,
10039614Sbde	/* read */	tapread,
10138653Sgpalmer	/* write */	tapwrite,
10238653Sgpalmer	/* ioctl */	tapioctl,
10338653Sgpalmer	/* poll */	tappoll,
10438653Sgpalmer	/* mmap */	nommap,
10538653Sgpalmer	/* startegy */	nostrategy,
10638653Sgpalmer	/* dev name */	CDEV_NAME,
10738653Sgpalmer	/* dev major */	CDEV_MAJOR,
10839914Sdfr	/* dump */	nodump,
10938653Sgpalmer	/* psize */	nopsize,
11038653Sgpalmer	/* flags */	0,
11138653Sgpalmer	/* bmaj */	-1
11238653Sgpalmer};
11338653Sgpalmer
11438653Sgpalmerstatic int		taprefcnt = 0;		/* module ref. counter   */
11538653Sgpalmerstatic int		taplastunit = -1;	/* max. open unit number */
11638653Sgpalmerstatic int		tapdebug = 0;		/* debug flag            */
11738653Sgpalmer
11838653SgpalmerMALLOC_DECLARE(M_TAP);
11938653SgpalmerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
12038653SgpalmerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
12138653SgpalmerDEV_MODULE(if_tap, tapmodevent, NULL);
12238653Sgpalmer
12338653Sgpalmer/*
12438653Sgpalmer * tapmodevent
12538653Sgpalmer *
12638653Sgpalmer * module event handler
12738653Sgpalmer */
12838653Sgpalmerstatic int
12938653Sgpalmertapmodevent(mod, type, data)
13038653Sgpalmer	module_t	 mod;
13138653Sgpalmer	int		 type;
13238653Sgpalmer	void		*data;
13338653Sgpalmer{
13438653Sgpalmer	static int		 attached = 0;
13538653Sgpalmer	struct ifnet		*ifp = NULL;
13638653Sgpalmer	int			 unit, s;
13738653Sgpalmer
13838653Sgpalmer	switch (type) {
13938653Sgpalmer	case MOD_LOAD:
14038653Sgpalmer		if (attached)
14138653Sgpalmer			return (EEXIST);
14238653Sgpalmer
14338653Sgpalmer		cdevsw_add(&tap_cdevsw);
14438653Sgpalmer		attached = 1;
14538653Sgpalmer	break;
14638653Sgpalmer
14741035Sdima	case MOD_UNLOAD:
14838653Sgpalmer		if (taprefcnt > 0)
14938653Sgpalmer			return (EBUSY);
15038653Sgpalmer
15138653Sgpalmer		cdevsw_remove(&tap_cdevsw);
15238653Sgpalmer
15338653Sgpalmer		unit = 0;
15438653Sgpalmer		while (unit <= taplastunit) {
15538653Sgpalmer			s = splimp();
15638653Sgpalmer			TAILQ_FOREACH(ifp, &ifnet, if_link)
15738653Sgpalmer				if ((strcmp(ifp->if_name, TAP) == 0) ||
15838653Sgpalmer				    (strcmp(ifp->if_name, VMNET) == 0))
15938653Sgpalmer					if (ifp->if_unit == unit)
16038653Sgpalmer						break;
16138653Sgpalmer			splx(s);
16239928Ssef
16338653Sgpalmer			if (ifp != NULL) {
16438653Sgpalmer				struct tap_softc	*tp = ifp->if_softc;
16538653Sgpalmer
16638653Sgpalmer				TAPDEBUG("detaching %s%d. minor = %#x, " \
16738653Sgpalmer					"taplastunit = %d\n",
16838653Sgpalmer					ifp->if_name, unit, minor(tp->tap_dev),
16938653Sgpalmer					taplastunit);
17038653Sgpalmer
17138653Sgpalmer				s = splimp();
17238653Sgpalmer				ether_ifdetach(ifp, 1);
17338653Sgpalmer				splx(s);
17438653Sgpalmer				destroy_dev(tp->tap_dev);
17538653Sgpalmer				FREE(tp, M_TAP);
17638653Sgpalmer			}
17738653Sgpalmer			else
17841035Sdima				unit ++;
17938653Sgpalmer		}
18038653Sgpalmer
18138653Sgpalmer		attached = 0;
18238653Sgpalmer	break;
18338653Sgpalmer
18438653Sgpalmer	default:
18538653Sgpalmer		return (EOPNOTSUPP);
18638653Sgpalmer	}
18738653Sgpalmer
18838653Sgpalmer	return (0);
18938653Sgpalmer} /* tapmodevent */
19038653Sgpalmer
19138653Sgpalmer
19238653Sgpalmer/*
19338653Sgpalmer * tapcreate
19438653Sgpalmer *
19538653Sgpalmer * to create interface
19638653Sgpalmer */
19738653Sgpalmerstatic void
19838653Sgpalmertapcreate(dev)
19938653Sgpalmer	dev_t	dev;
2001590Srgrimes{
20139614Sbde	struct ifnet		*ifp = NULL;
20239614Sbde	struct tap_softc	*tp = NULL;
20339614Sbde	unsigned short		 macaddr_hi;
20434554Sjb	int			 unit, s;
20534554Sjb	char			*name = NULL;
20634554Sjb
20734554Sjb	/* allocate driver storage and create device */
20836064Sjb	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK);
20938653Sgpalmer	bzero(tp, sizeof(*tp));
21038653Sgpalmer
21138653Sgpalmer	/* select device: tap or vmnet */
21238653Sgpalmer	if (minor(dev) & VMNET_DEV_MASK) {
21338653Sgpalmer		name = VMNET;
21438653Sgpalmer		unit = lminor(dev) & 0xff;
21538653Sgpalmer		tp->tap_flags |= TAP_VMNET;
21638653Sgpalmer	}
21738653Sgpalmer	else {
21838653Sgpalmer		name = TAP;
21938653Sgpalmer		unit = lminor(dev);
22038653Sgpalmer	}
22141035Sdima
22236064Sjb	tp->tap_dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL,
22334554Sjb						0600, "%s%d", name, unit);
2241590Srgrimes	tp->tap_dev->si_drv1 = dev->si_drv1 = tp;
225
226	/* generate fake MAC address: 00 bd xx xx xx unit_no */
227	macaddr_hi = htons(0x00bd);
228	bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
229	bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
230	tp->arpcom.ac_enaddr[5] = (u_char)unit;
231
232	/* fill the rest and attach interface */
233	ifp = &tp->tap_if;
234	ifp->if_softc = tp;
235
236	ifp->if_unit = unit;
237	if (unit > taplastunit)
238		taplastunit = unit;
239
240	ifp->if_name = name;
241	ifp->if_init = tapifinit;
242	ifp->if_output = ether_output;
243	ifp->if_start = tapifstart;
244	ifp->if_ioctl = tapifioctl;
245	ifp->if_mtu = ETHERMTU;
246	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
247	ifp->if_snd.ifq_maxlen = ifqmaxlen;
248
249	s = splimp();
250	ether_ifattach(ifp, 1);
251	splx(s);
252
253	tp->tap_flags |= TAP_INITED;
254
255	TAPDEBUG("interface %s%d created. minor = %#x\n",
256			ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
257} /* tapcreate */
258
259
260/*
261 * tapopen
262 *
263 * to open tunnel. must be superuser
264 */
265static int
266tapopen(dev, flag, mode, p)
267	dev_t		 dev;
268	int		 flag;
269	int		 mode;
270	struct proc	*p;
271{
272	struct tap_softc	*tp = NULL;
273	int			 error;
274
275	if ((error = suser(p)) != 0)
276		return (error);
277
278	tp = dev->si_drv1;
279	if (tp == NULL) {
280		tapcreate(dev);
281		tp = dev->si_drv1;
282	}
283
284	if (tp->tap_flags & TAP_OPEN)
285		return (EBUSY);
286
287	tp->tap_pid = p->p_pid;
288	tp->tap_flags |= TAP_OPEN;
289	taprefcnt ++;
290
291	TAPDEBUG("%s%d is open. minor = %#x, refcnt = %d, taplastunit = %d\n",
292		tp->tap_if.if_name, tp->tap_if.if_unit,
293		minor(tp->tap_dev), taprefcnt, taplastunit);
294
295	return (0);
296} /* tapopen */
297
298
299/*
300 * tapclose
301 *
302 * close the device - mark i/f down & delete routing info
303 */
304static int
305tapclose(dev, foo, bar, p)
306	dev_t		 dev;
307	int		 foo;
308	int		 bar;
309	struct proc	*p;
310{
311	int			 s;
312	struct tap_softc	*tp = dev->si_drv1;
313	struct ifnet		*ifp = &tp->tap_if;
314	struct mbuf		*m = NULL;
315
316	/* junk all pending output */
317
318	s = splimp();
319	do {
320		IF_DEQUEUE(&ifp->if_snd, m);
321		if (m != NULL)
322			m_freem(m);
323	} while (m != NULL);
324	splx(s);
325
326	/*
327	 * do not bring the interface down, and do not anything with
328	 * interface, if we are in VMnet mode. just close the device.
329	 */
330
331	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
332		s = splimp();
333		if_down(ifp);
334		if (ifp->if_flags & IFF_RUNNING) {
335			/* find internet addresses and delete routes */
336			struct ifaddr	*ifa = NULL;
337
338			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
339				if (ifa->ifa_addr->sa_family == AF_INET) {
340					rtinit(ifa, (int)RTM_DELETE, 0);
341
342					/* remove address from interface */
343					bzero(ifa->ifa_addr,
344						   sizeof(*(ifa->ifa_addr)));
345					bzero(ifa->ifa_dstaddr,
346						   sizeof(*(ifa->ifa_dstaddr)));
347					bzero(ifa->ifa_netmask,
348						   sizeof(*(ifa->ifa_netmask)));
349				}
350			}
351
352			ifp->if_flags &= ~IFF_RUNNING;
353		}
354		splx(s);
355	}
356
357	funsetown(tp->tap_sigio);
358	selwakeup(&tp->tap_rsel);
359
360	tp->tap_flags &= ~TAP_OPEN;
361	tp->tap_pid = 0;
362
363	taprefcnt --;
364	if (taprefcnt < 0) {
365		taprefcnt = 0;
366		printf("%s%d minor = %#x, refcnt = %d is out of sync. " \
367			"set refcnt to 0\n", ifp->if_name, ifp->if_unit,
368			minor(tp->tap_dev), taprefcnt);
369	}
370
371	TAPDEBUG("%s%d is closed. minor = %#x, refcnt = %d, taplastunit = %d\n",
372			ifp->if_name, ifp->if_unit, minor(tp->tap_dev),
373			taprefcnt, taplastunit);
374
375	return (0);
376} /* tapclose */
377
378
379/*
380 * tapifinit
381 *
382 * network interface initialization function
383 */
384static void
385tapifinit(xtp)
386	void	*xtp;
387{
388	struct tap_softc	*tp = (struct tap_softc *)xtp;
389	struct ifnet		*ifp = &tp->tap_if;
390
391	TAPDEBUG("initializing %s%d, minor = %#x\n",
392			ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
393
394	ifp->if_flags |= IFF_RUNNING;
395	ifp->if_flags &= ~IFF_OACTIVE;
396
397	/* attempt to start output */
398	tapifstart(ifp);
399} /* tapifinit */
400
401
402/*
403 * tapifioctl
404 *
405 * Process an ioctl request on network interface
406 */
407int
408tapifioctl(ifp, cmd, data)
409	struct ifnet	*ifp;
410	u_long		 cmd;
411	caddr_t		 data;
412{
413	struct tap_softc 	*tp = (struct tap_softc *)(ifp->if_softc);
414	struct ifstat		*ifs = NULL;
415	int			 s, dummy;
416
417	switch (cmd) {
418		case SIOCSIFADDR:
419		case SIOCGIFADDR:
420		case SIOCSIFMTU:
421			s = splimp();
422			dummy = ether_ioctl(ifp, cmd, data);
423			splx(s);
424			return (dummy);
425
426		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
427		case SIOCADDMULTI:
428		case SIOCDELMULTI:
429		break;
430
431		case SIOCGIFSTATUS:
432			s = splimp();
433			ifs = (struct ifstat *)data;
434			dummy = strlen(ifs->ascii);
435			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
436				snprintf(ifs->ascii + dummy,
437					sizeof(ifs->ascii) - dummy,
438					"\tOpened by PID %d\n", tp->tap_pid);
439			splx(s);
440		break;
441
442		default:
443			return (EINVAL);
444	}
445
446	return (0);
447} /* tapifioctl */
448
449
450/*
451 * tapifstart
452 *
453 * queue packets from higher level ready to put out
454 */
455static void
456tapifstart(ifp)
457	struct ifnet	*ifp;
458{
459	struct tap_softc	*tp = ifp->if_softc;
460	int			 s;
461
462	TAPDEBUG("%s%d starting, minor = %#x\n",
463			ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
464
465	/*
466	 * do not junk pending output if we are in VMnet mode.
467	 * XXX: can this do any harm because of queue overflow?
468	 */
469
470	if (((tp->tap_flags & TAP_VMNET) == 0) &&
471	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
472		struct mbuf	*m = NULL;
473
474		TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
475			ifp->if_name, ifp->if_unit,
476			minor(tp->tap_dev), tp->tap_flags);
477
478		s = splimp();
479		do {
480			IF_DEQUEUE(&ifp->if_snd, m);
481			if (m != NULL)
482				m_freem(m);
483			ifp->if_oerrors ++;
484		} while (m != NULL);
485		splx(s);
486
487		return;
488	}
489
490	s = splimp();
491	ifp->if_flags |= IFF_OACTIVE;
492
493	if (ifp->if_snd.ifq_len != 0) {
494		if (tp->tap_flags & TAP_RWAIT) {
495			tp->tap_flags &= ~TAP_RWAIT;
496			wakeup((caddr_t)tp);
497		}
498
499		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
500			pgsigio(tp->tap_sigio, SIGIO, 0);
501
502		selwakeup(&tp->tap_rsel);
503		ifp->if_opackets ++; /* obytes are counted in ether_output */
504	}
505
506	ifp->if_flags &= ~IFF_OACTIVE;
507	splx(s);
508} /* tapifstart */
509
510
511/*
512 * tapioctl
513 *
514 * the cdevsw interface is now pretty minimal
515 */
516static int
517tapioctl(dev, cmd, data, flag, p)
518	dev_t		 dev;
519	u_long		 cmd;
520	caddr_t		 data;
521	int		 flag;
522	struct proc	*p;
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 */
614		case SIOCGIFADDR:
615			bcopy(tp->arpcom.ac_enaddr, data, ETHER_ADDR_LEN);
616		break;
617
618		case SIOCSIFADDR:	/* set MAC address */
619			s = splimp();
620			bcopy(data, tp->arpcom.ac_enaddr, ETHER_ADDR_LEN);
621			splx(s);
622		break;
623
624		default:
625			return (ENOTTY);
626	}
627	return (0);
628} /* tapioctl */
629
630
631/*
632 * tapread
633 *
634 * the cdevsw read interface - reads a packet at a time, or at
635 * least as much of a packet as can be read
636 */
637static int
638tapread(dev, uio, flag)
639	dev_t		 dev;
640	struct uio	*uio;
641	int		 flag;
642{
643	struct tap_softc	*tp = dev->si_drv1;
644	struct ifnet		*ifp = &tp->tap_if;
645	struct mbuf		*m = NULL, *m0 = NULL;
646	int			 error = 0, len, s;
647
648	TAPDEBUG("%s%d reading, minor = %#x\n",
649			ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
650
651	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
652		TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
653				ifp->if_name, ifp->if_unit,
654				minor(tp->tap_dev), tp->tap_flags);
655
656		return (EHOSTDOWN);
657	}
658
659	tp->tap_flags &= ~TAP_RWAIT;
660
661	/* sleep until we get a packet */
662	do {
663		s = splimp();
664		IF_DEQUEUE(&ifp->if_snd, m0);
665		splx(s);
666
667		if (m0 == NULL) {
668			if (flag & IO_NDELAY)
669				return (EWOULDBLOCK);
670
671			tp->tap_flags |= TAP_RWAIT;
672			error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0);
673			if (error)
674				return (error);
675		}
676	} while (m0 == NULL);
677
678	/* feed packet to bpf */
679	if (ifp->if_bpf != NULL)
680		bpf_mtap(ifp, m0);
681
682	/* xfer packet to user space */
683	while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) {
684		len = min(uio->uio_resid, m0->m_len);
685		if (len == 0)
686			break;
687
688		error = uiomove(mtod(m0, caddr_t), len, uio);
689		MFREE(m0, m);
690		m0 = m;
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 */
708static int
709tapwrite(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 */
789static int
790tappoll(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 */
825